devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
244 lines (198 loc) • 7.84 kB
JavaScript
"use strict";
var $ = require("../../core/renderer"),
domAdapter = require("../../core/dom_adapter"),
eventsEngine = require("../../events/core/events_engine"),
ready = require("../../core/utils/ready_callbacks").add,
translator = require("../../animation/translator"),
Widget = require("../widget/ui.widget"),
eventUtils = require("../../events/utils"),
commonUtils = require("../../core/utils/common"),
isPlainObject = require("../../core/utils/type").isPlainObject,
extend = require("../../core/utils/extend").extend,
pointerEvents = require("../../events/pointer");
var SCROLLBAR = "dxScrollbar",
SCROLLABLE_SCROLLBAR_CLASS = "dx-scrollable-scrollbar",
SCROLLABLE_SCROLLBAR_ACTIVE_CLASS = SCROLLABLE_SCROLLBAR_CLASS + "-active",
SCROLLABLE_SCROLL_CLASS = "dx-scrollable-scroll",
SCROLLABLE_SCROLL_CONTENT_CLASS = "dx-scrollable-scroll-content",
HOVER_ENABLED_STATE = "dx-scrollbar-hoverable",
HORIZONTAL = "horizontal",
THUMB_MIN_SIZE = 15;
var SCROLLBAR_VISIBLE = {
onScroll: "onScroll",
onHover: "onHover",
always: "always",
never: "never"
};
var Scrollbar = Widget.inherit({
_getDefaultOptions: function _getDefaultOptions() {
return extend(this.callBase(), {
direction: null,
visible: false,
activeStateEnabled: false,
visibilityMode: SCROLLBAR_VISIBLE.onScroll,
containerSize: 0,
contentSize: 0,
expandable: true
});
},
_init: function _init() {
this.callBase();
this._isHovered = false;
},
_initMarkup: function _initMarkup() {
this._renderThumb();
this.callBase();
},
_render: function _render() {
this.callBase();
this._renderDirection();
this._update();
this._attachPointerDownHandler();
this.option("hoverStateEnabled", this._isHoverMode());
this.$element().toggleClass(HOVER_ENABLED_STATE, this.option("hoverStateEnabled"));
},
_renderThumb: function _renderThumb() {
this._$thumb = $("<div>").addClass(SCROLLABLE_SCROLL_CLASS);
$("<div>").addClass(SCROLLABLE_SCROLL_CONTENT_CLASS).appendTo(this._$thumb);
this.$element().addClass(SCROLLABLE_SCROLLBAR_CLASS).append(this._$thumb);
},
isThumb: function isThumb($element) {
return !!this.$element().find($element).length;
},
_isHoverMode: function _isHoverMode() {
var visibilityMode = this.option("visibilityMode");
return (visibilityMode === SCROLLBAR_VISIBLE.onHover || visibilityMode === SCROLLBAR_VISIBLE.always) && this.option("expandable");
},
_renderDirection: function _renderDirection() {
var direction = this.option("direction");
this.$element().addClass("dx-scrollbar-" + direction);
this._dimension = direction === HORIZONTAL ? "width" : "height";
this._prop = direction === HORIZONTAL ? "left" : "top";
},
_attachPointerDownHandler: function _attachPointerDownHandler() {
eventsEngine.on(this._$thumb, eventUtils.addNamespace(pointerEvents.down, SCROLLBAR), this.feedbackOn.bind(this));
},
feedbackOn: function feedbackOn() {
this.$element().addClass(SCROLLABLE_SCROLLBAR_ACTIVE_CLASS);
activeScrollbar = this;
},
feedbackOff: function feedbackOff() {
this.$element().removeClass(SCROLLABLE_SCROLLBAR_ACTIVE_CLASS);
activeScrollbar = null;
},
cursorEnter: function cursorEnter() {
this._isHovered = true;
this.option("visible", true);
},
cursorLeave: function cursorLeave() {
this._isHovered = false;
this.option("visible", false);
},
_renderDimensions: function _renderDimensions() {
this._$thumb.css({
width: this.option("width"),
height: this.option("height")
});
},
_toggleVisibility: function _toggleVisibility(visible) {
if (this.option("visibilityMode") === SCROLLBAR_VISIBLE.onScroll) {
// NOTE: need to relayout thumb and show it instantly
this._$thumb.css("opacity");
}
visible = this._adjustVisibility(visible);
this.option().visible = visible;
this._$thumb.toggleClass("dx-state-invisible", !visible);
},
_adjustVisibility: function _adjustVisibility(visible) {
if (this.containerToContentRatio() && !this._needScrollbar()) {
return false;
}
switch (this.option("visibilityMode")) {
case SCROLLBAR_VISIBLE.onScroll:
break;
case SCROLLBAR_VISIBLE.onHover:
visible = visible || !!this._isHovered;
break;
case SCROLLBAR_VISIBLE.never:
visible = false;
break;
case SCROLLBAR_VISIBLE.always:
visible = true;
break;
}
return visible;
},
moveTo: function moveTo(location) {
if (this._isHidden()) {
return;
}
if (isPlainObject(location)) {
location = location[this._prop] || 0;
}
var scrollBarLocation = {};
scrollBarLocation[this._prop] = this._calculateScrollBarPosition(location);
translator.move(this._$thumb, scrollBarLocation);
},
_calculateScrollBarPosition: function _calculateScrollBarPosition(location) {
return -location * this._thumbRatio;
},
_update: function _update() {
var containerSize = Math.round(this.option("containerSize")),
contentSize = Math.round(this.option("contentSize"));
this._containerToContentRatio = contentSize ? containerSize / contentSize : containerSize;
var thumbSize = Math.round(Math.max(Math.round(containerSize * this._containerToContentRatio), THUMB_MIN_SIZE));
this._thumbRatio = (containerSize - thumbSize) / (contentSize - containerSize);
this.option(this._dimension, thumbSize);
this.$element().css("display", this._needScrollbar() ? "" : "none");
},
_isHidden: function _isHidden() {
return this.option("visibilityMode") === SCROLLBAR_VISIBLE.never;
},
_needScrollbar: function _needScrollbar() {
return !this._isHidden() && this._containerToContentRatio < 1;
},
containerToContentRatio: function containerToContentRatio() {
return this._containerToContentRatio;
},
_normalizeSize: function _normalizeSize(size) {
return isPlainObject(size) ? size[this._dimension] || 0 : size;
},
_clean: function _clean() {
this.callBase();
if (this === activeScrollbar) {
activeScrollbar = null;
}
eventsEngine.off(this._$thumb, "." + SCROLLBAR);
},
_optionChanged: function _optionChanged(args) {
if (this._isHidden()) {
return;
}
switch (args.name) {
case "containerSize":
case "contentSize":
this.option()[args.name] = this._normalizeSize(args.value);
this._update();
break;
case "visibilityMode":
case "direction":
this._invalidate();
break;
default:
this.callBase.apply(this, arguments);
}
},
update: commonUtils.deferRenderer(function () {
this._adjustVisibility() && this.option("visible", true);
})
});
var activeScrollbar = null;
ready(function () {
eventsEngine.subscribeGlobal(domAdapter.getDocument(), eventUtils.addNamespace(pointerEvents.up, SCROLLBAR), function () {
if (activeScrollbar) {
activeScrollbar.feedbackOff();
}
});
});
module.exports = Scrollbar;