devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
292 lines (239 loc) • 9.95 kB
JavaScript
"use strict";
var $ = require("../../core/renderer"),
eventsEngine = require("../../events/core/events_engine"),
noop = require("../../core/utils/common").noop,
each = require("../../core/utils/iterator").each,
devices = require("../../core/devices"),
Class = require("../../core/class"),
Scrollbar = require("./ui.scrollbar");
var SCROLLABLE_NATIVE = "dxNativeScrollable",
SCROLLABLE_NATIVE_CLASS = "dx-scrollable-native",
SCROLLABLE_SCROLLBAR_SIMULATED = "dx-scrollable-scrollbar-simulated",
SCROLLABLE_SCROLLBARS_HIDDEN = "dx-scrollable-scrollbars-hidden",
VERTICAL = "vertical",
HORIZONTAL = "horizontal",
HIDE_SCROLLBAR_TIMEOUT = 500;
var NativeStrategy = Class.inherit({
ctor: function ctor(scrollable) {
this._init(scrollable);
},
_init: function _init(scrollable) {
this._component = scrollable;
this._$element = scrollable.$element();
this._$container = scrollable._$container;
this._$content = scrollable._$content;
this._direction = scrollable.option("direction");
this._useSimulatedScrollbar = scrollable.option("useSimulatedScrollbar");
this._showScrollbar = scrollable.option("showScrollbar");
this.option = scrollable.option.bind(scrollable);
this._createActionByOption = scrollable._createActionByOption.bind(scrollable);
this._isLocked = scrollable._isLocked.bind(scrollable);
this._isDirection = scrollable._isDirection.bind(scrollable);
this._allowedDirection = scrollable._allowedDirection.bind(scrollable);
},
render: function render() {
this._renderPushBackOffset();
var device = devices.real(),
deviceType = device.platform;
this._$element.addClass(SCROLLABLE_NATIVE_CLASS).addClass(SCROLLABLE_NATIVE_CLASS + "-" + deviceType).toggleClass(SCROLLABLE_SCROLLBARS_HIDDEN, !this._showScrollbar);
if (this._showScrollbar && this._useSimulatedScrollbar) {
this._renderScrollbars();
}
},
updateBounds: noop,
_renderPushBackOffset: function _renderPushBackOffset() {
var pushBackValue = this.option("pushBackValue");
if (!pushBackValue && !this._component._lastPushBackValue) {
return;
}
this._$content.css({
paddingTop: pushBackValue,
paddingBottom: pushBackValue
});
this._component._lastPushBackValue = pushBackValue;
},
_renderScrollbars: function _renderScrollbars() {
this._scrollbars = {};
this._hideScrollbarTimeout = 0;
this._$element.addClass(SCROLLABLE_SCROLLBAR_SIMULATED);
this._renderScrollbar(VERTICAL);
this._renderScrollbar(HORIZONTAL);
},
_renderScrollbar: function _renderScrollbar(direction) {
if (!this._isDirection(direction)) {
return;
}
this._scrollbars[direction] = new Scrollbar($("<div>").appendTo(this._$element), {
direction: direction,
expandable: this._component.option("scrollByThumb")
});
},
handleInit: noop,
handleStart: function handleStart() {
this._disablePushBack = true;
},
handleMove: function handleMove(e) {
if (this._isLocked()) {
e.cancel = true;
return;
}
if (this._allowedDirection()) {
e.originalEvent.isScrollingEvent = true;
}
},
handleEnd: function handleEnd() {
this._disablePushBack = false;
},
handleCancel: noop,
handleStop: noop,
_eachScrollbar: function _eachScrollbar(callback) {
callback = callback.bind(this);
each(this._scrollbars || {}, function (direction, scrollbar) {
callback(scrollbar, direction);
});
},
createActions: function createActions() {
this._scrollAction = this._createActionByOption("onScroll");
this._updateAction = this._createActionByOption("onUpdated");
},
_createActionArgs: function _createActionArgs() {
var location = this.location();
return {
event: this._eventForUserAction,
scrollOffset: {
top: -location.top,
left: -location.left
},
reachedLeft: this._isDirection(HORIZONTAL) ? location.left >= 0 : undefined,
reachedRight: this._isDirection(HORIZONTAL) ? location.left <= this._containerSize.width - this._componentContentSize.width : undefined,
reachedTop: this._isDirection(VERTICAL) ? location.top >= 0 : undefined,
reachedBottom: this._isDirection(VERTICAL) ? location.top <= this._containerSize.height - this._componentContentSize.height : undefined
};
},
handleScroll: function handleScroll(e) {
// NOTE: ignoring scroll events when scroll location was not changed (for Android browser - B250122)
if (!this._isScrollLocationChanged()) {
e.stopImmediatePropagation();
return;
}
this._eventForUserAction = e;
this._moveScrollbars();
this._scrollAction(this._createActionArgs());
this._lastLocation = this.location();
this._pushBackFromBoundary();
},
_pushBackFromBoundary: function _pushBackFromBoundary() {
var pushBackValue = this.option("pushBackValue");
if (!pushBackValue || this._disablePushBack) {
return;
}
var scrollOffset = this._containerSize.height - this._contentSize.height,
scrollTopPos = this._$container.scrollTop(),
scrollBottomPos = scrollOffset + scrollTopPos - pushBackValue * 2;
if (!scrollTopPos) {
this._$container.scrollTop(pushBackValue);
} else if (!scrollBottomPos) {
this._$container.scrollTop(pushBackValue - scrollOffset);
}
},
_isScrollLocationChanged: function _isScrollLocationChanged() {
var currentLocation = this.location(),
lastLocation = this._lastLocation || {},
isTopChanged = lastLocation.top !== currentLocation.top,
isLeftChanged = lastLocation.left !== currentLocation.left;
return isTopChanged || isLeftChanged;
},
_moveScrollbars: function _moveScrollbars() {
this._eachScrollbar(function (scrollbar) {
scrollbar.moveTo(this.location());
scrollbar.option("visible", true);
});
this._hideScrollbars();
},
_hideScrollbars: function _hideScrollbars() {
clearTimeout(this._hideScrollbarTimeout);
this._hideScrollbarTimeout = setTimeout(function () {
this._eachScrollbar(function (scrollbar) {
scrollbar.option("visible", false);
});
}.bind(this), HIDE_SCROLLBAR_TIMEOUT);
},
location: function location() {
return {
left: -this._$container.scrollLeft(),
top: this.option("pushBackValue") - this._$container.scrollTop()
};
},
disabledChanged: noop,
update: function update() {
this._update();
this._updateAction(this._createActionArgs());
},
_update: function _update() {
this._updateDimensions();
this._updateScrollbars();
},
_updateDimensions: function _updateDimensions() {
this._containerSize = {
height: this._$container.height(),
width: this._$container.width()
};
this._componentContentSize = {
height: this._component.$content().height(),
width: this._component.$content().width()
};
this._contentSize = {
height: this._$content.height(),
width: this._$content.width()
};
this._pushBackFromBoundary();
},
_updateScrollbars: function _updateScrollbars() {
this._eachScrollbar(function (scrollbar, direction) {
var dimension = direction === VERTICAL ? "height" : "width";
scrollbar.option({
containerSize: this._containerSize[dimension],
contentSize: this._componentContentSize[dimension]
});
scrollbar.update();
});
},
_allowedDirections: function _allowedDirections() {
return {
vertical: this._isDirection(VERTICAL) && this._contentSize.height > this._containerSize.height,
horizontal: this._isDirection(HORIZONTAL) && this._contentSize.width > this._containerSize.width
};
},
dispose: function dispose() {
var className = this._$element.get(0).className;
var scrollableNativeRegexp = new RegExp(SCROLLABLE_NATIVE_CLASS + "\\S*", "g");
if (scrollableNativeRegexp.test(className)) {
this._$element.removeClass(className.match(scrollableNativeRegexp).join(" "));
}
eventsEngine.off(this._$element, "." + SCROLLABLE_NATIVE);
eventsEngine.off(this._$container, "." + SCROLLABLE_NATIVE);
this._removeScrollbars();
clearTimeout(this._gestureEndTimer);
clearTimeout(this._hideScrollbarTimeout);
},
_removeScrollbars: function _removeScrollbars() {
this._eachScrollbar(function (scrollbar) {
scrollbar.$element().remove();
});
},
scrollBy: function scrollBy(distance) {
var location = this.location();
this._$container.scrollTop(-location.top - distance.top + this.option("pushBackValue"));
this._$container.scrollLeft(-location.left - distance.left);
},
validate: function validate() {
return !this.option("disabled") && this._allowedDirection();
},
getDirection: function getDirection() {
return this._allowedDirection();
},
verticalOffset: function verticalOffset() {
return this.option("pushBackValue");
}
});
module.exports = NativeStrategy;