PageSourceSearch

https://honmoku-mattari.com/js/iscroll.js?_ravenCacheKey=48dea54694c1a0a316208bf92bde44f09ec5ec2d

js honmoku-mattari.com collected 2026-10-04 13:21:51 UTC 75,762 bytes, 2,201 lines download raw bytes

vendor: 10,254 bytes, lines 1-290
1/*! iScroll v5.2.0-snapshot ~ (c) 2008-2017 Matteo Spinelli ~ http://cubiq.org/license */
2(function (window, document, Math) {
3    var rAF = window.requestAnimationFrame ||
4        window.webkitRequestAnimationFrame ||
5        window.mozRequestAnimationFrame ||
6        window.oRequestAnimationFrame ||
7        window.msRequestAnimationFrame ||
8        function (callback) {
9            window.setTimeout(callback, 1000 / 60);
10        };
11
12    var utils = (function () {
13        var me = {};
14
15        var _elementStyle = document.createElement('div').style;
16        var _vendor = (function () {
17            var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
18                transform,
19                i = 0,
20                l = vendors.length;
21
22            for (; i < l; i++) {
23                transform = vendors[i] + 'ransform';
24                if (transform in _elementStyle) return vendors[i].substr(0, vendors[i].length - 1);
25            }
26
27            return false;
28        })();
29
30        function _prefixStyle(style) {
31            if (_vendor === false) return false;
32            if (_vendor === '') return style;
33            return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
34        }
35
36        me.getTime = Date.now || function getTime() {
37            return new Date().getTime();
38        };
39
40        me.extend = function (target, obj) {
41            for (var i in obj) {
42                target[i] = obj[i];
43            }
44        };
45
46        me.addEvent = function (el, type, fn, capture) {
47            el.addEventListener(type, fn, !!capture);
48        };
49
50        me.removeEvent = function (el, type, fn, capture) {
51            el.removeEventListener(type, fn, !!capture);
52        };
53
54        me.prefixPointerEvent = function (pointerEvent) {
55            return window.MSPointerEvent ?
56                'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8) :
57                pointerEvent;
58        };
59
60        me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
61            var distance = current - start,
62                speed = Math.abs(distance) / time,
63                destination,
64                duration;
65
66            deceleration = deceleration === undefined ? 0.0006 : deceleration;
67
68            destination = current + (speed * speed) / (2 * deceleration) * (distance < 0 ? -1 : 1);
69            duration = speed / deceleration;
70
71            if (destination < lowerMargin) {
72                destination = wrapperSize ? lowerMargin - (wrapperSize / 2.5 * (speed / 8)) : lowerMargin;
73                distance = Math.abs(destination - current);
74                duration = distance / speed;
75            } else if (destination > 0) {
76                destination = wrapperSize ? wrapperSize / 2.5 * (speed / 8) : 0;
77                distance = Math.abs(current) + destination;
78                duration = distance / speed;
79            }
80
81            return {
82                destination: Math.round(destination),
83                duration: duration
84            };
85        };
86
87        var _transform = _prefixStyle('transform');
88
89        me.extend(me, {
90            hasTransform: _transform !== false,
91            hasPerspective: _prefixStyle('perspective') in _elementStyle,
92            hasTouch: 'ontouchstart' in window,
93            hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
94            hasTransition: _prefixStyle('transition') in _elementStyle
95        });
96
97        /*
98	This should find all Android browsers lower than build 535.19 (both stock browser and webview)
99	- galaxy S2 is ok
100    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
101    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
102   - galaxy S3 is badAndroid (stock brower, webview)
103     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
104   - galaxy S4 is badAndroid (stock brower, webview)
105     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
106   - galaxy S5 is OK
107     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
108   - galaxy S6 is OK
109     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
110  */
111        me.isBadAndroid = (function () {
112            var appVersion = window.navigator.appVersion;
113            // Android browser is not a chrome browser.
114            if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
115                var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
116                if (safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
117                    return parseFloat(safariVersion[1]) < 535.19;
118                } else {
119                    return true;
120                }
121            } else {
122                return false;
123            }
124        })();
125
126        me.extend(me.style = {}, {
127            transform: _transform,
128            transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
129            transitionDuration: _prefixStyle('transitionDuration'),
130            transitionDelay: _prefixStyle('transitionDelay'),
131            transformOrigin: _prefixStyle('transformOrigin'),
132            touchAction: _prefixStyle('touchAction')
133        });
134
135        me.hasClass = function (e, c) {
136            var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
137            return re.test(e.className);
138        };
139
140        me.addClass = function (e, c) {
141            if (me.hasClass(e, c)) {
142                return;
143            }
144
145            var newclass = e.className.split(' ');
146            newclass.push(c);
147            e.className = newclass.join(' ');
148        };
149
150        me.removeClass = function (e, c) {
151            if (!me.hasClass(e, c)) {
152                return;
153            }
154
155            var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
156            e.className = e.className.replace(re, ' ');
157        };
158
159        me.offset = function (el) {
160            var left = -el.offsetLeft,
161                top = -el.offsetTop;
162
163            // jshint -W084
164            while (el = el.offsetParent) {
165                left -= el.offsetLeft;
166                top -= el.offsetTop;
167            }
168            // jshint +W084
169
170            return {
171                left: left,
172                top: top
173            };
174        };
175
176        me.preventDefaultException = function (el, exceptions) {
177            for (var i in exceptions) {
178                if (exceptions[i].test(el[i])) {
179                    return true;
180                }
181            }
182
183            return false;
184        };
185
186        me.extend(me.eventType = {}, {
187            touchstart: 1,
188            touchmove: 1,
189            touchend: 1,
190
191            mousedown: 2,
192            mousemove: 2,
193            mouseup: 2,
194
195            pointerdown: 3,
196            pointermove: 3,
197            pointerup: 3,
198
199            MSPointerDown: 3,
200            MSPointerMove: 3,
201            MSPointerUp: 3
202        });
203
204        me.extend(me.ease = {}, {
205            quadratic: {
206                style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
207                fn: function (k) {
208                    return k * (2 - k);
209                }
210            },
211            circular: {
212                style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
213                fn: function (k) {
214                    return Math.sqrt(1 - (--k * k));
215                }
216            },
217            back: {
218                style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
219                fn: function (k) {
220                    var b = 4;
221                    return (k = k - 1) * k * ((b + 1) * k + b) + 1;
222                }
223            },
224            bounce: {
225                style: '',
226                fn: function (k) {
227                    if ((k /= 1) < (1 / 2.75)) {
228                        return 7.5625 * k * k;
229                    } else if (k < (2 / 2.75)) {
230                        return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
231                    } else if (k < (2.5 / 2.75)) {
232                        return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
233                    } else {
234                        return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
235                    }
236                }
237            },
238            elastic: {
239                style: '',
240                fn: function (k) {
241                    var f = 0.22,
242                        e = 0.4;
243
244                    if (k === 0) {
245                        return 0;
246                    }
247                    if (k == 1) {
248                        return 1;
249                    }
250
251                    return (e * Math.pow(2, -10 * k) * Math.sin((k - f / 4) * (2 * Math.PI) / f) + 1);
252                }
253            }
254        });
255
256        me.tap = function (e, eventName) {
257            var ev = document.createEvent('Event');
258            ev.initEvent(eventName, true, true);
259            ev.pageX = e.pageX;
260            ev.pageY = e.pageY;
261            e.target.dispatchEvent(ev);
262        };
263
264        me.click = function (e) {
265            var target = e.target,
266                ev;
267
268            if (!(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName)) {
269                // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
270                // initMouseEvent is deprecated.
271                ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
272                ev.initEvent('click', true, true);
273                ev.view = e.view || window;
274                ev.detail = 1;
275                ev.screenX = target.screenX || 0;
276                ev.screenY = target.screenY || 0;
277                ev.clientX = target.clientX || 0;
278                ev.clientY = target.clientY || 0;
279                ev.ctrlKey = !!e.ctrlKey;
280                ev.altKey = !!e.altKey;
281                ev.shiftKey = !!e.shiftKey;
282                ev.metaKey = !!e.metaKey;
283                ev.button = 0;
284                ev.relatedTarget = null;
285                ev._constructed = true;
286                target.dispatchEvent(ev);
287            }
288        };
289
290        me.getTouchAction = function (eventPassthrough, addPinch) {
291            var touchAction = 'none';
292            if (eventPassthrough === 'vertical') {
293                touchAction = 'pan-y';
294            } else if (eventPassthrough === 'horizontal') {
295                touchAction = 'pan-x';
296            }
297            if (addPinch && touchAction != 'none') {
298                // add pinch-zoom support if the browser supports it, but if not (eg. Chrome <55) do nothing
299                touchAction += ' pinch-zoom';
300            }
301            return touchAction;
302        };
303
304        me.getRect = function (el) {
305            if (el instanceof SVGElement) {
306                var rect = el.getBoundingClientRect();
307                return {
308                    top: rect.top,
309                    left: rect.left,
310                    width: rect.width,
311                    height: rect.height
312                };
313            } else {
314                return {
315                    top: el.offsetTop,
316                    left: el.offsetLeft,
317                    width: el.offsetWidth,
318                    height: el.offsetHeight
319                };
320            }
321        };
322
323        return me;
324    })();
325
326    function IScroll(el, options) {
327        this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
328        this.scroller = this.wrapper.children[0];
329        this.scrollerStyle = this.scroller.style; // cache style for better performance
330
331        this.options = {
332
333            resizeScrollbars: true,
334
335            mouseWheelSpeed: 20,
336
337            snapThreshold: 0.334,
338
339            // INSERT POINT: OPTIONS
340            disablePointer: !utils.hasPointer,
341            disableTouch: utils.hasPointer || !utils.hasTouch,
342            disableMouse: utils.hasPointer || utils.hasTouch,
343            startX: 0,
344            startY: 0,
345            scrollY: true,
346            directionLockThreshold: 5,
347            momentum: true,
348
349            bounce: true,
350            bounceTime: 600,
351            bounceEasing: '',
352
353            preventDefault: true,
354            preventDefaultException: {
355                tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/
356            },
357
358            HWCompositing: true,
359            useTransition: true,
360            useTransform: true,
361            bindToWrapper: typeof window.onmousedown === "undefined"
362        };
363
364        for (var i in options) {
365            this.options[i] = options[i];
366        }
367
368        // Normalize options
369        this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
370
371        this.options.useTransition = utils.hasTransition && this.options.useTransition;
372        this.options.useTransform = utils.hasTransform && this.options.useTransform;
373
374        this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
375        this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
376
377        // If you want eventPassthrough I have to lock one of the axes
378        this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
379        this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
380
381        // With eventPassthrough we also need lockDirection mechanism
382        this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
383        this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
384
385        this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
386
387        this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
388
389        if (this.options.tap === true) {
390            this.options.tap = 'tap';
391        }
392
393        // https://github.com/cubiq/iscroll/issues/1029
394        if (!this.options.useTransition && !this.options.useTransform) {
395            if (!(/relative|absolute/i).test(this.scrollerStyle.position)) {
396                this.scrollerStyle.position = "relative";
397            }
398        }
399
400        if (this.options.shrinkScrollbars == 'scale') {
401            this.options.useTransition = false;
vendor: 4,951 bytes, lines 402-561
402        }
403
404        this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
405
406        // INSERT POINT: NORMALIZATION
407
408        // Some defaults
409        this.x = 0;
410        this.y = 0;
411        this.directionX = 0;
412        this.directionY = 0;
413        this._events = {};
414
415        // INSERT POINT: DEFAULTS
416
417        this._init();
418        this.refresh();
419
420        this.scrollTo(this.options.startX, this.options.startY);
421        this.enable();
422    }
423
424    IScroll.prototype = {
425        version: '5.2.0-snapshot',
426
427        _init: function () {
428            this._initEvents();
429
430            if (this.options.scrollbars || this.options.indicators) {
431                this._initIndicators();
432            }
433
434            if (this.options.mouseWheel) {
435                this._initWheel();
436            }
437
438            if (this.options.snap) {
439                this._initSnap();
440            }
441
442            if (this.options.keyBindings) {
443                this._initKeys();
444            }
445
446            // INSERT POINT: _init
447
448        },
449
450        destroy: function () {
451            this._initEvents(true);
452            clearTimeout(this.resizeTimeout);
453            this.resizeTimeout = null;
454            this._execEvent('destroy');
455        },
456
457        _transitionEnd: function (e) {
458            if (e.target != this.scroller || !this.isInTransition) {
459                return;
460            }
461
462            this._transitionTime();
463            if (!this.resetPosition(this.options.bounceTime)) {
464                this.isInTransition = false;
465                this._execEvent('scrollEnd');
466            }
467        },
468
469        _start: function (e) {
470            // React to left mouse button only
471            if (utils.eventType[e.type] != 1) {
472                // for button property
473                // http://unixpapa.com/js/mouse.html
474                var button;
475                if (!e.which) {
476                    /* IE case */
477                    button = (e.button < 2) ? 0 :
478                        ((e.button == 4) ? 1 : 2);
479                } else {
480                    /* All others */
481                    button = e.button;
482                }
483                if (button !== 0) {
484                    return;
485                }
486            }
487
488            if (!this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated)) {
489                return;
490            }
491
492            if (this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
493                e.preventDefault();
494            }
495
496            var point = e.touches ? e.touches[0] : e,
497                pos;
498
499            this.initiated = utils.eventType[e.type];
500            this.moved = false;
501            this.distX = 0;
502            this.distY = 0;
503            this.directionX = 0;
504            this.directionY = 0;
505            this.directionLocked = 0;
506
507            this.startTime = utils.getTime();
508
509            if (this.options.useTransition && this.isInTransition) {
510                this._transitionTime();
511                this.isInTransition = false;
512                pos = this.getComputedPosition();
513                this._translate(Math.round(pos.x), Math.round(pos.y));
514                this._execEvent('scrollEnd');
515            } else if (!this.options.useTransition && this.isAnimating) {
516                this.isAnimating = false;
517                this._execEvent('scrollEnd');
518            }
519
520            this.startX = this.x;
521            this.startY = this.y;
522            this.absStartX = this.x;
523            this.absStartY = this.y;
524            this.pointX = point.pageX;
525            this.pointY = point.pageY;
526
527            this._execEvent('beforeScrollStart');
528        },
529
530        _move: function (e) {
531            if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
532                return;
533            }
534
535            if (this.options.preventDefault) { // increases performance on Android? TODO: check!
536                e.preventDefault();
537            }
538
539            var point = e.touches ? e.touches[0] : e,
540                deltaX = point.pageX - this.pointX,
541                deltaY = point.pageY - this.pointY,
542                timestamp = utils.getTime(),
543                newX, newY,
544                absDistX, absDistY;
545
546            this.pointX = point.pageX;
547            this.pointY = point.pageY;
548
549            this.distX += deltaX;
550            this.distY += deltaY;
551            absDistX = Math.abs(this.distX);
552            absDistY = Math.abs(this.distY);
553
554            // We need to move at least 10 pixels for the scrolling to initiate
555            if (timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10)) {
556                return;
557            }
558
559            // If you are scrolling in one direction lock the other
560            if (!this.directionLocked && !this.options.freeScroll) {
561                if (absDistX > absDistY + this.options.directionLockThreshold) {
vendor: 4,162 bytes, lines 562-679
562                    this.directionLocked = 'h'; // lock horizontally
563                } else if (absDistY >= absDistX + this.options.directionLockThreshold) {
564                    this.directionLocked = 'v'; // lock vertically
565                } else {
566                    this.directionLocked = 'n'; // no lock
567                }
568            }
569
570            if (this.directionLocked == 'h') {
571                if (this.options.eventPassthrough == 'vertical') {
572                    e.preventDefault();
573                } else if (this.options.eventPassthrough == 'horizontal') {
574                    this.initiated = false;
575                    return;
576                }
577
578                deltaY = 0;
579            } else if (this.directionLocked == 'v') {
580                if (this.options.eventPassthrough == 'horizontal') {
581                    e.preventDefault();
582                } else if (this.options.eventPassthrough == 'vertical') {
583                    this.initiated = false;
584                    return;
585                }
586
587                deltaX = 0;
588            }
589
590            deltaX = this.hasHorizontalScroll ? deltaX : 0;
591            deltaY = this.hasVerticalScroll ? deltaY : 0;
592
593            newX = this.x + deltaX;
594            newY = this.y + deltaY;
595
596            // Slow down if outside of the boundaries
597            if (newX > 0 || newX < this.maxScrollX) {
598                newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
599            }
600            if (newY > 0 || newY < this.maxScrollY) {
601                newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
602            }
603
604            this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
605            this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
606
607            if (!this.moved) {
608                this._execEvent('scrollStart');
609            }
610
611            this.moved = true;
612
613            this._translate(newX, newY);
614
615            /* REPLACE START: _move */
616
617            if (timestamp - this.startTime > 300) {
618                this.startTime = timestamp;
619                this.startX = this.x;
620                this.startY = this.y;
621            }
622
623            /* REPLACE END: _move */
624
625        },
626
627        _end: function (e) {
628            if (!this.enabled || utils.eventType[e.type] !== this.initiated) {
629                return;
630            }
631
632            if (this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
633                e.preventDefault();
634            }
635
636            var point = e.changedTouches ? e.changedTouches[0] : e,
637                momentumX,
638                momentumY,
639                duration = utils.getTime() - this.startTime,
640                newX = Math.round(this.x),
641                newY = Math.round(this.y),
642                distanceX = Math.abs(newX - this.startX),
643                distanceY = Math.abs(newY - this.startY),
644                time = 0,
645                easing = '';
646
647            this.isInTransition = 0;
648            this.initiated = 0;
649            this.endTime = utils.getTime();
650
651            // reset if we are outside of the boundaries
652            if (this.resetPosition(this.options.bounceTime)) {
653                return;
654            }
655
656            this.scrollTo(newX, newY); // ensures that the last position is rounded
657
658            // we scrolled less than 10 pixels
659            if (!this.moved) {
660                if (this.options.tap) {
661                    utils.tap(e, this.options.tap);
662                }
663
664                if (this.options.click) {
665                    utils.click(e);
666                }
667
668                this._execEvent('scrollCancel');
669                return;
670            }
671
672            if (this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100) {
673                this._execEvent('flick');
674                return;
675            }
676
677            // start momentum animation if needed
678            if (this.options.momentum && duration < 300) {
679                momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
vendor: 4,788 bytes, lines 679-823
679idth : 0, this.options.deceleration) : {
680                    destination: newX,
681                    duration: 0
682                };
683                momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : {
684                    destination: newY,
685                    duration: 0
686                };
687                newX = momentumX.destination;
688                newY = momentumY.destination;
689                time = Math.max(momentumX.duration, momentumY.duration);
690                this.isInTransition = 1;
691            }
692
693
694            if (this.options.snap) {
695                var snap = this._nearestSnap(newX, newY);
696                this.currentPage = snap;
697                time = this.options.snapSpeed || Math.max(
698                    Math.max(
699                        Math.min(Math.abs(newX - snap.x), 1000),
700                        Math.min(Math.abs(newY - snap.y), 1000)
701                    ), 300);
702                newX = snap.x;
703                newY = snap.y;
704
705                this.directionX = 0;
706                this.directionY = 0;
707                easing = this.options.bounceEasing;
708            }
709
710            // INSERT POINT: _end
711
712            if (newX != this.x || newY != this.y) {
713                // change easing function when scroller goes out of the boundaries
714                if (newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY) {
715                    easing = utils.ease.quadratic;
716                }
717
718                this.scrollTo(newX, newY, time, easing);
719                return;
720            }
721
722            this._execEvent('scrollEnd');
723        },
724
725        _resize: function () {
726            var that = this;
727
728            clearTimeout(this.resizeTimeout);
729
730            this.resizeTimeout = setTimeout(function () {
731                that.refresh();
732            }, this.options.resizePolling);
733        },
734
735        resetPosition: function (time) {
736            var x = this.x,
737                y = this.y;
738
739            time = time || 0;
740
741            if (!this.hasHorizontalScroll || this.x > 0) {
742                x = 0;
743            } else if (this.x < this.maxScrollX) {
744                x = this.maxScrollX;
745            }
746
747            if (!this.hasVerticalScroll || this.y > 0) {
748                y = 0;
749            } else if (this.y < this.maxScrollY) {
750                y = this.maxScrollY;
751            }
752
753            if (x == this.x && y == this.y) {
754                return false;
755            }
756
757            this.scrollTo(x, y, time, this.options.bounceEasing);
758
759            return true;
760        },
761
762        disable: function () {
763            this.enabled = false;
764        },
765
766        enable: function () {
767            this.enabled = true;
768        },
769
770        refresh: function () {
771            utils.getRect(this.wrapper); // Force reflow
772
773            this.wrapperWidth = this.wrapper.clientWidth;
774            this.wrapperHeight = this.wrapper.clientHeight;
775
776            var rect = utils.getRect(this.scroller);
777            /* REPLACE START: refresh */
778
779            this.scrollerWidth = rect.width;
780            this.scrollerHeight = rect.height;
781
782            this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
783            this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
784
785            /* REPLACE END: refresh */
786
787            this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
788            this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
789
790            if (!this.hasHorizontalScroll) {
791                this.maxScrollX = 0;
792                this.scrollerWidth = this.wrapperWidth;
793            }
794
795            if (!this.hasVerticalScroll) {
796                this.maxScrollY = 0;
797                this.scrollerHeight = this.wrapperHeight;
798            }
799
800            this.endTime = 0;
801            this.directionX = 0;
802            this.directionY = 0;
803
804            if (utils.hasPointer && !this.options.disablePointer) {
805                // The wrapper should have `touchAction` property for using pointerEvent.
806                this.wrapper.style[utils.style.touchAction] = utils.getTouchAction(this.options.eventPassthrough, true);
807
808                // case. not support 'pinch-zoom'
809                // https://github.com/cubiq/iscroll/issues/1118#issuecomment-270057583
810                if (!this.wrapper.style[utils.style.touchAction]) {
811                    this.wrapper.style[utils.style.touchAction] = utils.getTouchAction(this.options.eventPassthrough, false);
812                }
813            }
814            this.wrapperOffset = utils.offset(this.wrapper);
815
816            this._execEvent('refresh');
817
818            this.resetPosition();
819
820            // INSERT POINT: _refresh
821
822        },
823
vendor: 15,364 bytes, lines 824-1285
824        on: function (type, fn) {
825            if (!this._events[type]) {
826                this._events[type] = [];
827            }
828
829            this._events[type].push(fn);
830        },
831
832        off: function (type, fn) {
833            if (!this._events[type]) {
834                return;
835            }
836
837            var index = this._events[type].indexOf(fn);
838
839            if (index > -1) {
840                this._events[type].splice(index, 1);
841            }
842        },
843
844        _execEvent: function (type) {
845            if (!this._events[type]) {
846                return;
847            }
848
849            var i = 0,
850                l = this._events[type].length;
851
852            if (!l) {
853                return;
854            }
855
856            for (; i < l; i++) {
857                this._events[type][i].apply(this, [].slice.call(arguments, 1));
858            }
859        },
860
861        scrollBy: function (x, y, time, easing) {
862            x = this.x + x;
863            y = this.y + y;
864            time = time || 0;
865
866            this.scrollTo(x, y, time, easing);
867        },
868
869        scrollTo: function (x, y, time, easing) {
870            easing = easing || utils.ease.circular;
871
872            this.isInTransition = this.options.useTransition && time > 0;
873            var transitionType = this.options.useTransition && easing.style;
874            if (!time || transitionType) {
875                if (transitionType) {
876                    this._transitionTimingFunction(easing.style);
877                    this._transitionTime(time);
878                }
879                this._translate(x, y);
880            } else {
881                this._animate(x, y, time, easing.fn);
882            }
883        },
884
885        scrollToElement: function (el, time, offsetX, offsetY, easing) {
886            el = el.nodeType ? el : this.scroller.querySelector(el);
887
888            if (!el) {
889                return;
890            }
891
892            var pos = utils.offset(el);
893
894            pos.left -= this.wrapperOffset.left;
895            pos.top -= this.wrapperOffset.top;
896
897            // if offsetX/Y are true we center the element to the screen
898            var elRect = utils.getRect(el);
899            var wrapperRect = utils.getRect(this.wrapper);
900            if (offsetX === true) {
901                offsetX = Math.round(elRect.width / 2 - wrapperRect.width / 2);
902            }
903            if (offsetY === true) {
904                offsetY = Math.round(elRect.height / 2 - wrapperRect.height / 2);
905            }
906
907            pos.left -= offsetX || 0;
908            pos.top -= offsetY || 0;
909
910            pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
911            pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;
912
913            time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x - pos.left), Math.abs(this.y - pos.top)) : time;
914
915            this.scrollTo(pos.left, pos.top, time, easing);
916        },
917
918        _transitionTime: function (time) {
919            if (!this.options.useTransition) {
920                return;
921            }
922            time = time || 0;
923            var durationProp = utils.style.transitionDuration;
924            if (!durationProp) {
925                return;
926            }
927
928            this.scrollerStyle[durationProp] = time + 'ms';
929
930            if (!time && utils.isBadAndroid) {
931                this.scrollerStyle[durationProp] = '0.0001ms';
932                // remove 0.0001ms
933                var self = this;
934                rAF(function () {
935                    if (self.scrollerStyle[durationProp] === '0.0001ms') {
936                        self.scrollerStyle[durationProp] = '0s';
937                    }
938                });
939            }
940
941
942            if (this.indicators) {
943                for (var i = this.indicators.length; i--;) {
944                    this.indicators[i].transitionTime(time);
945                }
946            }
947
948
949            // INSERT POINT: _transitionTime
950
951        },
952
953        _transitionTimingFunction: function (easing) {
954            this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
955
956
957            if (this.indicators) {
958                for (var i = this.indicators.length; i--;) {
959                    this.indicators[i].transitionTimingFunction(easing);
960                }
961            }
962
963
964            // INSERT POINT: _transitionTimingFunction
965
966        },
967
968        _translate: function (x, y) {
969            if (this.options.useTransform) {
970
971                /* REPLACE START: _translate */
972
973                this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
974
975                /* REPLACE END: _translate */
976
977            } else {
978                x = Math.round(x);
979                y = Math.round(y);
980                this.scrollerStyle.left = x + 'px';
981                this.scrollerStyle.top = y + 'px';
982            }
983
984            this.x = x;
985            this.y = y;
986
987
988            if (this.indicators) {
989                for (var i = this.indicators.length; i--;) {
990                    this.indicators[i].updatePosition();
991                }
992            }
993
994
995            // INSERT POINT: _translate
996
997        },
998
999        _initEvents: function (remove) {
1000            var eventType = remove ? utils.removeEvent : utils.addEvent,
1001                target = this.options.bindToWrapper ? this.wrapper : window;
1002
1003            eventType(window, 'orientationchange', this);
1004            eventType(window, 'resize', this);
1005
1006            if (this.options.click) {
1007                eventType(this.wrapper, 'click', this, true);
1008            }
1009
1010            if (!this.options.disableMouse) {
1011                eventType(this.wrapper, 'mousedown', this);
1012                eventType(target, 'mousemove', this);
1013                eventType(target, 'mousecancel', this);
1014                eventType(target, 'mouseup', this);
1015            }
1016
1017            if (utils.hasPointer && !this.options.disablePointer) {
1018                eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
1019                eventType(target, utils.prefixPointerEvent('pointermove'), this);
1020                eventType(target, utils.prefixPointerEvent('pointercancel'), this);
1021                eventType(target, utils.prefixPointerEvent('pointerup'), this);
1022            }
1023
1024            if (utils.hasTouch && !this.options.disableTouch) {
1025                eventType(this.wrapper, 'touchstart', this);
1026                eventType(target, 'touchmove', this);
1027                eventType(target, 'touchcancel', this);
1028                eventType(target, 'touchend', this);
1029            }
1030
1031            eventType(this.scroller, 'transitionend', this);
1032            eventType(this.scroller, 'webkitTransitionEnd', this);
1033            eventType(this.scroller, 'oTransitionEnd', this);
1034            eventType(this.scroller, 'MSTransitionEnd', this);
1035        },
1036
1037        getComputedPosition: function () {
1038            var matrix = window.getComputedStyle(this.scroller, null),
1039                x, y;
1040
1041            if (this.options.useTransform) {
1042                matrix = matrix[utils.style.transform].split(')')[0].split(', ');
1043                x = +(matrix[12] || matrix[4]);
1044                y = +(matrix[13] || matrix[5]);
1045            } else {
1046                x = +matrix.left.replace(/[^-\d.]/g, '');
1047                y = +matrix.top.replace(/[^-\d.]/g, '');
1048            }
1049
1050            return {
1051                x: x,
1052                y: y
1053            };
1054        },
1055        _initIndicators: function () {
1056            var interactive = this.options.interactiveScrollbars,
1057                customStyle = typeof this.options.scrollbars != 'string',
1058                indicators = [],
1059                indicator;
1060
1061            var that = this;
1062
1063            this.indicators = [];
1064
1065            if (this.options.scrollbars) {
1066                // Vertical scrollbar
1067                if (this.options.scrollY) {
1068                    indicator = {
1069                        el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
1070                        interactive: interactive,
1071                        defaultScrollbars: true,
1072                        customStyle: customStyle,
1073                        resize: this.options.resizeScrollbars,
1074                        shrink: this.options.shrinkScrollbars,
1075                        fade: this.options.fadeScrollbars,
1076                        listenX: false
1077                    };
1078
1079                    this.wrapper.appendChild(indicator.el);
1080                    indicators.push(indicator);
1081                }
1082
1083                // Horizontal scrollbar
1084                if (this.options.scrollX) {
1085                    indicator = {
1086                        el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
1087                        interactive: interactive,
1088                        defaultScrollbars: true,
1089                        customStyle: customStyle,
1090                        resize: this.options.resizeScrollbars,
1091                        shrink: this.options.shrinkScrollbars,
1092                        fade: this.options.fadeScrollbars,
1093                        listenY: false
1094                    };
1095
1096                    this.wrapper.appendChild(indicator.el);
1097                    indicators.push(indicator);
1098                }
1099            }
1100
1101            if (this.options.indicators) {
1102                // TODO: check concat compatibility
1103                indicators = indicators.concat(this.options.indicators);
1104            }
1105
1106            for (var i = indicators.length; i--;) {
1107                this.indicators.push(new Indicator(this, indicators[i]));
1108            }
1109
1110            // TODO: check if we can use array.map (wide compatibility and performance issues)
1111            function _indicatorsMap(fn) {
1112                if (that.indicators) {
1113                    for (var i = that.indicators.length; i--;) {
1114                        fn.call(that.indicators[i]);
1115                    }
1116                }
1117            }
1118
1119            if (this.options.fadeScrollbars) {
1120                this.on('scrollEnd', function () {
1121                    _indicatorsMap(function () {
1122                        this.fade();
1123                    });
1124                });
1125
1126                this.on('scrollCancel', function () {
1127                    _indicatorsMap(function () {
1128                        this.fade();
1129                    });
1130                });
1131
1132                this.on('scrollStart', function () {
1133                    _indicatorsMap(function () {
1134                        this.fade(1);
1135                    });
1136                });
1137
1138                this.on('beforeScrollStart', function () {
1139                    _indicatorsMap(function () {
1140                        this.fade(1, true);
1141                    });
1142                });
1143            }
1144
1145
1146            this.on('refresh', function () {
1147                _indicatorsMap(function () {
1148                    this.refresh();
1149                });
1150            });
1151
1152            this.on('destroy', function () {
1153                _indicatorsMap(function () {
1154                    this.destroy();
1155                });
1156
1157                delete this.indicators;
1158            });
1159        },
1160
1161        _initWheel: function () {
1162            utils.addEvent(this.wrapper, 'wheel', this);
1163            utils.addEvent(this.wrapper, 'mousewheel', this);
1164            utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
1165
1166            this.on('destroy', function () {
1167                clearTimeout(this.wheelTimeout);
1168                this.wheelTimeout = null;
1169                utils.removeEvent(this.wrapper, 'wheel', this);
1170                utils.removeEvent(this.wrapper, 'mousewheel', this);
1171                utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
1172            });
1173        },
1174
1175        _wheel: function (e) {
1176            if (!this.enabled) {
1177                return;
1178            }
1179
1180            e.preventDefault();
1181
1182            var wheelDeltaX, wheelDeltaY,
1183                newX, newY,
1184                that = this;
1185
1186            if (this.wheelTimeout === undefined) {
1187                that._execEvent('scrollStart');
1188            }
1189
1190            // Execute the scrollEnd event after 400ms the wheel stopped scrolling
1191            clearTimeout(this.wheelTimeout);
1192            this.wheelTimeout = setTimeout(function () {
1193                if (!that.options.snap) {
1194                    that._execEvent('scrollEnd');
1195                }
1196                that.wheelTimeout = undefined;
1197            }, 400);
1198
1199            if ('deltaX' in e) {
1200                if (e.deltaMode === 1) {
1201                    wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
1202                    wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
1203                } else {
1204                    wheelDeltaX = -e.deltaX;
1205                    wheelDeltaY = -e.deltaY;
1206                }
1207            } else if ('wheelDeltaX' in e) {
1208                wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
1209                wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
1210            } else if ('wheelDelta' in e) {
1211                wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
1212            } else if ('detail' in e) {
1213                wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
1214            } else {
1215                return;
1216            }
1217
1218            wheelDeltaX *= this.options.invertWheelDirection;
1219            wheelDeltaY *= this.options.invertWheelDirection;
1220
1221            if (!this.hasVerticalScroll) {
1222                wheelDeltaX = wheelDeltaY;
1223                wheelDeltaY = 0;
1224            }
1225
1226            if (this.options.snap) {
1227                newX = this.currentPage.pageX;
1228                newY = this.currentPage.pageY;
1229
1230                if (wheelDeltaX > 0) {
1231                    newX--;
1232                } else if (wheelDeltaX < 0) {
1233                    newX++;
1234                }
1235
1236                if (wheelDeltaY > 0) {
1237                    newY--;
1238                } else if (wheelDeltaY < 0) {
1239                    newY++;
1240                }
1241
1242                this.goToPage(newX, newY);
1243
1244                return;
1245            }
1246
1247            newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
1248            newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
1249
1250            this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
1251            this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
1252
1253            if (newX > 0) {
1254                newX = 0;
1255            } else if (newX < this.maxScrollX) {
1256                newX = this.maxScrollX;
1257            }
1258
1259            if (newY > 0) {
1260                newY = 0;
1261            } else if (newY < this.maxScrollY) {
1262                newY = this.maxScrollY;
1263            }
1264
1265            this.scrollTo(newX, newY, 0);
1266
1267            // INSERT POINT: _wheel
1268        },
1269
1270        _initSnap: function () {
1271            this.currentPage = {};
1272
1273            if (typeof this.options.snap == 'string') {
1274                this.options.snap = this.scroller.querySelectorAll(this.options.snap);
1275            }
1276
1277            this.on('refresh', function () {
1278                var i = 0,
1279                    l,
1280                    m = 0,
1281                    n,
1282                    cx, cy,
1283                    x = 0,
1284                    y,
1285                    stepX = this.options.snapStepX || this.wrapperW
vendor: 12,312 bytes, lines 1285-1663
1285idth,
1286                    stepY = this.options.snapStepY || this.wrapperHeight,
1287                    el,
1288                    rect;
1289
1290                this.pages = [];
1291
1292                if (!this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight) {
1293                    return;
1294                }
1295
1296                if (this.options.snap === true) {
1297                    cx = Math.round(stepX / 2);
1298                    cy = Math.round(stepY / 2);
1299
1300                    while (x > -this.scrollerWidth) {
1301                        this.pages[i] = [];
1302                        l = 0;
1303                        y = 0;
1304
1305                        while (y > -this.scrollerHeight) {
1306                            this.pages[i][l] = {
1307                                x: Math.max(x, this.maxScrollX),
1308                                y: Math.max(y, this.maxScrollY),
1309                                width: stepX,
1310                                height: stepY,
1311                                cx: x - cx,
1312                                cy: y - cy
1313                            };
1314
1315                            y -= stepY;
1316                            l++;
1317                        }
1318
1319                        x -= stepX;
1320                        i++;
1321                    }
1322                } else {
1323                    el = this.options.snap;
1324                    l = el.length;
1325                    n = -1;
1326
1327                    for (; i < l; i++) {
1328                        rect = utils.getRect(el[i]);
1329                        if (i === 0 || rect.left <= utils.getRect(el[i - 1]).left) {
1330                            m = 0;
1331                            n++;
1332                        }
1333
1334                        if (!this.pages[m]) {
1335                            this.pages[m] = [];
1336                        }
1337
1338                        x = Math.max(-rect.left, this.maxScrollX);
1339                        y = Math.max(-rect.top, this.maxScrollY);
1340                        cx = x - Math.round(rect.width / 2);
1341                        cy = y - Math.round(rect.height / 2);
1342
1343                        this.pages[m][n] = {
1344                            x: x,
1345                            y: y,
1346                            width: rect.width,
1347                            height: rect.height,
1348                            cx: cx,
1349                            cy: cy
1350                        };
1351
1352                        if (x > this.maxScrollX) {
1353                            m++;
1354                        }
1355                    }
1356                }
1357
1358                this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
1359
1360                // Update snap threshold if needed
1361                if (this.options.snapThreshold % 1 === 0) {
1362                    this.snapThresholdX = this.options.snapThreshold;
1363                    this.snapThresholdY = this.options.snapThreshold;
1364                } else {
1365                    this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
1366                    this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
1367                }
1368            });
1369
1370            this.on('flick', function () {
1371                var time = this.options.snapSpeed || Math.max(
1372                    Math.max(
1373                        Math.min(Math.abs(this.x - this.startX), 1000),
1374                        Math.min(Math.abs(this.y - this.startY), 1000)
1375                    ), 300);
1376
1377                this.goToPage(
1378                    this.currentPage.pageX + this.directionX,
1379                    this.currentPage.pageY + this.directionY,
1380                    time
1381                );
1382            });
1383        },
1384
1385        _nearestSnap: function (x, y) {
1386            if (!this.pages.length) {
1387                return {
1388                    x: 0,
1389                    y: 0,
1390                    pageX: 0,
1391                    pageY: 0
1392                };
1393            }
1394
1395            var i = 0,
1396                l = this.pages.length,
1397                m = 0;
1398
1399            // Check if we exceeded the snap threshold
1400            if (Math.abs(x - this.absStartX) < this.snapThresholdX &&
1401                Math.abs(y - this.absStartY) < this.snapThresholdY) {
1402                return this.currentPage;
1403            }
1404
1405            if (x > 0) {
1406                x = 0;
1407            } else if (x < this.maxScrollX) {
1408                x = this.maxScrollX;
1409            }
1410
1411            if (y > 0) {
1412                y = 0;
1413            } else if (y < this.maxScrollY) {
1414                y = this.maxScrollY;
1415            }
1416
1417            for (; i < l; i++) {
1418                if (x >= this.pages[i][0].cx) {
1419                    x = this.pages[i][0].x;
1420                    break;
1421                }
1422            }
1423
1424            l = this.pages[i].length;
1425
1426            for (; m < l; m++) {
1427                if (y >= this.pages[0][m].cy) {
1428                    y = this.pages[0][m].y;
1429                    break;
1430                }
1431            }
1432
1433            if (i == this.currentPage.pageX) {
1434                i += this.directionX;
1435
1436                if (i < 0) {
1437                    i = 0;
1438                } else if (i >= this.pages.length) {
1439                    i = this.pages.length - 1;
1440                }
1441
1442                x = this.pages[i][0].x;
1443            }
1444
1445            if (m == this.currentPage.pageY) {
1446                m += this.directionY;
1447
1448                if (m < 0) {
1449                    m = 0;
1450                } else if (m >= this.pages[0].length) {
1451                    m = this.pages[0].length - 1;
1452                }
1453
1454                y = this.pages[0][m].y;
1455            }
1456
1457            return {
1458                x: x,
1459                y: y,
1460                pageX: i,
1461                pageY: m
1462            };
1463        },
1464
1465        goToPage: function (x, y, time, easing) {
1466            easing = easing || this.options.bounceEasing;
1467
1468            if (x >= this.pages.length) {
1469                x = this.pages.length - 1;
1470            } else if (x < 0) {
1471                x = 0;
1472            }
1473
1474            if (y >= this.pages[x].length) {
1475                y = this.pages[x].length - 1;
1476            } else if (y < 0) {
1477                y = 0;
1478            }
1479
1480            var posX = this.pages[x][y].x,
1481                posY = this.pages[x][y].y;
1482
1483            time = time === undefined ? this.options.snapSpeed || Math.max(
1484                Math.max(
1485                    Math.min(Math.abs(posX - this.x), 1000),
1486                    Math.min(Math.abs(posY - this.y), 1000)
1487                ), 300) : time;
1488
1489            this.currentPage = {
1490                x: posX,
1491                y: posY,
1492                pageX: x,
1493                pageY: y
1494            };
1495
1496            this.scrollTo(posX, posY, time, easing);
1497        },
1498
1499        next: function (time, easing) {
1500            var x = this.currentPage.pageX,
1501                y = this.currentPage.pageY;
1502
1503            x++;
1504
1505            if (x >= this.pages.length && this.hasVerticalScroll) {
1506                x = 0;
1507                y++;
1508            }
1509
1510            this.goToPage(x, y, time, easing);
1511        },
1512
1513        prev: function (time, easing) {
1514            var x = this.currentPage.pageX,
1515                y = this.currentPage.pageY;
1516
1517            x--;
1518
1519            if (x < 0 && this.hasVerticalScroll) {
1520                x = 0;
1521                y--;
1522            }
1523
1524            this.goToPage(x, y, time, easing);
1525        },
1526
1527        _initKeys: function (e) {
1528            // default key bindings
1529            var keys = {
1530                pageUp: 33,
1531                pageDown: 34,
1532                end: 35,
1533                home: 36,
1534                left: 37,
1535                up: 38,
1536                right: 39,
1537                down: 40
1538            };
1539            var i;
1540
1541            // if you give me characters I give you keycode
1542            if (typeof this.options.keyBindings == 'object') {
1543                for (i in this.options.keyBindings) {
1544                    if (typeof this.options.keyBindings[i] == 'string') {
1545                        this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);
1546                    }
1547                }
1548            } else {
1549                this.options.keyBindings = {};
1550            }
1551
1552            for (i in keys) {
1553                this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
1554            }
1555
1556            utils.addEvent(window, 'keydown', this);
1557
1558            this.on('destroy', function () {
1559                utils.removeEvent(window, 'keydown', this);
1560            });
1561        },
1562
1563        _key: function (e) {
1564            if (!this.enabled) {
1565                return;
1566            }
1567
1568            var snap = this.options.snap, // we are using this alot, better to cache it
1569                newX = snap ? this.currentPage.pageX : this.x,
1570                newY = snap ? this.currentPage.pageY : this.y,
1571                now = utils.getTime(),
1572                prevTime = this.keyTime || 0,
1573                acceleration = 0.250,
1574                pos;
1575
1576            if (this.options.useTransition && this.isInTransition) {
1577                pos = this.getComputedPosition();
1578
1579                this._translate(Math.round(pos.x), Math.round(pos.y));
1580                this.isInTransition = false;
1581            }
1582
1583            this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
1584
1585            switch (e.keyCode) {
1586                case this.options.keyBindings.pageUp:
1587                    if (this.hasHorizontalScroll && !this.hasVerticalScroll) {
1588                        newX += snap ? 1 : this.wrapperWidth;
1589                    } else {
1590                        newY += snap ? 1 : this.wrapperHeight;
1591                    }
1592                    break;
1593                case this.options.keyBindings.pageDown:
1594                    if (this.hasHorizontalScroll && !this.hasVerticalScroll) {
1595                        newX -= snap ? 1 : this.wrapperWidth;
1596                    } else {
1597                        newY -= snap ? 1 : this.wrapperHeight;
1598                    }
1599                    break;
1600                case this.options.keyBindings.end:
1601                    newX = snap ? this.pages.length - 1 : this.maxScrollX;
1602                    newY = snap ? this.pages[0].length - 1 : this.maxScrollY;
1603                    break;
1604                case this.options.keyBindings.home:
1605                    newX = 0;
1606                    newY = 0;
1607                    break;
1608                case this.options.keyBindings.left:
1609                    newX += snap ? -1 : 5 + this.keyAcceleration >> 0;
1610                    break;
1611                case this.options.keyBindings.up:
1612                    newY += snap ? 1 : 5 + this.keyAcceleration >> 0;
1613                    break;
1614                case this.options.keyBindings.right:
1615                    newX -= snap ? -1 : 5 + this.keyAcceleration >> 0;
1616                    break;
1617                case this.options.keyBindings.down:
1618                    newY -= snap ? 1 : 5 + this.keyAcceleration >> 0;
1619                    break;
1620                default:
1621                    return;
1622            }
1623
1624            if (snap) {
1625                this.goToPage(newX, newY);
1626                return;
1627            }
1628
1629            if (newX > 0) {
1630                newX = 0;
1631                this.keyAcceleration = 0;
1632            } else if (newX < this.maxScrollX) {
1633                newX = this.maxScrollX;
1634                this.keyAcceleration = 0;
1635            }
1636
1637            if (newY > 0) {
1638                newY = 0;
1639                this.keyAcceleration = 0;
1640            } else if (newY < this.maxScrollY) {
1641                newY = this.maxScrollY;
1642                this.keyAcceleration = 0;
1643            }
1644
1645            this.scrollTo(newX, newY, 0);
1646
1647            this.keyTime = now;
1648        },
1649
1650        _animate: function (destX, destY, duration, easingFn) {
1651            var that = this,
1652                startX = this.x,
1653                startY = this.y,
1654                startTime = utils.getTime(),
1655                destTime = startTime + duration;
1656
1657            function step() {
1658                var now = utils.getTime(),
1659                    newX, newY,
1660                    easing;
1661
1662                if (now >= destTime) {
1663                    that.isAnimating = false;
vendor: 8,137 bytes, lines 1664-1899
1664                    that._translate(destX, destY);
1665
1666                    if (!that.resetPosition(that.options.bounceTime)) {
1667                        that._execEvent('scrollEnd');
1668                    }
1669
1670                    return;
1671                }
1672
1673                now = (now - startTime) / duration;
1674                easing = easingFn(now);
1675                newX = (destX - startX) * easing + startX;
1676                newY = (destY - startY) * easing + startY;
1677                that._translate(newX, newY);
1678
1679                if (that.isAnimating) {
1680                    rAF(step);
1681                }
1682            }
1683
1684            this.isAnimating = true;
1685            step();
1686        },
1687        handleEvent: function (e) {
1688            switch (e.type) {
1689                case 'touchstart':
1690                case 'pointerdown':
1691                case 'MSPointerDown':
1692                case 'mousedown':
1693                    this._start(e);
1694                    break;
1695                case 'touchmove':
1696                case 'pointermove':
1697                case 'MSPointerMove':
1698                case 'mousemove':
1699                    this._move(e);
1700                    break;
1701                case 'touchend':
1702                case 'pointerup':
1703                case 'MSPointerUp':
1704                case 'mouseup':
1705                case 'touchcancel':
1706                case 'pointercancel':
1707                case 'MSPointerCancel':
1708                case 'mousecancel':
1709                    this._end(e);
1710                    break;
1711                case 'orientationchange':
1712                case 'resize':
1713                    this._resize();
1714                    break;
1715                case 'transitionend':
1716                case 'webkitTransitionEnd':
1717                case 'oTransitionEnd':
1718                case 'MSTransitionEnd':
1719                    this._transitionEnd(e);
1720                    break;
1721                case 'wheel':
1722                case 'DOMMouseScroll':
1723                case 'mousewheel':
1724                    this._wheel(e);
1725                    break;
1726                case 'keydown':
1727                    this._key(e);
1728                    break;
1729                case 'click':
1730                    if (this.enabled && !e._constructed) {
1731                        e.preventDefault();
1732                        e.stopPropagation();
1733                    }
1734                    break;
1735            }
1736        }
1737    };
1738
1739    function createDefaultScrollbar(direction, interactive, type) {
1740        var scrollbar = document.createElement('div'),
1741            indicator = document.createElement('div');
1742
1743        if (type === true) {
1744            scrollbar.style.cssText = 'position:absolute;z-index:9999';
1745            indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
1746        }
1747
1748        indicator.className = 'iScrollIndicator';
1749
1750        if (direction == 'h') {
1751            if (type === true) {
1752                scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
1753                indicator.style.height = '100%';
1754            }
1755            scrollbar.className = 'iScrollHorizontalScrollbar';
1756        } else {
1757            if (type === true) {
1758                scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
1759                indicator.style.width = '100%';
1760            }
1761            scrollbar.className = 'iScrollVerticalScrollbar';
1762        }
1763
1764        scrollbar.style.cssText += ';overflow:hidden';
1765
1766        if (!interactive) {
1767            scrollbar.style.pointerEvents = 'none';
1768        }
1769
1770        scrollbar.appendChild(indicator);
1771
1772        return scrollbar;
1773    }
1774
1775    function Indicator(scroller, options) {
1776        this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
1777        this.wrapperStyle = this.wrapper.style;
1778        this.indicator = this.wrapper.children[0];
1779        this.indicatorStyle = this.indicator.style;
1780        this.scroller = scroller;
1781
1782        this.options = {
1783            listenX: true,
1784            listenY: true,
1785            interactive: false,
1786            resize: true,
1787            defaultScrollbars: false,
1788            shrink: false,
1789            fade: false,
1790            speedRatioX: 0,
1791            speedRatioY: 0
1792        };
1793
1794        for (var i in options) {
1795            this.options[i] = options[i];
1796        }
1797
1798        this.sizeRatioX = 1;
1799        this.sizeRatioY = 1;
1800        this.maxPosX = 0;
1801        this.maxPosY = 0;
1802
1803        if (this.options.interactive) {
1804            if (!this.options.disableTouch) {
1805                utils.addEvent(this.indicator, 'touchstart', this);
1806                utils.addEvent(window, 'touchend', this);
1807            }
1808            if (!this.options.disablePointer) {
1809                utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
1810                utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
1811            }
1812            if (!this.options.disableMouse) {
1813                utils.addEvent(this.indicator, 'mousedown', this);
1814                utils.addEvent(window, 'mouseup', this);
1815            }
1816        }
1817
1818        if (this.options.fade) {
1819            this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
1820            var durationProp = utils.style.transitionDuration;
1821            if (!durationProp) {
1822                return;
1823            }
1824            this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
1825            // remove 0.0001ms
1826            var self = this;
1827            if (utils.isBadAndroid) {
1828                rAF(function () {
1829                    if (self.wrapperStyle[durationProp] === '0.0001ms') {
1830                        self.wrapperStyle[durationProp] = '0s';
1831                    }
1832                });
1833            }
1834            this.wrapperStyle.opacity = '0';
1835        }
1836    }
1837
1838    Indicator.prototype = {
1839        handleEvent: function (e) {
1840            switch (e.type) {
1841                case 'touchstart':
1842                case 'pointerdown':
1843                case 'MSPointerDown':
1844                case 'mousedown':
1845                    this._start(e);
1846                    break;
1847                case 'touchmove':
1848                case 'pointermove':
1849                case 'MSPointerMove':
1850                case 'mousemove':
1851                    this._move(e);
1852                    break;
1853                case 'touchend':
1854                case 'pointerup':
1855                case 'MSPointerUp':
1856                case 'mouseup':
1857                case 'touchcancel':
1858                case 'pointercancel':
1859                case 'MSPointerCancel':
1860                case 'mousecancel':
1861                    this._end(e);
1862                    break;
1863            }
1864        },
1865
1866        destroy: function () {
1867            if (this.options.fadeScrollbars) {
1868                clearTimeout(this.fadeTimeout);
1869                this.fadeTimeout = null;
1870            }
1871            if (this.options.interactive) {
1872                utils.removeEvent(this.indicator, 'touchstart', this);
1873                utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
1874                utils.removeEvent(this.indicator, 'mousedown', this);
1875
1876                utils.removeEvent(window, 'touchmove', this);
1877                utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
1878                utils.removeEvent(window, 'mousemove', this);
1879
1880                utils.removeEvent(window, 'touchend', this);
1881                utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
1882                utils.removeEvent(window, 'mouseup', this);
1883            }
1884
1885            if (this.options.defaultScrollbars && this.wrapper.parentNode) {
1886                this.wrapper.parentNode.removeChild(this.wrapper);
1887            }
1888        },
1889
1890        _start: function (e) {
1891            var point = e.touches ? e.touches[0] : e;
1892
1893            e.preventDefault();
1894            e.stopPropagation();
1895
1896            this.transitionTime();
1897
1898            this.initiated = true;
1899            this.moved = false;
vendor: 11,556 bytes, lines 1900-2201
1900            this.lastPointX = point.pageX;
1901            this.lastPointY = point.pageY;
1902
1903            this.startTime = utils.getTime();
1904
1905            if (!this.options.disableTouch) {
1906                utils.addEvent(window, 'touchmove', this);
1907            }
1908            if (!this.options.disablePointer) {
1909                utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
1910            }
1911            if (!this.options.disableMouse) {
1912                utils.addEvent(window, 'mousemove', this);
1913            }
1914
1915            this.scroller._execEvent('beforeScrollStart');
1916        },
1917
1918        _move: function (e) {
1919            var point = e.touches ? e.touches[0] : e,
1920                deltaX, deltaY,
1921                newX, newY,
1922                timestamp = utils.getTime();
1923
1924            if (!this.moved) {
1925                this.scroller._execEvent('scrollStart');
1926            }
1927
1928            this.moved = true;
1929
1930            deltaX = point.pageX - this.lastPointX;
1931            this.lastPointX = point.pageX;
1932
1933            deltaY = point.pageY - this.lastPointY;
1934            this.lastPointY = point.pageY;
1935
1936            newX = this.x + deltaX;
1937            newY = this.y + deltaY;
1938
1939            this._pos(newX, newY);
1940
1941            // INSERT POINT: indicator._move
1942
1943            e.preventDefault();
1944            e.stopPropagation();
1945        },
1946
1947        _end: function (e) {
1948            if (!this.initiated) {
1949                return;
1950            }
1951
1952            this.initiated = false;
1953
1954            e.preventDefault();
1955            e.stopPropagation();
1956
1957            utils.removeEvent(window, 'touchmove', this);
1958            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
1959            utils.removeEvent(window, 'mousemove', this);
1960
1961            if (this.scroller.options.snap) {
1962                var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
1963
1964                var time = this.options.snapSpeed || Math.max(
1965                    Math.max(
1966                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
1967                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
1968                    ), 300);
1969
1970                if (this.scroller.x != snap.x || this.scroller.y != snap.y) {
1971                    this.scroller.directionX = 0;
1972                    this.scroller.directionY = 0;
1973                    this.scroller.currentPage = snap;
1974                    this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
1975                }
1976            }
1977
1978            if (this.moved) {
1979                this.scroller._execEvent('scrollEnd');
1980            }
1981        },
1982
1983        transitionTime: function (time) {
1984            time = time || 0;
1985            var durationProp = utils.style.transitionDuration;
1986            if (!durationProp) {
1987                return;
1988            }
1989
1990            this.indicatorStyle[durationProp] = time + 'ms';
1991
1992            if (!time && utils.isBadAndroid) {
1993                this.indicatorStyle[durationProp] = '0.0001ms';
1994                // remove 0.0001ms
1995                var self = this;
1996                rAF(function () {
1997                    if (self.indicatorStyle[durationProp] === '0.0001ms') {
1998                        self.indicatorStyle[durationProp] = '0s';
1999                    }
2000                });
2001            }
2002        },
2003
2004        transitionTimingFunction: function (easing) {
2005            this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
2006        },
2007
2008        refresh: function () {
2009            this.transitionTime();
2010
2011            if (this.options.listenX && !this.options.listenY) {
2012                this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
2013            } else if (this.options.listenY && !this.options.listenX) {
2014                this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
2015            } else {
2016                this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
2017            }
2018
2019            if (this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll) {
2020                utils.addClass(this.wrapper, 'iScrollBothScrollbars');
2021                utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
2022
2023                if (this.options.defaultScrollbars && this.options.customStyle) {
2024                    if (this.options.listenX) {
2025                        this.wrapper.style.right = '8px';
2026                    } else {
2027                        this.wrapper.style.bottom = '8px';
2028                    }
2029                }
2030            } else {
2031                utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
2032                utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
2033
2034                if (this.options.defaultScrollbars && this.options.customStyle) {
2035                    if (this.options.listenX) {
2036                        this.wrapper.style.right = '2px';
2037                    } else {
2038                        this.wrapper.style.bottom = '2px';
2039                    }
2040                }
2041            }
2042
2043            utils.getRect(this.wrapper); // force refresh
2044
2045            if (this.options.listenX) {
2046                this.wrapperWidth = this.wrapper.clientWidth;
2047                if (this.options.resize) {
2048                    this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
2049                    this.indicatorStyle.width = this.indicatorWidth + 'px';
2050                } else {
2051                    this.indicatorWidth = this.indicator.clientWidth;
2052                }
2053
2054                this.maxPosX = this.wrapperWidth - this.indicatorWidth;
2055
2056                if (this.options.shrink == 'clip') {
2057                    this.minBoundaryX = -this.indicatorWidth + 8;
2058                    this.maxBoundaryX = this.wrapperWidth - 8;
2059                } else {
2060                    this.minBoundaryX = 0;
2061                    this.maxBoundaryX = this.maxPosX;
2062                }
2063
2064                this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
2065            }
2066
2067            if (this.options.listenY) {
2068                this.wrapperHeight = this.wrapper.clientHeight;
2069                if (this.options.resize) {
2070                    this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
2071                    this.indicatorStyle.height = this.indicatorHeight + 'px';
2072                } else {
2073                    this.indicatorHeight = this.indicator.clientHeight;
2074                }
2075
2076                this.maxPosY = this.wrapperHeight - this.indicatorHeight;
2077
2078                if (this.options.shrink == 'clip') {
2079                    this.minBoundaryY = -this.indicatorHeight + 8;
2080                    this.maxBoundaryY = this.wrapperHeight - 8;
2081                } else {
2082                    this.minBoundaryY = 0;
2083                    this.maxBoundaryY = this.maxPosY;
2084                }
2085
2086                this.maxPosY = this.wrapperHeight - this.indicatorHeight;
2087                this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
2088            }
2089
2090            this.updatePosition();
2091        },
2092
2093        updatePosition: function () {
2094            var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
2095                y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
2096
2097            if (!this.options.ignoreBoundaries) {
2098                if (x < this.minBoundaryX) {
2099                    if (this.options.shrink == 'scale') {
2100                        this.width = Math.max(this.indicatorWidth + x, 8);
2101                        this.indicatorStyle.width = this.width + 'px';
2102                    }
2103                    x = this.minBoundaryX;
2104                } else if (x > this.maxBoundaryX) {
2105                    if (this.options.shrink == 'scale') {
2106                        this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
2107                        this.indicatorStyle.width = this.width + 'px';
2108                        x = this.maxPosX + this.indicatorWidth - this.width;
2109                    } else {
2110                        x = this.maxBoundaryX;
2111                    }
2112                } else if (this.options.shrink == 'scale' && this.width != this.indicatorWidth) {
2113                    this.width = this.indicatorWidth;
2114                    this.indicatorStyle.width = this.width + 'px';
2115                }
2116
2117                if (y < this.minBoundaryY) {
2118                    if (this.options.shrink == 'scale') {
2119                        this.height = Math.max(this.indicatorHeight + y * 3, 8);
2120                        this.indicatorStyle.height = this.height + 'px';
2121                    }
2122                    y = this.minBoundaryY;
2123                } else if (y > this.maxBoundaryY) {
2124                    if (this.options.shrink == 'scale') {
2125                        this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
2126                        this.indicatorStyle.height = this.height + 'px';
2127                        y = this.maxPosY + this.indicatorHeight - this.height;
2128                    } else {
2129                        y = this.maxBoundaryY;
2130                    }
2131                } else if (this.options.shrink == 'scale' && this.height != this.indicatorHeight) {
2132                    this.height = this.indicatorHeight;
2133                    this.indicatorStyle.height = this.height + 'px';
2134                }
2135            }
2136
2137            this.x = x;
2138            this.y = y;
2139
2140            if (this.scroller.options.useTransform) {
2141                this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
2142            } else {
2143                this.indicatorStyle.left = x + 'px';
2144                this.indicatorStyle.top = y + 'px';
2145            }
2146        },
2147
2148        _pos: function (x, y) {
2149            if (x < 0) {
2150                x = 0;
2151            } else if (x > this.maxPosX) {
2152                x = this.maxPosX;
2153            }
2154
2155            if (y < 0) {
2156                y = 0;
2157            } else if (y > this.maxPosY) {
2158                y = this.maxPosY;
2159            }
2160
2161            x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
2162            y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
2163
2164            this.scroller.scrollTo(x, y);
2165        },
2166
2167        fade: function (val, hold) {
2168            if (hold && !this.visible) {
2169                return;
2170            }
2171
2172            clearTimeout(this.fadeTimeout);
2173            this.fadeTimeout = null;
2174
2175            var time = val ? 250 : 500,
2176                delay = val ? 0 : 300;
2177
2178            val = val ? '1' : '0';
2179
2180            this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
2181
2182            this.fadeTimeout = setTimeout((function (val) {
2183                this.wrapperStyle.opacity = val;
2184                this.visible = +val;
2185            }).bind(this, val), delay);
2186        }
2187    };
2188
2189    IScroll.utils = utils;
2190
2191    if (typeof module != 'undefined' && module.exports) {
2192        module.exports = IScroll;
2193    } else if (typeof define == 'function' && define.amd) {
2194        define(function () {
2195            return IScroll;
2196        });
2197    } else {
2198        window.IScroll = IScroll;
2199    }
2200
2201})(window, document, Math);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.