UNPKG

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