UNPKG

89.8 kBJavaScriptView Raw
1/*!
2 * better-scroll / core
3 * (c) 2016-2023 ustbhuangyi
4 * Released under the MIT License.
5 */
6/*! *****************************************************************************
7Copyright (c) Microsoft Corporation.
8
9Permission to use, copy, modify, and/or distribute this software for any
10purpose with or without fee is hereby granted.
11
12THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
13REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
14AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
15INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
17OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18PERFORMANCE OF THIS SOFTWARE.
19***************************************************************************** */
20/* global Reflect, Promise */
21
22var extendStatics = function(d, b) {
23 extendStatics = Object.setPrototypeOf ||
24 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
25 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
26 return extendStatics(d, b);
27};
28
29function __extends(d, b) {
30 extendStatics(d, b);
31 function __() { this.constructor = d; }
32 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
33}
34
35var __assign = function() {
36 __assign = Object.assign || function __assign(t) {
37 for (var s, i = 1, n = arguments.length; i < n; i++) {
38 s = arguments[i];
39 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
40 }
41 return t;
42 };
43 return __assign.apply(this, arguments);
44};
45
46function __spreadArrays() {
47 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
48 for (var r = Array(s), k = 0, i = 0; i < il; i++)
49 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
50 r[k] = a[j];
51 return r;
52}
53
54var propertiesConfig = [
55 {
56 sourceKey: 'scroller.scrollBehaviorX.currentPos',
57 key: 'x'
58 },
59 {
60 sourceKey: 'scroller.scrollBehaviorY.currentPos',
61 key: 'y'
62 },
63 {
64 sourceKey: 'scroller.scrollBehaviorX.hasScroll',
65 key: 'hasHorizontalScroll'
66 },
67 {
68 sourceKey: 'scroller.scrollBehaviorY.hasScroll',
69 key: 'hasVerticalScroll'
70 },
71 {
72 sourceKey: 'scroller.scrollBehaviorX.contentSize',
73 key: 'scrollerWidth'
74 },
75 {
76 sourceKey: 'scroller.scrollBehaviorY.contentSize',
77 key: 'scrollerHeight'
78 },
79 {
80 sourceKey: 'scroller.scrollBehaviorX.maxScrollPos',
81 key: 'maxScrollX'
82 },
83 {
84 sourceKey: 'scroller.scrollBehaviorY.maxScrollPos',
85 key: 'maxScrollY'
86 },
87 {
88 sourceKey: 'scroller.scrollBehaviorX.minScrollPos',
89 key: 'minScrollX'
90 },
91 {
92 sourceKey: 'scroller.scrollBehaviorY.minScrollPos',
93 key: 'minScrollY'
94 },
95 {
96 sourceKey: 'scroller.scrollBehaviorX.movingDirection',
97 key: 'movingDirectionX'
98 },
99 {
100 sourceKey: 'scroller.scrollBehaviorY.movingDirection',
101 key: 'movingDirectionY'
102 },
103 {
104 sourceKey: 'scroller.scrollBehaviorX.direction',
105 key: 'directionX'
106 },
107 {
108 sourceKey: 'scroller.scrollBehaviorY.direction',
109 key: 'directionY'
110 },
111 {
112 sourceKey: 'scroller.actions.enabled',
113 key: 'enabled'
114 },
115 {
116 sourceKey: 'scroller.animater.pending',
117 key: 'pending'
118 },
119 {
120 sourceKey: 'scroller.animater.stop',
121 key: 'stop'
122 },
123 {
124 sourceKey: 'scroller.scrollTo',
125 key: 'scrollTo'
126 },
127 {
128 sourceKey: 'scroller.scrollBy',
129 key: 'scrollBy'
130 },
131 {
132 sourceKey: 'scroller.scrollToElement',
133 key: 'scrollToElement'
134 },
135 {
136 sourceKey: 'scroller.resetPosition',
137 key: 'resetPosition'
138 }
139];
140
141function warn(msg) {
142 console.error("[BScroll warn]: " + msg);
143}
144
145// ssr support
146var inBrowser = typeof window !== 'undefined';
147var ua = inBrowser && navigator.userAgent.toLowerCase();
148var isWeChatDevTools = !!(ua && /wechatdevtools/.test(ua));
149var isAndroid = ua && ua.indexOf('android') > 0;
150/* istanbul ignore next */
151var isIOSBadVersion = (function () {
152 if (typeof ua === 'string') {
153 var regex = /os (\d\d?_\d(_\d)?)/;
154 var matches = regex.exec(ua);
155 if (!matches)
156 return false;
157 var parts = matches[1].split('_').map(function (item) {
158 return parseInt(item, 10);
159 });
160 // ios version >= 13.4 issue 982
161 return !!(parts[0] === 13 && parts[1] >= 4);
162 }
163 return false;
164})();
165/* istanbul ignore next */
166var supportsPassive = false;
167/* istanbul ignore next */
168if (inBrowser) {
169 var EventName = 'test-passive';
170 try {
171 var opts = {};
172 Object.defineProperty(opts, 'passive', {
173 get: function () {
174 supportsPassive = true;
175 },
176 }); // https://github.com/facebook/flow/issues/285
177 window.addEventListener(EventName, function () { }, opts);
178 }
179 catch (e) { }
180}
181
182function getNow() {
183 return window.performance &&
184 window.performance.now &&
185 window.performance.timing
186 ? window.performance.now() + window.performance.timing.navigationStart
187 : +new Date();
188}
189var extend = function (target, source) {
190 for (var key in source) {
191 target[key] = source[key];
192 }
193 return target;
194};
195function isUndef(v) {
196 return v === undefined || v === null;
197}
198function between(x, min, max) {
199 if (x < min) {
200 return min;
201 }
202 if (x > max) {
203 return max;
204 }
205 return x;
206}
207
208var elementStyle = (inBrowser &&
209 document.createElement('div').style);
210var vendor = (function () {
211 /* istanbul ignore if */
212 if (!inBrowser) {
213 return false;
214 }
215 var transformNames = [
216 {
217 key: 'standard',
218 value: 'transform',
219 },
220 {
221 key: 'webkit',
222 value: 'webkitTransform',
223 },
224 {
225 key: 'Moz',
226 value: 'MozTransform',
227 },
228 {
229 key: 'O',
230 value: 'OTransform',
231 },
232 {
233 key: 'ms',
234 value: 'msTransform',
235 },
236 ];
237 for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
238 var obj = transformNames_1[_i];
239 if (elementStyle[obj.value] !== undefined) {
240 return obj.key;
241 }
242 }
243 /* istanbul ignore next */
244 return false;
245})();
246/* istanbul ignore next */
247function prefixStyle(style) {
248 if (vendor === false) {
249 return style;
250 }
251 if (vendor === 'standard') {
252 if (style === 'transitionEnd') {
253 return 'transitionend';
254 }
255 return style;
256 }
257 return vendor + style.charAt(0).toUpperCase() + style.substr(1);
258}
259function getElement(el) {
260 return (typeof el === 'string' ? document.querySelector(el) : el);
261}
262function addEvent(el, type, fn, capture) {
263 var useCapture = supportsPassive
264 ? {
265 passive: false,
266 capture: !!capture,
267 }
268 : !!capture;
269 el.addEventListener(type, fn, useCapture);
270}
271function removeEvent(el, type, fn, capture) {
272 el.removeEventListener(type, fn, {
273 capture: !!capture,
274 });
275}
276function maybePrevent(e) {
277 if (e.cancelable) {
278 e.preventDefault();
279 }
280}
281function offset(el) {
282 var left = 0;
283 var top = 0;
284 while (el) {
285 left -= el.offsetLeft;
286 top -= el.offsetTop;
287 el = el.offsetParent;
288 }
289 return {
290 left: left,
291 top: top,
292 };
293}
294vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
295var transform = prefixStyle('transform');
296var transition = prefixStyle('transition');
297var hasPerspective = inBrowser && prefixStyle('perspective') in elementStyle;
298// fix issue #361
299var hasTouch = inBrowser && ('ontouchstart' in window || isWeChatDevTools);
300var hasTransition = inBrowser && transition in elementStyle;
301var style = {
302 transform: transform,
303 transition: transition,
304 transitionTimingFunction: prefixStyle('transitionTimingFunction'),
305 transitionDuration: prefixStyle('transitionDuration'),
306 transitionDelay: prefixStyle('transitionDelay'),
307 transformOrigin: prefixStyle('transformOrigin'),
308 transitionEnd: prefixStyle('transitionEnd'),
309 transitionProperty: prefixStyle('transitionProperty'),
310};
311var eventTypeMap = {
312 touchstart: 1,
313 touchmove: 1,
314 touchend: 1,
315 touchcancel: 1,
316 mousedown: 2,
317 mousemove: 2,
318 mouseup: 2,
319};
320function getRect(el) {
321 /* istanbul ignore if */
322 if (el instanceof window.SVGElement) {
323 var rect = el.getBoundingClientRect();
324 return {
325 top: rect.top,
326 left: rect.left,
327 width: rect.width,
328 height: rect.height,
329 };
330 }
331 else {
332 return {
333 top: el.offsetTop,
334 left: el.offsetLeft,
335 width: el.offsetWidth,
336 height: el.offsetHeight,
337 };
338 }
339}
340function preventDefaultExceptionFn(el, exceptions) {
341 for (var i in exceptions) {
342 if (exceptions[i].test(el[i])) {
343 return true;
344 }
345 }
346 return false;
347}
348var tagExceptionFn = preventDefaultExceptionFn;
349function tap(e, eventName) {
350 var ev = document.createEvent('Event');
351 ev.initEvent(eventName, true, true);
352 ev.pageX = e.pageX;
353 ev.pageY = e.pageY;
354 e.target.dispatchEvent(ev);
355}
356function click(e, event) {
357 if (event === void 0) { event = 'click'; }
358 var eventSource;
359 if (e.type === 'mouseup') {
360 eventSource = e;
361 }
362 else if (e.type === 'touchend' || e.type === 'touchcancel') {
363 eventSource = e.changedTouches[0];
364 }
365 var posSrc = {};
366 if (eventSource) {
367 posSrc.screenX = eventSource.screenX || 0;
368 posSrc.screenY = eventSource.screenY || 0;
369 posSrc.clientX = eventSource.clientX || 0;
370 posSrc.clientY = eventSource.clientY || 0;
371 }
372 var ev;
373 var bubbles = true;
374 var cancelable = true;
375 var ctrlKey = e.ctrlKey, shiftKey = e.shiftKey, altKey = e.altKey, metaKey = e.metaKey;
376 var pressedKeysMap = {
377 ctrlKey: ctrlKey,
378 shiftKey: shiftKey,
379 altKey: altKey,
380 metaKey: metaKey,
381 };
382 if (typeof MouseEvent !== 'undefined') {
383 try {
384 ev = new MouseEvent(event, extend(__assign({ bubbles: bubbles,
385 cancelable: cancelable }, pressedKeysMap), posSrc));
386 }
387 catch (e) {
388 /* istanbul ignore next */
389 createEvent();
390 }
391 }
392 else {
393 createEvent();
394 }
395 function createEvent() {
396 ev = document.createEvent('Event');
397 ev.initEvent(event, bubbles, cancelable);
398 extend(ev, posSrc);
399 }
400 // forwardedTouchEvent set to true in case of the conflict with fastclick
401 ev.forwardedTouchEvent = true;
402 ev._constructed = true;
403 e.target.dispatchEvent(ev);
404}
405function dblclick(e) {
406 click(e, 'dblclick');
407}
408
409var ease = {
410 // easeOutQuint
411 swipe: {
412 style: 'cubic-bezier(0.23, 1, 0.32, 1)',
413 fn: function (t) {
414 return 1 + --t * t * t * t * t;
415 }
416 },
417 // easeOutQuard
418 swipeBounce: {
419 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
420 fn: function (t) {
421 return t * (2 - t);
422 }
423 },
424 // easeOutQuart
425 bounce: {
426 style: 'cubic-bezier(0.165, 0.84, 0.44, 1)',
427 fn: function (t) {
428 return 1 - --t * t * t * t;
429 }
430 }
431};
432
433var DEFAULT_INTERVAL = 1000 / 60;
434var windowCompat = inBrowser && window;
435/* istanbul ignore next */
436function noop$1() { }
437var requestAnimationFrame = (function () {
438 /* istanbul ignore if */
439 if (!inBrowser) {
440 return noop$1;
441 }
442 return (windowCompat.requestAnimationFrame ||
443 windowCompat.webkitRequestAnimationFrame ||
444 windowCompat.mozRequestAnimationFrame ||
445 windowCompat.oRequestAnimationFrame ||
446 // if all else fails, use setTimeout
447 function (callback) {
448 return window.setTimeout(callback, callback.interval || DEFAULT_INTERVAL); // make interval as precise as possible.
449 });
450})();
451var cancelAnimationFrame = (function () {
452 /* istanbul ignore if */
453 if (!inBrowser) {
454 return noop$1;
455 }
456 return (windowCompat.cancelAnimationFrame ||
457 windowCompat.webkitCancelAnimationFrame ||
458 windowCompat.mozCancelAnimationFrame ||
459 windowCompat.oCancelAnimationFrame ||
460 function (id) {
461 window.clearTimeout(id);
462 });
463})();
464
465/* istanbul ignore next */
466var noop = function (val) { };
467var sharedPropertyDefinition = {
468 enumerable: true,
469 configurable: true,
470 get: noop,
471 set: noop,
472};
473var getProperty = function (obj, key) {
474 var keys = key.split('.');
475 for (var i = 0; i < keys.length - 1; i++) {
476 obj = obj[keys[i]];
477 if (typeof obj !== 'object' || !obj)
478 return;
479 }
480 var lastKey = keys.pop();
481 if (typeof obj[lastKey] === 'function') {
482 return function () {
483 return obj[lastKey].apply(obj, arguments);
484 };
485 }
486 else {
487 return obj[lastKey];
488 }
489};
490var setProperty = function (obj, key, value) {
491 var keys = key.split('.');
492 var temp;
493 for (var i = 0; i < keys.length - 1; i++) {
494 temp = keys[i];
495 if (!obj[temp])
496 obj[temp] = {};
497 obj = obj[temp];
498 }
499 obj[keys.pop()] = value;
500};
501function propertiesProxy(target, sourceKey, key) {
502 sharedPropertyDefinition.get = function proxyGetter() {
503 return getProperty(this, sourceKey);
504 };
505 sharedPropertyDefinition.set = function proxySetter(val) {
506 setProperty(this, sourceKey, val);
507 };
508 Object.defineProperty(target, key, sharedPropertyDefinition);
509}
510
511var EventEmitter = /** @class */ (function () {
512 function EventEmitter(names) {
513 this.events = {};
514 this.eventTypes = {};
515 this.registerType(names);
516 }
517 EventEmitter.prototype.on = function (type, fn, context) {
518 if (context === void 0) { context = this; }
519 this.hasType(type);
520 if (!this.events[type]) {
521 this.events[type] = [];
522 }
523 this.events[type].push([fn, context]);
524 return this;
525 };
526 EventEmitter.prototype.once = function (type, fn, context) {
527 var _this = this;
528 if (context === void 0) { context = this; }
529 this.hasType(type);
530 var magic = function () {
531 var args = [];
532 for (var _i = 0; _i < arguments.length; _i++) {
533 args[_i] = arguments[_i];
534 }
535 _this.off(type, magic);
536 var ret = fn.apply(context, args);
537 if (ret === true) {
538 return ret;
539 }
540 };
541 magic.fn = fn;
542 this.on(type, magic);
543 return this;
544 };
545 EventEmitter.prototype.off = function (type, fn) {
546 if (!type && !fn) {
547 this.events = {};
548 return this;
549 }
550 if (type) {
551 this.hasType(type);
552 if (!fn) {
553 this.events[type] = [];
554 return this;
555 }
556 var events = this.events[type];
557 if (!events) {
558 return this;
559 }
560 var count = events.length;
561 while (count--) {
562 if (events[count][0] === fn ||
563 (events[count][0] && events[count][0].fn === fn)) {
564 events.splice(count, 1);
565 }
566 }
567 return this;
568 }
569 };
570 EventEmitter.prototype.trigger = function (type) {
571 var args = [];
572 for (var _i = 1; _i < arguments.length; _i++) {
573 args[_i - 1] = arguments[_i];
574 }
575 this.hasType(type);
576 var events = this.events[type];
577 if (!events) {
578 return;
579 }
580 var len = events.length;
581 var eventsCopy = __spreadArrays(events);
582 var ret;
583 for (var i = 0; i < len; i++) {
584 var event_1 = eventsCopy[i];
585 var fn = event_1[0], context = event_1[1];
586 if (fn) {
587 ret = fn.apply(context, args);
588 if (ret === true) {
589 return ret;
590 }
591 }
592 }
593 };
594 EventEmitter.prototype.registerType = function (names) {
595 var _this = this;
596 names.forEach(function (type) {
597 _this.eventTypes[type] = type;
598 });
599 };
600 EventEmitter.prototype.destroy = function () {
601 this.events = {};
602 this.eventTypes = {};
603 };
604 EventEmitter.prototype.hasType = function (type) {
605 var types = this.eventTypes;
606 var isType = types[type] === type;
607 if (!isType) {
608 warn("EventEmitter has used unknown event type: \"" + type + "\", should be oneof [" +
609 ("" + Object.keys(types).map(function (_) { return JSON.stringify(_); })) +
610 "]");
611 }
612 };
613 return EventEmitter;
614}());
615var EventRegister = /** @class */ (function () {
616 function EventRegister(wrapper, events) {
617 this.wrapper = wrapper;
618 this.events = events;
619 this.addDOMEvents();
620 }
621 EventRegister.prototype.destroy = function () {
622 this.removeDOMEvents();
623 this.events = [];
624 };
625 EventRegister.prototype.addDOMEvents = function () {
626 this.handleDOMEvents(addEvent);
627 };
628 EventRegister.prototype.removeDOMEvents = function () {
629 this.handleDOMEvents(removeEvent);
630 };
631 EventRegister.prototype.handleDOMEvents = function (eventOperation) {
632 var _this = this;
633 var wrapper = this.wrapper;
634 this.events.forEach(function (event) {
635 eventOperation(wrapper, event.name, _this, !!event.capture);
636 });
637 };
638 EventRegister.prototype.handleEvent = function (e) {
639 var eventType = e.type;
640 this.events.some(function (event) {
641 if (event.name === eventType) {
642 event.handler(e);
643 return true;
644 }
645 return false;
646 });
647 };
648 return EventRegister;
649}());
650
651var CustomOptions = /** @class */ (function () {
652 function CustomOptions() {
653 }
654 return CustomOptions;
655}());
656var OptionsConstructor = /** @class */ (function (_super) {
657 __extends(OptionsConstructor, _super);
658 function OptionsConstructor() {
659 var _this = _super.call(this) || this;
660 _this.startX = 0;
661 _this.startY = 0;
662 _this.scrollX = false;
663 _this.scrollY = true;
664 _this.freeScroll = false;
665 _this.directionLockThreshold = 0;
666 _this.eventPassthrough = "" /* None */;
667 _this.click = false;
668 _this.dblclick = false;
669 _this.tap = '';
670 _this.bounce = {
671 top: true,
672 bottom: true,
673 left: true,
674 right: true,
675 };
676 _this.bounceTime = 800;
677 _this.momentum = true;
678 _this.momentumLimitTime = 300;
679 _this.momentumLimitDistance = 15;
680 _this.swipeTime = 2500;
681 _this.swipeBounceTime = 500;
682 _this.deceleration = 0.0015;
683 _this.flickLimitTime = 200;
684 _this.flickLimitDistance = 100;
685 _this.resizePolling = 60;
686 _this.probeType = 0 /* Default */;
687 _this.stopPropagation = false;
688 _this.preventDefault = true;
689 _this.preventDefaultException = {
690 tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO)$/,
691 };
692 _this.tagException = {
693 tagName: /^TEXTAREA$/,
694 };
695 _this.HWCompositing = true;
696 _this.useTransition = true;
697 _this.bindToWrapper = false;
698 _this.bindToTarget = false;
699 _this.disableMouse = hasTouch;
700 _this.disableTouch = !hasTouch;
701 _this.autoBlur = true;
702 _this.autoEndDistance = 5;
703 _this.outOfBoundaryDampingFactor = 1 / 3;
704 _this.specifiedIndexAsContent = 0;
705 _this.quadrant = 1 /* First */;
706 return _this;
707 }
708 OptionsConstructor.prototype.merge = function (options) {
709 if (!options)
710 return this;
711 for (var key in options) {
712 if (key === 'bounce') {
713 this.bounce = this.resolveBounce(options[key]);
714 continue;
715 }
716 this[key] = options[key];
717 }
718 return this;
719 };
720 OptionsConstructor.prototype.process = function () {
721 this.translateZ =
722 this.HWCompositing && hasPerspective ? ' translateZ(1px)' : '';
723 this.useTransition = this.useTransition && hasTransition;
724 this.preventDefault = !this.eventPassthrough && this.preventDefault;
725 // If you want eventPassthrough I have to lock one of the axes
726 this.scrollX =
727 this.eventPassthrough === "horizontal" /* Horizontal */
728 ? false
729 : this.scrollX;
730 this.scrollY =
731 this.eventPassthrough === "vertical" /* Vertical */ ? false : this.scrollY;
732 // With eventPassthrough we also need lockDirection mechanism
733 this.freeScroll = this.freeScroll && !this.eventPassthrough;
734 // force true when freeScroll is true
735 this.scrollX = this.freeScroll ? true : this.scrollX;
736 this.scrollY = this.freeScroll ? true : this.scrollY;
737 this.directionLockThreshold = this.eventPassthrough
738 ? 0
739 : this.directionLockThreshold;
740 return this;
741 };
742 OptionsConstructor.prototype.resolveBounce = function (bounceOptions) {
743 var DEFAULT_BOUNCE = {
744 top: true,
745 right: true,
746 bottom: true,
747 left: true,
748 };
749 var NEGATED_BOUNCE = {
750 top: false,
751 right: false,
752 bottom: false,
753 left: false,
754 };
755 var ret;
756 if (typeof bounceOptions === 'object') {
757 ret = extend(DEFAULT_BOUNCE, bounceOptions);
758 }
759 else {
760 ret = bounceOptions ? DEFAULT_BOUNCE : NEGATED_BOUNCE;
761 }
762 return ret;
763 };
764 return OptionsConstructor;
765}(CustomOptions));
766
767var ActionsHandler = /** @class */ (function () {
768 function ActionsHandler(wrapper, options) {
769 this.wrapper = wrapper;
770 this.options = options;
771 this.hooks = new EventEmitter([
772 'beforeStart',
773 'start',
774 'move',
775 'end',
776 'click',
777 ]);
778 this.handleDOMEvents();
779 }
780 ActionsHandler.prototype.handleDOMEvents = function () {
781 var _a = this.options, bindToWrapper = _a.bindToWrapper, disableMouse = _a.disableMouse, disableTouch = _a.disableTouch, click = _a.click;
782 var wrapper = this.wrapper;
783 var target = bindToWrapper ? wrapper : window;
784 var wrapperEvents = [];
785 var targetEvents = [];
786 var shouldRegisterTouch = !disableTouch;
787 var shouldRegisterMouse = !disableMouse;
788 if (click) {
789 wrapperEvents.push({
790 name: 'click',
791 handler: this.click.bind(this),
792 capture: true,
793 });
794 }
795 if (shouldRegisterTouch) {
796 wrapperEvents.push({
797 name: 'touchstart',
798 handler: this.start.bind(this),
799 });
800 targetEvents.push({
801 name: 'touchmove',
802 handler: this.move.bind(this),
803 }, {
804 name: 'touchend',
805 handler: this.end.bind(this),
806 }, {
807 name: 'touchcancel',
808 handler: this.end.bind(this),
809 });
810 }
811 if (shouldRegisterMouse) {
812 wrapperEvents.push({
813 name: 'mousedown',
814 handler: this.start.bind(this),
815 });
816 targetEvents.push({
817 name: 'mousemove',
818 handler: this.move.bind(this),
819 }, {
820 name: 'mouseup',
821 handler: this.end.bind(this),
822 });
823 }
824 this.wrapperEventRegister = new EventRegister(wrapper, wrapperEvents);
825 this.targetEventRegister = new EventRegister(target, targetEvents);
826 };
827 ActionsHandler.prototype.beforeHandler = function (e, type) {
828 var _a = this.options, preventDefault = _a.preventDefault, stopPropagation = _a.stopPropagation, preventDefaultException = _a.preventDefaultException;
829 var preventDefaultConditions = {
830 start: function () {
831 return (preventDefault &&
832 !preventDefaultExceptionFn(e.target, preventDefaultException));
833 },
834 end: function () {
835 return (preventDefault &&
836 !preventDefaultExceptionFn(e.target, preventDefaultException));
837 },
838 move: function () {
839 return preventDefault;
840 },
841 };
842 if (preventDefaultConditions[type]()) {
843 e.preventDefault();
844 }
845 if (stopPropagation) {
846 e.stopPropagation();
847 }
848 };
849 ActionsHandler.prototype.setInitiated = function (type) {
850 if (type === void 0) { type = 0; }
851 this.initiated = type;
852 };
853 ActionsHandler.prototype.start = function (e) {
854 var _eventType = eventTypeMap[e.type];
855 if (this.initiated && this.initiated !== _eventType) {
856 return;
857 }
858 this.setInitiated(_eventType);
859 // if textarea or other html tags in options.tagException is manipulated
860 // do not make bs scroll
861 if (tagExceptionFn(e.target, this.options.tagException)) {
862 this.setInitiated();
863 return;
864 }
865 // only allow mouse left button
866 if (_eventType === 2 /* Mouse */ && e.button !== 0 /* Left */)
867 return;
868 if (this.hooks.trigger(this.hooks.eventTypes.beforeStart, e)) {
869 return;
870 }
871 this.beforeHandler(e, 'start');
872 var point = (e.touches ? e.touches[0] : e);
873 this.pointX = point.pageX;
874 this.pointY = point.pageY;
875 this.hooks.trigger(this.hooks.eventTypes.start, e);
876 };
877 ActionsHandler.prototype.move = function (e) {
878 if (eventTypeMap[e.type] !== this.initiated) {
879 return;
880 }
881 this.beforeHandler(e, 'move');
882 var point = (e.touches ? e.touches[0] : e);
883 var deltaX = point.pageX - this.pointX;
884 var deltaY = point.pageY - this.pointY;
885 this.pointX = point.pageX;
886 this.pointY = point.pageY;
887 if (this.hooks.trigger(this.hooks.eventTypes.move, {
888 deltaX: deltaX,
889 deltaY: deltaY,
890 e: e,
891 })) {
892 return;
893 }
894 // auto end when out of viewport
895 var scrollLeft = document.documentElement.scrollLeft ||
896 window.pageXOffset ||
897 document.body.scrollLeft;
898 var scrollTop = document.documentElement.scrollTop ||
899 window.pageYOffset ||
900 document.body.scrollTop;
901 var pX = this.pointX - scrollLeft;
902 var pY = this.pointY - scrollTop;
903 var autoEndDistance = this.options.autoEndDistance;
904 if (pX > document.documentElement.clientWidth - autoEndDistance ||
905 pY > document.documentElement.clientHeight - autoEndDistance ||
906 pX < autoEndDistance ||
907 pY < autoEndDistance) {
908 this.end(e);
909 }
910 };
911 ActionsHandler.prototype.end = function (e) {
912 if (eventTypeMap[e.type] !== this.initiated) {
913 return;
914 }
915 this.setInitiated();
916 this.beforeHandler(e, 'end');
917 this.hooks.trigger(this.hooks.eventTypes.end, e);
918 };
919 ActionsHandler.prototype.click = function (e) {
920 this.hooks.trigger(this.hooks.eventTypes.click, e);
921 };
922 ActionsHandler.prototype.setContent = function (content) {
923 if (content !== this.wrapper) {
924 this.wrapper = content;
925 this.rebindDOMEvents();
926 }
927 };
928 ActionsHandler.prototype.rebindDOMEvents = function () {
929 this.wrapperEventRegister.destroy();
930 this.targetEventRegister.destroy();
931 this.handleDOMEvents();
932 };
933 ActionsHandler.prototype.destroy = function () {
934 this.wrapperEventRegister.destroy();
935 this.targetEventRegister.destroy();
936 this.hooks.destroy();
937 };
938 return ActionsHandler;
939}());
940
941var translaterMetaData = {
942 x: ['translateX', 'px'],
943 y: ['translateY', 'px'],
944};
945var Translater = /** @class */ (function () {
946 function Translater(content) {
947 this.setContent(content);
948 this.hooks = new EventEmitter(['beforeTranslate', 'translate']);
949 }
950 Translater.prototype.getComputedPosition = function () {
951 var cssStyle = window.getComputedStyle(this.content, null);
952 var matrix = cssStyle[style.transform].split(')')[0].split(', ');
953 var x = +(matrix[12] || matrix[4]) || 0;
954 var y = +(matrix[13] || matrix[5]) || 0;
955 return {
956 x: x,
957 y: y,
958 };
959 };
960 Translater.prototype.translate = function (point) {
961 var transformStyle = [];
962 Object.keys(point).forEach(function (key) {
963 if (!translaterMetaData[key]) {
964 return;
965 }
966 var transformFnName = translaterMetaData[key][0];
967 if (transformFnName) {
968 var transformFnArgUnit = translaterMetaData[key][1];
969 var transformFnArg = point[key];
970 transformStyle.push(transformFnName + "(" + transformFnArg + transformFnArgUnit + ")");
971 }
972 });
973 this.hooks.trigger(this.hooks.eventTypes.beforeTranslate, transformStyle, point);
974 this.style[style.transform] = transformStyle.join(' ');
975 this.hooks.trigger(this.hooks.eventTypes.translate, point);
976 };
977 Translater.prototype.setContent = function (content) {
978 if (this.content !== content) {
979 this.content = content;
980 this.style = content.style;
981 }
982 };
983 Translater.prototype.destroy = function () {
984 this.hooks.destroy();
985 };
986 return Translater;
987}());
988
989var Base = /** @class */ (function () {
990 function Base(content, translater, options) {
991 this.translater = translater;
992 this.options = options;
993 this.timer = 0;
994 this.hooks = new EventEmitter([
995 'move',
996 'end',
997 'beforeForceStop',
998 'forceStop',
999 'callStop',
1000 'time',
1001 'timeFunction',
1002 ]);
1003 this.setContent(content);
1004 }
1005 Base.prototype.translate = function (endPoint) {
1006 this.translater.translate(endPoint);
1007 };
1008 Base.prototype.setPending = function (pending) {
1009 this.pending = pending;
1010 };
1011 Base.prototype.setForceStopped = function (forceStopped) {
1012 this.forceStopped = forceStopped;
1013 };
1014 Base.prototype.setCallStop = function (called) {
1015 this.callStopWhenPending = called;
1016 };
1017 Base.prototype.setContent = function (content) {
1018 if (this.content !== content) {
1019 this.content = content;
1020 this.style = content.style;
1021 this.stop();
1022 }
1023 };
1024 Base.prototype.clearTimer = function () {
1025 if (this.timer) {
1026 cancelAnimationFrame(this.timer);
1027 this.timer = 0;
1028 }
1029 };
1030 Base.prototype.destroy = function () {
1031 this.hooks.destroy();
1032 cancelAnimationFrame(this.timer);
1033 };
1034 return Base;
1035}());
1036
1037// iOS 13.6 - 14.x, window.getComputedStyle sometimes will get wrong transform value
1038// when bs use transition mode
1039// eg: translateY -100px -> -200px, when the last frame which is about to scroll to -200px
1040// window.getComputedStyle(this.content) will calculate transformY to be -100px(startPoint)
1041// it is weird
1042// so we should validate position caculated by 'window.getComputedStyle'
1043var isValidPostion = function (startPoint, endPoint, currentPos, prePos) {
1044 var computeDirection = function (endValue, startValue) {
1045 var delta = endValue - startValue;
1046 var direction = delta > 0
1047 ? -1 /* Negative */
1048 : delta < 0
1049 ? 1 /* Positive */
1050 : 0 /* Default */;
1051 return direction;
1052 };
1053 var directionX = computeDirection(endPoint.x, startPoint.x);
1054 var directionY = computeDirection(endPoint.y, startPoint.y);
1055 var deltaX = currentPos.x - prePos.x;
1056 var deltaY = currentPos.y - prePos.y;
1057 return directionX * deltaX <= 0 && directionY * deltaY <= 0;
1058};
1059
1060var Transition = /** @class */ (function (_super) {
1061 __extends(Transition, _super);
1062 function Transition() {
1063 return _super !== null && _super.apply(this, arguments) || this;
1064 }
1065 Transition.prototype.startProbe = function (startPoint, endPoint) {
1066 var _this = this;
1067 var prePos = startPoint;
1068 var probe = function () {
1069 var pos = _this.translater.getComputedPosition();
1070 if (isValidPostion(startPoint, endPoint, pos, prePos)) {
1071 _this.hooks.trigger(_this.hooks.eventTypes.move, pos);
1072 }
1073 // call bs.stop() should not dispatch end hook again.
1074 // forceStop hook will do this.
1075 /* istanbul ignore if */
1076 if (!_this.pending) {
1077 if (_this.callStopWhenPending) {
1078 _this.callStopWhenPending = false;
1079 }
1080 else {
1081 // transition ends should dispatch end hook.
1082 _this.hooks.trigger(_this.hooks.eventTypes.end, pos);
1083 }
1084 }
1085 prePos = pos;
1086 if (_this.pending) {
1087 _this.timer = requestAnimationFrame(probe);
1088 }
1089 };
1090 // when manually call bs.stop(), then bs.scrollTo()
1091 // we should reset callStopWhenPending to dispatch end hook
1092 if (this.callStopWhenPending) {
1093 this.setCallStop(false);
1094 }
1095 cancelAnimationFrame(this.timer);
1096 probe();
1097 };
1098 Transition.prototype.transitionTime = function (time) {
1099 if (time === void 0) { time = 0; }
1100 this.style[style.transitionDuration] = time + 'ms';
1101 this.hooks.trigger(this.hooks.eventTypes.time, time);
1102 };
1103 Transition.prototype.transitionTimingFunction = function (easing) {
1104 this.style[style.transitionTimingFunction] = easing;
1105 this.hooks.trigger(this.hooks.eventTypes.timeFunction, easing);
1106 };
1107 Transition.prototype.transitionProperty = function () {
1108 this.style[style.transitionProperty] = style.transform;
1109 };
1110 Transition.prototype.move = function (startPoint, endPoint, time, easingFn) {
1111 this.setPending(time > 0);
1112 this.transitionTimingFunction(easingFn);
1113 this.transitionProperty();
1114 this.transitionTime(time);
1115 this.translate(endPoint);
1116 var isRealtimeProbeType = this.options.probeType === 3 /* Realtime */;
1117 if (time && isRealtimeProbeType) {
1118 this.startProbe(startPoint, endPoint);
1119 }
1120 // if we change content's transformY in a tick
1121 // such as: 0 -> 50px -> 0
1122 // transitionend will not be triggered
1123 // so we forceupdate by reflow
1124 if (!time) {
1125 this._reflow = this.content.offsetHeight;
1126 if (isRealtimeProbeType) {
1127 this.hooks.trigger(this.hooks.eventTypes.move, endPoint);
1128 }
1129 this.hooks.trigger(this.hooks.eventTypes.end, endPoint);
1130 }
1131 };
1132 Transition.prototype.doStop = function () {
1133 var pending = this.pending;
1134 this.setForceStopped(false);
1135 this.setCallStop(false);
1136 // still in transition
1137 if (pending) {
1138 this.setPending(false);
1139 cancelAnimationFrame(this.timer);
1140 var _a = this.translater.getComputedPosition(), x = _a.x, y = _a.y;
1141 this.transitionTime();
1142 this.translate({ x: x, y: y });
1143 this.setForceStopped(true);
1144 this.setCallStop(true);
1145 this.hooks.trigger(this.hooks.eventTypes.forceStop, { x: x, y: y });
1146 }
1147 return pending;
1148 };
1149 Transition.prototype.stop = function () {
1150 var stopFromTransition = this.doStop();
1151 if (stopFromTransition) {
1152 this.hooks.trigger(this.hooks.eventTypes.callStop);
1153 }
1154 };
1155 return Transition;
1156}(Base));
1157
1158var Animation = /** @class */ (function (_super) {
1159 __extends(Animation, _super);
1160 function Animation() {
1161 return _super !== null && _super.apply(this, arguments) || this;
1162 }
1163 Animation.prototype.move = function (startPoint, endPoint, time, easingFn) {
1164 // time is 0
1165 if (!time) {
1166 this.translate(endPoint);
1167 if (this.options.probeType === 3 /* Realtime */) {
1168 this.hooks.trigger(this.hooks.eventTypes.move, endPoint);
1169 }
1170 this.hooks.trigger(this.hooks.eventTypes.end, endPoint);
1171 return;
1172 }
1173 this.animate(startPoint, endPoint, time, easingFn);
1174 };
1175 Animation.prototype.animate = function (startPoint, endPoint, duration, easingFn) {
1176 var _this = this;
1177 var startTime = getNow();
1178 var destTime = startTime + duration;
1179 var isRealtimeProbeType = this.options.probeType === 3 /* Realtime */;
1180 var step = function () {
1181 var now = getNow();
1182 // js animation end
1183 if (now >= destTime) {
1184 _this.translate(endPoint);
1185 if (isRealtimeProbeType) {
1186 _this.hooks.trigger(_this.hooks.eventTypes.move, endPoint);
1187 }
1188 _this.hooks.trigger(_this.hooks.eventTypes.end, endPoint);
1189 return;
1190 }
1191 now = (now - startTime) / duration;
1192 var easing = easingFn(now);
1193 var newPoint = {};
1194 Object.keys(endPoint).forEach(function (key) {
1195 var startValue = startPoint[key];
1196 var endValue = endPoint[key];
1197 newPoint[key] = (endValue - startValue) * easing + startValue;
1198 });
1199 _this.translate(newPoint);
1200 if (isRealtimeProbeType) {
1201 _this.hooks.trigger(_this.hooks.eventTypes.move, newPoint);
1202 }
1203 if (_this.pending) {
1204 _this.timer = requestAnimationFrame(step);
1205 }
1206 // call bs.stop() should not dispatch end hook again.
1207 // forceStop hook will do this.
1208 /* istanbul ignore if */
1209 if (!_this.pending) {
1210 if (_this.callStopWhenPending) {
1211 _this.callStopWhenPending = false;
1212 }
1213 else {
1214 // raf ends should dispatch end hook.
1215 _this.hooks.trigger(_this.hooks.eventTypes.end, endPoint);
1216 }
1217 }
1218 };
1219 this.setPending(true);
1220 // when manually call bs.stop(), then bs.scrollTo()
1221 // we should reset callStopWhenPending to dispatch end hook
1222 if (this.callStopWhenPending) {
1223 this.setCallStop(false);
1224 }
1225 cancelAnimationFrame(this.timer);
1226 step();
1227 };
1228 Animation.prototype.doStop = function () {
1229 var pending = this.pending;
1230 this.setForceStopped(false);
1231 this.setCallStop(false);
1232 // still in requestFrameAnimation
1233 if (pending) {
1234 this.setPending(false);
1235 cancelAnimationFrame(this.timer);
1236 var pos = this.translater.getComputedPosition();
1237 this.setForceStopped(true);
1238 this.setCallStop(true);
1239 this.hooks.trigger(this.hooks.eventTypes.forceStop, pos);
1240 }
1241 return pending;
1242 };
1243 Animation.prototype.stop = function () {
1244 var stopFromAnimation = this.doStop();
1245 if (stopFromAnimation) {
1246 this.hooks.trigger(this.hooks.eventTypes.callStop);
1247 }
1248 };
1249 return Animation;
1250}(Base));
1251
1252function createAnimater(element, translater, options) {
1253 var useTransition = options.useTransition;
1254 var animaterOptions = {};
1255 Object.defineProperty(animaterOptions, 'probeType', {
1256 enumerable: true,
1257 configurable: false,
1258 get: function () {
1259 return options.probeType;
1260 },
1261 });
1262 if (useTransition) {
1263 return new Transition(element, translater, animaterOptions);
1264 }
1265 else {
1266 return new Animation(element, translater, animaterOptions);
1267 }
1268}
1269
1270var Behavior = /** @class */ (function () {
1271 function Behavior(wrapper, content, options) {
1272 this.wrapper = wrapper;
1273 this.options = options;
1274 this.hooks = new EventEmitter([
1275 'beforeComputeBoundary',
1276 'computeBoundary',
1277 'momentum',
1278 'end',
1279 'ignoreHasScroll'
1280 ]);
1281 this.refresh(content);
1282 }
1283 Behavior.prototype.start = function () {
1284 this.dist = 0;
1285 this.setMovingDirection(0 /* Default */);
1286 this.setDirection(0 /* Default */);
1287 };
1288 Behavior.prototype.move = function (delta) {
1289 delta = this.hasScroll ? delta : 0;
1290 this.setMovingDirection(delta);
1291 return this.performDampingAlgorithm(delta, this.options.outOfBoundaryDampingFactor);
1292 };
1293 Behavior.prototype.setMovingDirection = function (delta) {
1294 this.movingDirection =
1295 delta > 0
1296 ? -1 /* Negative */
1297 : delta < 0
1298 ? 1 /* Positive */
1299 : 0 /* Default */;
1300 };
1301 Behavior.prototype.setDirection = function (delta) {
1302 this.direction =
1303 delta > 0
1304 ? -1 /* Negative */
1305 : delta < 0
1306 ? 1 /* Positive */
1307 : 0 /* Default */;
1308 };
1309 Behavior.prototype.performDampingAlgorithm = function (delta, dampingFactor) {
1310 var newPos = this.currentPos + delta;
1311 // Slow down or stop if outside of the boundaries
1312 if (newPos > this.minScrollPos || newPos < this.maxScrollPos) {
1313 if ((newPos > this.minScrollPos && this.options.bounces[0]) ||
1314 (newPos < this.maxScrollPos && this.options.bounces[1])) {
1315 newPos = this.currentPos + delta * dampingFactor;
1316 }
1317 else {
1318 newPos =
1319 newPos > this.minScrollPos ? this.minScrollPos : this.maxScrollPos;
1320 }
1321 }
1322 return newPos;
1323 };
1324 Behavior.prototype.end = function (duration) {
1325 var momentumInfo = {
1326 duration: 0
1327 };
1328 var absDist = Math.abs(this.currentPos - this.startPos);
1329 // start momentum animation if needed
1330 if (this.options.momentum &&
1331 duration < this.options.momentumLimitTime &&
1332 absDist > this.options.momentumLimitDistance) {
1333 var wrapperSize = (this.direction === -1 /* Negative */ && this.options.bounces[0]) ||
1334 (this.direction === 1 /* Positive */ && this.options.bounces[1])
1335 ? this.wrapperSize
1336 : 0;
1337 momentumInfo = this.hasScroll
1338 ? this.momentum(this.currentPos, this.startPos, duration, this.maxScrollPos, this.minScrollPos, wrapperSize, this.options)
1339 : { destination: this.currentPos, duration: 0 };
1340 }
1341 else {
1342 this.hooks.trigger(this.hooks.eventTypes.end, momentumInfo);
1343 }
1344 return momentumInfo;
1345 };
1346 Behavior.prototype.momentum = function (current, start, time, lowerMargin, upperMargin, wrapperSize, options) {
1347 if (options === void 0) { options = this.options; }
1348 var distance = current - start;
1349 var speed = Math.abs(distance) / time;
1350 var deceleration = options.deceleration, swipeBounceTime = options.swipeBounceTime, swipeTime = options.swipeTime;
1351 var duration = Math.min(swipeTime, (speed * 2) / deceleration);
1352 var momentumData = {
1353 destination: current + ((speed * speed) / deceleration) * (distance < 0 ? -1 : 1),
1354 duration: duration,
1355 rate: 15
1356 };
1357 this.hooks.trigger(this.hooks.eventTypes.momentum, momentumData, distance);
1358 if (momentumData.destination < lowerMargin) {
1359 momentumData.destination = wrapperSize
1360 ? Math.max(lowerMargin - wrapperSize / 4, lowerMargin - (wrapperSize / momentumData.rate) * speed)
1361 : lowerMargin;
1362 momentumData.duration = swipeBounceTime;
1363 }
1364 else if (momentumData.destination > upperMargin) {
1365 momentumData.destination = wrapperSize
1366 ? Math.min(upperMargin + wrapperSize / 4, upperMargin + (wrapperSize / momentumData.rate) * speed)
1367 : upperMargin;
1368 momentumData.duration = swipeBounceTime;
1369 }
1370 momentumData.destination = Math.round(momentumData.destination);
1371 return momentumData;
1372 };
1373 Behavior.prototype.updateDirection = function () {
1374 var absDist = this.currentPos - this.absStartPos;
1375 this.setDirection(absDist);
1376 };
1377 Behavior.prototype.refresh = function (content) {
1378 var _a = this.options.rect, size = _a.size, position = _a.position;
1379 var isWrapperStatic = window.getComputedStyle(this.wrapper, null).position === 'static';
1380 // Force reflow
1381 var wrapperRect = getRect(this.wrapper);
1382 // use client is more fair than offset
1383 this.wrapperSize = this.wrapper[size === 'width' ? 'clientWidth' : 'clientHeight'];
1384 this.setContent(content);
1385 var contentRect = getRect(this.content);
1386 this.contentSize = contentRect[size];
1387 this.relativeOffset = contentRect[position];
1388 /* istanbul ignore if */
1389 if (isWrapperStatic) {
1390 this.relativeOffset -= wrapperRect[position];
1391 }
1392 this.computeBoundary();
1393 this.setDirection(0 /* Default */);
1394 };
1395 Behavior.prototype.setContent = function (content) {
1396 if (content !== this.content) {
1397 this.content = content;
1398 this.resetState();
1399 }
1400 };
1401 Behavior.prototype.resetState = function () {
1402 this.currentPos = 0;
1403 this.startPos = 0;
1404 this.dist = 0;
1405 this.setDirection(0 /* Default */);
1406 this.setMovingDirection(0 /* Default */);
1407 this.resetStartPos();
1408 };
1409 Behavior.prototype.computeBoundary = function () {
1410 this.hooks.trigger(this.hooks.eventTypes.beforeComputeBoundary);
1411 var boundary = {
1412 minScrollPos: 0,
1413 maxScrollPos: this.wrapperSize - this.contentSize
1414 };
1415 if (boundary.maxScrollPos < 0) {
1416 boundary.maxScrollPos -= this.relativeOffset;
1417 if (this.options.specifiedIndexAsContent === 0) {
1418 boundary.minScrollPos = -this.relativeOffset;
1419 }
1420 }
1421 this.hooks.trigger(this.hooks.eventTypes.computeBoundary, boundary);
1422 this.minScrollPos = boundary.minScrollPos;
1423 this.maxScrollPos = boundary.maxScrollPos;
1424 this.hasScroll =
1425 this.options.scrollable && this.maxScrollPos < this.minScrollPos;
1426 if (!this.hasScroll && this.minScrollPos < this.maxScrollPos) {
1427 this.maxScrollPos = this.minScrollPos;
1428 this.contentSize = this.wrapperSize;
1429 }
1430 };
1431 Behavior.prototype.updatePosition = function (pos) {
1432 this.currentPos = pos;
1433 };
1434 Behavior.prototype.getCurrentPos = function () {
1435 return this.currentPos;
1436 };
1437 Behavior.prototype.checkInBoundary = function () {
1438 var position = this.adjustPosition(this.currentPos);
1439 var inBoundary = position === this.getCurrentPos();
1440 return {
1441 position: position,
1442 inBoundary: inBoundary
1443 };
1444 };
1445 // adjust position when out of boundary
1446 Behavior.prototype.adjustPosition = function (pos) {
1447 if (!this.hasScroll &&
1448 !this.hooks.trigger(this.hooks.eventTypes.ignoreHasScroll)) {
1449 pos = this.minScrollPos;
1450 }
1451 else if (pos > this.minScrollPos) {
1452 pos = this.minScrollPos;
1453 }
1454 else if (pos < this.maxScrollPos) {
1455 pos = this.maxScrollPos;
1456 }
1457 return pos;
1458 };
1459 Behavior.prototype.updateStartPos = function () {
1460 this.startPos = this.currentPos;
1461 };
1462 Behavior.prototype.updateAbsStartPos = function () {
1463 this.absStartPos = this.currentPos;
1464 };
1465 Behavior.prototype.resetStartPos = function () {
1466 this.updateStartPos();
1467 this.updateAbsStartPos();
1468 };
1469 Behavior.prototype.getAbsDist = function (delta) {
1470 this.dist += delta;
1471 return Math.abs(this.dist);
1472 };
1473 Behavior.prototype.destroy = function () {
1474 this.hooks.destroy();
1475 };
1476 return Behavior;
1477}());
1478
1479var _a, _b, _c, _d;
1480var PassthroughHandlers = (_a = {},
1481 _a["yes" /* Yes */] = function (e) {
1482 return true;
1483 },
1484 _a["no" /* No */] = function (e) {
1485 maybePrevent(e);
1486 return false;
1487 },
1488 _a);
1489var DirectionMap = (_b = {},
1490 _b["horizontal" /* Horizontal */] = (_c = {},
1491 _c["yes" /* Yes */] = "horizontal" /* Horizontal */,
1492 _c["no" /* No */] = "vertical" /* Vertical */,
1493 _c),
1494 _b["vertical" /* Vertical */] = (_d = {},
1495 _d["yes" /* Yes */] = "vertical" /* Vertical */,
1496 _d["no" /* No */] = "horizontal" /* Horizontal */,
1497 _d),
1498 _b);
1499var DirectionLockAction = /** @class */ (function () {
1500 function DirectionLockAction(directionLockThreshold, freeScroll, eventPassthrough) {
1501 this.directionLockThreshold = directionLockThreshold;
1502 this.freeScroll = freeScroll;
1503 this.eventPassthrough = eventPassthrough;
1504 this.reset();
1505 }
1506 DirectionLockAction.prototype.reset = function () {
1507 this.directionLocked = "" /* Default */;
1508 };
1509 DirectionLockAction.prototype.checkMovingDirection = function (absDistX, absDistY, e) {
1510 this.computeDirectionLock(absDistX, absDistY);
1511 return this.handleEventPassthrough(e);
1512 };
1513 DirectionLockAction.prototype.adjustDelta = function (deltaX, deltaY) {
1514 if (this.directionLocked === "horizontal" /* Horizontal */) {
1515 deltaY = 0;
1516 }
1517 else if (this.directionLocked === "vertical" /* Vertical */) {
1518 deltaX = 0;
1519 }
1520 return {
1521 deltaX: deltaX,
1522 deltaY: deltaY,
1523 };
1524 };
1525 DirectionLockAction.prototype.computeDirectionLock = function (absDistX, absDistY) {
1526 // If you are scrolling in one direction, lock it
1527 if (this.directionLocked === "" /* Default */ && !this.freeScroll) {
1528 if (absDistX > absDistY + this.directionLockThreshold) {
1529 this.directionLocked = "horizontal" /* Horizontal */; // lock horizontally
1530 }
1531 else if (absDistY >= absDistX + this.directionLockThreshold) {
1532 this.directionLocked = "vertical" /* Vertical */; // lock vertically
1533 }
1534 else {
1535 this.directionLocked = "none" /* None */; // no lock
1536 }
1537 }
1538 };
1539 DirectionLockAction.prototype.handleEventPassthrough = function (e) {
1540 var handleMap = DirectionMap[this.directionLocked];
1541 if (handleMap) {
1542 if (this.eventPassthrough === handleMap["yes" /* Yes */]) {
1543 return PassthroughHandlers["yes" /* Yes */](e);
1544 }
1545 else if (this.eventPassthrough === handleMap["no" /* No */]) {
1546 return PassthroughHandlers["no" /* No */](e);
1547 }
1548 }
1549 return false;
1550 };
1551 return DirectionLockAction;
1552}());
1553
1554var applyQuadrantTransformation = function (deltaX, deltaY, quadrant) {
1555 if (quadrant === 2 /* Second */) {
1556 return [deltaY, -deltaX];
1557 }
1558 else if (quadrant === 3 /* Third */) {
1559 return [-deltaX, -deltaY];
1560 }
1561 else if (quadrant === 4 /* Forth */) {
1562 return [-deltaY, deltaX];
1563 }
1564 else {
1565 return [deltaX, deltaY];
1566 }
1567};
1568var ScrollerActions = /** @class */ (function () {
1569 function ScrollerActions(scrollBehaviorX, scrollBehaviorY, actionsHandler, animater, options) {
1570 this.hooks = new EventEmitter([
1571 'start',
1572 'beforeMove',
1573 'scrollStart',
1574 'scroll',
1575 'beforeEnd',
1576 'end',
1577 'scrollEnd',
1578 'contentNotMoved',
1579 'detectMovingDirection',
1580 'coordinateTransformation',
1581 ]);
1582 this.scrollBehaviorX = scrollBehaviorX;
1583 this.scrollBehaviorY = scrollBehaviorY;
1584 this.actionsHandler = actionsHandler;
1585 this.animater = animater;
1586 this.options = options;
1587 this.directionLockAction = new DirectionLockAction(options.directionLockThreshold, options.freeScroll, options.eventPassthrough);
1588 this.enabled = true;
1589 this.bindActionsHandler();
1590 }
1591 ScrollerActions.prototype.bindActionsHandler = function () {
1592 var _this = this;
1593 // [mouse|touch]start event
1594 this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.start, function (e) {
1595 if (!_this.enabled)
1596 return true;
1597 return _this.handleStart(e);
1598 });
1599 // [mouse|touch]move event
1600 this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.move, function (_a) {
1601 var deltaX = _a.deltaX, deltaY = _a.deltaY, e = _a.e;
1602 if (!_this.enabled)
1603 return true;
1604 var _b = applyQuadrantTransformation(deltaX, deltaY, _this.options.quadrant), transformateDeltaX = _b[0], transformateDeltaY = _b[1];
1605 var transformateDeltaData = {
1606 deltaX: transformateDeltaX,
1607 deltaY: transformateDeltaY,
1608 };
1609 _this.hooks.trigger(_this.hooks.eventTypes.coordinateTransformation, transformateDeltaData);
1610 return _this.handleMove(transformateDeltaData.deltaX, transformateDeltaData.deltaY, e);
1611 });
1612 // [mouse|touch]end event
1613 this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.end, function (e) {
1614 if (!_this.enabled)
1615 return true;
1616 return _this.handleEnd(e);
1617 });
1618 // click
1619 this.actionsHandler.hooks.on(this.actionsHandler.hooks.eventTypes.click, function (e) {
1620 // handle native click event
1621 if (_this.enabled && !e._constructed) {
1622 _this.handleClick(e);
1623 }
1624 });
1625 };
1626 ScrollerActions.prototype.handleStart = function (e) {
1627 var timestamp = getNow();
1628 this.fingerMoved = false;
1629 this.contentMoved = false;
1630 this.startTime = timestamp;
1631 this.directionLockAction.reset();
1632 this.scrollBehaviorX.start();
1633 this.scrollBehaviorY.start();
1634 // force stopping last transition or animation
1635 this.animater.doStop();
1636 this.scrollBehaviorX.resetStartPos();
1637 this.scrollBehaviorY.resetStartPos();
1638 this.hooks.trigger(this.hooks.eventTypes.start, e);
1639 };
1640 ScrollerActions.prototype.handleMove = function (deltaX, deltaY, e) {
1641 if (this.hooks.trigger(this.hooks.eventTypes.beforeMove, e)) {
1642 return;
1643 }
1644 var absDistX = this.scrollBehaviorX.getAbsDist(deltaX);
1645 var absDistY = this.scrollBehaviorY.getAbsDist(deltaY);
1646 var timestamp = getNow();
1647 // We need to move at least momentumLimitDistance pixels
1648 // for the scrolling to initiate
1649 if (this.checkMomentum(absDistX, absDistY, timestamp)) {
1650 return true;
1651 }
1652 if (this.directionLockAction.checkMovingDirection(absDistX, absDistY, e)) {
1653 this.actionsHandler.setInitiated();
1654 return true;
1655 }
1656 var delta = this.directionLockAction.adjustDelta(deltaX, deltaY);
1657 var prevX = this.scrollBehaviorX.getCurrentPos();
1658 var newX = this.scrollBehaviorX.move(delta.deltaX);
1659 var prevY = this.scrollBehaviorY.getCurrentPos();
1660 var newY = this.scrollBehaviorY.move(delta.deltaY);
1661 if (this.hooks.trigger(this.hooks.eventTypes.detectMovingDirection)) {
1662 return;
1663 }
1664 if (!this.fingerMoved) {
1665 this.fingerMoved = true;
1666 }
1667 var positionChanged = newX !== prevX || newY !== prevY;
1668 if (!this.contentMoved && !positionChanged) {
1669 this.hooks.trigger(this.hooks.eventTypes.contentNotMoved);
1670 }
1671 if (!this.contentMoved && positionChanged) {
1672 this.contentMoved = true;
1673 this.hooks.trigger(this.hooks.eventTypes.scrollStart);
1674 }
1675 if (this.contentMoved && positionChanged) {
1676 this.animater.translate({
1677 x: newX,
1678 y: newY,
1679 });
1680 this.dispatchScroll(timestamp);
1681 }
1682 };
1683 ScrollerActions.prototype.dispatchScroll = function (timestamp) {
1684 // dispatch scroll in interval time
1685 if (timestamp - this.startTime > this.options.momentumLimitTime) {
1686 // refresh time and starting position to initiate a momentum
1687 this.startTime = timestamp;
1688 this.scrollBehaviorX.updateStartPos();
1689 this.scrollBehaviorY.updateStartPos();
1690 if (this.options.probeType === 1 /* Throttle */) {
1691 this.hooks.trigger(this.hooks.eventTypes.scroll, this.getCurrentPos());
1692 }
1693 }
1694 // dispatch scroll all the time
1695 if (this.options.probeType > 1 /* Throttle */) {
1696 this.hooks.trigger(this.hooks.eventTypes.scroll, this.getCurrentPos());
1697 }
1698 };
1699 ScrollerActions.prototype.checkMomentum = function (absDistX, absDistY, timestamp) {
1700 return (timestamp - this.endTime > this.options.momentumLimitTime &&
1701 absDistY < this.options.momentumLimitDistance &&
1702 absDistX < this.options.momentumLimitDistance);
1703 };
1704 ScrollerActions.prototype.handleEnd = function (e) {
1705 if (this.hooks.trigger(this.hooks.eventTypes.beforeEnd, e)) {
1706 return;
1707 }
1708 var currentPos = this.getCurrentPos();
1709 this.scrollBehaviorX.updateDirection();
1710 this.scrollBehaviorY.updateDirection();
1711 if (this.hooks.trigger(this.hooks.eventTypes.end, e, currentPos)) {
1712 return true;
1713 }
1714 currentPos = this.ensureIntegerPos(currentPos);
1715 this.animater.translate(currentPos);
1716 this.endTime = getNow();
1717 var duration = this.endTime - this.startTime;
1718 this.hooks.trigger(this.hooks.eventTypes.scrollEnd, currentPos, duration);
1719 };
1720 ScrollerActions.prototype.ensureIntegerPos = function (currentPos) {
1721 this.ensuringInteger = true;
1722 var x = currentPos.x, y = currentPos.y;
1723 var _a = this.scrollBehaviorX, minScrollPosX = _a.minScrollPos, maxScrollPosX = _a.maxScrollPos;
1724 var _b = this.scrollBehaviorY, minScrollPosY = _b.minScrollPos, maxScrollPosY = _b.maxScrollPos;
1725 x = x > 0 ? Math.ceil(x) : Math.floor(x);
1726 y = y > 0 ? Math.ceil(y) : Math.floor(y);
1727 x = between(x, maxScrollPosX, minScrollPosX);
1728 y = between(y, maxScrollPosY, minScrollPosY);
1729 return { x: x, y: y };
1730 };
1731 ScrollerActions.prototype.handleClick = function (e) {
1732 if (!preventDefaultExceptionFn(e.target, this.options.preventDefaultException)) {
1733 maybePrevent(e);
1734 e.stopPropagation();
1735 }
1736 };
1737 ScrollerActions.prototype.getCurrentPos = function () {
1738 return {
1739 x: this.scrollBehaviorX.getCurrentPos(),
1740 y: this.scrollBehaviorY.getCurrentPos(),
1741 };
1742 };
1743 ScrollerActions.prototype.refresh = function () {
1744 this.endTime = 0;
1745 };
1746 ScrollerActions.prototype.destroy = function () {
1747 this.hooks.destroy();
1748 };
1749 return ScrollerActions;
1750}());
1751
1752function createActionsHandlerOptions(bsOptions) {
1753 var options = [
1754 'click',
1755 'bindToWrapper',
1756 'disableMouse',
1757 'disableTouch',
1758 'preventDefault',
1759 'stopPropagation',
1760 'tagException',
1761 'preventDefaultException',
1762 'autoEndDistance',
1763 ].reduce(function (prev, cur) {
1764 prev[cur] = bsOptions[cur];
1765 return prev;
1766 }, {});
1767 return options;
1768}
1769function createBehaviorOptions(bsOptions, extraProp, bounces, rect) {
1770 var options = [
1771 'momentum',
1772 'momentumLimitTime',
1773 'momentumLimitDistance',
1774 'deceleration',
1775 'swipeBounceTime',
1776 'swipeTime',
1777 'outOfBoundaryDampingFactor',
1778 'specifiedIndexAsContent',
1779 ].reduce(function (prev, cur) {
1780 prev[cur] = bsOptions[cur];
1781 return prev;
1782 }, {});
1783 // add extra property
1784 options.scrollable = !!bsOptions[extraProp];
1785 options.bounces = bounces;
1786 options.rect = rect;
1787 return options;
1788}
1789
1790function bubbling(source, target, events) {
1791 events.forEach(function (event) {
1792 var sourceEvent;
1793 var targetEvent;
1794 if (typeof event === 'string') {
1795 sourceEvent = targetEvent = event;
1796 }
1797 else {
1798 sourceEvent = event.source;
1799 targetEvent = event.target;
1800 }
1801 source.on(sourceEvent, function () {
1802 var args = [];
1803 for (var _i = 0; _i < arguments.length; _i++) {
1804 args[_i] = arguments[_i];
1805 }
1806 return target.trigger.apply(target, __spreadArrays([targetEvent], args));
1807 });
1808 });
1809}
1810
1811function isSamePoint(startPoint, endPoint) {
1812 // keys of startPoint and endPoint should be equal
1813 var keys = Object.keys(startPoint);
1814 for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
1815 var key = keys_1[_i];
1816 if (startPoint[key] !== endPoint[key])
1817 return false;
1818 }
1819 return true;
1820}
1821
1822var MIN_SCROLL_DISTANCE = 1;
1823var Scroller = /** @class */ (function () {
1824 function Scroller(wrapper, content, options) {
1825 this.wrapper = wrapper;
1826 this.content = content;
1827 this.resizeTimeout = 0;
1828 this.hooks = new EventEmitter([
1829 'beforeStart',
1830 'beforeMove',
1831 'beforeScrollStart',
1832 'scrollStart',
1833 'scroll',
1834 'beforeEnd',
1835 'scrollEnd',
1836 'resize',
1837 'touchEnd',
1838 'end',
1839 'flick',
1840 'scrollCancel',
1841 'momentum',
1842 'scrollTo',
1843 'minDistanceScroll',
1844 'scrollToElement',
1845 'beforeRefresh',
1846 ]);
1847 this.options = options;
1848 var _a = this.options.bounce, left = _a.left, right = _a.right, top = _a.top, bottom = _a.bottom;
1849 // direction X
1850 this.scrollBehaviorX = new Behavior(wrapper, content, createBehaviorOptions(options, 'scrollX', [left, right], {
1851 size: 'width',
1852 position: 'left',
1853 }));
1854 // direction Y
1855 this.scrollBehaviorY = new Behavior(wrapper, content, createBehaviorOptions(options, 'scrollY', [top, bottom], {
1856 size: 'height',
1857 position: 'top',
1858 }));
1859 this.translater = new Translater(this.content);
1860 this.animater = createAnimater(this.content, this.translater, this.options);
1861 this.actionsHandler = new ActionsHandler(this.options.bindToTarget ? this.content : wrapper, createActionsHandlerOptions(this.options));
1862 this.actions = new ScrollerActions(this.scrollBehaviorX, this.scrollBehaviorY, this.actionsHandler, this.animater, this.options);
1863 var resizeHandler = this.resize.bind(this);
1864 this.resizeRegister = new EventRegister(window, [
1865 {
1866 name: 'orientationchange',
1867 handler: resizeHandler,
1868 },
1869 {
1870 name: 'resize',
1871 handler: resizeHandler,
1872 },
1873 ]);
1874 this.registerTransitionEnd();
1875 this.init();
1876 }
1877 Scroller.prototype.init = function () {
1878 var _this = this;
1879 this.bindTranslater();
1880 this.bindAnimater();
1881 this.bindActions();
1882 // enable pointer events when scrolling ends
1883 this.hooks.on(this.hooks.eventTypes.scrollEnd, function () {
1884 _this.togglePointerEvents(true);
1885 });
1886 };
1887 Scroller.prototype.registerTransitionEnd = function () {
1888 this.transitionEndRegister = new EventRegister(this.content, [
1889 {
1890 name: style.transitionEnd,
1891 handler: this.transitionEnd.bind(this),
1892 },
1893 ]);
1894 };
1895 Scroller.prototype.bindTranslater = function () {
1896 var _this = this;
1897 var hooks = this.translater.hooks;
1898 hooks.on(hooks.eventTypes.beforeTranslate, function (transformStyle) {
1899 if (_this.options.translateZ) {
1900 transformStyle.push(_this.options.translateZ);
1901 }
1902 });
1903 // disable pointer events when scrolling
1904 hooks.on(hooks.eventTypes.translate, function (pos) {
1905 var prevPos = _this.getCurrentPos();
1906 _this.updatePositions(pos);
1907 // scrollEnd will dispatch when scroll is force stopping in touchstart handler
1908 // so in touchend handler, don't toggle pointer-events
1909 if (_this.actions.ensuringInteger === true) {
1910 _this.actions.ensuringInteger = false;
1911 return;
1912 }
1913 // a valid translate
1914 if (pos.x !== prevPos.x || pos.y !== prevPos.y) {
1915 _this.togglePointerEvents(false);
1916 }
1917 });
1918 };
1919 Scroller.prototype.bindAnimater = function () {
1920 var _this = this;
1921 // reset position
1922 this.animater.hooks.on(this.animater.hooks.eventTypes.end, function (pos) {
1923 if (!_this.resetPosition(_this.options.bounceTime)) {
1924 _this.animater.setPending(false);
1925 _this.hooks.trigger(_this.hooks.eventTypes.scrollEnd, pos);
1926 }
1927 });
1928 bubbling(this.animater.hooks, this.hooks, [
1929 {
1930 source: this.animater.hooks.eventTypes.move,
1931 target: this.hooks.eventTypes.scroll,
1932 },
1933 {
1934 source: this.animater.hooks.eventTypes.forceStop,
1935 target: this.hooks.eventTypes.scrollEnd,
1936 },
1937 ]);
1938 };
1939 Scroller.prototype.bindActions = function () {
1940 var _this = this;
1941 var actions = this.actions;
1942 bubbling(actions.hooks, this.hooks, [
1943 {
1944 source: actions.hooks.eventTypes.start,
1945 target: this.hooks.eventTypes.beforeStart,
1946 },
1947 {
1948 source: actions.hooks.eventTypes.start,
1949 target: this.hooks.eventTypes.beforeScrollStart,
1950 },
1951 {
1952 source: actions.hooks.eventTypes.beforeMove,
1953 target: this.hooks.eventTypes.beforeMove,
1954 },
1955 {
1956 source: actions.hooks.eventTypes.scrollStart,
1957 target: this.hooks.eventTypes.scrollStart,
1958 },
1959 {
1960 source: actions.hooks.eventTypes.scroll,
1961 target: this.hooks.eventTypes.scroll,
1962 },
1963 {
1964 source: actions.hooks.eventTypes.beforeEnd,
1965 target: this.hooks.eventTypes.beforeEnd,
1966 },
1967 ]);
1968 actions.hooks.on(actions.hooks.eventTypes.end, function (e, pos) {
1969 _this.hooks.trigger(_this.hooks.eventTypes.touchEnd, pos);
1970 if (_this.hooks.trigger(_this.hooks.eventTypes.end, pos)) {
1971 return true;
1972 }
1973 // check if it is a click operation
1974 if (!actions.fingerMoved) {
1975 _this.hooks.trigger(_this.hooks.eventTypes.scrollCancel);
1976 if (_this.checkClick(e)) {
1977 return true;
1978 }
1979 }
1980 // reset if we are outside of the boundaries
1981 if (_this.resetPosition(_this.options.bounceTime, ease.bounce)) {
1982 _this.animater.setForceStopped(false);
1983 return true;
1984 }
1985 });
1986 actions.hooks.on(actions.hooks.eventTypes.scrollEnd, function (pos, duration) {
1987 var deltaX = Math.abs(pos.x - _this.scrollBehaviorX.startPos);
1988 var deltaY = Math.abs(pos.y - _this.scrollBehaviorY.startPos);
1989 if (_this.checkFlick(duration, deltaX, deltaY)) {
1990 _this.animater.setForceStopped(false);
1991 _this.hooks.trigger(_this.hooks.eventTypes.flick);
1992 return;
1993 }
1994 if (_this.momentum(pos, duration)) {
1995 _this.animater.setForceStopped(false);
1996 return;
1997 }
1998 if (actions.contentMoved) {
1999 _this.hooks.trigger(_this.hooks.eventTypes.scrollEnd, pos);
2000 }
2001 if (_this.animater.forceStopped) {
2002 _this.animater.setForceStopped(false);
2003 }
2004 });
2005 };
2006 Scroller.prototype.checkFlick = function (duration, deltaX, deltaY) {
2007 var flickMinMovingDistance = 1; // distinguish flick from click
2008 if (this.hooks.events.flick.length > 1 &&
2009 duration < this.options.flickLimitTime &&
2010 deltaX < this.options.flickLimitDistance &&
2011 deltaY < this.options.flickLimitDistance &&
2012 (deltaY > flickMinMovingDistance || deltaX > flickMinMovingDistance)) {
2013 return true;
2014 }
2015 };
2016 Scroller.prototype.momentum = function (pos, duration) {
2017 var meta = {
2018 time: 0,
2019 easing: ease.swiper,
2020 newX: pos.x,
2021 newY: pos.y,
2022 };
2023 // start momentum animation if needed
2024 var momentumX = this.scrollBehaviorX.end(duration);
2025 var momentumY = this.scrollBehaviorY.end(duration);
2026 meta.newX = isUndef(momentumX.destination)
2027 ? meta.newX
2028 : momentumX.destination;
2029 meta.newY = isUndef(momentumY.destination)
2030 ? meta.newY
2031 : momentumY.destination;
2032 meta.time = Math.max(momentumX.duration, momentumY.duration);
2033 this.hooks.trigger(this.hooks.eventTypes.momentum, meta, this);
2034 // when x or y changed, do momentum animation now!
2035 if (meta.newX !== pos.x || meta.newY !== pos.y) {
2036 // change easing function when scroller goes out of the boundaries
2037 if (meta.newX > this.scrollBehaviorX.minScrollPos ||
2038 meta.newX < this.scrollBehaviorX.maxScrollPos ||
2039 meta.newY > this.scrollBehaviorY.minScrollPos ||
2040 meta.newY < this.scrollBehaviorY.maxScrollPos) {
2041 meta.easing = ease.swipeBounce;
2042 }
2043 this.scrollTo(meta.newX, meta.newY, meta.time, meta.easing);
2044 return true;
2045 }
2046 };
2047 Scroller.prototype.checkClick = function (e) {
2048 var cancelable = {
2049 preventClick: this.animater.forceStopped,
2050 };
2051 // we scrolled less than momentumLimitDistance pixels
2052 if (this.hooks.trigger(this.hooks.eventTypes.checkClick)) {
2053 this.animater.setForceStopped(false);
2054 return true;
2055 }
2056 if (!cancelable.preventClick) {
2057 var _dblclick = this.options.dblclick;
2058 var dblclickTrigged = false;
2059 if (_dblclick && this.lastClickTime) {
2060 var _a = _dblclick.delay, delay = _a === void 0 ? 300 : _a;
2061 if (getNow() - this.lastClickTime < delay) {
2062 dblclickTrigged = true;
2063 dblclick(e);
2064 }
2065 }
2066 if (this.options.tap) {
2067 tap(e, this.options.tap);
2068 }
2069 if (this.options.click &&
2070 !preventDefaultExceptionFn(e.target, this.options.preventDefaultException)) {
2071 click(e);
2072 }
2073 this.lastClickTime = dblclickTrigged ? null : getNow();
2074 return true;
2075 }
2076 return false;
2077 };
2078 Scroller.prototype.resize = function () {
2079 var _this = this;
2080 if (!this.actions.enabled) {
2081 return;
2082 }
2083 // fix a scroll problem under Android condition
2084 /* istanbul ignore if */
2085 if (isAndroid) {
2086 this.wrapper.scrollTop = 0;
2087 }
2088 clearTimeout(this.resizeTimeout);
2089 this.resizeTimeout = window.setTimeout(function () {
2090 _this.hooks.trigger(_this.hooks.eventTypes.resize);
2091 }, this.options.resizePolling);
2092 };
2093 /* istanbul ignore next */
2094 Scroller.prototype.transitionEnd = function (e) {
2095 if (e.target !== this.content || !this.animater.pending) {
2096 return;
2097 }
2098 var animater = this.animater;
2099 animater.transitionTime();
2100 if (!this.resetPosition(this.options.bounceTime, ease.bounce)) {
2101 this.animater.setPending(false);
2102 if (this.options.probeType !== 3 /* Realtime */) {
2103 this.hooks.trigger(this.hooks.eventTypes.scrollEnd, this.getCurrentPos());
2104 }
2105 }
2106 };
2107 Scroller.prototype.togglePointerEvents = function (enabled) {
2108 if (enabled === void 0) { enabled = true; }
2109 var el = this.content.children.length
2110 ? this.content.children
2111 : [this.content];
2112 var pointerEvents = enabled ? 'auto' : 'none';
2113 for (var i = 0; i < el.length; i++) {
2114 var node = el[i];
2115 // ignore BetterScroll instance's wrapper DOM
2116 /* istanbul ignore if */
2117 if (node.isBScrollContainer) {
2118 continue;
2119 }
2120 node.style.pointerEvents = pointerEvents;
2121 }
2122 };
2123 Scroller.prototype.refresh = function (content) {
2124 var contentChanged = this.setContent(content);
2125 this.hooks.trigger(this.hooks.eventTypes.beforeRefresh);
2126 this.scrollBehaviorX.refresh(content);
2127 this.scrollBehaviorY.refresh(content);
2128 if (contentChanged) {
2129 this.translater.setContent(content);
2130 this.animater.setContent(content);
2131 this.transitionEndRegister.destroy();
2132 this.registerTransitionEnd();
2133 if (this.options.bindToTarget) {
2134 this.actionsHandler.setContent(content);
2135 }
2136 }
2137 this.actions.refresh();
2138 this.wrapperOffset = offset(this.wrapper);
2139 };
2140 Scroller.prototype.setContent = function (content) {
2141 var contentChanged = content !== this.content;
2142 if (contentChanged) {
2143 this.content = content;
2144 }
2145 return contentChanged;
2146 };
2147 Scroller.prototype.scrollBy = function (deltaX, deltaY, time, easing) {
2148 if (time === void 0) { time = 0; }
2149 var _a = this.getCurrentPos(), x = _a.x, y = _a.y;
2150 easing = !easing ? ease.bounce : easing;
2151 deltaX += x;
2152 deltaY += y;
2153 this.scrollTo(deltaX, deltaY, time, easing);
2154 };
2155 Scroller.prototype.scrollTo = function (x, y, time, easing, extraTransform) {
2156 if (time === void 0) { time = 0; }
2157 if (easing === void 0) { easing = ease.bounce; }
2158 if (extraTransform === void 0) { extraTransform = {
2159 start: {},
2160 end: {},
2161 }; }
2162 var easingFn = this.options.useTransition ? easing.style : easing.fn;
2163 var currentPos = this.getCurrentPos();
2164 var startPoint = __assign({ x: currentPos.x, y: currentPos.y }, extraTransform.start);
2165 var endPoint = __assign({ x: x,
2166 y: y }, extraTransform.end);
2167 this.hooks.trigger(this.hooks.eventTypes.scrollTo, endPoint);
2168 // it is an useless move
2169 if (isSamePoint(startPoint, endPoint))
2170 return;
2171 var deltaX = Math.abs(endPoint.x - startPoint.x);
2172 var deltaY = Math.abs(endPoint.y - startPoint.y);
2173 // considering of browser compatibility for decimal transform value
2174 // force translating immediately
2175 if (deltaX < MIN_SCROLL_DISTANCE && deltaY < MIN_SCROLL_DISTANCE) {
2176 time = 0;
2177 this.hooks.trigger(this.hooks.eventTypes.minDistanceScroll);
2178 }
2179 this.animater.move(startPoint, endPoint, time, easingFn);
2180 };
2181 Scroller.prototype.scrollToElement = function (el, time, offsetX, offsetY, easing) {
2182 var targetEle = getElement(el);
2183 var pos = offset(targetEle);
2184 var getOffset = function (offset, size, wrapperSize) {
2185 if (typeof offset === 'number') {
2186 return offset;
2187 }
2188 // if offsetX/Y are true we center the element to the screen
2189 return offset ? Math.round(size / 2 - wrapperSize / 2) : 0;
2190 };
2191 offsetX = getOffset(offsetX, targetEle.offsetWidth, this.wrapper.offsetWidth);
2192 offsetY = getOffset(offsetY, targetEle.offsetHeight, this.wrapper.offsetHeight);
2193 var getPos = function (pos, wrapperPos, offset, scrollBehavior) {
2194 pos -= wrapperPos;
2195 pos = scrollBehavior.adjustPosition(pos - offset);
2196 return pos;
2197 };
2198 pos.left = getPos(pos.left, this.wrapperOffset.left, offsetX, this.scrollBehaviorX);
2199 pos.top = getPos(pos.top, this.wrapperOffset.top, offsetY, this.scrollBehaviorY);
2200 if (this.hooks.trigger(this.hooks.eventTypes.scrollToElement, targetEle, pos)) {
2201 return;
2202 }
2203 this.scrollTo(pos.left, pos.top, time, easing);
2204 };
2205 Scroller.prototype.resetPosition = function (time, easing) {
2206 if (time === void 0) { time = 0; }
2207 if (easing === void 0) { easing = ease.bounce; }
2208 var _a = this.scrollBehaviorX.checkInBoundary(), x = _a.position, xInBoundary = _a.inBoundary;
2209 var _b = this.scrollBehaviorY.checkInBoundary(), y = _b.position, yInBoundary = _b.inBoundary;
2210 if (xInBoundary && yInBoundary) {
2211 return false;
2212 }
2213 /* istanbul ignore if */
2214 if (isIOSBadVersion) {
2215 // fix ios 13.4 bouncing
2216 // see it in issues 982
2217 this.reflow();
2218 }
2219 // out of boundary
2220 this.scrollTo(x, y, time, easing);
2221 return true;
2222 };
2223 /* istanbul ignore next */
2224 Scroller.prototype.reflow = function () {
2225 this._reflow = this.content.offsetHeight;
2226 };
2227 Scroller.prototype.updatePositions = function (pos) {
2228 this.scrollBehaviorX.updatePosition(pos.x);
2229 this.scrollBehaviorY.updatePosition(pos.y);
2230 };
2231 Scroller.prototype.getCurrentPos = function () {
2232 return this.actions.getCurrentPos();
2233 };
2234 Scroller.prototype.enable = function () {
2235 this.actions.enabled = true;
2236 };
2237 Scroller.prototype.disable = function () {
2238 cancelAnimationFrame(this.animater.timer);
2239 this.actions.enabled = false;
2240 };
2241 Scroller.prototype.destroy = function () {
2242 var _this = this;
2243 var keys = [
2244 'resizeRegister',
2245 'transitionEndRegister',
2246 'actionsHandler',
2247 'actions',
2248 'hooks',
2249 'animater',
2250 'translater',
2251 'scrollBehaviorX',
2252 'scrollBehaviorY',
2253 ];
2254 keys.forEach(function (key) { return _this[key].destroy(); });
2255 };
2256 return Scroller;
2257}());
2258
2259var BScrollConstructor = /** @class */ (function (_super) {
2260 __extends(BScrollConstructor, _super);
2261 function BScrollConstructor(el, options) {
2262 var _this = _super.call(this, [
2263 'refresh',
2264 'contentChanged',
2265 'enable',
2266 'disable',
2267 'beforeScrollStart',
2268 'scrollStart',
2269 'scroll',
2270 'scrollEnd',
2271 'scrollCancel',
2272 'touchEnd',
2273 'flick',
2274 'destroy'
2275 ]) || this;
2276 var wrapper = getElement(el);
2277 if (!wrapper) {
2278 warn('Can not resolve the wrapper DOM.');
2279 return _this;
2280 }
2281 _this.plugins = {};
2282 _this.options = new OptionsConstructor().merge(options).process();
2283 if (!_this.setContent(wrapper).valid) {
2284 return _this;
2285 }
2286 _this.hooks = new EventEmitter([
2287 'refresh',
2288 'enable',
2289 'disable',
2290 'destroy',
2291 'beforeInitialScrollTo',
2292 'contentChanged'
2293 ]);
2294 _this.init(wrapper);
2295 return _this;
2296 }
2297 BScrollConstructor.use = function (ctor) {
2298 var name = ctor.pluginName;
2299 var installed = BScrollConstructor.plugins.some(function (plugin) { return ctor === plugin.ctor; });
2300 if (installed)
2301 return BScrollConstructor;
2302 if (isUndef(name)) {
2303 warn("Plugin Class must specify plugin's name in static property by 'pluginName' field.");
2304 return BScrollConstructor;
2305 }
2306 BScrollConstructor.pluginsMap[name] = true;
2307 BScrollConstructor.plugins.push({
2308 name: name,
2309 applyOrder: ctor.applyOrder,
2310 ctor: ctor
2311 });
2312 return BScrollConstructor;
2313 };
2314 BScrollConstructor.prototype.setContent = function (wrapper) {
2315 var contentChanged = false;
2316 var valid = true;
2317 var content = wrapper.children[this.options.specifiedIndexAsContent];
2318 if (!content) {
2319 warn('The wrapper need at least one child element to be content element to scroll.');
2320 valid = false;
2321 }
2322 else {
2323 contentChanged = this.content !== content;
2324 if (contentChanged) {
2325 this.content = content;
2326 }
2327 }
2328 return {
2329 valid: valid,
2330 contentChanged: contentChanged
2331 };
2332 };
2333 BScrollConstructor.prototype.init = function (wrapper) {
2334 var _this = this;
2335 this.wrapper = wrapper;
2336 // mark wrapper to recognize bs instance by DOM attribute
2337 wrapper.isBScrollContainer = true;
2338 this.scroller = new Scroller(wrapper, this.content, this.options);
2339 this.scroller.hooks.on(this.scroller.hooks.eventTypes.resize, function () {
2340 _this.refresh();
2341 });
2342 this.eventBubbling();
2343 this.handleAutoBlur();
2344 this.enable();
2345 this.proxy(propertiesConfig);
2346 this.applyPlugins();
2347 // maybe boundary has changed, should refresh
2348 this.refreshWithoutReset(this.content);
2349 var _a = this.options, startX = _a.startX, startY = _a.startY;
2350 var position = {
2351 x: startX,
2352 y: startY
2353 };
2354 // maybe plugins want to control scroll position
2355 if (this.hooks.trigger(this.hooks.eventTypes.beforeInitialScrollTo, position)) {
2356 return;
2357 }
2358 this.scroller.scrollTo(position.x, position.y);
2359 };
2360 BScrollConstructor.prototype.applyPlugins = function () {
2361 var _this = this;
2362 var options = this.options;
2363 BScrollConstructor.plugins
2364 .sort(function (a, b) {
2365 var _a;
2366 var applyOrderMap = (_a = {},
2367 _a["pre" /* Pre */] = -1,
2368 _a["post" /* Post */] = 1,
2369 _a);
2370 var aOrder = a.applyOrder ? applyOrderMap[a.applyOrder] : 0;
2371 var bOrder = b.applyOrder ? applyOrderMap[b.applyOrder] : 0;
2372 return aOrder - bOrder;
2373 })
2374 .forEach(function (item) {
2375 var ctor = item.ctor;
2376 if (options[item.name] && typeof ctor === 'function') {
2377 _this.plugins[item.name] = new ctor(_this);
2378 }
2379 });
2380 };
2381 BScrollConstructor.prototype.handleAutoBlur = function () {
2382 /* istanbul ignore if */
2383 if (this.options.autoBlur) {
2384 this.on(this.eventTypes.beforeScrollStart, function () {
2385 var activeElement = document.activeElement;
2386 if (activeElement &&
2387 (activeElement.tagName === 'INPUT' ||
2388 activeElement.tagName === 'TEXTAREA')) {
2389 activeElement.blur();
2390 }
2391 });
2392 }
2393 };
2394 BScrollConstructor.prototype.eventBubbling = function () {
2395 bubbling(this.scroller.hooks, this, [
2396 this.eventTypes.beforeScrollStart,
2397 this.eventTypes.scrollStart,
2398 this.eventTypes.scroll,
2399 this.eventTypes.scrollEnd,
2400 this.eventTypes.scrollCancel,
2401 this.eventTypes.touchEnd,
2402 this.eventTypes.flick
2403 ]);
2404 };
2405 BScrollConstructor.prototype.refreshWithoutReset = function (content) {
2406 this.scroller.refresh(content);
2407 this.hooks.trigger(this.hooks.eventTypes.refresh, content);
2408 this.trigger(this.eventTypes.refresh, content);
2409 };
2410 BScrollConstructor.prototype.proxy = function (propertiesConfig) {
2411 var _this = this;
2412 propertiesConfig.forEach(function (_a) {
2413 var key = _a.key, sourceKey = _a.sourceKey;
2414 propertiesProxy(_this, sourceKey, key);
2415 });
2416 };
2417 BScrollConstructor.prototype.refresh = function () {
2418 var _a = this.setContent(this.wrapper), contentChanged = _a.contentChanged, valid = _a.valid;
2419 if (valid) {
2420 var content = this.content;
2421 this.refreshWithoutReset(content);
2422 if (contentChanged) {
2423 this.hooks.trigger(this.hooks.eventTypes.contentChanged, content);
2424 this.trigger(this.eventTypes.contentChanged, content);
2425 }
2426 this.scroller.resetPosition();
2427 }
2428 };
2429 BScrollConstructor.prototype.enable = function () {
2430 this.scroller.enable();
2431 this.hooks.trigger(this.hooks.eventTypes.enable);
2432 this.trigger(this.eventTypes.enable);
2433 };
2434 BScrollConstructor.prototype.disable = function () {
2435 this.scroller.disable();
2436 this.hooks.trigger(this.hooks.eventTypes.disable);
2437 this.trigger(this.eventTypes.disable);
2438 };
2439 BScrollConstructor.prototype.destroy = function () {
2440 this.hooks.trigger(this.hooks.eventTypes.destroy);
2441 this.trigger(this.eventTypes.destroy);
2442 this.scroller.destroy();
2443 };
2444 BScrollConstructor.prototype.eventRegister = function (names) {
2445 this.registerType(names);
2446 };
2447 BScrollConstructor.plugins = [];
2448 BScrollConstructor.pluginsMap = {};
2449 return BScrollConstructor;
2450}(EventEmitter));
2451function createBScroll(el, options) {
2452 var bs = new BScrollConstructor(el, options);
2453 return bs;
2454}
2455createBScroll.use = BScrollConstructor.use;
2456createBScroll.plugins = BScrollConstructor.plugins;
2457createBScroll.pluginsMap = BScrollConstructor.pluginsMap;
2458var BScroll = createBScroll;
2459
2460export { Behavior, CustomOptions, createBScroll, BScroll as default };