You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5249 lines
215 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*!
* better-scroll / better-scroll
* (c) 2016-2020 ustbhuangyi
* Released under the MIT License.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BetterScroll = {}));
}(this, (function (exports) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
var propertiesConfig = [
{
sourceKey: 'scroller.scrollBehaviorX.currentPos',
key: 'x'
},
{
sourceKey: 'scroller.scrollBehaviorY.currentPos',
key: 'y'
},
{
sourceKey: 'scroller.scrollBehaviorX.hasScroll',
key: 'hasHorizontalScroll'
},
{
sourceKey: 'scroller.scrollBehaviorY.hasScroll',
key: 'hasVerticalScroll'
},
{
sourceKey: 'scroller.scrollBehaviorX.contentSize',
key: 'scrollerWidth'
},
{
sourceKey: 'scroller.scrollBehaviorY.contentSize',
key: 'scrollerHeight'
},
{
sourceKey: 'scroller.scrollBehaviorX.maxScrollPos',
key: 'maxScrollX'
},
{
sourceKey: 'scroller.scrollBehaviorY.maxScrollPos',
key: 'maxScrollY'
},
{
sourceKey: 'scroller.scrollBehaviorX.minScrollPos',
key: 'minScrollX'
},
{
sourceKey: 'scroller.scrollBehaviorY.minScrollPos',
key: 'minScrollY'
},
{
sourceKey: 'scroller.scrollBehaviorX.movingDirection',
key: 'movingDirectionX'
},
{
sourceKey: 'scroller.scrollBehaviorY.movingDirection',
key: 'movingDirectionY'
},
{
sourceKey: 'scroller.scrollBehaviorX.direction',
key: 'directionX'
},
{
sourceKey: 'scroller.scrollBehaviorY.direction',
key: 'directionY'
},
{
sourceKey: 'scroller.actions.enabled',
key: 'enabled'
},
{
sourceKey: 'scroller.animater.pending',
key: 'pending'
},
{
sourceKey: 'scroller.animater.stop',
key: 'stop'
},
{
sourceKey: 'scroller.scrollTo',
key: 'scrollTo'
},
{
sourceKey: 'scroller.scrollBy',
key: 'scrollBy'
},
{
sourceKey: 'scroller.scrollToElement',
key: 'scrollToElement'
},
{
sourceKey: 'scroller.resetPosition',
key: 'resetPosition'
}
];
function warn(msg) {
console.error("[BScroll warn]: " + msg);
}
// ssr support
var inBrowser = typeof window !== 'undefined';
var ua = inBrowser && navigator.userAgent.toLowerCase();
var isWeChatDevTools = !!(ua && /wechatdevtools/.test(ua));
var isAndroid = ua && ua.indexOf('android') > 0;
var isIOSBadVersion = (function () {
if (typeof ua === 'string') {
var regex = /os (\d\d?_\d(_\d)?)/;
var matches = regex.exec(ua);
if (!matches)
return false;
var parts = matches[1].split('_').map(function (item) {
return parseInt(item, 10);
});
// ios version >= 13.4 issue 982
return !!(parts[0] >= 13 && parts[1] >= 4);
}
return false;
})();
function getNow() {
return window.performance &&
window.performance.now &&
window.performance.timing
? window.performance.now() + window.performance.timing.navigationStart
: +new Date();
}
var extend = function (target, source) {
for (var key in source) {
target[key] = source[key];
}
return target;
};
function isUndef(v) {
return v === undefined || v === null;
}
function getDistance(x, y) {
return Math.sqrt(x * x + y * y);
}
function between(x, min, max) {
if (x < min) {
return min;
}
if (x > max) {
return max;
}
return x;
}
var elementStyle = (inBrowser &&
document.createElement('div').style);
var vendor = (function () {
if (!inBrowser) {
return false;
}
var transformNames = [
{
key: 'standard',
value: 'transform',
},
{
key: 'webkit',
value: 'webkitTransform',
},
{
key: 'Moz',
value: 'MozTransform',
},
{
key: 'O',
value: 'OTransform',
},
{
key: 'ms',
value: 'msTransform',
},
];
for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
var obj = transformNames_1[_i];
if (elementStyle[obj.value] !== undefined) {
return obj.key;
}
}
return false;
})();
function prefixStyle(style) {
if (vendor === false) {
return style;
}
if (vendor === 'standard') {
if (style === 'transitionEnd') {
return 'transitionend';
}
return style;
}
return vendor + style.charAt(0).toUpperCase() + style.substr(1);
}
function getElement(el) {
return (typeof el === 'string'
? document.querySelector(el)
: el);
}
function addEvent(el, type, fn, capture) {
el.addEventListener(type, fn, {
passive: false,
capture: !!capture,
});
}
function removeEvent(el, type, fn, capture) {
el.removeEventListener(type, fn, {
capture: !!capture,
});
}
function offset(el) {
var left = 0;
var top = 0;
while (el) {
left -= el.offsetLeft;
top -= el.offsetTop;
el = el.offsetParent;
}
return {
left: left,
top: top,
};
}
function offsetToBody(el) {
var rect = el.getBoundingClientRect();
return {
left: -(rect.left + window.pageXOffset),
top: -(rect.top + window.pageYOffset),
};
}
var cssVendor = vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
var transform = prefixStyle('transform');
var transition = prefixStyle('transition');
var hasPerspective = inBrowser && prefixStyle('perspective') in elementStyle;
// fix issue #361
var hasTouch = inBrowser && ('ontouchstart' in window || isWeChatDevTools);
var hasTransition = inBrowser && transition in elementStyle;
var style = {
transform: transform,
transition: transition,
transitionTimingFunction: prefixStyle('transitionTimingFunction'),
transitionDuration: prefixStyle('transitionDuration'),
transitionDelay: prefixStyle('transitionDelay'),
transformOrigin: prefixStyle('transformOrigin'),
transitionEnd: prefixStyle('transitionEnd'),
transitionProperty: prefixStyle('transitionProperty'),
};
var eventTypeMap = {
touchstart: 1,
touchmove: 1,
touchend: 1,
mousedown: 2,
mousemove: 2,
mouseup: 2,
};
function getRect(el) {
if (el instanceof window.SVGElement) {
var rect = el.getBoundingClientRect();
return {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height,
};
}
else {
return {
top: el.offsetTop,
left: el.offsetLeft,
width: el.offsetWidth,
height: el.offsetHeight,
};
}
}
function preventDefaultExceptionFn(el, exceptions) {
for (var i in exceptions) {
if (exceptions[i].test(el[i])) {
return true;
}
}
return false;
}
var tagExceptionFn = preventDefaultExceptionFn;
function tap(e, eventName) {
var ev = document.createEvent('Event');
ev.initEvent(eventName, true, true);
ev.pageX = e.pageX;
ev.pageY = e.pageY;
e.target.dispatchEvent(ev);
}
function click(e, event) {
if (event === void 0) { event = 'click'; }
var eventSource;
if (e.type === 'mouseup') {
eventSource = e;
}
else if (e.type === 'touchend' || e.type === 'touchcancel') {
eventSource = e.changedTouches[0];
}
var posSrc = {};
if (eventSource) {
posSrc.screenX = eventSource.screenX || 0;
posSrc.screenY = eventSource.screenY || 0;
posSrc.clientX = eventSource.clientX || 0;
posSrc.clientY = eventSource.clientY || 0;
}
var ev;
var bubbles = true;
var cancelable = true;
if (typeof MouseEvent !== 'undefined') {
try {
ev = new MouseEvent(event, extend({
bubbles: bubbles,
cancelable: cancelable,
}, posSrc));
}
catch (e) {
createEvent();
}
}
else {
createEvent();
}
function createEvent() {
ev = document.createEvent('Event');
ev.initEvent(event, bubbles, cancelable);
extend(ev, posSrc);
}
// forwardedTouchEvent set to true in case of the conflict with fastclick
ev.forwardedTouchEvent = true;
ev._constructed = true;
e.target.dispatchEvent(ev);
}
function dblclick(e) {
click(e, 'dblclick');
}
function prepend(el, target) {
var firstChild = target.firstChild;
if (firstChild) {
before(el, firstChild);
}
else {
target.appendChild(el);
}
}
function before(el, target) {
target.parentNode.insertBefore(el, target);
}
function removeChild(el, child) {
el.removeChild(child);
}
function hasClass(el, className) {
var reg = new RegExp('(^|\\s)' + className + '(\\s|$)');
return reg.test(el.className);
}
var ease = {
// easeOutQuint
swipe: {
style: 'cubic-bezier(0.23, 1, 0.32, 1)',
fn: function (t) {
return 1 + --t * t * t * t * t;
}
},
// easeOutQuard
swipeBounce: {
style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
fn: function (t) {
return t * (2 - t);
}
},
// easeOutQuart
bounce: {
style: 'cubic-bezier(0.165, 0.84, 0.44, 1)',
fn: function (t) {
return 1 - --t * t * t * t;
}
}
};
var DEFAULT_INTERVAL = 100 / 60;
var windowCompat = inBrowser && window;
function noop() { }
var requestAnimationFrame = (function () {
if (!inBrowser) {
/* istanbul ignore if */
return noop;
}
return (windowCompat.requestAnimationFrame ||
windowCompat.webkitRequestAnimationFrame ||
windowCompat.mozRequestAnimationFrame ||
windowCompat.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function (callback) {
return window.setTimeout(callback, (callback.interval || DEFAULT_INTERVAL) / 2); // make interval as precise as possible.
});
})();
var cancelAnimationFrame = (function () {
if (!inBrowser) {
/* istanbul ignore if */
return noop;
}
return (windowCompat.cancelAnimationFrame ||
windowCompat.webkitCancelAnimationFrame ||
windowCompat.mozCancelAnimationFrame ||
windowCompat.oCancelAnimationFrame ||
function (id) {
window.clearTimeout(id);
});
})();
var noop$1 = function (val) { };
var sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop$1,
set: noop$1
};
var getProperty = function (obj, key) {
var keys = key.split('.');
for (var i = 0; i < keys.length - 1; i++) {
obj = obj[keys[i]];
if (typeof obj !== 'object' || !obj)
return;
}
var lastKey = keys.pop();
if (typeof obj[lastKey] === 'function') {
return function () {
return obj[lastKey].apply(obj, arguments);
};
}
else {
return obj[lastKey];
}
};
var setProperty = function (obj, key, value) {
var keys = key.split('.');
var temp;
for (var i = 0; i < keys.length - 1; i++) {
temp = keys[i];
if (!obj[temp])
obj[temp] = {};
obj = obj[temp];
}
obj[keys.pop()] = value;
};
function propertiesProxy(target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter() {
return getProperty(this, sourceKey);
};
sharedPropertyDefinition.set = function proxySetter(val) {
setProperty(this, sourceKey, val);
};
Object.defineProperty(target, key, sharedPropertyDefinition);
}
var EventEmitter = /** @class */ (function () {
function EventEmitter(names) {
this.events = {};
this.eventTypes = {};
this.registerType(names);
}
EventEmitter.prototype.on = function (type, fn, context) {
if (context === void 0) { context = this; }
this.hasType(type);
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push([fn, context]);
return this;
};
EventEmitter.prototype.once = function (type, fn, context) {
var _this = this;
if (context === void 0) { context = this; }
this.hasType(type);
var magic = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
_this.off(type, magic);
fn.apply(context, args);
};
magic.fn = fn;
this.on(type, magic);
return this;
};
EventEmitter.prototype.off = function (type, fn) {
if (!type && !fn) {
this.events = {};
return this;
}
if (type) {
this.hasType(type);
if (!fn) {
this.events[type] = [];
return this;
}
var events = this.events[type];
if (!events) {
return this;
}
var count = events.length;
while (count--) {
if (events[count][0] === fn ||
(events[count][0] && events[count][0].fn === fn)) {
events.splice(count, 1);
}
}
return this;
}
};
EventEmitter.prototype.trigger = function (type) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
this.hasType(type);
var events = this.events[type];
if (!events) {
return;
}
var len = events.length;
var eventsCopy = __spreadArrays(events);
var ret;
for (var i = 0; i < len; i++) {
var event_1 = eventsCopy[i];
var fn = event_1[0], context = event_1[1];
if (fn) {
ret = fn.apply(context, args);
if (ret === true) {
return ret;
}
}
}
};
EventEmitter.prototype.registerType = function (names) {
var _this = this;
names.forEach(function (type) {
_this.eventTypes[type] = type;
});
};
EventEmitter.prototype.destroy = function () {
this.events = {};
this.eventTypes = {};
};
EventEmitter.prototype.hasType = function (type) {
var types = this.eventTypes;
var isType = types[type] === type;
if (!isType) {
warn("EventEmitter has used unknown event type: \"" + type + "\", should be oneof [" +
("" + Object.keys(types).map(function (_) { return JSON.stringify(_); })) +
"]");
}
};
return EventEmitter;
}());
var EventRegister = /** @class */ (function () {
function EventRegister(wrapper, events) {
this.wrapper = wrapper;
this.events = events;
this.addDOMEvents();
}
EventRegister.prototype.destroy = function () {
this.removeDOMEvents();
this.events = [];
};
EventRegister.prototype.addDOMEvents = function () {
this.handleDOMEvents(addEvent);
};
EventRegister.prototype.removeDOMEvents = function () {
this.handleDOMEvents(removeEvent);
};
EventRegister.prototype.handleDOMEvents = function (eventOperation) {
var _this = this;
var wrapper = this.wrapper;
this.events.forEach(function (event) {
eventOperation(wrapper, event.name, _this, !!event.capture);
});
};
EventRegister.prototype.handleEvent = function (e) {
var eventType = e.type;
this.events.some(function (event) {
if (event.name === eventType) {
event.handler(e);
return true;
}
return false;
});
};
return EventRegister;
}());
var CustomOptions = /** @class */ (function () {
function CustomOptions() {
}
return CustomOptions;
}());
var OptionsConstructor = /** @class */ (function (_super) {
__extends(OptionsConstructor, _super);
function OptionsConstructor() {
var _this = _super.call(this) || this;
_this.startX = 0;
_this.startY = 0;
_this.scrollX = false;
_this.scrollY = true;
_this.freeScroll = false;
_this.directionLockThreshold = 5;
_this.eventPassthrough = "" /* None */;
_this.click = false;
_this.dblclick = false;
_this.tap = '';
_this.bounce = {
top: true,
bottom: true,
left: true,
right: true,
};
_this.bounceTime = 800;
_this.momentum = true;
_this.momentumLimitTime = 300;
_this.momentumLimitDistance = 15;
_this.swipeTime = 2500;
_this.swipeBounceTime = 500;
_this.deceleration = 0.0015;
_this.flickLimitTime = 200;
_this.flickLimitDistance = 100;
_this.resizePolling = 60;
_this.probeType = 0 /* Default */;
_this.stopPropagation = false;
_this.preventDefault = true;
_this.preventDefaultException = {
tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO)$/,
};
_this.tagException = {
tagName: /^TEXTAREA$/,
};
_this.HWCompositing = true;
_this.useTransition = true;
_this.bindToWrapper = false;
_this.bindToTarget = false;
_this.disableMouse = hasTouch;
_this.disableTouch = !hasTouch;
_this.autoBlur = true;
_this.autoEndDistance = 5;
_this.outOfBoundaryDampingFactor = 1 / 3;
return _this;
}
OptionsConstructor.prototype.merge = function (options) {
if (!options)
return this;
for (var key in options) {
this[key] = options[key];
}
return this;
};
OptionsConstructor.prototype.process = function () {
this.translateZ =
this.HWCompositing && hasPerspective ? ' translateZ(1px)' : '';
this.useTransition = this.useTransition && hasTransition;
this.preventDefault = !this.eventPassthrough && this.preventDefault;
this.resolveBounce();
// If you want eventPassthrough I have to lock one of the axes
this.scrollX =
this.eventPassthrough === "horizontal" /* Horizontal */
? false
: this.scrollX;
this.scrollY =
this.eventPassthrough === "vertical" /* Vertical */ ? false : this.scrollY;
// With eventPassthrough we also need lockDirection mechanism
this.freeScroll = this.freeScroll && !this.eventPassthrough;
// force true when freeScroll is true
this.scrollX = this.freeScroll ? true : this.scrollX;
this.scrollY = this.freeScroll ? true : this.scrollY;
this.directionLockThreshold = this.eventPassthrough
? 0
: this.directionLockThreshold;
return this;
};
OptionsConstructor.prototype.resolveBounce = function () {
var directions = ['top', 'right', 'bottom', 'left'];
var bounce = this.bounce;
if (typeof bounce === 'boolean') {
this.bounce = makeMap(directions, bounce);
}
};
return OptionsConstructor;
}(CustomOptions));
function makeMap(keys, val) {
if (val === void 0) { val = true; }
var ret = {};
keys.forEach(function (key) {
ret[key] = val;
});
return ret;
}
var ActionsHandler = /** @class */ (function () {
function ActionsHandler(wrapper, options) {
this.wrapper = wrapper;
this.options = options;
this.hooks = new EventEmitter([
'beforeStart',
'start',
'move',
'end',
'click'
]);
this.handleDOMEvents();
}
ActionsHandler.prototype.handleDOMEvents = function () {
var _a = this.options, bindToWrapper = _a.bindToWrapper, disableMouse = _a.disableMouse, disableTouch = _a.disableTouch, click = _a.click;
var wrapper = this.wrapper;
var target = bindToWrapper ? wrapper : window;
var wrapperEvents = [];
var targetEvents = [];
var shouldRegisterTouch = !disableTouch;
var shouldRegisterMouse = !disableMouse;
if (click) {
wrapperEvents.push({
name: 'click',
handler: this.click.bind(this),
capture: true
});
}
if (shouldRegisterTouch) {
wrapperEvents.push({
name: 'touchstart',
handler: this.start.bind(this)
});
targetEvents.push({
name: 'touchmove',
handler: this.move.bind(this)
}, {
name: 'touchend',
handler: this.end.bind(this)
}, {
name: 'touchcancel',
handler: this.end.bind(this)
});
}
if (shouldRegisterMouse) {
wrapperEvents.push({
name: 'mousedown',
handler: this.start.bind(this)
});
targetEvents.push({
name: 'mousemove',
handler: this.move.bind(this)
}, {
name: 'mouseup',
handler: this.end.bind(this)
});
}
this.wrapperEventRegister = new EventRegister(wrapper, wrapperEvents);
this.targetEventRegister = new EventRegister(target, targetEvents);
};
ActionsHandler.prototype.beforeHandler = function (e, type) {
var _a = this.options, preventDefault = _a.preventDefault, stopPropagation = _a.stopPropagation, preventDefaultException = _a.preventDefaultException;
var preventDefaultConditions = {
start: function () {
return (preventDefault &&
!preventDefaultExceptionFn(e.target, preventDefaultException));
},
end: function () {
return (preventDefault &&
!preventDefaultExceptionFn(e.target, preventDefaultException));
},
move: function () {
return preventDefault;
}
};
if (preventDefaultConditions[type]()) {
e.preventDefault();
}
if (stopPropagation) {
e.stopPropagation();
}
};
ActionsHandler.prototype.setInitiated = function (type) {
if (type === void 0) { type = 0; }
this.initiated = type;
};
ActionsHandler.prototype.start = function (e) {
var _eventType = eventTypeMap[e.type];
if (this.initiated && this.initiated !== _eventType) {
return;
}
this.setInitiated(_eventType);
// if textarea or other html tags in options.tagException is manipulated
// do not make bs scroll
if (tagExceptionFn(e.target, this.options.tagException)) {
this.setInitiated();
return;
}
// only allow mouse left button
if (_eventType === 2 /* Mouse */ && e.button !== 0 /* Left */)
return;
if (this.hooks.trigger(this.hooks.eventTypes.beforeStart, e)) {
return;
}
this.beforeHandler(e, 'start');
var point = (e.touches ? e.touches[0] : e);
this.pointX = point.pageX;
this.pointY = point.pageY;
this.hooks.trigger(this.hooks.eventTypes.start, e);
};
ActionsHandler.prototype.move = function (e) {
if (eventTypeMap[e.type] !== this.initiated) {
return;
}
this.beforeHandler(e, 'move');
var point = (e.touches ? e.touches[0] : e);
var deltaX = point.pageX - this.pointX;
var deltaY = point.pageY - this.pointY;
this.pointX = point.pageX;
this.pointY = point.pageY;
if (this.hooks.trigger(this.hooks.eventTypes.move, {
deltaX: deltaX,
deltaY: deltaY,
e: e
})) {
return;
}
// auto end when out of viewport
var scrollLeft = document.documentElement.scrollLeft ||
window.pageXOffset ||
document.body.scrollLeft;
var scrollTop = document.documentElement.scrollTop ||
window.pageYOffset ||
document.body.scrollTop;
var pX = this.pointX - scrollLeft;
var pY = this.pointY - scrollTop;
var autoEndDistance = this.options.autoEndDistance;
if (pX > document.documentElement.clientWidth - autoEndDistance ||
pY > document.documentElement.clientHeight - autoEndDistance ||
pX < autoEndDistance ||
pY < autoEndDistance) {
this.end(e);
}
};
ActionsHandler.prototype.end = function (e) {
if (eventTypeMap[e.type] !== this.initiated) {
return;
}
this.setInitiated();
this.beforeHandler(e, 'end');
this.hooks.trigger(this.hooks.eventTypes.end, e);
};
ActionsHandler.prototype.click = function (e) {
this.hooks.trigger(this.hooks.eventTypes.click, e);
};
ActionsHandler.prototype.destroy = function () {
this.wrapperEventRegister.destroy();
this.targetEventRegister.destroy();
this.hooks.destroy();
};
return ActionsHandler;
}());
var translaterMetaData = {
x: ['translateX', 'px'],
y: ['translateY', 'px']
};
var Translater = /** @class */ (function () {
function Translater(content) {
this.content = content;
this.style = content.style;
this.hooks = new EventEmitter(['beforeTranslate', 'translate']);
}
Translater.prototype.getComputedPosition = function () {
var cssStyle = window.getComputedStyle(this.content, null);
var matrix = cssStyle[style.transform].split(')')[0].split(', ');
var x = +(matrix[12] || matrix[4]);
var y = +(matrix[13] || matrix[5]);
return {
x: x,
y: y
};
};
Translater.prototype.translate = function (point) {
var transformStyle = [];
Object.keys(point).forEach(function (key) {
if (!translaterMetaData[key]) {
return;
}
var transformFnName = translaterMetaData[key][0];
if (transformFnName) {
var transformFnArgUnit = translaterMetaData[key][1];
var transformFnArg = point[key];
transformStyle.push(transformFnName + "(" + transformFnArg + transformFnArgUnit + ")");
}
});
this.hooks.trigger(this.hooks.eventTypes.beforeTranslate, transformStyle, point);
this.style[style.transform] = transformStyle.join(' ');
this.hooks.trigger(this.hooks.eventTypes.translate, point);
};
Translater.prototype.destroy = function () {
this.hooks.destroy();
};
return Translater;
}());
var Base = /** @class */ (function () {
function Base(content, translater, options) {
this.content = content;
this.translater = translater;
this.options = options;
this.timer = 0;
this.hooks = new EventEmitter([
'move',
'end',
'beforeForceStop',
'forceStop',
'callStop',
'time',
'timeFunction',
]);
this.style = content.style;
}
Base.prototype.translate = function (endPoint) {
this.translater.translate(endPoint);
};
Base.prototype.setPending = function (pending) {
this.pending = pending;
};
Base.prototype.setForceStopped = function (forceStopped) {
this.forceStopped = forceStopped;
};
Base.prototype.destroy = function () {
this.hooks.destroy();
cancelAnimationFrame(this.timer);
};
return Base;
}());
var Transition = /** @class */ (function (_super) {
__extends(Transition, _super);
function Transition() {
return _super !== null && _super.apply(this, arguments) || this;
}
Transition.prototype.startProbe = function () {
var _this = this;
var probe = function () {
var pos = _this.translater.getComputedPosition();
_this.hooks.trigger(_this.hooks.eventTypes.move, pos);
// transition ends should dispatch end hook.
// but when call stop() in animation.hooks.move or bs.scroll
// should not dispatch end hook, because forceStop hook will do this.
if (!_this.pending && !_this.forceStopped) {
_this.hooks.trigger(_this.hooks.eventTypes.end, pos);
}
if (_this.pending) {
_this.timer = requestAnimationFrame(probe);
}
};
cancelAnimationFrame(this.timer);
probe();
};
Transition.prototype.transitionTime = function (time) {
if (time === void 0) { time = 0; }
this.style[style.transitionDuration] = time + 'ms';
this.hooks.trigger(this.hooks.eventTypes.time, time);
};
Transition.prototype.transitionTimingFunction = function (easing) {
this.style[style.transitionTimingFunction] = easing;
this.hooks.trigger(this.hooks.eventTypes.timeFunction, easing);
};
Transition.prototype.transitionProperty = function () {
this.style[style.transitionProperty] = style.transform;
};
Transition.prototype.move = function (startPoint, endPoint, time, easingFn) {
this.setPending(time > 0);
this.transitionTimingFunction(easingFn);
this.transitionProperty();
this.transitionTime(time);
this.translate(endPoint);
if (time && this.options.probeType === 3 /* Realtime */) {
this.startProbe();
}
// if we change content's transformY in a tick
// such as: 0 -> 50px -> 0
// transitionend will not be triggered
// so we forceupdate by reflow
if (!time) {
this._reflow = this.content.offsetHeight;
this.hooks.trigger(this.hooks.eventTypes.move, endPoint);
this.hooks.trigger(this.hooks.eventTypes.end, endPoint);
}
};
Transition.prototype.doStop = function () {
var pending = this.pending;
this.setForceStopped(false);
// still in transition
if (pending) {
this.setPending(false);
cancelAnimationFrame(this.timer);
var _a = this.translater.getComputedPosition(), x = _a.x, y = _a.y;
this.transitionTime();
this.translate({ x: x, y: y });
this.setForceStopped(true);
if (this.hooks.trigger(this.hooks.eventTypes.beforeForceStop, { x: x, y: y })) {
return true;
}
this.hooks.trigger(this.hooks.eventTypes.forceStop, { x: x, y: y });
}
return pending;
};
Transition.prototype.stop = function () {
var stopFromTransition = this.doStop();
if (stopFromTransition) {
this.hooks.trigger(this.hooks.eventTypes.callStop);
}
};
return Transition;
}(Base));
var Animation = /** @class */ (function (_super) {
__extends(Animation, _super);
function Animation() {
return _super !== null && _super.apply(this, arguments) || this;
}
Animation.prototype.move = function (startPoint, endPoint, time, easingFn) {
// time is 0
if (!time) {
this.translate(endPoint);
this.hooks.trigger(this.hooks.eventTypes.move, endPoint);
this.hooks.trigger(this.hooks.eventTypes.end, endPoint);
return;
}
this.animate(startPoint, endPoint, time, easingFn);
};
Animation.prototype.animate = function (startPoint, endPoint, duration, easingFn) {
var _this = this;
var startTime = getNow();
var destTime = startTime + duration;
var step = function () {
var now = getNow();
// js animation end
if (now >= destTime) {
_this.translate(endPoint);
_this.hooks.trigger(_this.hooks.eventTypes.move, endPoint);
_this.hooks.trigger(_this.hooks.eventTypes.end, endPoint);
return;
}
now = (now - startTime) / duration;
var easing = easingFn(now);
var newPoint = {};
Object.keys(endPoint).forEach(function (key) {
var startValue = startPoint[key];
var endValue = endPoint[key];
newPoint[key] = (endValue - startValue) * easing + startValue;
});
_this.translate(newPoint);
if (_this.options.probeType === 3 /* Realtime */) {
_this.hooks.trigger(_this.hooks.eventTypes.move, newPoint);
}
if (_this.pending) {
_this.timer = requestAnimationFrame(step);
}
// when call stop() in animation.hooks.move or bs.scroll
// should not dispatch end hook, because forceStop hook will do this.
if (!_this.pending && !_this.forceStopped) {
console.log(_this.forceStopped);
_this.hooks.trigger(_this.hooks.eventTypes.end, endPoint);
}
};
this.setPending(true);
cancelAnimationFrame(this.timer);
step();
};
Animation.prototype.doStop = function () {
var pending = this.pending;
this.setForceStopped(false);
// still in requestFrameAnimation
if (pending) {
this.setPending(false);
cancelAnimationFrame(this.timer);
var pos = this.translater.getComputedPosition();
this.setForceStopped(true);
if (this.hooks.trigger(this.hooks.eventTypes.beforeForceStop, pos)) {
return true;
}
this.hooks.trigger(this.hooks.eventTypes.forceStop, pos);
}
return pending;
};
Animation.prototype.stop = function () {
var stopFromAnimation = this.doStop();
if (stopFromAnimation) {
this.hooks.trigger(this.hooks.eventTypes.callStop);
}
};
return Animation;
}(Base));
function createAnimater(element, translater, options) {
var useTransition = options.useTransition;
var animaterOptions = {};
Object.defineProperty(animaterOptions, 'probeType', {
enumerable: true,
configurable: false,
get: function () {
return options.probeType;
}
});
if (useTransition) {
return new Transition(element, translater, animaterOptions);
}
else {
return new Animation(element, translater, animaterOptions);
}
}
var Behavior = /** @class */ (function () {
function Behavior(wrapper, options) {
this.wrapper = wrapper;
this.options = options;
this.hooks = new EventEmitter([
'beforeComputeBoundary',
'computeBoundary',
'momentum',
'end',
]);
this.content = this.wrapper.children[0];
this.currentPos = 0;
this.startPos = 0;
this.refresh();
}
Behavior.prototype.start = function () {
this.dist = 0;
this.setMovingDirection(0 /* Default */);
this.setDirection(0 /* Default */);
};
Behavior.prototype.move = function (delta) {
delta = this.hasScroll ? delta : 0;
this.setMovingDirection(delta);
return this.performDampingAlgorithm(delta, this.options.outOfBoundaryDampingFactor);
};
Behavior.prototype.setMovingDirection = function (delta) {
this.movingDirection =
delta > 0
? -1 /* Negative */
: delta < 0
? 1 /* Positive */
: 0 /* Default */;
};
Behavior.prototype.setDirection = function (delta) {
this.direction =
delta > 0
? -1 /* Negative */
: delta < 0
? 1 /* Positive */
: 0 /* Default */;
};
Behavior.prototype.performDampingAlgorithm = function (delta, dampingFactor) {
var newPos = this.currentPos + delta;
// Slow down or stop if outside of the boundaries
if (newPos > this.minScrollPos || newPos < this.maxScrollPos) {
if ((newPos > this.minScrollPos && this.options.bounces[0]) ||
(newPos < this.maxScrollPos && this.options.bounces[1])) {
newPos = this.currentPos + delta * dampingFactor;
}
else {
newPos =
newPos > this.minScrollPos ? this.minScrollPos : this.maxScrollPos;
}
}
return newPos;
};
Behavior.prototype.end = function (duration) {
var momentumInfo = {
duration: 0,
};
var absDist = Math.abs(this.currentPos - this.startPos);
// start momentum animation if needed
if (this.options.momentum &&
duration < this.options.momentumLimitTime &&
absDist > this.options.momentumLimitDistance) {
var wrapperSize = (this.direction === -1 /* Negative */ && this.options.bounces[0]) ||
(this.direction === 1 /* Positive */ && this.options.bounces[1])
? this.wrapperSize
: 0;
momentumInfo = this.hasScroll
? this.momentum(this.currentPos, this.startPos, duration, this.maxScrollPos, this.minScrollPos, wrapperSize, this.options)
: { destination: this.currentPos, duration: 0 };
}
else {
this.hooks.trigger(this.hooks.eventTypes.end, momentumInfo);
}
return momentumInfo;
};
Behavior.prototype.momentum = function (current, start, time, lowerMargin, upperMargin, wrapperSize, options) {
if (options === void 0) { options = this.options; }
var distance = current - start;
var speed = Math.abs(distance) / time;
var deceleration = options.deceleration, swipeBounceTime = options.swipeBounceTime, swipeTime = options.swipeTime;
var momentumData = {
destination: current + (speed / deceleration) * (distance < 0 ? -1 : 1),
duration: swipeTime,
rate: 15,
};
this.hooks.trigger(this.hooks.eventTypes.momentum, momentumData, distance);
if (momentumData.destination < lowerMargin) {
momentumData.destination = wrapperSize
? Math.max(lowerMargin - wrapperSize / 4, lowerMargin - (wrapperSize / momentumData.rate) * speed)
: lowerMargin;
momentumData.duration = swipeBounceTime;
}
else if (momentumData.destination > upperMargin) {
momentumData.destination = wrapperSize
? Math.min(upperMargin + wrapperSize / 4, upperMargin + (wrapperSize / momentumData.rate) * speed)
: upperMargin;
momentumData.duration = swipeBounceTime;
}
momentumData.destination = Math.round(momentumData.destination);
return momentumData;
};
Behavior.prototype.updateDirection = function () {
var absDist = Math.round(this.currentPos) - this.absStartPos;
this.setDirection(absDist);
};
Behavior.prototype.refresh = function () {
var _a = this.options.rect, size = _a.size, position = _a.position;
var isWrapperStatic = window.getComputedStyle(this.wrapper, null).position === 'static';
var wrapperRect = getRect(this.wrapper);
this.wrapperSize = wrapperRect[size];
var contentRect = getRect(this.content);
this.contentSize = contentRect[size];
this.relativeOffset = contentRect[position];
if (isWrapperStatic) {
this.relativeOffset -= wrapperRect[position];
}
this.computeBoundary();
this.setDirection(0 /* Default */);
};
Behavior.prototype.computeBoundary = function () {
this.hooks.trigger(this.hooks.eventTypes.beforeComputeBoundary);
var boundary = {
minScrollPos: 0,
maxScrollPos: this.wrapperSize - this.contentSize,
};
if (boundary.maxScrollPos < 0) {
boundary.maxScrollPos -= this.relativeOffset;
boundary.minScrollPos = -this.relativeOffset;
}
this.hooks.trigger(this.hooks.eventTypes.computeBoundary, boundary);
this.minScrollPos = boundary.minScrollPos;
this.maxScrollPos = boundary.maxScrollPos;
this.hasScroll =
this.options.scrollable && this.maxScrollPos < this.minScrollPos;
if (!this.hasScroll) {
this.maxScrollPos = this.minScrollPos;
this.contentSize = this.wrapperSize;
}
};
Behavior.prototype.updatePosition = function (pos) {
this.currentPos = pos;
};
Behavior.prototype.getCurrentPos = function () {
return Math.round(this.currentPos);
};
Behavior.prototype.checkInBoundary = function () {
var position = this.adjustPosition(this.currentPos);
var inBoundary = position === this.getCurrentPos();
return {
position: position,
inBoundary: inBoundary,
};
};
// adjust position when out of boundary
Behavior.prototype.adjustPosition = function (pos) {
var roundPos = Math.round(pos);
if (!this.hasScroll || roundPos > this.minScrollPos) {
roundPos = this.minScrollPos;
}
else if (roundPos < this.maxScrollPos) {
roundPos = this.maxScrollPos;
}
return roundPos;
};
Behavior.prototype.updateStartPos = function () {
this.startPos = this.currentPos;
};
Behavior.prototype.updateAbsStartPos = function () {
this.absStartPos = this.currentPos;
};
Behavior.prototype.resetStartPos = function () {
this.updateStartPos();
this.updateAbsStartPos();
};
Behavior.prototype.getAbsDist = function (delta) {
this.dist += delta;
return Math.abs(this.dist);
};
Behavior.prototype.destroy = function () {
this.hooks.destroy();
};
return Behavior;
}());
var _a, _b, _c, _d;
var PassthroughHandlers = (_a = {},
_a["yes" /* Yes */] = function (e) {
return true;
},
_a["no" /* No */] = function (e) {
e.preventDefault();
return false;
},
_a);
var DirectionMap = (_b = {},
_b["horizontal" /* Horizontal */] = (_c = {},
_c["yes" /* Yes */] = "horizontal" /* Horizontal */,
_c["no" /* No */] = "vertical" /* Vertical */,
_c),
_b["vertical" /* Vertical */] = (_d = {},
_d["yes" /* Yes */] = "vertical" /* Vertical */,
_d["no" /* No */] = "horizontal" /* Horizontal */,
_d),
_b);
var DirectionLockAction = /** @class */ (function () {
function DirectionLockAction(directionLockThreshold, freeScroll, eventPassthrough) {
this.directionLockThreshold = directionLockThreshold;
this.freeScroll = freeScroll;
this.eventPassthrough = eventPassthrough;
this.reset();
}
DirectionLockAction.prototype.reset = function () {
this.directionLocked = "" /* Default */;
};
DirectionLockAction.prototype.checkMovingDirection = function (absDistX, absDistY, e) {
this.computeDirectionLock(absDistX, absDistY);
return this.handleEventPassthrough(e);
};
DirectionLockAction.prototype.adjustDelta = function (deltaX, deltaY) {
if (this.directionLocked === "horizontal" /* Horizontal */) {
deltaY = 0;
}
else if (this.directionLocked === "vertical" /* Vertical */) {
deltaX = 0;
}
return {
deltaX: deltaX,
deltaY: deltaY
};
};
DirectionLockAction.prototype.computeDirectionLock = function (absDistX, absDistY) {
// If you are scrolling in one direction, lock it
if (this.directionLocked === "" /* Default */ && !this.freeScroll) {
if (absDistX > absDistY + this.directionLockThreshold) {
this.directionLocked = "horizontal" /* Horizontal */; // lock horizontally
}
else if (absDistY >= absDistX + this.directionLockThreshold) {
this.directionLocked = "vertical" /* Vertical */; // lock vertically
}
else {
this.directionLocked = "none" /* None */; // no lock
}
}
};
DirectionLockAction.prototype.handleEventPassthrough = function (e) {
var handleMap = DirectionMap[this.directionLocked];
if (handleMap) {
if (this.eventPassthrough === handleMap["yes" /* Yes */]) {
return PassthroughHandlers["yes" /* Yes */](e);
}
else if (this.eventPassthrough === handleMap["no" /* No */]) {
return PassthroughHandlers["no" /* No */](e);
}
}
return false;
};
return DirectionLockAction;
}());
var ScrollerActions = /** @class */ (function () {
function ScrollerActions(scrollBehaviorX, scrollBehaviorY, actionsHandler, animater, options) {
this.hooks = new EventEmitter([
'start',
'beforeMove',
'scrollStart',
'scroll',
'beforeEnd',
'end',
'scrollEnd'
]);
this.scrollBehaviorX = scrollBehaviorX;
this.scrollBehaviorY = scrollBehaviorY;
this.actionsHandler = actionsHandler;
this.animater = animater;
this.options = options;
this.directionLockAction = new DirectionLockAction(options.directionLockThreshold, options.freeScroll, options.eventPassthrough);
this.enabled = true;
this.bindActionsHandler();
}
ScrollerActions.prototype.bindActionsHandler = function () {
var _this = this;
// [mouse|touch]start event
this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.start, function (e) {
if (!_this.enabled)
return true;
return _this.handleStart(e);
});
// [mouse|touch]move event
this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.move, function (_a) {
var deltaX = _a.deltaX, deltaY = _a.deltaY, e = _a.e;
if (!_this.enabled)
return true;
return _this.handleMove(deltaX, deltaY, e);
});
// [mouse|touch]end event
this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.end, function (e) {
if (!_this.enabled)
return true;
return _this.handleEnd(e);
});
// click
this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.click, function (e) {
// handle native click event
if (_this.enabled && !e._constructed) {
_this.handleClick(e);
}
});
};
ScrollerActions.prototype.handleStart = function (e) {
var timestamp = getNow();
this.moved = false;
this.startTime = timestamp;
this.directionLockAction.reset();
this.scrollBehaviorX.start();
this.scrollBehaviorY.start();
// force stopping last transition or animation
this.animater.doStop();
this.scrollBehaviorX.resetStartPos();
this.scrollBehaviorY.resetStartPos();
this.hooks.trigger(this.hooks.eventTypes.start, e);
};
ScrollerActions.prototype.handleMove = function (deltaX, deltaY, e) {
if (this.hooks.trigger(this.hooks.eventTypes.beforeMove, e)) {
return;
}
var absDistX = this.scrollBehaviorX.getAbsDist(deltaX);
var absDistY = this.scrollBehaviorY.getAbsDist(deltaY);
var timestamp = getNow();
// We need to move at least momentumLimitDistance pixels
// for the scrolling to initiate
if (this.checkMomentum(absDistX, absDistY, timestamp)) {
return true;
}
if (this.directionLockAction.checkMovingDirection(absDistX, absDistY, e)) {
this.actionsHandler.setInitiated();
return true;
}
var delta = this.directionLockAction.adjustDelta(deltaX, deltaY);
var newX = this.scrollBehaviorX.move(delta.deltaX);
var newY = this.scrollBehaviorY.move(delta.deltaY);
if (!this.moved) {
this.moved = true;
this.hooks.trigger(this.hooks.eventTypes.scrollStart);
}
this.animater.translate({
x: newX,
y: newY
});
this.dispatchScroll(timestamp);
};
ScrollerActions.prototype.dispatchScroll = function (timestamp) {
// dispatch scroll in interval time
if (timestamp - this.startTime > this.options.momentumLimitTime) {
// refresh time and starting position to initiate a momentum
this.startTime = timestamp;
this.scrollBehaviorX.updateStartPos();
this.scrollBehaviorY.updateStartPos();
if (this.options.probeType === 1 /* Throttle */) {
this.hooks.trigger(this.hooks.eventTypes.scroll, this.getCurrentPos());
}
}
// dispatch scroll all the time
if (this.options.probeType > 1 /* Throttle */) {
this.hooks.trigger(this.hooks.eventTypes.scroll, this.getCurrentPos());
}
};
ScrollerActions.prototype.checkMomentum = function (absDistX, absDistY, timestamp) {
return (timestamp - this.endTime > this.options.momentumLimitTime &&
absDistY < this.options.momentumLimitDistance &&
absDistX < this.options.momentumLimitDistance);
};
ScrollerActions.prototype.handleEnd = function (e) {
if (this.hooks.trigger(this.hooks.eventTypes.beforeEnd, e)) {
return;
}
var currentPos = this.getCurrentPos();
this.scrollBehaviorX.updateDirection();
this.scrollBehaviorY.updateDirection();
if (this.hooks.trigger(this.hooks.eventTypes.end, e, currentPos)) {
return true;
}
this.animater.translate(currentPos);
this.endTime = getNow();
var duration = this.endTime - this.startTime;
this.hooks.trigger(this.hooks.eventTypes.scrollEnd, currentPos, duration);
};
ScrollerActions.prototype.handleClick = function (e) {
if (!preventDefaultExceptionFn(e.target, this.options.preventDefaultException)) {
e.preventDefault();
e.stopPropagation();
}
};
ScrollerActions.prototype.getCurrentPos = function () {
return {
x: this.scrollBehaviorX.getCurrentPos(),
y: this.scrollBehaviorY.getCurrentPos()
};
};
ScrollerActions.prototype.refresh = function () {
this.endTime = 0;
};
ScrollerActions.prototype.destroy = function () {
this.hooks.destroy();
};
return ScrollerActions;
}());
function createActionsHandlerOptions(bsOptions) {
var options = [
'click',
'bindToWrapper',
'disableMouse',
'disableTouch',
'preventDefault',
'stopPropagation',
'tagException',
'preventDefaultException',
'autoEndDistance',
].reduce(function (prev, cur) {
prev[cur] = bsOptions[cur];
return prev;
}, {});
return options;
}
function createBehaviorOptions(bsOptions, extraProp, bounces, rect) {
var options = [
'momentum',
'momentumLimitTime',
'momentumLimitDistance',
'deceleration',
'swipeBounceTime',
'swipeTime',
'outOfBoundaryDampingFactor',
].reduce(function (prev, cur) {
prev[cur] = bsOptions[cur];
return prev;
}, {});
// add extra property
options.scrollable = !!bsOptions[extraProp];
options.bounces = bounces;
options.rect = rect;
return options;
}
function bubbling(source, target, events) {
events.forEach(function (event) {
var sourceEvent;
var targetEvent;
if (typeof event === 'string') {
sourceEvent = targetEvent = event;
}
else {
sourceEvent = event.source;
targetEvent = event.target;
}
source.on(sourceEvent, function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return target.trigger.apply(target, __spreadArrays([targetEvent], args));
});
});
}
function isSamePoint(startPoint, endPoint) {
// keys of startPoint and endPoint should be equal
var keys = Object.keys(startPoint);
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
if (startPoint[key] !== endPoint[key])
return false;
}
return true;
}
var Scroller = /** @class */ (function () {
function Scroller(wrapper, options) {
this.resizeTimeout = 0;
this.hooks = new EventEmitter([
'beforeStart',
'beforeMove',
'beforeScrollStart',
'scrollStart',
'scroll',
'beforeEnd',
'scrollEnd',
'resize',
'touchEnd',
'end',
'flick',
'scrollCancel',
'momentum',
'scrollTo',
'scrollToElement',
'beforeRefresh',
]);
this.wrapper = wrapper;
this.content = wrapper.children[0];
this.options = options;
var _a = this
.options.bounce, _b = _a.left, left = _b === void 0 ? true : _b, _c = _a.right, right = _c === void 0 ? true : _c, _d = _a.top, top = _d === void 0 ? true : _d, _e = _a.bottom, bottom = _e === void 0 ? true : _e;
// direction X
this.scrollBehaviorX = new Behavior(wrapper, createBehaviorOptions(options, 'scrollX', [left, right], {
size: 'width',
position: 'left',
}));
// direction Y
this.scrollBehaviorY = new Behavior(wrapper, createBehaviorOptions(options, 'scrollY', [top, bottom], {
size: 'height',
position: 'top',
}));
this.translater = new Translater(this.content);
this.animater = createAnimater(this.content, this.translater, this.options);
this.actionsHandler = new ActionsHandler(this.options.bindToTarget ? this.content : wrapper, createActionsHandlerOptions(this.options));
this.actions = new ScrollerActions(this.scrollBehaviorX, this.scrollBehaviorY, this.actionsHandler, this.animater, this.options);
var resizeHandler = this.resize.bind(this);
this.resizeRegister = new EventRegister(window, [
{
name: 'orientationchange',
handler: resizeHandler,
},
{
name: 'resize',
handler: resizeHandler,
},
]);
this.transitionEndRegister = new EventRegister(this.content, [
{
name: style.transitionEnd,
handler: this.transitionEnd.bind(this),
},
]);
this.init();
}
Scroller.prototype.init = function () {
var _this = this;
this.bindTranslater();
this.bindAnimater();
this.bindActions();
// enable pointer events when scrolling ends
this.hooks.on(this.hooks.eventTypes.scrollEnd, function () {
_this.togglePointerEvents(true);
});
};
Scroller.prototype.bindTranslater = function () {
var _this = this;
var hooks = this.translater.hooks;
hooks.on(hooks.eventTypes.beforeTranslate, function (transformStyle) {
if (_this.options.translateZ) {
transformStyle.push(_this.options.translateZ);
}
});
// disable pointer events when scrolling
hooks.on(hooks.eventTypes.translate, function (pos) {
var prevPos = _this.getCurrentPos();
_this.updatePositions(pos);
// a valid translate
if (pos.x !== prevPos.x || pos.y !== prevPos.y) {
_this.togglePointerEvents(false);
}
});
};
Scroller.prototype.bindAnimater = function () {
var _this = this;
// reset position
this.animater.hooks.on(this.animater.hooks.eventTypes.end, function (pos) {
if (!_this.resetPosition(_this.options.bounceTime)) {
_this.animater.setPending(false);
_this.hooks.trigger(_this.hooks.eventTypes.scrollEnd, pos);
}
});
bubbling(this.animater.hooks, this.hooks, [
{
source: this.animater.hooks.eventTypes.move,
target: this.hooks.eventTypes.scroll,
},
{
source: this.animater.hooks.eventTypes.forceStop,
target: this.hooks.eventTypes.scrollEnd,
},
]);
};
Scroller.prototype.bindActions = function () {
var _this = this;
var actions = this.actions;
bubbling(actions.hooks, this.hooks, [
{
source: actions.hooks.eventTypes.start,
target: this.hooks.eventTypes.beforeStart,
},
{
source: actions.hooks.eventTypes.start,
target: this.hooks.eventTypes.beforeScrollStart,
},
{
source: actions.hooks.eventTypes.beforeMove,
target: this.hooks.eventTypes.beforeMove,
},
{
source: actions.hooks.eventTypes.scrollStart,
target: this.hooks.eventTypes.scrollStart,
},
{
source: actions.hooks.eventTypes.scroll,
target: this.hooks.eventTypes.scroll,
},
{
source: actions.hooks.eventTypes.beforeEnd,
target: this.hooks.eventTypes.beforeEnd,
},
]);
actions.hooks.on(actions.hooks.eventTypes.end, function (e, pos) {
_this.hooks.trigger(_this.hooks.eventTypes.touchEnd, pos);
if (_this.hooks.trigger(_this.hooks.eventTypes.end, pos)) {
return true;
}
// check if it is a click operation
if (!actions.moved && _this.checkClick(e)) {
_this.hooks.trigger(_this.hooks.eventTypes.scrollCancel);
return true;
}
// reset if we are outside of the boundaries
if (_this.resetPosition(_this.options.bounceTime, ease.bounce)) {
_this.animater.setForceStopped(false);
return true;
}
});
actions.hooks.on(actions.hooks.eventTypes.scrollEnd, function (pos, duration) {
var deltaX = Math.abs(pos.x - _this.scrollBehaviorX.startPos);
var deltaY = Math.abs(pos.y - _this.scrollBehaviorY.startPos);
if (_this.checkFlick(duration, deltaX, deltaY)) {
_this.hooks.trigger(_this.hooks.eventTypes.flick);
return;
}
if (_this.momentum(pos, duration)) {
return;
}
// force stop from transition or animation when click a point
if (!_this.animater.forceStopped || actions.moved) {
_this.hooks.trigger(_this.hooks.eventTypes.scrollEnd, pos);
}
else {
_this.animater.setForceStopped(false);
}
});
};
Scroller.prototype.checkFlick = function (duration, deltaX, deltaY) {
var flickMinMovingDistance = 1; // distinguish flick from click
if (this.hooks.events.flick.length > 1 &&
duration < this.options.flickLimitTime &&
deltaX < this.options.flickLimitDistance &&
deltaY < this.options.flickLimitDistance &&
(deltaY > flickMinMovingDistance || deltaX > flickMinMovingDistance)) {
return true;
}
};
Scroller.prototype.momentum = function (pos, duration) {
var meta = {
time: 0,
easing: ease.swiper,
newX: pos.x,
newY: pos.y,
};
// start momentum animation if needed
var momentumX = this.scrollBehaviorX.end(duration);
var momentumY = this.scrollBehaviorY.end(duration);
meta.newX = isUndef(momentumX.destination)
? meta.newX
: momentumX.destination;
meta.newY = isUndef(momentumY.destination)
? meta.newY
: momentumY.destination;
meta.time = Math.max(momentumX.duration, momentumY.duration);
this.hooks.trigger(this.hooks.eventTypes.momentum, meta, this);
// when x or y changed, do momentum animation now!
if (meta.newX !== pos.x || meta.newY !== pos.y) {
// change easing function when scroller goes out of the boundaries
if (meta.newX > this.scrollBehaviorX.minScrollPos ||
meta.newX < this.scrollBehaviorX.maxScrollPos ||
meta.newY > this.scrollBehaviorY.minScrollPos ||
meta.newY < this.scrollBehaviorY.maxScrollPos) {
meta.easing = ease.swipeBounce;
}
this.scrollTo(meta.newX, meta.newY, meta.time, meta.easing);
return true;
}
};
Scroller.prototype.checkClick = function (e) {
var cancelable = {
preventClick: this.animater.forceStopped,
};
// we scrolled less than momentumLimitDistance pixels
if (this.hooks.trigger(this.hooks.eventTypes.checkClick)) {
this.animater.setForceStopped(false);
return true;
}
if (!cancelable.preventClick) {
var _dblclick = this.options.dblclick;
var dblclickTrigged = false;
if (_dblclick && this.lastClickTime) {
var _a = _dblclick.delay, delay = _a === void 0 ? 300 : _a;
if (getNow() - this.lastClickTime < delay) {
dblclickTrigged = true;
dblclick(e);
}
}
if (this.options.tap) {
tap(e, this.options.tap);
}
if (this.options.click &&
!preventDefaultExceptionFn(e.target, this.options.preventDefaultException)) {
click(e);
}
this.lastClickTime = dblclickTrigged ? null : getNow();
return true;
}
return false;
};
Scroller.prototype.resize = function () {
var _this = this;
if (!this.actions.enabled) {
return;
}
// fix a scroll problem under Android condition
if (isAndroid) {
this.wrapper.scrollTop = 0;
}
clearTimeout(this.resizeTimeout);
this.resizeTimeout = window.setTimeout(function () {
_this.hooks.trigger(_this.hooks.eventTypes.resize);
}, this.options.resizePolling);
};
Scroller.prototype.transitionEnd = function (e) {
if (e.target !== this.content || !this.animater.pending) {
return;
}
var animater = this.animater;
animater.transitionTime();
if (!this.resetPosition(this.options.bounceTime, ease.bounce)) {
this.animater.setPending(false);
if (this.options.probeType !== 3 /* Realtime */) {
this.hooks.trigger(this.hooks.eventTypes.scrollEnd, this.getCurrentPos());
}
}
};
Scroller.prototype.togglePointerEvents = function (enabled) {
if (enabled === void 0) { enabled = true; }
var el = this.content.children.length
? this.content.children
: [this.content];
var pointerEvents = enabled ? 'auto' : 'none';
for (var i = 0; i < el.length; i++) {
var node = el[i];
// ignore BetterScroll instance's wrapper DOM
if (node.isBScrollContainer) {
continue;
}
node.style.pointerEvents = pointerEvents;
}
};
Scroller.prototype.refresh = function () {
this.hooks.trigger(this.hooks.eventTypes.beforeRefresh);
this.scrollBehaviorX.refresh();
this.scrollBehaviorY.refresh();
this.actions.refresh();
this.wrapperOffset = offset(this.wrapper);
};
Scroller.prototype.scrollBy = function (deltaX, deltaY, time, easing) {
if (time === void 0) { time = 0; }
var _a = this.getCurrentPos(), x = _a.x, y = _a.y;
easing = !easing ? ease.bounce : easing;
deltaX += x;
deltaY += y;
this.scrollTo(deltaX, deltaY, time, easing);
};
Scroller.prototype.scrollTo = function (x, y, time, easing, extraTransform) {
if (time === void 0) { time = 0; }
if (easing === void 0) { easing = ease.bounce; }
if (extraTransform === void 0) { extraTransform = {
start: {},
end: {},
}; }
var easingFn = this.options.useTransition ? easing.style : easing.fn;
var currentPos = this.getCurrentPos();
var startPoint = __assign({ x: currentPos.x, y: currentPos.y }, extraTransform.start);
var endPoint = __assign({ x: x,
y: y }, extraTransform.end);
this.hooks.trigger(this.hooks.eventTypes.scrollTo, endPoint);
// it is an useless move
if (isSamePoint(startPoint, endPoint))
return;
this.animater.move(startPoint, endPoint, time, easingFn);
};
Scroller.prototype.scrollToElement = function (el, time, offsetX, offsetY, easing) {
var targetEle = getElement(el);
var pos = offset(targetEle);
var getOffset = function (offset, size, wrapperSize) {
if (typeof offset === 'number') {
return offset;
}
// if offsetX/Y are true we center the element to the screen
return offset ? Math.round(size / 2 - wrapperSize / 2) : 0;
};
offsetX = getOffset(offsetX, targetEle.offsetWidth, this.wrapper.offsetWidth);
offsetY = getOffset(offsetY, targetEle.offsetHeight, this.wrapper.offsetHeight);
var getPos = function (pos, wrapperPos, offset, scrollBehavior) {
pos -= wrapperPos;
pos = scrollBehavior.adjustPosition(pos - offset);
return pos;
};
pos.left = getPos(pos.left, this.wrapperOffset.left, offsetX, this.scrollBehaviorX);
pos.top = getPos(pos.top, this.wrapperOffset.top, offsetY, this.scrollBehaviorY);
if (this.hooks.trigger(this.hooks.eventTypes.scrollToElement, targetEle, pos)) {
return;
}
this.scrollTo(pos.left, pos.top, time, easing);
};
Scroller.prototype.resetPosition = function (time, easing) {
if (time === void 0) { time = 0; }
if (easing === void 0) { easing = ease.bounce; }
var _a = this.scrollBehaviorX.checkInBoundary(), x = _a.position, xInBoundary = _a.inBoundary;
var _b = this.scrollBehaviorY.checkInBoundary(), y = _b.position, yInBoundary = _b.inBoundary;
if (xInBoundary && yInBoundary) {
return false;
}
if (isIOSBadVersion) {
// fix ios 13.4 bouncing
// see it in issues 982
this._reflow = this.content.offsetHeight;
}
// out of boundary
this.scrollTo(x, y, time, easing);
return true;
};
Scroller.prototype.updatePositions = function (pos) {
this.scrollBehaviorX.updatePosition(pos.x);
this.scrollBehaviorY.updatePosition(pos.y);
};
Scroller.prototype.getCurrentPos = function () {
return this.actions.getCurrentPos();
};
Scroller.prototype.enable = function () {
this.actions.enabled = true;
};
Scroller.prototype.disable = function () {
cancelAnimationFrame(this.animater.timer);
this.actions.enabled = false;
};
Scroller.prototype.destroy = function () {
var _this = this;
var keys = [
'resizeRegister',
'transitionEndRegister',
'actionsHandler',
'actions',
'hooks',
'animater',
'translater',
'scrollBehaviorX',
'scrollBehaviorY',
];
keys.forEach(function (key) { return _this[key].destroy(); });
};
return Scroller;
}());
var BScrollConstructor = /** @class */ (function (_super) {
__extends(BScrollConstructor, _super);
function BScrollConstructor(el, options) {
var _this = _super.call(this, [
'refresh',
'enable',
'disable',
'beforeScrollStart',
'scrollStart',
'scroll',
'scrollEnd',
'scrollCancel',
'touchEnd',
'flick',
'destroy',
]) || this;
var wrapper = getElement(el);
if (!wrapper) {
warn('Can not resolve the wrapper DOM.');
return _this;
}
var content = wrapper.children[0];
if (!content) {
warn('The wrapper need at least one child element to be scroller.');
return _this;
}
_this.plugins = {};
_this.options = new OptionsConstructor().merge(options).process();
_this.hooks = new EventEmitter([
'refresh',
'enable',
'disable',
'destroy',
'beforeInitialScrollTo',
]);
_this.init(wrapper);
return _this;
}
BScrollConstructor.use = function (ctor) {
var name = ctor.pluginName;
var installed = BScrollConstructor.plugins.some(function (plugin) { return ctor === plugin.ctor; });
if (installed)
return BScrollConstructor;
if (isUndef(name)) {
warn("Plugin Class must specify plugin's name in static property by 'pluginName' field.");
return BScrollConstructor;
}
if (BScrollConstructor.pluginsMap[name]) {
warn("This plugin has been registered, maybe you need change plugin's name");
return BScrollConstructor;
}
BScrollConstructor.pluginsMap[name] = true;
BScrollConstructor.plugins.push({
name: name,
applyOrder: ctor.applyOrder,
ctor: ctor,
});
return BScrollConstructor;
};
BScrollConstructor.prototype.init = function (wrapper) {
var _this = this;
this.wrapper = wrapper;
// mark wrapper to recognize bs instance by DOM attribute
wrapper.isBScrollContainer = true;
this.scroller = new Scroller(wrapper, this.options);
this.scroller.hooks.on(this.scroller.hooks.eventTypes.resize, function () {
_this.refresh();
});
this.eventBubbling();
this.handleAutoBlur();
this.enable();
this.proxy(propertiesConfig);
this.applyPlugins();
// maybe boundary has changed, should refresh
this.refreshWithoutReset();
var _a = this.options, startX = _a.startX, startY = _a.startY;
var position = {
x: startX,
y: startY,
};
// maybe plugins want to control scroll position
if (this.hooks.trigger(this.hooks.eventTypes.beforeInitialScrollTo, position)) {
return;
}
this.scroller.scrollTo(position.x, position.y);
};
BScrollConstructor.prototype.applyPlugins = function () {
var _this = this;
var options = this.options;
BScrollConstructor.plugins
.sort(function (a, b) {
var _a;
var applyOrderMap = (_a = {},
_a["pre" /* Pre */] = -1,
_a["post" /* Post */] = 1,
_a);
var aOrder = a.applyOrder ? applyOrderMap[a.applyOrder] : 0;
var bOrder = b.applyOrder ? applyOrderMap[b.applyOrder] : 0;
return aOrder - bOrder;
})
.forEach(function (item) {
var ctor = item.ctor;
if (options[item.name] && typeof ctor === 'function') {
_this.plugins[item.name] = new ctor(_this);
}
});
};
BScrollConstructor.prototype.handleAutoBlur = function () {
if (this.options.autoBlur) {
this.on(this.eventTypes.beforeScrollStart, function () {
var activeElement = document.activeElement;
if (activeElement &&
(activeElement.tagName === 'INPUT' ||
activeElement.tagName === 'TEXTAREA')) {
activeElement.blur();
}
});
}
};
BScrollConstructor.prototype.eventBubbling = function () {
bubbling(this.scroller.hooks, this, [
this.eventTypes.beforeScrollStart,
this.eventTypes.scrollStart,
this.eventTypes.scroll,
this.eventTypes.scrollEnd,
this.eventTypes.scrollCancel,
this.eventTypes.touchEnd,
this.eventTypes.flick,
]);
};
BScrollConstructor.prototype.refreshWithoutReset = function () {
this.scroller.refresh();
this.hooks.trigger(this.hooks.eventTypes.refresh);
this.trigger(this.eventTypes.refresh);
};
BScrollConstructor.prototype.proxy = function (propertiesConfig) {
var _this = this;
propertiesConfig.forEach(function (_a) {
var key = _a.key, sourceKey = _a.sourceKey;
propertiesProxy(_this, sourceKey, key);
});
};
BScrollConstructor.prototype.refresh = function () {
this.refreshWithoutReset();
this.scroller.resetPosition();
};
BScrollConstructor.prototype.enable = function () {
this.scroller.enable();
this.hooks.trigger(this.hooks.eventTypes.enable);
this.trigger(this.eventTypes.enable);
};
BScrollConstructor.prototype.disable = function () {
this.scroller.disable();
this.hooks.trigger(this.hooks.eventTypes.disable);
this.trigger(this.eventTypes.disable);
};
BScrollConstructor.prototype.destroy = function () {
this.hooks.trigger(this.hooks.eventTypes.destroy);
this.trigger(this.eventTypes.destroy);
this.scroller.destroy();
};
BScrollConstructor.prototype.eventRegister = function (names) {
this.registerType(names);
};
BScrollConstructor.plugins = [];
BScrollConstructor.pluginsMap = {};
return BScrollConstructor;
}(EventEmitter));
function createBScroll(el, options) {
var bs = new BScrollConstructor(el, options);
return bs;
}
createBScroll.use = BScrollConstructor.use;
createBScroll.plugins = BScrollConstructor.plugins;
createBScroll.pluginsMap = BScrollConstructor.pluginsMap;
var BScroll = createBScroll;
var MouseWheel = /** @class */ (function () {
function MouseWheel(scroll) {
this.scroll = scroll;
this.wheelEndTimer = 0;
this.wheelMoveTimer = 0;
this.wheelStart = false;
this.init();
}
MouseWheel.prototype.init = function () {
this.handleBScroll();
this.handleOptions();
this.handleHooks();
this.registerEvent();
};
MouseWheel.prototype.handleBScroll = function () {
this.scroll.registerType([
'alterOptions',
'mousewheelStart',
'mousewheelMove',
'mousewheelEnd',
]);
};
MouseWheel.prototype.handleOptions = function () {
var userOptions = (this.scroll.options.mouseWheel === true
? {}
: this.scroll.options.mouseWheel);
var defaultOptions = {
speed: 20,
invert: false,
easeTime: 300,
discreteTime: 400,
throttleTime: 0,
dampingFactor: 0.1,
};
this.mouseWheelOpt = extend(defaultOptions, userOptions);
};
MouseWheel.prototype.handleHooks = function () {
this.hooksFn = [];
this.registerHooks(this.scroll.hooks, 'destroy', this.destroy);
};
MouseWheel.prototype.registerEvent = function () {
this.eventRegister = new EventRegister(this.scroll.scroller.wrapper, [
{
name: 'wheel',
handler: this.wheelHandler.bind(this),
},
{
name: 'mousewheel',
handler: this.wheelHandler.bind(this),
},
{
name: 'DOMMouseScroll',
handler: this.wheelHandler.bind(this),
},
]);
};
MouseWheel.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
MouseWheel.prototype.wheelHandler = function (e) {
if (!this.scroll.enabled) {
return;
}
this.beforeHandler(e);
// start
if (!this.wheelStart) {
this.wheelStartHandler(e);
this.wheelStart = true;
}
// move
var delta = this.getWheelDelta(e);
this.wheelMoveHandler(delta);
// end
this.wheelEndDetector(delta);
};
MouseWheel.prototype.wheelStartHandler = function (e) {
this.cleanCache();
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
scrollBehaviorX.setMovingDirection(0 /* Default */);
scrollBehaviorY.setMovingDirection(0 /* Default */);
scrollBehaviorX.setDirection(0 /* Default */);
scrollBehaviorY.setDirection(0 /* Default */);
this.scroll.trigger(this.scroll.eventTypes.alterOptions, this.mouseWheelOpt);
this.scroll.trigger(this.scroll.eventTypes.mousewheelStart);
};
MouseWheel.prototype.cleanCache = function () {
this.deltaCache = [];
};
MouseWheel.prototype.wheelMoveHandler = function (delta) {
var _this = this;
var _a = this.mouseWheelOpt, throttleTime = _a.throttleTime, dampingFactor = _a.dampingFactor;
if (throttleTime && this.wheelMoveTimer) {
this.deltaCache.push(delta);
}
else {
var cachedDelta = this.deltaCache.reduce(function (prev, current) {
return {
x: prev.x + current.x,
y: prev.y + current.y,
};
}, { x: 0, y: 0 });
this.cleanCache();
var _b = this.scroll.scroller, scrollBehaviorX = _b.scrollBehaviorX, scrollBehaviorY = _b.scrollBehaviorY;
scrollBehaviorX.setMovingDirection(-delta.directionX);
scrollBehaviorY.setMovingDirection(-delta.directionY);
scrollBehaviorX.setDirection(delta.x);
scrollBehaviorY.setDirection(delta.y);
// when out of boundary, perform a damping scroll
var newX = scrollBehaviorX.performDampingAlgorithm(Math.round(delta.x) + cachedDelta.x, dampingFactor);
var newY = scrollBehaviorY.performDampingAlgorithm(Math.round(delta.y) + cachedDelta.x, dampingFactor);
if (!this.scroll.trigger(this.scroll.eventTypes.mousewheelMove, {
x: newX,
y: newY,
})) {
var easeTime = this.getEaseTime();
if (newX !== this.scroll.x || newY !== this.scroll.y) {
this.scroll.scrollTo(newX, newY, easeTime);
}
}
if (throttleTime) {
this.wheelMoveTimer = window.setTimeout(function () {
_this.wheelMoveTimer = 0;
}, throttleTime);
}
}
};
MouseWheel.prototype.wheelEndDetector = function (delta) {
var _this = this;
window.clearTimeout(this.wheelEndTimer);
this.wheelEndTimer = window.setTimeout(function () {
_this.wheelStart = false;
window.clearTimeout(_this.wheelMoveTimer);
_this.wheelMoveTimer = 0;
_this.scroll.trigger(_this.scroll.eventTypes.mousewheelEnd, delta);
}, this.mouseWheelOpt.discreteTime);
};
MouseWheel.prototype.getWheelDelta = function (e) {
var _a = this.mouseWheelOpt, speed = _a.speed, invert = _a.invert;
var wheelDeltaX = 0;
var wheelDeltaY = 0;
var direction = invert ? -1 /* Negative */ : 1 /* Positive */;
switch (true) {
case 'deltaX' in e:
if (e.deltaMode === 1) {
wheelDeltaX = -e.deltaX * speed;
wheelDeltaY = -e.deltaY * speed;
}
else {
wheelDeltaX = -e.deltaX;
wheelDeltaY = -e.deltaY;
}
break;
case 'wheelDeltaX' in e:
wheelDeltaX = (e.wheelDeltaX / 120) * speed;
wheelDeltaY = (e.wheelDeltaY / 120) * speed;
break;
case 'wheelDelta' in e:
wheelDeltaX = wheelDeltaY = (e.wheelDelta / 120) * speed;
break;
case 'detail' in e:
wheelDeltaX = wheelDeltaY = (-e.detail / 3) * speed;
break;
}
wheelDeltaX *= direction;
wheelDeltaY *= direction;
if (!this.scroll.hasVerticalScroll) {
wheelDeltaX = wheelDeltaY;
wheelDeltaY = 0;
}
if (!this.scroll.hasHorizontalScroll) {
wheelDeltaX = 0;
}
var directionX = wheelDeltaX > 0
? -1 /* Negative */
: wheelDeltaX < 0
? 1 /* Positive */
: 0 /* Default */;
var directionY = wheelDeltaY > 0
? -1 /* Negative */
: wheelDeltaY < 0
? 1 /* Positive */
: 0 /* Default */;
return {
x: wheelDeltaX,
y: wheelDeltaY,
directionX: directionX,
directionY: directionY,
};
};
MouseWheel.prototype.beforeHandler = function (e) {
var _a = this.scroll.options, preventDefault = _a.preventDefault, stopPropagation = _a.stopPropagation, preventDefaultException = _a.preventDefaultException;
if (preventDefault &&
!preventDefaultExceptionFn(e.target, preventDefaultException)) {
e.preventDefault();
}
if (stopPropagation) {
e.stopPropagation();
}
};
MouseWheel.prototype.getEaseTime = function () {
var SAFE_EASETIME = 100;
var easeTime = this.mouseWheelOpt.easeTime;
// scrollEnd event will be triggered in every calling of scrollTo when easeTime is too small
// easeTime needs to be greater than 100
if (easeTime < SAFE_EASETIME) {
warn("easeTime should be greater than 100." +
"If mouseWheel easeTime is too small," +
"scrollEnd will be triggered many times.");
}
return Math.max(easeTime, SAFE_EASETIME);
};
MouseWheel.prototype.destroy = function () {
this.eventRegister.destroy();
window.clearTimeout(this.wheelEndTimer);
window.clearTimeout(this.wheelMoveTimer);
this.hooksFn.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
};
MouseWheel.pluginName = 'mouseWheel';
MouseWheel.applyOrder = "pre" /* Pre */;
return MouseWheel;
}());
var ObserveDOM = /** @class */ (function () {
function ObserveDOM(scroll) {
this.scroll = scroll;
this.stopObserver = false;
this.init();
}
ObserveDOM.prototype.init = function () {
this.handleMutationObserver();
this.handleHooks();
};
ObserveDOM.prototype.handleMutationObserver = function () {
var _this = this;
if (typeof MutationObserver !== 'undefined') {
var timer_1 = 0;
this.observer = new MutationObserver(function (mutations) {
_this.mutationObserverHandler(mutations, timer_1);
});
this.startObserve(this.observer);
}
else {
this.checkDOMUpdate();
}
};
ObserveDOM.prototype.handleHooks = function () {
var _this = this;
this.hooksFn = [];
this.registerHooks(this.scroll.hooks, this.scroll.hooks.eventTypes.enable, function () {
if (_this.stopObserver) {
_this.init();
}
});
this.registerHooks(this.scroll.hooks, this.scroll.hooks.eventTypes.disable, function () {
_this.stopObserve();
});
this.registerHooks(this.scroll.hooks, this.scroll.hooks.eventTypes.destroy, function () {
_this.destroy();
});
};
ObserveDOM.prototype.mutationObserverHandler = function (mutations, timer) {
var _this = this;
if (this.shouldNotRefresh()) {
return;
}
var immediateRefresh = false;
var deferredRefresh = false;
for (var i = 0; i < mutations.length; i++) {
var mutation = mutations[i];
if (mutation.type !== 'attributes') {
immediateRefresh = true;
break;
}
else {
if (mutation.target !== this.scroll.scroller.content) {
deferredRefresh = true;
break;
}
}
}
if (immediateRefresh) {
this.scroll.refresh();
}
else if (deferredRefresh) {
// attributes changes too often
clearTimeout(timer);
timer = window.setTimeout(function () {
if (!_this.shouldNotRefresh()) {
_this.scroll.refresh();
}
}, 60);
}
};
ObserveDOM.prototype.startObserve = function (observer) {
var config = {
attributes: true,
childList: true,
subtree: true,
};
observer.observe(this.scroll.scroller.content, config);
};
ObserveDOM.prototype.shouldNotRefresh = function () {
var scroller = this.scroll.scroller;
var scrollBehaviorX = scroller.scrollBehaviorX, scrollBehaviorY = scroller.scrollBehaviorY;
var outsideBoundaries = scrollBehaviorX.currentPos > scrollBehaviorX.minScrollPos ||
scrollBehaviorX.currentPos < scrollBehaviorX.maxScrollPos ||
scrollBehaviorY.currentPos > scrollBehaviorY.minScrollPos ||
scrollBehaviorY.currentPos < scrollBehaviorY.maxScrollPos;
return scroller.animater.pending || outsideBoundaries;
};
ObserveDOM.prototype.checkDOMUpdate = function () {
var _this = this;
var scrollerEl = this.scroll.scroller.content;
var scrollerRect = getRect(scrollerEl);
var oldWidth = scrollerRect.width;
var oldHeight = scrollerRect.height;
var check = function () {
if (_this.stopObserver) {
return;
}
scrollerRect = getRect(scrollerEl);
var newWidth = scrollerRect.width;
var newHeight = scrollerRect.height;
if (oldWidth !== newWidth || oldHeight !== newHeight) {
_this.scroll.refresh();
}
oldWidth = newWidth;
oldHeight = newHeight;
next();
};
var next = function () {
setTimeout(function () {
check();
}, 1000);
};
next();
};
ObserveDOM.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
ObserveDOM.prototype.stopObserve = function () {
this.stopObserver = true;
if (this.observer) {
this.observer.disconnect();
}
};
ObserveDOM.prototype.destroy = function () {
this.stopObserve();
this.hooksFn.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
this.hooksFn.length = 0;
};
ObserveDOM.pluginName = 'observeDOM';
return ObserveDOM;
}());
var sourcePrefix = 'plugins.pullDownRefresh';
var propertiesMap = [
{
key: 'finishPullDown',
name: 'finishPullDown'
},
{
key: 'openPullDown',
name: 'openPullDown'
},
{
key: 'closePullDown',
name: 'closePullDown'
},
{
key: 'autoPullDownRefresh',
name: 'autoPullDownRefresh'
}
];
var propertiesConfig$1 = propertiesMap.map(function (item) {
return {
key: item.key,
sourceKey: sourcePrefix + "." + item.name
};
});
var PULL_DOWN_HOOKS_NAME = 'pullingDown';
var PullDown = /** @class */ (function () {
function PullDown(scroll) {
this.scroll = scroll;
this.pulling = false;
this.init();
}
PullDown.prototype.init = function () {
this.handleBScroll();
this.handleOptions(this.scroll.options.pullDownRefresh);
this.handleHooks();
this.watch();
};
PullDown.prototype.handleBScroll = function () {
this.scroll.registerType([PULL_DOWN_HOOKS_NAME]);
this.scroll.proxy(propertiesConfig$1);
};
PullDown.prototype.handleOptions = function (userOptions) {
if (userOptions === void 0) { userOptions = {}; }
userOptions = (userOptions === true ? {} : userOptions);
var defaultOptions = {
threshold: 90,
stop: 40,
};
this.options = extend(defaultOptions, userOptions);
// plugin relies on scrollTo api
// set it to Realtime make bs dispatch scroll、scrollEnd hooks
this.scroll.options.probeType = 3 /* Realtime */;
};
PullDown.prototype.handleHooks = function () {
var _this = this;
this.hooksFn = [];
var scroller = this.scroll.scroller;
var scrollBehaviorY = scroller.scrollBehaviorY;
this.currentMinScrollY = this.cachedOriginanMinScrollY =
scrollBehaviorY.minScrollPos;
this.registerHooks(scrollBehaviorY.hooks, scrollBehaviorY.hooks.eventTypes.computeBoundary, function (boundary) {
// content is smaller than wrapper
if (boundary.maxScrollPos > 0) {
// allow scrolling when content is not full of wrapper
boundary.maxScrollPos = -1;
}
boundary.minScrollPos = _this.currentMinScrollY;
});
// integrate with mousewheel
if (this.scroll.eventTypes.alterOptions) {
this.registerHooks(this.scroll, this.scroll.eventTypes.alterOptions, function (mouseWheelOptions) {
var SANE_DISCRETE_TIME = 300;
var SANE_EASE_TIME = 350;
mouseWheelOptions.discreteTime = SANE_DISCRETE_TIME;
// easeTime > discreteTime ensure goInto checkPullDown function
mouseWheelOptions.easeTime = SANE_EASE_TIME;
});
this.registerHooks(this.scroll, this.scroll.eventTypes.mousewheelEnd, function () {
// mouseWheel need trigger checkPullDown manually
scroller.hooks.trigger(scroller.hooks.eventTypes.end);
});
}
};
PullDown.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
PullDown.prototype.watch = function () {
var scroller = this.scroll.scroller;
this.watching = true;
this.registerHooks(scroller.hooks, scroller.hooks.eventTypes.end, this.checkPullDown);
};
PullDown.prototype.unwatch = function () {
var scroller = this.scroll.scroller;
this.watching = false;
scroller.hooks.off(scroller.hooks.eventTypes.end, this.checkPullDown);
};
PullDown.prototype.checkPullDown = function () {
var _a = this.options, threshold = _a.threshold, stop = _a.stop;
// check if a real pull down action
if (this.scroll.directionY !== -1 /* Negative */ ||
this.scroll.y < threshold) {
return false;
}
if (!this.pulling) {
this.modifyBehaviorYBoundary(stop);
this.pulling = true;
this.scroll.trigger(PULL_DOWN_HOOKS_NAME);
}
this.scroll.scrollTo(this.scroll.x, stop, this.scroll.options.bounceTime, ease.bounce);
return this.pulling;
};
PullDown.prototype.modifyBehaviorYBoundary = function (stopDistance) {
var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
// manually modify minScrollPos for a hang animation
// to prevent from resetPosition
this.cachedOriginanMinScrollY = scrollBehaviorY.minScrollPos;
this.currentMinScrollY = stopDistance;
scrollBehaviorY.computeBoundary();
};
PullDown.prototype.finishPullDown = function () {
var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
// restore minScrollY since the hang animation has ended
this.currentMinScrollY = this.cachedOriginanMinScrollY;
scrollBehaviorY.computeBoundary();
this.pulling = false;
this.scroll.resetPosition(this.scroll.options.bounceTime, ease.bounce);
};
// allow 'true' type is compat for beta version implements
PullDown.prototype.openPullDown = function (config) {
if (config === void 0) { config = {}; }
this.handleOptions(config);
if (!this.watching) {
this.watch();
}
};
PullDown.prototype.closePullDown = function () {
this.unwatch();
};
PullDown.prototype.autoPullDownRefresh = function () {
var _a = this.options, threshold = _a.threshold, stop = _a.stop;
if (this.pulling || !this.watching) {
return;
}
this.pulling = true;
this.modifyBehaviorYBoundary(stop);
this.scroll.scrollTo(this.scroll.x, threshold);
this.scroll.trigger(PULL_DOWN_HOOKS_NAME);
this.scroll.scrollTo(this.scroll.x, stop, this.scroll.options.bounceTime, ease.bounce);
};
PullDown.pluginName = 'pullDownRefresh';
return PullDown;
}());
var sourcePrefix$1 = 'plugins.pullUpLoad';
var propertiesMap$1 = [
{
key: 'finishPullUp',
name: 'finishPullUp'
},
{
key: 'openPullUp',
name: 'openPullUp'
},
{
key: 'closePullUp',
name: 'closePullUp'
},
{
key: 'autoPullUpLoad',
name: 'autoPullUpLoad'
}
];
var propertiesConfig$2 = propertiesMap$1.map(function (item) {
return {
key: item.key,
sourceKey: sourcePrefix$1 + "." + item.name
};
});
var PULL_UP_HOOKS_NAME = 'pullingUp';
var PullUp = /** @class */ (function () {
function PullUp(scroll) {
this.scroll = scroll;
this.pulling = false;
this.watching = false;
this.init();
}
PullUp.prototype.init = function () {
this.handleBScroll();
this.handleOptions(this.scroll.options.pullUpLoad);
this.handleHooks();
this.watch();
};
PullUp.prototype.handleBScroll = function () {
this.scroll.registerType([PULL_UP_HOOKS_NAME]);
this.scroll.proxy(propertiesConfig$2);
};
PullUp.prototype.handleOptions = function (userOptions) {
if (userOptions === void 0) { userOptions = {}; }
userOptions = (userOptions === true ? {} : userOptions);
var defaultOptions = {
threshold: 0,
};
this.options = extend(defaultOptions, userOptions);
this.scroll.options.probeType = 3 /* Realtime */;
};
PullUp.prototype.handleHooks = function () {
this.hooksFn = [];
var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
this.registerHooks(scrollBehaviorY.hooks, scrollBehaviorY.hooks.eventTypes.computeBoundary, function (boundary) {
// content is smaller than wrapper
if (boundary.maxScrollPos > 0) {
// allow scrolling when content is not full of wrapper
boundary.maxScrollPos = -1;
}
});
};
PullUp.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
PullUp.prototype.watch = function () {
if (this.watching) {
return;
}
this.watching = true;
this.registerHooks(this.scroll, this.scroll.eventTypes.scroll, this.checkPullUp);
};
PullUp.prototype.unwatch = function () {
this.watching = false;
this.scroll.off(this.scroll.eventTypes.scroll, this.checkPullUp);
};
PullUp.prototype.checkPullUp = function (pos) {
var _this = this;
var threshold = this.options.threshold;
if (this.scroll.movingDirectionY === 1 /* Positive */ &&
pos.y <= this.scroll.maxScrollY + threshold) {
this.pulling = true;
// must reset pulling after scrollEnd
this.scroll.once(this.scroll.eventTypes.scrollEnd, function () {
_this.pulling = false;
});
this.unwatch();
this.scroll.trigger(PULL_UP_HOOKS_NAME);
}
};
PullUp.prototype.finishPullUp = function () {
var _this = this;
// reset Direction, fix #936
this.scroll.scroller.scrollBehaviorY.setMovingDirection(0 /* Default */);
if (this.pulling) {
this.scroll.once(this.scroll.eventTypes.scrollEnd, function () {
_this.watch();
});
}
else {
this.watch();
}
};
// allow 'true' type is compat for beta version implements
PullUp.prototype.openPullUp = function (config) {
if (config === void 0) { config = {}; }
this.handleOptions(config);
this.watch();
};
PullUp.prototype.closePullUp = function () {
this.unwatch();
};
PullUp.prototype.autoPullUpLoad = function () {
var threshold = this.options.threshold;
var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
if (this.pulling || !this.watching) {
return;
}
// simulate a pullUp action
var NEGATIVE_VALUE = -1;
var outOfBoundaryPos = scrollBehaviorY.maxScrollPos + threshold + NEGATIVE_VALUE;
this.scroll.scroller.scrollBehaviorY.setMovingDirection(NEGATIVE_VALUE);
this.scroll.scrollTo(this.scroll.x, outOfBoundaryPos, this.scroll.options.bounceTime);
};
PullUp.pluginName = 'pullUpLoad';
return PullUp;
}());
var EventHandler = /** @class */ (function () {
function EventHandler(indicator, options) {
this.indicator = indicator;
this.options = options;
this.bscroll = indicator.bscroll;
this.startEventRegister = new EventRegister(this.indicator.el, [
{
name: options.disableMouse ? 'touchstart' : 'mousedown',
handler: this._start.bind(this)
}
]);
this.endEventRegister = new EventRegister(window, [
{
name: options.disableMouse ? 'touchend' : 'mouseup',
handler: this._end.bind(this)
}
]);
this.hooks = new EventEmitter(['touchStart', 'touchMove', 'touchEnd']);
}
EventHandler.prototype._start = function (e) {
if (!this.bscroll.scroller.actions.enabled) {
return;
}
var point = (e.touches ? e.touches[0] : e);
e.preventDefault();
e.stopPropagation();
this.initiated = true;
this.moved = false;
this.lastPoint = point[this.indicator.keysMap.pointPos];
var disableMouse = this.bscroll.options.disableMouse;
this.moveEventRegister = new EventRegister(window, [
{
name: disableMouse ? 'touchmove' : 'mousemove',
handler: this._move.bind(this)
}
]);
this.hooks.trigger('touchStart');
};
EventHandler.prototype._move = function (e) {
var point = (e.touches ? e.touches[0] : e);
var pointPos = point[this.indicator.keysMap.pointPos];
e.preventDefault();
e.stopPropagation();
var delta = pointPos - this.lastPoint;
this.lastPoint = pointPos;
if (!this.moved) {
this.hooks.trigger('touchMove', this.moved, delta);
this.moved = true;
return;
}
this.hooks.trigger('touchMove', this.moved, delta);
};
EventHandler.prototype._end = function (e) {
if (!this.initiated) {
return;
}
this.initiated = false;
e.preventDefault();
e.stopPropagation();
this.moveEventRegister.destroy();
this.hooks.trigger('touchEnd', this.moved);
};
EventHandler.prototype.destroy = function () {
this.startEventRegister.destroy();
this.moveEventRegister && this.moveEventRegister.destroy();
this.endEventRegister.destroy();
};
return EventHandler;
}());
var INDICATOR_MIN_LEN = 8;
var Indicator = /** @class */ (function () {
function Indicator(bscroll, options) {
this.bscroll = bscroll;
this.options = options;
this.keyVals = {
sizeRatio: 1,
maxPos: 0,
initialSize: 0
};
this.curPos = 0;
this.hooksHandlers = [];
this.wrapper = options.wrapper;
this.wrapperStyle = this.wrapper.style;
this.el = this.wrapper.children[0];
this.elStyle = this.el.style;
this.bscroll = bscroll;
this.direction = options.direction;
this.keysMap = this._getKeysMap();
if (options.fade) {
this.visible = 0;
this.wrapperStyle.opacity = '0';
}
else {
this.visible = 1;
}
this._listenHooks(options.fade, options.interactive);
this.refresh();
}
Indicator.prototype._listenHooks = function (fade, interactive) {
var _this = this;
var bscroll = this.bscroll;
var bscrollHooks = bscroll;
var translaterHooks = bscroll.scroller.translater.hooks;
var animaterHooks = bscroll.scroller.animater.hooks;
this._listen(bscrollHooks, 'refresh', this.refresh);
this._listen(translaterHooks, 'translate', this.updatePosAndSize);
this._listen(animaterHooks, 'time', function (time) {
_this.setTransitionTime(time);
});
this._listen(animaterHooks, 'timeFunction', function (ease) {
_this.setTransitionTimingFunction(ease);
});
if (fade) {
this._listen(bscrollHooks, 'scrollEnd', function () {
_this.fade();
});
this._listen(bscrollHooks, 'scrollStart', function () {
_this.fade(true);
});
// for mousewheel event
if (bscroll.eventTypes.mousewheelStart &&
bscroll.eventTypes.mousewheelEnd) {
this._listen(bscrollHooks, 'mousewheelStart', function () {
_this.fade(true);
});
this._listen(bscrollHooks, 'mousewheelEnd', function () {
_this.fade();
});
}
}
if (interactive) {
var disableMouse = this.bscroll.options.disableMouse;
this.eventHandler = new EventHandler(this, { disableMouse: disableMouse });
var eventHandlerHooks = this.eventHandler.hooks;
this._listen(eventHandlerHooks, 'touchStart', this.startHandler);
this._listen(eventHandlerHooks, 'touchMove', this.moveHandler);
this._listen(eventHandlerHooks, 'touchEnd', this.endHandler);
}
};
Indicator.prototype._getKeysMap = function () {
if (this.direction === "vertical" /* Vertical */) {
return {
hasScroll: 'hasVerticalScroll',
size: 'height',
wrapperSize: 'clientHeight',
scrollerSize: 'scrollerHeight',
maxScroll: 'maxScrollY',
pos: 'y',
pointPos: 'pageY',
translate: 'translateY'
};
}
return {
hasScroll: 'hasHorizontalScroll',
size: 'width',
wrapperSize: 'clientWidth',
scrollerSize: 'scrollerWidth',
maxScroll: 'maxScrollX',
pos: 'x',
pointPos: 'pageX',
translate: 'translateX'
};
};
Indicator.prototype.fade = function (visible) {
var time = visible ? 250 : 500;
this.wrapperStyle[style.transitionDuration] = time + 'ms';
this.wrapperStyle.opacity = visible ? '1' : '0';
this.visible = visible ? 1 : 0;
};
Indicator.prototype.refresh = function () {
var hasScroll = this.keysMap.hasScroll;
if (this._setShowBy(this.bscroll[hasScroll])) {
var _a = this.keysMap, wrapperSize = _a.wrapperSize, scrollerSize = _a.scrollerSize, maxScroll = _a.maxScroll;
this.keyVals = this._refreshKeyValues(this.wrapper[wrapperSize], this.bscroll[scrollerSize], this.bscroll[maxScroll]);
this.updatePosAndSize({
x: this.bscroll.x,
y: this.bscroll.y
});
}
};
Indicator.prototype._setShowBy = function (hasScroll) {
if (hasScroll) {
this.wrapper.style.display = '';
return true;
}
this.wrapper.style.display = 'none';
return false;
};
Indicator.prototype._refreshKeyValues = function (wrapperSize, scrollerSize, maxScroll) {
var initialSize = Math.max(Math.round((wrapperSize * wrapperSize) / (scrollerSize || wrapperSize || 1)), INDICATOR_MIN_LEN);
var maxPos = wrapperSize - initialSize;
// sizeRatio is negative
var sizeRatio = maxPos / maxScroll;
return {
initialSize: initialSize,
maxPos: maxPos,
sizeRatio: sizeRatio
};
};
Indicator.prototype.updatePosAndSize = function (endPoint) {
var _a = this._refreshPosAndSizeValue(endPoint, this.keyVals), pos = _a.pos, size = _a.size;
this.curPos = pos;
this._refreshPosAndSizeStyle(size, pos);
};
Indicator.prototype._refreshPosAndSizeValue = function (endPoint, keyVals) {
var posKey = this.keysMap.pos;
var sizeRatio = keyVals.sizeRatio, initialSize = keyVals.initialSize, maxPos = keyVals.maxPos;
var pos = Math.round(sizeRatio * endPoint[posKey]);
var size;
if (pos < 0) {
size = Math.max(initialSize + pos * 3, INDICATOR_MIN_LEN);
pos = 0;
}
else if (pos > maxPos) {
size = Math.max(initialSize - (pos - maxPos) * 3, INDICATOR_MIN_LEN);
pos = maxPos + initialSize - size;
}
else {
size = initialSize;
}
return {
pos: pos,
size: size
};
};
Indicator.prototype._refreshPosAndSizeStyle = function (size, pos) {
var _a = this.keysMap, translate = _a.translate, sizeKey = _a.size;
this.elStyle[sizeKey] = size + "px";
this.elStyle[style.transform] = translate + "(" + pos + "px)" + this.bscroll.options.translateZ;
};
Indicator.prototype.setTransitionTime = function (time) {
if (time === void 0) { time = 0; }
this.elStyle[style.transitionDuration] = time + 'ms';
};
Indicator.prototype.setTransitionTimingFunction = function (easing) {
this.elStyle[style.transitionTimingFunction] = easing;
};
Indicator.prototype.startHandler = function () {
this.setTransitionTime();
this.bscroll.trigger('beforeScrollStart');
};
Indicator.prototype.moveHandler = function (moved, delta) {
if (!moved) {
this.bscroll.trigger('scrollStart');
}
var newScrollPos = this._calScrollDesPos(this.curPos, delta, this.keyVals);
// TODO freeScroll
if (this.direction === "vertical" /* Vertical */) {
this.bscroll.scrollTo(this.bscroll.x, newScrollPos);
}
else {
this.bscroll.scrollTo(newScrollPos, this.bscroll.y);
}
this.bscroll.trigger('scroll', {
x: this.bscroll.x,
y: this.bscroll.y
});
};
Indicator.prototype._calScrollDesPos = function (curPos, delta, keyVals) {
var maxPos = keyVals.maxPos, sizeRatio = keyVals.sizeRatio;
var newPos = curPos + delta;
if (newPos < 0) {
newPos = 0;
}
else if (newPos > maxPos) {
newPos = maxPos;
}
return Math.round(newPos / sizeRatio);
};
Indicator.prototype.endHandler = function (moved) {
if (moved) {
this.bscroll.trigger('scrollEnd', {
x: this.bscroll.x,
y: this.bscroll.y
});
}
};
Indicator.prototype.destroy = function () {
if (this.options.interactive) {
this.eventHandler.destroy();
}
this.wrapper.parentNode.removeChild(this.wrapper);
this.hooksHandlers.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
this.hooksHandlers.length = 0;
};
Indicator.prototype._listen = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksHandlers.push([hooks, name, handler]);
};
return Indicator;
}());
var ScrollBar = /** @class */ (function () {
function ScrollBar(scroll) {
this.indicators = [];
this.indicators = this.createIndicators(scroll);
scroll.on(scroll.eventTypes.destroy, this.destroy, this);
}
ScrollBar.prototype.createIndicators = function (bscroll) {
var _this = this;
var _a = bscroll.options
.scrollbar, _b = _a.fade, fade = _b === void 0 ? true : _b, _c = _a.interactive, interactive = _c === void 0 ? false : _c;
var indicatorOption;
var scrolls = {
scrollX: "horizontal" /* Horizontal */,
scrollY: "vertical" /* Vertical */
};
var indicators = [];
Object.keys(scrolls).forEach(function (key) {
var direction = scrolls[key];
if (bscroll.options[key]) {
indicatorOption = {
wrapper: _this.createIndicatorElement(direction),
direction: direction,
fade: fade,
interactive: interactive
};
bscroll.wrapper.appendChild(indicatorOption.wrapper);
indicators.push(new Indicator(bscroll, indicatorOption));
}
});
return indicators;
};
ScrollBar.prototype.createIndicatorElement = function (direction) {
var scrollbarEl = document.createElement('div');
var indicatorEl = document.createElement('div');
scrollbarEl.style.cssText =
'position:absolute;z-index:9999;pointerEvents:none';
indicatorEl.style.cssText =
'box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px;';
indicatorEl.className = 'bscroll-indicator';
if (direction === 'horizontal') {
scrollbarEl.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
indicatorEl.style.height = '100%';
scrollbarEl.className = 'bscroll-horizontal-scrollbar';
}
else {
scrollbarEl.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
indicatorEl.style.width = '100%';
scrollbarEl.className = 'bscroll-vertical-scrollbar';
}
scrollbarEl.style.cssText += ';overflow:hidden';
scrollbarEl.appendChild(indicatorEl);
return scrollbarEl;
};
ScrollBar.prototype.destroy = function () {
for (var _i = 0, _a = this.indicators; _i < _a.length; _i++) {
var indicator = _a[_i];
indicator.destroy();
}
};
ScrollBar.pluginName = 'scrollbar';
return ScrollBar;
}());
var PagesMatrix = /** @class */ (function () {
function PagesMatrix(scroll) {
this.scroll = scroll;
this.init();
}
PagesMatrix.prototype.init = function () {
var scroller = this.scroll.scroller;
var scrollBehaviorX = scroller.scrollBehaviorX, scrollBehaviorY = scroller.scrollBehaviorY;
this.wrapperWidth = scrollBehaviorX.wrapperSize;
this.wrapperHeight = scrollBehaviorY.wrapperSize;
this.scrollerHeight = scrollBehaviorY.contentSize;
this.scrollerWidth = scrollBehaviorX.contentSize;
this.pages = this.buildPagesMatrix(this.wrapperWidth, this.wrapperHeight);
this.pageLengthOfX = this.pages ? this.pages.length : 0;
this.pageLengthOfY = this.pages && this.pages[0] ? this.pages[0].length : 0;
};
PagesMatrix.prototype.getPageStats = function (pageX, pageY) {
return this.pages[pageX][pageY];
};
PagesMatrix.prototype.getNearestPageIndex = function (x, y) {
var pageX = 0;
var pageY = 0;
var l = this.pages.length;
for (; pageX < l - 1; pageX++) {
if (x >= this.pages[pageX][0].cx) {
break;
}
}
l = this.pages[pageX].length;
for (; pageY < l - 1; pageY++) {
if (y >= this.pages[0][pageY].cy) {
break;
}
}
return {
pageX: pageX,
pageY: pageY,
};
};
// (n x 1) matrix for horizontal scroll or
// (1 * n) matrix for vertical scroll
PagesMatrix.prototype.buildPagesMatrix = function (stepX, stepY) {
var pages = [];
var x = 0;
var y;
var cx;
var cy;
var i = 0;
var l;
var maxScrollPosX = this.scroll.scroller.scrollBehaviorX.maxScrollPos;
var maxScrollPosY = this.scroll.scroller.scrollBehaviorY.maxScrollPos;
cx = Math.round(stepX / 2);
cy = Math.round(stepY / 2);
while (x > -this.scrollerWidth) {
pages[i] = [];
l = 0;
y = 0;
while (y > -this.scrollerHeight) {
pages[i][l] = {
x: Math.max(x, maxScrollPosX),
y: Math.max(y, maxScrollPosY),
width: stepX,
height: stepY,
cx: x - cx,
cy: y - cy,
};
y -= stepY;
l++;
}
x -= stepX;
i++;
}
return pages;
};
return PagesMatrix;
}());
var BASE_PAGE = {
pageX: 0,
pageY: 0,
x: 0,
y: 0,
};
var SlidePages = /** @class */ (function () {
function SlidePages(scroll, slideOptions) {
this.scroll = scroll;
this.slideOptions = slideOptions;
this.slideX = false;
this.slideY = false;
this.currentPage = extend({}, BASE_PAGE);
}
SlidePages.prototype.refresh = function () {
this.pagesMatrix = new PagesMatrix(this.scroll);
var _a = this.currentPage, pageX = _a.pageX, pageY = _a.pageY;
// when refresh or resize, currenpage.(x|y) need recaculate
var _b = this.pagesMatrix.getPageStats(pageX, pageY), x = _b.x, y = _b.y;
this.currentPage = { pageX: pageX, pageY: pageY, x: x, y: y };
this.checkSlideLoop();
};
SlidePages.prototype.setCurrentPage = function (newPage) {
this.currentPage = newPage;
};
SlidePages.prototype.getInternalPage = function (pageX, pageY) {
if (pageX >= this.pagesMatrix.pageLengthOfX) {
pageX = this.pagesMatrix.pageLengthOfX - 1;
}
else if (pageX < 0) {
pageX = 0;
}
if (pageY >= this.pagesMatrix.pageLengthOfY) {
pageY = this.pagesMatrix.pageLengthOfY - 1;
}
else if (pageY < 0) {
pageY = 0;
}
var _a = this.pagesMatrix.getPageStats(pageX, pageY), x = _a.x, y = _a.y;
return {
pageX: pageX,
pageY: pageY,
x: x,
y: y,
};
};
SlidePages.prototype.getInitialPage = function () {
var initPageX = this.loopX ? 1 : 0;
var initPageY = this.loopY ? 1 : 0;
var pageX = this.currentPage.pageX || initPageX;
var pageY = this.currentPage.pageY || initPageY;
var _a = this.pagesMatrix.getPageStats(pageX, pageY), x = _a.x, y = _a.y;
return {
pageX: pageX,
pageY: pageY,
x: x,
y: y,
};
};
SlidePages.prototype.getExposedPage = function () {
var exposedPage = extend({}, this.currentPage);
// only pageX or pageY need fix
if (this.loopX) {
exposedPage.pageX = this.fixedPage(exposedPage.pageX, this.pagesMatrix.pageLengthOfX - 2);
}
if (this.loopY) {
exposedPage.pageY = this.fixedPage(exposedPage.pageY, this.pagesMatrix.pageLengthOfY - 2);
}
return exposedPage;
};
SlidePages.prototype.getWillChangedPage = function (page) {
page = extend({}, page);
// Page need fix
if (this.loopX) {
page.pageX = this.fixedPage(page.pageX, this.pagesMatrix.pageLengthOfX - 2);
page.x = this.pagesMatrix.getPageStats(page.pageX + 1, 0).x;
}
if (this.loopY) {
page.pageY = this.fixedPage(page.pageY, this.pagesMatrix.pageLengthOfY - 2);
page.y = this.pagesMatrix.getPageStats(0, page.pageY + 1).y;
}
return page;
};
SlidePages.prototype.fixedPage = function (page, realPageLen) {
var pageIndex = [];
for (var i = 0; i < realPageLen; i++) {
pageIndex.push(i);
}
pageIndex.unshift(realPageLen - 1);
pageIndex.push(0);
return pageIndex[page];
};
SlidePages.prototype.getPageStats = function () {
return this.pagesMatrix.getPageStats(this.currentPage.pageX, this.currentPage.pageY);
};
SlidePages.prototype.getValidPageIndex = function (x, y) {
var lastX = this.pagesMatrix.pageLengthOfX - 1;
var lastY = this.pagesMatrix.pageLengthOfY - 1;
var firstX = 0;
var firstY = 0;
if (this.loopX) {
x += 1;
firstX = firstX + 1;
lastX = lastX - 1;
}
if (this.loopY) {
y += 1;
firstY = firstY + 1;
lastY = lastY - 1;
}
x = between(x, firstX, lastX);
y = between(y, firstY, lastY);
return {
pageX: x,
pageY: y,
};
};
SlidePages.prototype.nextPageIndex = function () {
return this.getPageIndexByDirection("positive" /* Positive */);
};
SlidePages.prototype.prevPageIndex = function () {
return this.getPageIndexByDirection("negative" /* Negative */);
};
SlidePages.prototype.nearestPage = function (x, y, directionX, directionY) {
var pageIndex = this.pagesMatrix.getNearestPageIndex(x, y);
var pageX = pageIndex.pageX, pageY = pageIndex.pageY;
var newX;
var newY;
if (pageX === this.currentPage.pageX) {
pageX += directionX;
pageX = between(pageX, 0, this.pagesMatrix.pageLengthOfX - 1);
}
if (pageY === this.currentPage.pageY) {
pageY += directionY;
pageY = between(pageY, 0, this.pagesMatrix.pageLengthOfY - 1);
}
newX = this.pagesMatrix.getPageStats(pageX, 0).x;
newY = this.pagesMatrix.getPageStats(0, pageY).y;
return {
x: newX,
y: newY,
pageX: pageX,
pageY: pageY,
};
};
SlidePages.prototype.resetLoopPage = function () {
if (this.loopX) {
if (this.currentPage.pageX === 0) {
return {
pageX: this.pagesMatrix.pageLengthOfX - 2,
pageY: this.currentPage.pageY,
};
}
if (this.currentPage.pageX === this.pagesMatrix.pageLengthOfX - 1) {
return {
pageX: 1,
pageY: this.currentPage.pageY,
};
}
}
if (this.loopY) {
if (this.currentPage.pageY === 0) {
return {
pageX: this.currentPage.pageX,
pageY: this.pagesMatrix.pageLengthOfY - 2,
};
}
if (this.currentPage.pageY === this.pagesMatrix.pageLengthOfY - 1) {
return {
pageX: this.currentPage.pageX,
pageY: 1,
};
}
}
};
SlidePages.prototype.getPageIndexByDirection = function (direction) {
var x = this.currentPage.pageX;
var y = this.currentPage.pageY;
if (this.slideX) {
x = direction === "negative" /* Negative */ ? x - 1 : x + 1;
}
if (this.slideY) {
y = direction === "negative" /* Negative */ ? y - 1 : y + 1;
}
return {
pageX: x,
pageY: y,
};
};
SlidePages.prototype.checkSlideLoop = function () {
this.needLoop = this.slideOptions.loop;
if (this.pagesMatrix.pageLengthOfX > 1) {
this.slideX = true;
}
if (this.pagesMatrix.pages[0] && this.pagesMatrix.pageLengthOfY > 1) {
this.slideY = true;
}
this.loopX = this.needLoop && this.slideX;
this.loopY = this.needLoop && this.slideY;
if (this.slideX && this.slideY) {
warn('slide does not support two direction at the same time.');
}
};
return SlidePages;
}());
var sourcePrefix$2 = 'plugins.slide';
var propertiesMap$2 = [
{
key: 'next',
name: 'next'
},
{
key: 'prev',
name: 'prev'
},
{
key: 'goToPage',
name: 'goToPage'
},
{
key: 'getCurrentPage',
name: 'getCurrentPage'
}
];
var propertiesConfig$3 = propertiesMap$2.map(function (item) {
return {
key: item.key,
sourceKey: sourcePrefix$2 + "." + item.name
};
});
var samePage = function (p1, p2) {
return p1.pageX === p2.pageX && p1.pageY === p2.pageY;
};
var Slide = /** @class */ (function () {
function Slide(scroll) {
this.scroll = scroll;
this.resetLooping = false;
this.isTouching = false;
this.autoplayTimer = 0;
if (!this.satisfyInitialization()) {
return;
}
this.init();
}
Slide.prototype.satisfyInitialization = function () {
if (this.scroll.scroller.content.children.length <= 0) {
warn("slide need at least one slide page to be initialised." +
"please check your DOM layout.");
return false;
}
return true;
};
Slide.prototype.init = function () {
this.willChangeToPage = extend({}, BASE_PAGE);
this.handleBScroll();
this.handleOptions();
this.handleHooks();
this.createPages();
};
Slide.prototype.createPages = function () {
this.pages = new SlidePages(this.scroll, this.options);
};
Slide.prototype.handleBScroll = function () {
this.scroll.registerType(['slideWillChange']);
this.scroll.proxy(propertiesConfig$3);
};
Slide.prototype.handleOptions = function () {
var userOptions = (this.scroll.options.slide === true
? {}
: this.scroll.options.slide);
var defaultOptions = {
loop: true,
threshold: 0.1,
speed: 400,
easing: ease.bounce,
listenFlick: true,
autoplay: true,
interval: 3000,
};
this.options = extend(defaultOptions, userOptions);
};
Slide.prototype.handleLoop = function () {
var loop = this.options.loop;
if (loop) {
var slideContent = this.scroll.scroller.content;
var slidePages = slideContent.children;
if (slidePages.length > 1) {
this.cloneFirstAndLastSlidePage(slideContent);
}
}
};
Slide.prototype.handleHooks = function () {
var _this = this;
var scrollHooks = this.scroll.hooks;
var scrollerHooks = this.scroll.scroller.hooks;
var listenFlick = this.options.listenFlick;
this.hooksFn = [];
// scroll
this.registerHooks(this.scroll, this.scroll.eventTypes.beforeScrollStart, this.pausePlay);
this.registerHooks(this.scroll, this.scroll.eventTypes.scrollEnd, this.modifyCurrentPage);
this.registerHooks(this.scroll, this.scroll.eventTypes.scrollEnd, this.startPlay);
// for mousewheel event
if (this.scroll.eventTypes.mousewheelMove) {
this.registerHooks(this.scroll, this.scroll.eventTypes.mousewheelMove, function () {
// prevent default action of mousewheelMove
return true;
});
this.registerHooks(this.scroll, this.scroll.eventTypes.mousewheelEnd, function (delta) {
if (delta.directionX === 1 /* Positive */ ||
delta.directionY === 1 /* Positive */) {
_this.next();
}
if (delta.directionX === -1 /* Negative */ ||
delta.directionY === -1 /* Negative */) {
_this.prev();
}
});
}
// scrollHooks
this.registerHooks(scrollHooks, scrollHooks.eventTypes.refresh, this.refreshHandler);
this.registerHooks(scrollHooks, scrollHooks.eventTypes.destroy, this.destroy);
// scroller
this.registerHooks(scrollerHooks, scrollerHooks.eventTypes.beforeRefresh, function () {
_this.handleLoop();
_this.setSlideInlineStyle();
});
this.registerHooks(scrollerHooks, scrollerHooks.eventTypes.momentum, this.modifyScrollMetaHandler);
this.registerHooks(scrollerHooks, scrollerHooks.eventTypes.beforeStart, this.setTouchFlag);
this.registerHooks(scrollerHooks, scrollerHooks.eventTypes.scroll, this.scrollMoving);
// a click operation will clearTimer, so restart a new one
this.registerHooks(scrollerHooks, scrollerHooks.eventTypes.checkClick, this.startPlay);
if (listenFlick) {
this.registerHooks(scrollerHooks, scrollerHooks.eventTypes.flick, this.flickHandler);
}
};
Slide.prototype.startPlay = function () {
var _this = this;
var _a = this.options, interval = _a.interval, autoplay = _a.autoplay;
if (autoplay) {
clearTimeout(this.autoplayTimer);
this.autoplayTimer = window.setTimeout(function () {
_this.next();
}, interval);
}
};
Slide.prototype.pausePlay = function () {
if (this.options.autoplay) {
clearTimeout(this.autoplayTimer);
}
};
Slide.prototype.setSlideInlineStyle = function () {
var styleConfigurations = [
{
direction: 'scrollX',
sizeType: 'offsetWidth',
styleType: 'width',
},
{
direction: 'scrollY',
sizeType: 'offsetHeight',
styleType: 'height',
},
];
var _a = this.scroll.scroller, slideContent = _a.content, slideWrapper = _a.wrapper;
var scrollOptions = this.scroll.options;
styleConfigurations.forEach(function (_a) {
var direction = _a.direction, sizeType = _a.sizeType, styleType = _a.styleType;
// wanna scroll in this direction
if (scrollOptions[direction]) {
var size = slideWrapper[sizeType];
var children = slideContent.children;
var length_1 = children.length;
for (var i = 0; i < length_1; i++) {
var slidePageDOM = children[i];
slidePageDOM.style[styleType] = size + 'px';
}
slideContent.style[styleType] = size * length_1 + 'px';
}
});
};
Slide.prototype.next = function (time, easing) {
var _a = this.pages.nextPageIndex(), pageX = _a.pageX, pageY = _a.pageY;
this.goTo(pageX, pageY, time, easing);
};
Slide.prototype.prev = function (time, easing) {
var _a = this.pages.prevPageIndex(), pageX = _a.pageX, pageY = _a.pageY;
this.goTo(pageX, pageY, time, easing);
};
Slide.prototype.goToPage = function (pageX, pageY, time, easing) {
var pageIndex = this.pages.getValidPageIndex(pageX, pageY);
if (!pageIndex) {
return;
}
this.goTo(pageIndex.pageX, pageIndex.pageY, time, easing);
};
Slide.prototype.getCurrentPage = function () {
return this.pages.getExposedPage();
};
Slide.prototype.nearestPage = function (x, y) {
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
var absStartPosX = scrollBehaviorX.absStartPos, maxScrollPosX = scrollBehaviorX.maxScrollPos, minScrollPosX = scrollBehaviorX.minScrollPos, directionX = scrollBehaviorX.direction;
var absStartPosY = scrollBehaviorY.absStartPos, maxScrollPosY = scrollBehaviorY.maxScrollPos, minScrollPosY = scrollBehaviorY.minScrollPos, directionY = scrollBehaviorY.direction;
var triggerThreshold = true;
if (Math.abs(x - absStartPosX) <= this.thresholdX &&
Math.abs(y - absStartPosY) <= this.thresholdY) {
triggerThreshold = false;
}
if (!triggerThreshold) {
return this.pages.currentPage;
}
return this.pages.nearestPage(between(x, maxScrollPosX, minScrollPosX), between(y, maxScrollPosY, minScrollPosY), directionX, directionY);
};
Slide.prototype.refreshHandler = function () {
var _this = this;
if (!this.satisfyInitialization()) {
return;
}
this.pages.refresh();
this.computeThreshold();
var initPage = this.pages.getInitialPage();
if (this.initialised) {
this.goTo(initPage.pageX, initPage.pageY, 0);
}
else {
this.registerHooks(this.scroll.hooks, this.scroll.hooks.eventTypes.beforeInitialScrollTo, function (position) {
_this.initialised = true;
position.x = initPage.x;
position.y = initPage.y;
_this.pages.setCurrentPage(initPage);
});
}
this.startPlay();
};
Slide.prototype.computeThreshold = function () {
var threshold = this.options.threshold;
// Integer
if (threshold % 1 === 0) {
this.thresholdX = threshold;
this.thresholdY = threshold;
}
else {
// decimal
var _a = this.pages.getPageStats(), width = _a.width, height = _a.height;
this.thresholdX = Math.round(width * threshold);
this.thresholdY = Math.round(height * threshold);
}
};
Slide.prototype.cloneFirstAndLastSlidePage = function (slideContent) {
if (this.initialised) {
this.removeClonedSlidePage(slideContent);
}
var children = slideContent.children;
prepend(children[children.length - 1].cloneNode(true), slideContent);
slideContent.appendChild(children[1].cloneNode(true));
};
Slide.prototype.removeClonedSlidePage = function (slideContent) {
var slidePages = slideContent.children;
if (slidePages.length > 2) {
removeChild(slideContent, slidePages[slidePages.length - 1]);
removeChild(slideContent, slidePages[0]);
}
};
Slide.prototype.modifyCurrentPage = function () {
this.isTouching = false;
if (!this.options.loop) {
return;
}
// triggered by resetLoop
if (this.resetLooping) {
this.resetLooping = false;
return;
}
var changePage = this.pages.resetLoopPage();
if (changePage) {
this.resetLooping = true;
this.goTo(changePage.pageX, changePage.pageY, 0);
// stop user's scrollEnd
// since it is a seamless scroll
return true;
}
this.pageWillChangeTo(this.pages.currentPage);
};
Slide.prototype.goTo = function (pageX, pageY, time, easing) {
var newPage = this.pages.getInternalPage(pageX, pageY);
if (!newPage) {
return;
}
var scrollEasing = easing || this.options.easing || ease.bounce;
var x = newPage.x, y = newPage.y;
var deltaX = x - this.scroll.scroller.scrollBehaviorX.currentPos;
var deltaY = y - this.scroll.scroller.scrollBehaviorY.currentPos;
if (!deltaX && !deltaY) {
return;
}
time = time === undefined ? this.getEaseTime(deltaX, deltaY) : time;
this.pages.setCurrentPage(newPage);
this.pageWillChangeTo(this.pages.currentPage);
this.scroll.scroller.scrollTo(x, y, time, scrollEasing);
};
Slide.prototype.flickHandler = function () {
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
var currentPosX = scrollBehaviorX.currentPos, startPosX = scrollBehaviorX.startPos, directionX = scrollBehaviorX.direction;
var currentPosY = scrollBehaviorY.currentPos, startPosY = scrollBehaviorY.startPos, directionY = scrollBehaviorY.direction;
var _b = this.pages.currentPage, pageX = _b.pageX, pageY = _b.pageY;
var time = this.getEaseTime(currentPosX - startPosX, currentPosY - startPosY);
this.goTo(pageX + directionX, pageY + directionY, time);
};
Slide.prototype.getEaseTime = function (deltaX, deltaY) {
return (this.options.speed ||
Math.max(Math.max(Math.min(Math.abs(deltaX), 1000), Math.min(Math.abs(deltaY), 1000)), 300));
};
Slide.prototype.modifyScrollMetaHandler = function (scrollMeta) {
var newPage = this.nearestPage(scrollMeta.newX, scrollMeta.newY);
scrollMeta.time = this.getEaseTime(scrollMeta.newX - newPage.x, scrollMeta.newY - newPage.y);
scrollMeta.newX = newPage.x;
scrollMeta.newY = newPage.y;
scrollMeta.easing = this.options.easing || ease.bounce;
this.pages.setCurrentPage(newPage);
this.pageWillChangeTo(this.pages.currentPage);
};
Slide.prototype.scrollMoving = function (point) {
if (this.isTouching) {
var newPos = this.nearestPage(point.x, point.y);
this.pageWillChangeTo(newPos);
}
};
Slide.prototype.pageWillChangeTo = function (newPage) {
var changeToPage = this.pages.getWillChangedPage(newPage);
if (!samePage(this.willChangeToPage, changeToPage)) {
this.willChangeToPage = changeToPage;
this.scroll.trigger(this.scroll.eventTypes.slideWillChange, this.willChangeToPage);
}
};
Slide.prototype.setTouchFlag = function () {
this.isTouching = true;
};
Slide.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
Slide.prototype.destroy = function () {
var slideContent = this.scroll.scroller.content;
var _a = this.options, loop = _a.loop, autoplay = _a.autoplay;
if (loop) {
this.removeClonedSlidePage(slideContent);
}
if (autoplay) {
clearTimeout(this.autoplayTimer);
}
this.hooksFn.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
if (hooks.eventTypes[hooksName]) {
hooks.off(hooksName, handlerFn);
}
});
this.hooksFn.length = 0;
};
Slide.pluginName = 'slide';
return Slide;
}());
var sourcePrefix$3 = 'plugins.wheel';
var propertiesMap$3 = [
{
key: 'wheelTo',
name: 'wheelTo'
},
{
key: 'getSelectedIndex',
name: 'getSelectedIndex'
}
];
var propertiesConfig$4 = propertiesMap$3.map(function (item) {
return {
key: item.key,
sourceKey: sourcePrefix$3 + "." + item.name
};
});
var CONSTANTS = {
rate: 4,
};
var Wheel = /** @class */ (function () {
function Wheel(scroll) {
this.scroll = scroll;
this.init();
}
Wheel.prototype.init = function () {
this.handleBScroll();
this.handleOptions();
this.handleHooks();
// init boundary for Wheel
this.refreshBoundary();
this.handleSelectedIndex();
};
Wheel.prototype.handleBScroll = function () {
this.scroll.proxy(propertiesConfig$4);
};
Wheel.prototype.handleOptions = function () {
var userOptions = (this.scroll.options.wheel === true
? {}
: this.scroll.options.wheel);
var defaultOptions = {
wheelWrapperClass: 'wheel-scroll',
wheelItemClass: 'wheel-item',
rotate: 25,
adjustTime: 400,
selectedIndex: 0,
wheelDisabledItemClass: 'wheel-disabled-item',
};
this.options = extend(defaultOptions, userOptions);
};
Wheel.prototype.handleHooks = function () {
var _this = this;
var scroller = this.scroll.scroller;
var actionsHandler = scroller.actionsHandler, scrollBehaviorX = scroller.scrollBehaviorX, scrollBehaviorY = scroller.scrollBehaviorY, animater = scroller.animater;
// BScroll
this.scroll.hooks.on(this.scroll.hooks.eventTypes.beforeInitialScrollTo, function (position) {
position.x = 0;
position.y = -(_this.selectedIndex * _this.itemHeight);
});
// Scroller
scroller.hooks.on(scroller.hooks.eventTypes.checkClick, function () {
var index = Array.prototype.slice
.call(_this.items, 0)
.indexOf(_this.target);
if (index === -1)
return true;
_this.wheelToAfterClick(index, _this.options.adjustTime, ease.swipe);
return true;
});
scroller.hooks.on(scroller.hooks.eventTypes.scrollTo, function (endPoint) {
endPoint.y = _this.findNearestValidWheel(endPoint.y).y;
});
scroller.hooks.on(scroller.hooks.eventTypes.scrollToElement, function (el, pos) {
if (!hasClass(el, _this.options.wheelItemClass)) {
return true;
}
else {
pos.top = _this.findNearestValidWheel(pos.top).y;
}
});
// ActionsHandler
actionsHandler.hooks.on(actionsHandler.hooks.eventTypes.beforeStart, function (e) {
_this.target = e.target;
});
// ScrollBehaviorX
// Wheel has no x direction now
scrollBehaviorX.hooks.on(scrollBehaviorX.hooks.eventTypes.computeBoundary, function (boundary) {
boundary.maxScrollPos = 0;
boundary.minScrollPos = 0;
});
// ScrollBehaviorY
scrollBehaviorY.hooks.on(scrollBehaviorY.hooks.eventTypes.computeBoundary, function (boundary) {
_this.items = _this.scroll.scroller.content.children;
_this.checkWheelAllDisabled();
_this.itemHeight =
_this.items.length > 0
? scrollBehaviorY.contentSize / _this.items.length
: 0;
boundary.maxScrollPos = -_this.itemHeight * (_this.items.length - 1);
boundary.minScrollPos = 0;
});
scrollBehaviorY.hooks.on(scrollBehaviorY.hooks.eventTypes.momentum, function (momentumInfo, distance) {
momentumInfo.rate = CONSTANTS.rate;
momentumInfo.destination = _this.findNearestValidWheel(momentumInfo.destination).y;
// TODO algorithm optimize
var maxDistance = 1000;
var minDuration = 800;
if (distance < maxDistance) {
momentumInfo.duration = Math.max(minDuration, (distance / maxDistance) * _this.scroll.options.swipeTime);
}
});
scrollBehaviorY.hooks.on(scrollBehaviorY.hooks.eventTypes.end, function (momentumInfo) {
var validWheel = _this.findNearestValidWheel(scrollBehaviorY.currentPos);
momentumInfo.destination = validWheel.y;
momentumInfo.duration = _this.options.adjustTime;
_this.selectedIndex = validWheel.index;
});
// Animater
animater.hooks.on(animater.hooks.eventTypes.time, function (time) {
_this.transitionDuration(time);
});
animater.hooks.on(animater.hooks.eventTypes.timeFunction, function (easing) {
_this.timeFunction(easing);
});
animater.hooks.on(animater.hooks.eventTypes.beforeForceStop, function (_a) {
var y = _a.y;
_this.target = _this.items[_this.findNearestValidWheel(y).index];
// don't dispatch scrollEnd when forceStop from transition or animation
return true;
});
// bs.stop() to make wheel stop at a correct position
animater.hooks.on(animater.hooks.eventTypes.callStop, function () {
var index = Array.prototype.slice
.call(_this.items, 0)
.indexOf(_this.target);
if (index > 0) {
var y = -(index * _this.itemHeight);
animater.translate({ x: 0, y: y });
}
});
// Translater
animater.translater.hooks.on(animater.translater.hooks.eventTypes.translate, function (endPoint) {
_this.rotateX(endPoint.y);
_this.selectedIndex = _this.findNearestValidWheel(endPoint.y).index;
});
};
Wheel.prototype.refreshBoundary = function () {
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
scrollBehaviorX.refresh();
scrollBehaviorY.refresh();
};
Wheel.prototype.handleSelectedIndex = function () {
this.selectedIndex = this.options.selectedIndex;
};
Wheel.prototype.getSelectedIndex = function () {
return this.selectedIndex;
};
Wheel.prototype.wheelTo = function (index, time, ease) {
if (index === void 0) { index = 0; }
if (time === void 0) { time = 0; }
var y = -index * this.itemHeight;
var currentY = Math.round(this.scroll.y);
this.scroll.scrollTo(0, y, time, ease);
return y === currentY;
};
Wheel.prototype.wheelToAfterClick = function (index, time, ease) {
if (index === void 0) { index = 0; }
if (time === void 0) { time = 0; }
var needDispatchScrollEnd = this.wheelTo(index, time, ease);
// startpoint === endpoint
// manually trigger scrollEnd
if (needDispatchScrollEnd) {
var hooks = this.scroll.scroller.hooks;
hooks.trigger(hooks.eventTypes.scrollEnd);
}
};
Wheel.prototype.transitionDuration = function (time) {
for (var i = 0; i < this.items.length; i++) {
this.items[i].style[style.transitionDuration] =
time + 'ms';
}
};
Wheel.prototype.timeFunction = function (easing) {
for (var i = 0; i < this.items.length; i++) {
this.items[i].style[style.transitionTimingFunction] = easing;
}
};
Wheel.prototype.rotateX = function (y) {
var _a = this.options.rotate, rotate = _a === void 0 ? 25 : _a;
for (var i = 0; i < this.items.length; i++) {
var deg = rotate * (y / this.itemHeight + i);
// Too small value is invalid in some phones, issue 1026
var SafeDeg = deg.toFixed(3);
this.items[i].style[style.transform] = "rotateX(" + SafeDeg + "deg)";
}
};
Wheel.prototype.findNearestValidWheel = function (y) {
y = y > 0 ? 0 : y < this.scroll.maxScrollY ? this.scroll.maxScrollY : y;
var currentIndex = Math.abs(Math.round(-y / this.itemHeight));
var cacheIndex = currentIndex;
var items = this.items;
var wheelDisabledItemClassName = this.options
.wheelDisabledItemClass;
// Impersonation web native select
// first, check whether there is a enable item whose index is smaller than currentIndex
// then, check whether there is a enable item whose index is bigger than currentIndex
// otherwise, there are all disabled items, just keep currentIndex unchange
while (currentIndex >= 0) {
if (!hasClass(items[currentIndex], wheelDisabledItemClassName)) {
break;
}
currentIndex--;
}
if (currentIndex < 0) {
currentIndex = cacheIndex;
while (currentIndex <= items.length - 1) {
if (!hasClass(items[currentIndex], wheelDisabledItemClassName)) {
break;
}
currentIndex++;
}
}
// keep it unchange when all the items are disabled
if (currentIndex === items.length) {
currentIndex = cacheIndex;
}
// when all the items are disabled, this.selectedIndex should always be -1
return {
index: this.wheelItemsAllDisabled ? -1 : currentIndex,
y: -currentIndex * this.itemHeight,
};
};
Wheel.prototype.checkWheelAllDisabled = function () {
var wheelDisabledItemClassName = this.options.wheelDisabledItemClass;
var items = this.items;
this.wheelItemsAllDisabled = true;
for (var i = 0; i < items.length; i++) {
if (!hasClass(items[i], wheelDisabledItemClassName)) {
this.wheelItemsAllDisabled = false;
break;
}
}
};
Wheel.pluginName = 'wheel';
return Wheel;
}());
var sourcePrefix$4 = 'plugins.zoom';
var propertiesMap$4 = [
{
key: 'zoomTo',
name: 'zoomTo'
}
];
var propertiesConfig$5 = propertiesMap$4.map(function (item) {
return {
key: item.key,
sourceKey: sourcePrefix$4 + "." + item.name
};
});
var TWO_FINGERS = 2;
var Zoom = /** @class */ (function () {
function Zoom(scroll) {
this.scroll = scroll;
this.scale = 1;
this.prevScale = 1;
this.init();
}
Zoom.prototype.init = function () {
this.handleBScroll();
this.handleOptions();
this.handleHooks();
this.tryInitialZoomTo(this.zoomOpt);
};
Zoom.prototype.zoomTo = function (scale, x, y, bounceTime) {
var _a = this.resolveOrigin(x, y), originX = _a.originX, originY = _a.originY;
var origin = {
x: originX,
y: originY,
baseScale: this.scale
};
this._doZoomTo(scale, origin, bounceTime, true);
};
Zoom.prototype.handleBScroll = function () {
this.scroll.proxy(propertiesConfig$5);
this.scroll.registerType([
'beforeZoomStart',
'zoomStart',
'zooming',
'zoomEnd'
]);
};
Zoom.prototype.handleOptions = function () {
var userOptions = (this.scroll.options.zoom === true
? {}
: this.scroll.options.zoom);
var defaultOptions = {
start: 1,
min: 1,
max: 4,
initialOrigin: [0, 0],
minimalZoomDistance: 5,
bounceTime: 800 // ms
};
this.zoomOpt = extend(defaultOptions, userOptions);
};
Zoom.prototype.handleHooks = function () {
var _this = this;
var scroll = this.scroll;
var scrollerIns = this.scroll.scroller;
this.wrapper = this.scroll.scroller.wrapper;
this.scaleElement = this.scroll.scroller.content;
this.scaleElement.style[style.transformOrigin] = '0 0';
this.scaleElementInitSize = getRect(this.scaleElement);
var scrollBehaviorX = scrollerIns.scrollBehaviorX;
var scrollBehaviorY = scrollerIns.scrollBehaviorY;
this.hooksFn = [];
// BScroll
this.registerHooks(scroll.hooks, scroll.hooks.eventTypes.beforeInitialScrollTo, function () {
// cancel coreScroll scrollTo logic when initialized
return true;
});
// enlarge boundary
this.registerHooks(scrollBehaviorX.hooks, scrollBehaviorX.hooks.eventTypes.beforeComputeBoundary, function () {
scrollBehaviorX.contentSize = Math.floor(_this.scaleElementInitSize.width * _this.scale);
});
this.registerHooks(scrollBehaviorY.hooks, scrollBehaviorY.hooks.eventTypes.beforeComputeBoundary, function () {
scrollBehaviorY.contentSize = Math.floor(_this.scaleElementInitSize.height * _this.scale);
});
// touch event
this.registerHooks(scrollerIns.actions.hooks, scrollerIns.actions.hooks.eventTypes.start, function (e) {
var numberOfFingers = (e.touches && e.touches.length) || 0;
_this.fingersOperation(numberOfFingers);
if (numberOfFingers === TWO_FINGERS) {
_this.zoomStart(e);
}
});
this.registerHooks(scrollerIns.actions.hooks, scrollerIns.actions.hooks.eventTypes.beforeMove, function (e) {
var numberOfFingers = (e.touches && e.touches.length) || 0;
_this.fingersOperation(numberOfFingers);
if (numberOfFingers === TWO_FINGERS) {
_this.zoom(e);
return true;
}
});
this.registerHooks(scrollerIns.actions.hooks, scrollerIns.actions.hooks.eventTypes.beforeEnd, function (e) {
var numberOfFingers = _this.fingersOperation();
if (numberOfFingers === TWO_FINGERS) {
_this.zoomEnd();
return true;
}
});
this.registerHooks(scrollerIns.translater.hooks, scrollerIns.translater.hooks.eventTypes.beforeTranslate, function (transformStyle, point) {
var scale = point.scale ? point.scale : _this.prevScale;
_this.prevScale = scale;
transformStyle.push("scale(" + scale + ")");
});
this.registerHooks(scrollerIns.hooks, scrollerIns.hooks.eventTypes.scrollEnd, function () {
if (_this.fingersOperation() === TWO_FINGERS) {
_this.scroll.trigger(_this.scroll.eventTypes.zoomEnd, {
scale: _this.scale
});
}
});
this.registerHooks(this.scroll.hooks, 'destroy', this.destroy);
};
Zoom.prototype.tryInitialZoomTo = function (options) {
var start = options.start, initialOrigin = options.initialOrigin;
this.zoomTo(start, initialOrigin[0], initialOrigin[1], 0);
};
// getter or setter operation
Zoom.prototype.fingersOperation = function (amounts) {
if (typeof amounts === 'number') {
this.numberOfFingers = amounts;
}
else {
return this.numberOfFingers;
}
};
Zoom.prototype._doZoomTo = function (scale, origin, time, useCurrentPos) {
var _this = this;
if (time === void 0) { time = this.zoomOpt.bounceTime; }
if (useCurrentPos === void 0) { useCurrentPos = false; }
var _a = this.zoomOpt, min = _a.min, max = _a.max;
var fromScale = this.scale;
var toScale = between(scale, min, max);
(function () {
if (time === 0) {
_this.scroll.trigger(_this.scroll.eventTypes.zooming, {
scale: toScale
});
return;
}
if (time > 0) {
var timer_1;
var startTime_1 = getNow();
var endTime_1 = startTime_1 + time;
var scheduler_1 = function () {
var now = getNow();
if (now >= endTime_1) {
_this.scroll.trigger(_this.scroll.eventTypes.zooming, {
scale: toScale
});
cancelAnimationFrame(timer_1);
return;
}
var ratio = ease.bounce.fn((now - startTime_1) / time);
var currentScale = ratio * (toScale - fromScale) + fromScale;
_this.scroll.trigger(_this.scroll.eventTypes.zooming, {
scale: currentScale
});
timer_1 = requestAnimationFrame(scheduler_1);
};
// start scheduler job
scheduler_1();
}
})();
// suppose you are zooming by two fingers
this.fingersOperation(2);
this._zoomTo(toScale, fromScale, origin, time, useCurrentPos);
};
Zoom.prototype._zoomTo = function (toScale, fromScale, origin, time, useCurrentPos) {
if (useCurrentPos === void 0) { useCurrentPos = false; }
var ratio = toScale / origin.baseScale;
this.setScale(toScale);
var scrollerIns = this.scroll.scroller;
var scrollBehaviorX = scrollerIns.scrollBehaviorX;
var scrollBehaviorY = scrollerIns.scrollBehaviorY;
this.resetBoundaries([scrollBehaviorX, scrollBehaviorY]);
// position is restrained in boundary
var newX = this.getNewPos(origin.x, ratio, scrollBehaviorX, true, useCurrentPos);
var newY = this.getNewPos(origin.y, ratio, scrollBehaviorY, true, useCurrentPos);
if (scrollBehaviorX.currentPos !== Math.round(newX) ||
scrollBehaviorY.currentPos !== Math.round(newY) ||
toScale !== fromScale) {
scrollerIns.scrollTo(newX, newY, time, ease.bounce, {
start: {
scale: fromScale
},
end: {
scale: toScale
}
});
}
};
Zoom.prototype.resolveOrigin = function (x, y) {
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
var resolveFormula = {
left: function () {
return 0;
},
top: function () {
return 0;
},
right: function () {
return scrollBehaviorX.contentSize;
},
bottom: function () {
return scrollBehaviorY.contentSize;
},
center: function (index) {
var baseSize = index === 0
? scrollBehaviorX.contentSize
: scrollBehaviorY.contentSize;
return baseSize / 2;
}
};
return {
originX: typeof x === 'number' ? x : resolveFormula[x](0),
originY: typeof y === 'number' ? y : resolveFormula[y](1)
};
};
Zoom.prototype.zoomStart = function (e) {
var firstFinger = e.touches[0];
var secondFinger = e.touches[1];
this.startDistance = this.getFingerDistance(e);
this.startScale = this.scale;
var _a = offsetToBody(this.wrapper), left = _a.left, top = _a.top;
this.origin = {
x: Math.abs(firstFinger.pageX + secondFinger.pageX) / 2 +
left -
this.scroll.x,
y: Math.abs(firstFinger.pageY + secondFinger.pageY) / 2 +
top -
this.scroll.y,
baseScale: this.startScale
};
this.scroll.trigger(this.scroll.eventTypes.beforeZoomStart);
};
Zoom.prototype.zoom = function (e) {
var currentDistance = this.getFingerDistance(e);
// at least minimalZoomDistance pixels for the zoom to initiate
if (!this.zoomed &&
Math.abs(currentDistance - this.startDistance) <
this.zoomOpt.minimalZoomDistance) {
return;
}
// when out of boundary , perform a damping algorithm
var endScale = this.dampingScale((currentDistance / this.startDistance) * this.startScale);
var ratio = endScale / this.startScale;
this.setScale(endScale);
if (!this.zoomed) {
this.zoomed = true;
this.scroll.trigger(this.scroll.eventTypes.zoomStart);
}
var scrollerIns = this.scroll.scroller;
var scrollBehaviorX = scrollerIns.scrollBehaviorX;
var scrollBehaviorY = scrollerIns.scrollBehaviorY;
var x = this.getNewPos(this.origin.x, ratio, scrollBehaviorX, false, false);
var y = this.getNewPos(this.origin.y, ratio, scrollBehaviorY, false, false);
this.scroll.trigger(this.scroll.eventTypes.zooming, {
scale: this.scale
});
scrollerIns.translater.translate({ x: x, y: y, scale: endScale });
};
Zoom.prototype.zoomEnd = function () {
if (!this.zoomed)
return;
// if out of boundary, do rebound!
if (this.shouldRebound()) {
this._doZoomTo(this.scale, this.origin, this.zoomOpt.bounceTime);
return;
}
this.scroll.trigger(this.scroll.eventTypes.zoomEnd, { scale: this.scale });
};
Zoom.prototype.getFingerDistance = function (e) {
var firstFinger = e.touches[0];
var secondFinger = e.touches[1];
var deltaX = Math.abs(firstFinger.pageX - secondFinger.pageX);
var deltaY = Math.abs(firstFinger.pageY - secondFinger.pageY);
return getDistance(deltaX, deltaY);
};
Zoom.prototype.shouldRebound = function () {
var _a = this.zoomOpt, min = _a.min, max = _a.max;
var currentScale = this.scale;
// scale exceeded!
if (currentScale !== between(currentScale, min, max)) {
return true;
}
var _b = this.scroll.scroller, scrollBehaviorX = _b.scrollBehaviorX, scrollBehaviorY = _b.scrollBehaviorY;
// enlarge boundaries manually when zoom is end
this.resetBoundaries([scrollBehaviorX, scrollBehaviorY]);
var xInBoundary = scrollBehaviorX.checkInBoundary().inBoundary;
var yInBoundary = scrollBehaviorX.checkInBoundary().inBoundary;
return !(xInBoundary && yInBoundary);
};
Zoom.prototype.dampingScale = function (scale) {
var _a = this.zoomOpt, min = _a.min, max = _a.max;
if (scale < min) {
scale = 0.5 * min * Math.pow(2.0, scale / min);
}
else if (scale > max) {
scale = 2.0 * max * Math.pow(0.5, max / scale);
}
return scale;
};
Zoom.prototype.setScale = function (scale) {
this.scale = scale;
};
Zoom.prototype.resetBoundaries = function (scrollBehaviorPairs) {
scrollBehaviorPairs.forEach(function (behavior) { return behavior.computeBoundary(); });
};
Zoom.prototype.getNewPos = function (origin, lastScale, scrollBehavior, shouldInBoundary, useCurrentPos) {
if (useCurrentPos === void 0) { useCurrentPos = false; }
var newPos = origin -
origin * lastScale +
(useCurrentPos ? scrollBehavior.currentPos : scrollBehavior.startPos);
if (shouldInBoundary) {
newPos = between(newPos, scrollBehavior.maxScrollPos, scrollBehavior.minScrollPos);
}
// maxScrollPos or minScrollPos maybe a negative or positive digital
return newPos > 0 ? Math.floor(newPos) : Math.ceil(newPos);
};
Zoom.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
Zoom.prototype.destroy = function () {
this.hooksFn.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
this.hooksFn.length = 0;
};
Zoom.pluginName = 'zoom';
return Zoom;
}());
var compatibleFeatures = {
duplicateClick: function (_a) {
var parentScroll = _a[0], childScroll = _a[1];
// no need to make childScroll's click true
if (parentScroll.options.click && childScroll.options.click) {
childScroll.options.click = false;
}
},
nestedScroll: function (scrollsPair) {
var parentScroll = scrollsPair[0], childScroll = scrollsPair[1];
var parentScrollX = parentScroll.options.scrollX;
var parentScrollY = parentScroll.options.scrollY;
var childScrollX = childScroll.options.scrollX;
var childScrollY = childScroll.options.scrollY;
// vertical nested in vertical scroll and horizontal nested in horizontal
// otherwise, no need to handle.
if (parentScrollX === childScrollX || parentScrollY === childScrollY) {
scrollsPair.forEach(function (scroll, index) {
var oppositeScroll = scrollsPair[(index + 1) % 2];
scroll.on(scroll.eventTypes.beforeScrollStart, function () {
if (oppositeScroll.pending) {
oppositeScroll.stop();
oppositeScroll.resetPosition();
}
setupData(oppositeScroll);
oppositeScroll.disable();
});
scroll.on(scroll.eventTypes.touchEnd, function () {
oppositeScroll.enable();
});
});
childScroll.on(childScroll.eventTypes.scrollStart, function () {
if (checkBeyondBoundary(childScroll)) {
childScroll.disable();
parentScroll.enable();
}
});
}
}
};
var NestedScroll = /** @class */ (function () {
function NestedScroll(scroll) {
var singleton = NestedScroll.nestedScroll;
if (!(singleton instanceof NestedScroll)) {
singleton = NestedScroll.nestedScroll = this;
singleton.stores = [];
}
singleton.setup(scroll);
singleton.addHooks(scroll);
return singleton;
}
NestedScroll.prototype.setup = function (scroll) {
this.appendBScroll(scroll);
this.handleContainRelationship();
this.handleCompatible();
};
NestedScroll.prototype.addHooks = function (scroll) {
var _this = this;
scroll.on('destroy', function () {
_this.teardown(scroll);
});
};
NestedScroll.prototype.teardown = function (scroll) {
this.removeBScroll(scroll);
this.handleContainRelationship();
this.handleCompatible();
};
NestedScroll.prototype.appendBScroll = function (scroll) {
this.stores.push(scroll);
};
NestedScroll.prototype.removeBScroll = function (scroll) {
var index = this.stores.indexOf(scroll);
if (index === -1) {
return;
}
scroll.wrapper.isBScrollContainer = undefined;
this.stores.splice(index, 1);
};
NestedScroll.prototype.handleContainRelationship = function () {
// bs's length <= 1
var stores = this.stores;
if (stores.length <= 1) {
// there is only a childBScroll left.
if (stores[0] && stores[0].__parentInfo) {
stores[0].__parentInfo = undefined;
}
return;
}
var outerBS;
var outerBSWrapper;
var innerBS;
var innerBSWrapper;
// Need two layers of "For loop" to calculate parent-child relationship
for (var i = 0; i < stores.length; i++) {
outerBS = stores[i];
outerBSWrapper = outerBS.wrapper;
for (var j = 0; j < stores.length; j++) {
innerBS = stores[j];
innerBSWrapper = innerBS.wrapper;
// same bs
if (outerBS === innerBS)
continue;
// now start calculating
if (!innerBSWrapper.contains(outerBSWrapper))
continue;
// now innerBS contains outerBS
// no parentInfo yet
if (!outerBS.__parentInfo) {
outerBS.__parentInfo = {
parent: innerBS,
depth: calculateDepths(outerBSWrapper, innerBSWrapper)
};
}
else {
// has parentInfo already!
// just judge the "true" parent by depth
// we regard the latest node as parent, not the furthest
var currentDepths = calculateDepths(outerBSWrapper, innerBSWrapper);
var prevDepths = outerBS.__parentInfo.depth;
// refresh currentBS as parentScroll
if (prevDepths > currentDepths) {
outerBS.__parentInfo = {
parent: innerBS,
depth: currentDepths
};
}
}
}
}
};
NestedScroll.prototype.handleCompatible = function () {
var pairs = this.availableBScrolls();
var keys = ['duplicateClick', 'nestedScroll'];
pairs.forEach(function (pair) {
keys.forEach(function (key) {
compatibleFeatures[key](pair);
});
});
};
NestedScroll.prototype.availableBScrolls = function () {
var ret = [];
ret = this.stores
.filter(function (bs) { return !!bs.__parentInfo; })
.map(function (bs) { return [bs.__parentInfo.parent, bs]; });
return ret;
};
NestedScroll.pluginName = 'nestedScroll';
return NestedScroll;
}());
function calculateDepths(childNode, parentNode) {
var depth = 0;
var parent = childNode.parentNode;
while (parent && parent !== parentNode) {
depth++;
parent = parent.parentNode;
}
return depth;
}
function checkBeyondBoundary(scroll) {
var _a = hasScroll(scroll), hasHorizontalScroll = _a.hasHorizontalScroll, hasVerticalScroll = _a.hasVerticalScroll;
var _b = scroll.scroller, scrollBehaviorX = _b.scrollBehaviorX, scrollBehaviorY = _b.scrollBehaviorY;
var hasReachLeft = scroll.x >= scroll.minScrollX && scrollBehaviorX.movingDirection === -1;
var hasReachRight = scroll.x <= scroll.maxScrollX && scrollBehaviorX.movingDirection === 1;
var hasReachTop = scroll.y >= scroll.minScrollY && scrollBehaviorY.movingDirection === -1;
var hasReachBottom = scroll.y <= scroll.maxScrollY && scrollBehaviorY.movingDirection === 1;
if (hasVerticalScroll) {
return hasReachTop || hasReachBottom;
}
else if (hasHorizontalScroll) {
return hasReachLeft || hasReachRight;
}
return false;
}
function setupData(scroll) {
var _a = hasScroll(scroll), hasHorizontalScroll = _a.hasHorizontalScroll, hasVerticalScroll = _a.hasVerticalScroll;
var _b = scroll.scroller, actions = _b.actions, scrollBehaviorX = _b.scrollBehaviorX, scrollBehaviorY = _b.scrollBehaviorY;
actions.startTime = +new Date();
if (hasVerticalScroll) {
scrollBehaviorY.startPos = scrollBehaviorY.currentPos;
}
else if (hasHorizontalScroll) {
scrollBehaviorX.startPos = scrollBehaviorX.currentPos;
}
}
function hasScroll(scroll) {
return {
hasHorizontalScroll: scroll.hasHorizontalScroll,
hasVerticalScroll: scroll.hasVerticalScroll
};
}
var PRE_NUM = 10;
var POST_NUM = 30;
var IndexCalculator = /** @class */ (function () {
function IndexCalculator(wrapperHeight, tombstoneHeight) {
this.wrapperHeight = wrapperHeight;
this.tombstoneHeight = tombstoneHeight;
this.lastDirection = 1 /* DOWN */;
this.lastPos = 0;
}
IndexCalculator.prototype.calculate = function (pos, list) {
var offset = pos - this.lastPos;
this.lastPos = pos;
var direction = this.getDirection(offset);
// important! start index is much more important than end index.
var start = this.calculateIndex(0, pos, list);
var end = this.calculateIndex(start, pos + this.wrapperHeight, list);
if (direction === 1 /* DOWN */) {
start -= PRE_NUM;
end += POST_NUM;
}
else {
start -= POST_NUM;
end += PRE_NUM;
}
if (start < 0) {
start = 0;
}
return {
start: start,
end: end
};
};
IndexCalculator.prototype.getDirection = function (offset) {
var direction;
if (offset > 0) {
direction = 1 /* DOWN */;
}
else if (offset < 0) {
direction = 0 /* UP */;
}
else {
return this.lastDirection;
}
this.lastDirection = direction;
return direction;
};
IndexCalculator.prototype.calculateIndex = function (start, offset, list) {
if (offset <= 0) {
return start;
}
var i = start;
var startPos = list[i] && list[i].pos !== -1 ? list[i].pos : 0;
var lastPos = startPos;
var tombstone = 0;
while (i < list.length && list[i].pos < offset) {
lastPos = list[i].pos;
i++;
}
if (i === list.length) {
tombstone = Math.floor((offset - lastPos) / this.tombstoneHeight);
}
i += tombstone;
return i;
};
return IndexCalculator;
}());
var ListItem = /** @class */ (function () {
function ListItem() {
this.data = null;
this.dom = null;
this.tombstone = null;
this.width = 0;
this.height = 0;
this.pos = 0;
}
return ListItem;
}());
var DataManager = /** @class */ (function () {
function DataManager(list, fetchFn, onFetchFinish) {
this.fetchFn = fetchFn;
this.onFetchFinish = onFetchFinish;
this.loadedNum = 0;
this.fetching = false;
this.hasMore = true;
this.list = list || [];
}
DataManager.prototype.update = function (end) {
return __awaiter(this, void 0, void 0, function () {
var len;
return __generator(this, function (_a) {
if (!this.hasMore) {
end = Math.min(end, this.list.length);
}
// add data placeholder
if (end > this.list.length) {
len = end - this.list.length;
this.addEmptyData(len);
}
// tslint:disable-next-line: no-floating-promises
return [2 /*return*/, this.checkToFetch(end)];
});
});
};
DataManager.prototype.add = function (data) {
for (var i = 0; i < data.length; i++) {
if (!this.list[this.loadedNum]) {
this.list[this.loadedNum] = { data: data[i] };
}
else {
this.list[this.loadedNum] = __assign(__assign({}, this.list[this.loadedNum]), { data: data[i] });
}
this.loadedNum++;
}
return this.list;
};
DataManager.prototype.addEmptyData = function (len) {
for (var i = 0; i < len; i++) {
this.list.push(new ListItem());
}
return this.list;
};
DataManager.prototype.fetch = function (len) {
return __awaiter(this, void 0, void 0, function () {
var data;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this.fetching) {
return [2 /*return*/, []];
}
this.fetching = true;
return [4 /*yield*/, this.fetchFn(len)];
case 1:
data = _a.sent();
this.fetching = false;
return [2 /*return*/, data];
}
});
});
};
DataManager.prototype.checkToFetch = function (end) {
return __awaiter(this, void 0, void 0, function () {
var min, newData, currentEnd;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.hasMore) {
return [2 /*return*/];
}
if (end <= this.loadedNum) {
return [2 /*return*/];
}
min = end - this.loadedNum;
return [4 /*yield*/, this.fetch(min)];
case 1:
newData = _a.sent();
if (newData instanceof Array && newData.length) {
this.add(newData);
currentEnd = this.onFetchFinish(this.list, true);
return [2 /*return*/, this.checkToFetch(currentEnd)];
}
else if (typeof newData === 'boolean' && newData === false) {
this.hasMore = false;
this.list.splice(this.loadedNum);
this.onFetchFinish(this.list, false);
}
return [2 /*return*/];
}
});
});
};
DataManager.prototype.getList = function () {
return this.list;
};
return DataManager;
}());
var Tombstone = /** @class */ (function () {
function Tombstone(create) {
this.create = create;
this.cached = [];
this.width = 0;
this.height = 0;
this.initialed = false;
this.getSize();
}
Tombstone.isTombstone = function (el) {
if (el && el.classList) {
return el.classList.contains('tombstone');
}
return false;
};
Tombstone.prototype.getSize = function () {
if (!this.initialed) {
var tombstone = this.create();
tombstone.style.position = 'absolute';
document.body.appendChild(tombstone);
tombstone.style.display = '';
this.height = tombstone.offsetHeight;
this.width = tombstone.offsetWidth;
document.body.removeChild(tombstone);
this.cached.push(tombstone);
}
};
Tombstone.prototype.getOne = function () {
var tombstone = this.cached.pop();
if (tombstone) {
var tombstoneStyle = tombstone.style;
tombstoneStyle.display = '';
tombstoneStyle.opacity = '1';
tombstoneStyle[style.transform] = '';
tombstoneStyle[style.transition] = '';
return tombstone;
}
return this.create();
};
Tombstone.prototype.recycle = function (tombstones) {
for (var _i = 0, tombstones_1 = tombstones; _i < tombstones_1.length; _i++) {
var tombstone = tombstones_1[_i];
tombstone.style.display = 'none';
this.cached.push(tombstone);
}
return this.cached;
};
Tombstone.prototype.recycleOne = function (tombstone) {
this.cached.push(tombstone);
return this.cached;
};
return Tombstone;
}());
var ANIMATION_DURATION_MS = 200;
var DomManager = /** @class */ (function () {
function DomManager(content, renderFn, tombstone) {
this.content = content;
this.renderFn = renderFn;
this.tombstone = tombstone;
this.unusedDom = [];
this.timers = [];
}
DomManager.prototype.update = function (list, start, end) {
if (start >= list.length) {
start = list.length - 1;
}
if (end > list.length) {
end = list.length;
}
this.collectUnusedDom(list, start, end);
this.createDom(list, start, end);
this.cacheHeight(list, start, end);
var _a = this.positionDom(list, start, end), startPos = _a.startPos, startDelta = _a.startDelta, endPos = _a.endPos;
return {
start: start,
startPos: startPos,
startDelta: startDelta,
end: end,
endPos: endPos
};
};
DomManager.prototype.collectUnusedDom = function (list, start, end) {
// TODO optimise
for (var i = 0; i < list.length; i++) {
if (i === start) {
i = end - 1;
continue;
}
if (list[i].dom) {
var dom = list[i].dom;
if (Tombstone.isTombstone(dom)) {
this.tombstone.recycleOne(dom);
dom.style.display = 'none';
}
else {
this.unusedDom.push(dom);
}
list[i].dom = null;
}
}
return list;
};
DomManager.prototype.createDom = function (list, start, end) {
for (var i = start; i < end; i++) {
var dom = list[i].dom;
var data = list[i].data;
if (dom) {
if (Tombstone.isTombstone(dom) && data) {
list[i].tombstone = dom;
list[i].dom = null;
}
else {
continue;
}
}
dom = data
? this.renderFn(data, this.unusedDom.pop())
: this.tombstone.getOne();
dom.style.position = 'absolute';
list[i].dom = dom;
list[i].pos = -1;
this.content.appendChild(dom);
}
};
DomManager.prototype.cacheHeight = function (list, start, end) {
for (var i = start; i < end; i++) {
if (list[i].data && !list[i].height) {
list[i].height = list[i].dom.offsetHeight;
}
}
};
DomManager.prototype.positionDom = function (list, start, end) {
var _this = this;
var tombstoneEles = [];
var _a = this.getStartPos(list, start, end), startPos = _a.start, startDelta = _a.delta;
var pos = startPos;
for (var i = start; i < end; i++) {
var tombstone = list[i].tombstone;
if (tombstone) {
var tombstoneStyle = tombstone.style;
tombstoneStyle[style.transition] = cssVendor + "transform " + ANIMATION_DURATION_MS + "ms, opacity " + ANIMATION_DURATION_MS + "ms";
tombstoneStyle[style.transform] = "translateY(" + pos + "px)";
tombstoneStyle.opacity = '0';
list[i].tombstone = null;
tombstoneEles.push(tombstone);
}
if (list[i].dom && list[i].pos !== pos) {
list[i].dom.style[style.transform] = "translateY(" + pos + "px)";
list[i].pos = pos;
}
pos += list[i].height || this.tombstone.height;
}
var timerId = window.setTimeout(function () {
_this.tombstone.recycle(tombstoneEles);
}, ANIMATION_DURATION_MS);
this.timers.push(timerId);
return {
startPos: startPos,
startDelta: startDelta,
endPos: pos
};
};
DomManager.prototype.getStartPos = function (list, start, end) {
if (list[start] && list[start].pos !== -1) {
return {
start: list[start].pos,
delta: 0
};
}
// TODO optimise
var pos = list[0].pos === -1 ? 0 : list[0].pos;
for (var i_1 = 0; i_1 < start; i_1++) {
pos += list[i_1].height || this.tombstone.height;
}
var originPos = pos;
var i;
for (i = start; i < end; i++) {
if (!Tombstone.isTombstone(list[i].dom) && list[i].pos !== -1) {
pos = list[i].pos;
break;
}
}
var x = i;
if (x < end) {
while (x > start) {
pos -= list[x - 1].height;
x--;
}
}
var delta = originPos - pos;
return {
start: pos,
delta: delta
};
};
DomManager.prototype.removeTombstone = function () {
var tombstones = this.content.querySelectorAll('.tombstone');
for (var i = tombstones.length - 1; i >= 0; i--) {
this.content.removeChild(tombstones[i]);
}
};
DomManager.prototype.destroy = function () {
this.removeTombstone();
this.timers.forEach(function (id) {
clearTimeout(id);
});
};
return DomManager;
}());
var EXTRA_SCROLL_Y = -2000;
var InfinityScroll = /** @class */ (function () {
function InfinityScroll(scroll) {
this.scroll = scroll;
this.start = 0;
this.end = 0;
this.init();
}
InfinityScroll.prototype.init = function () {
this.handleOptions();
var _a = this.options, fetchFn = _a.fetch, renderFn = _a.render, createTombstoneFn = _a.createTombstone;
this.tombstone = new Tombstone(createTombstoneFn);
this.indexCalculator = new IndexCalculator(this.scroll.scroller.scrollBehaviorY.wrapperSize, this.tombstone.height);
this.domManager = new DomManager(this.scroll.scroller.content, renderFn, this.tombstone);
this.dataManager = new DataManager([], fetchFn, this.onFetchFinish.bind(this));
this.scroll.on(this.scroll.eventTypes.destroy, this.destroy, this);
this.scroll.on(this.scroll.eventTypes.scroll, this.update, this);
var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
scrollBehaviorY.hooks.on(scrollBehaviorY.hooks.eventTypes.computeBoundary, this.modifyBoundary, this);
this.update({ y: 0 });
};
InfinityScroll.prototype.modifyBoundary = function (boundary) {
// manually set position to allow scroll
boundary.maxScrollPos = EXTRA_SCROLL_Y;
};
InfinityScroll.prototype.handleOptions = function () {
// narrow down type to an object
var infinityOptions = this.scroll.options.infinity;
if (infinityOptions) {
if (typeof infinityOptions.fetch !== 'function') {
warn('Infinity plugin need fetch Function to new data.');
}
if (typeof infinityOptions.render !== 'function') {
warn('Infinity plugin need render Function to render each item.');
}
if (typeof infinityOptions.render !== 'function') {
warn('Infinity plugin need createTombstone Function to create tombstone.');
}
this.options = infinityOptions;
}
this.scroll.options.probeType = 3 /* Realtime */;
};
InfinityScroll.prototype.update = function (pos) {
var position = Math.round(-pos.y);
// important! calculate start/end index to render
var _a = this.indexCalculator.calculate(position, this.dataManager.getList()), start = _a.start, end = _a.end;
this.start = start;
this.end = end;
// tslint:disable-next-line: no-floating-promises
this.dataManager.update(end);
this.updateDom(this.dataManager.getList());
};
InfinityScroll.prototype.onFetchFinish = function (list, hasMore) {
var end = this.updateDom(list).end;
if (!hasMore) {
this.domManager.removeTombstone();
this.scroll.scroller.animater.stop();
this.scroll.resetPosition();
}
// tslint:disable-next-line: no-floating-promises
return end;
};
InfinityScroll.prototype.updateDom = function (list) {
var _a = this.domManager.update(list, this.start, this.end), end = _a.end, startPos = _a.startPos, endPos = _a.endPos, startDelta = _a.startDelta;
if (startDelta) {
this.scroll.minScrollY = startDelta;
}
if (endPos > this.scroll.maxScrollY) {
this.scroll.maxScrollY = -(endPos - this.scroll.scroller.scrollBehaviorY.wrapperSize);
}
return {
end: end,
startPos: startPos,
endPos: endPos
};
};
InfinityScroll.prototype.destroy = function () {
var _a = this.scroll.scroller, content = _a.content, scrollBehaviorY = _a.scrollBehaviorY;
while (content.firstChild) {
content.removeChild(content.firstChild);
}
this.domManager.destroy();
this.scroll.off('scroll', this.update);
this.scroll.off('destroy', this.destroy);
scrollBehaviorY.hooks.off(scrollBehaviorY.hooks.eventTypes.computeBoundary);
};
InfinityScroll.pluginName = 'infinity';
return InfinityScroll;
}());
var Movable = /** @class */ (function () {
function Movable(scroll) {
this.scroll = scroll;
this.handleHooks();
}
Movable.prototype.handleHooks = function () {
var _this = this;
this.hooksFn = [];
var _a = this.scroll.scroller, scrollBehaviorX = _a.scrollBehaviorX, scrollBehaviorY = _a.scrollBehaviorY;
var computeBoundary = function (boundary, behavior) {
if (!behavior.options.scrollable)
return;
if (boundary.maxScrollPos > 0) {
// content is smaller than wrapper
boundary.minScrollPos = behavior.wrapperSize - behavior.contentSize;
boundary.maxScrollPos = 0;
}
};
this.registerHooks(scrollBehaviorX.hooks, scrollBehaviorX.hooks.eventTypes.computeBoundary, function (boundary) {
computeBoundary(boundary, scrollBehaviorX);
});
this.registerHooks(scrollBehaviorY.hooks, scrollBehaviorY.hooks.eventTypes.computeBoundary, function (boundary) {
computeBoundary(boundary, scrollBehaviorY);
});
this.registerHooks(this.scroll.hooks, this.scroll.hooks.eventTypes.destroy, function () {
_this.destroy();
});
};
Movable.prototype.destroy = function () {
this.hooksFn.forEach(function (item) {
var hooks = item[0];
var hooksName = item[1];
var handlerFn = item[2];
hooks.off(hooksName, handlerFn);
});
this.hooksFn.length = 0;
};
Movable.prototype.registerHooks = function (hooks, name, handler) {
hooks.on(name, handler, this);
this.hooksFn.push([hooks, name, handler]);
};
Movable.pluginName = 'movable';
return Movable;
}());
BScroll.use(MouseWheel)
.use(ObserveDOM)
.use(PullDown)
.use(PullUp)
.use(ScrollBar)
.use(Slide)
.use(Wheel)
.use(Zoom)
.use(NestedScroll)
.use(InfinityScroll)
.use(Movable);
exports.Behavior = Behavior;
exports.CustomOptions = CustomOptions;
exports.InfinityScroll = InfinityScroll;
exports.MouseWheel = MouseWheel;
exports.Movable = Movable;
exports.NestedScroll = NestedScroll;
exports.ObserveDom = ObserveDOM;
exports.PullDownRefresh = PullDown;
exports.PullUpLoad = PullUp;
exports.ScrollBar = ScrollBar;
exports.Slide = Slide;
exports.Wheel = Wheel;
exports.Zoom = Zoom;
exports.createBScroll = createBScroll;
exports.default = BScroll;
Object.defineProperty(exports, '__esModule', { value: true });
})));