pageflow 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pageflow might be problematic. Click here for more details.

@@ -0,0 +1,1811 @@
1
+ /*jshint trailing: false*/
2
+ /*! iScroll v5.0.4 ~ (c) 2008-2013 Matteo Spinelli ~ http://cubiq.org/license */
3
+ var IScroll = (function (window, document, Math) {
4
+ var rAF = window.requestAnimationFrame ||
5
+ window.webkitRequestAnimationFrame ||
6
+ window.mozRequestAnimationFrame ||
7
+ window.oRequestAnimationFrame ||
8
+ window.msRequestAnimationFrame ||
9
+ function (callback) { window.setTimeout(callback, 1000 / 60); };
10
+
11
+ var utils = (function () {
12
+ var me = {};
13
+
14
+ var _elementStyle = document.createElement('div').style;
15
+ var _vendor = (function () {
16
+ var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
17
+ transform,
18
+ i = 0,
19
+ l = vendors.length;
20
+
21
+ for ( ; i < l; i++ ) {
22
+ transform = vendors[i] + 'ransform';
23
+ if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
24
+ }
25
+
26
+ return false;
27
+ })();
28
+
29
+ function _prefixStyle (style) {
30
+ if ( _vendor === false ) return false;
31
+ if ( _vendor === '' ) return style;
32
+ return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
33
+ }
34
+
35
+ me.getTime = Date.now || function getTime () { return new Date().getTime(); };
36
+
37
+ me.extend = function (target, obj) {
38
+ for ( var i in obj ) {
39
+ target[i] = obj[i];
40
+ }
41
+ };
42
+
43
+ me.addEvent = function (el, type, fn, capture) {
44
+ if (el.addEventListener) {
45
+ el.addEventListener(type, fn, !!capture);
46
+ }
47
+ else {
48
+ if (typeof fn === 'function') {
49
+ el.attachEvent('on' + type, fn);
50
+ }
51
+ else {
52
+ fn.__handleEvent = fn.__handleEvent || function(e) {
53
+ e = jQuery.event.fix(e);
54
+ if (e.button === 1) { e.button = 0; }
55
+ e.wheelDelta = e.originalEvent.wheelDelta;
56
+ fn.handleEvent(e);
57
+ };
58
+ el.attachEvent('on' + type, fn.__handleEvent);
59
+ }
60
+ }
61
+ };
62
+
63
+ me.removeEvent = function (el, type, fn, capture) {
64
+ if (el.removeEventListener) {
65
+ el.removeEventListener(type, fn, !!capture);
66
+ }
67
+ else {
68
+ el.detachEvent('on' + type, fn.__handleEvent || fn);
69
+ }
70
+ };
71
+
72
+ me.momentum = function (current, start, time, lowerMargin, wrapperSize) {
73
+ var distance = current - start,
74
+ speed = time > 0 ? Math.abs(distance) / time : 0,
75
+ destination,
76
+ duration,
77
+ deceleration = 0.0006;
78
+
79
+ destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
80
+ duration = speed / deceleration;
81
+
82
+ if ( destination < lowerMargin ) {
83
+ destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
84
+ distance = Math.abs(destination - current);
85
+ duration = distance / speed;
86
+ } else if ( destination > 0 ) {
87
+ destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
88
+ distance = Math.abs(current) + destination;
89
+ duration = distance / speed;
90
+ }
91
+
92
+ return {
93
+ destination: Math.round(destination),
94
+ duration: duration
95
+ };
96
+ };
97
+
98
+ var _transform = _prefixStyle('transform');
99
+
100
+ me.extend(me, {
101
+ hasTransform: _transform !== false,
102
+ hasPerspective: _prefixStyle('perspective') in _elementStyle,
103
+ hasTouch: 'ontouchstart' in window,
104
+ hasPointer: navigator.msPointerEnabled,
105
+ hasTransition: _prefixStyle('transition') in _elementStyle
106
+ });
107
+
108
+ me.isAndroidBrowser = /Android/.test(window.navigator.appVersion) && /Version\/\d/.test(window.navigator.appVersion);
109
+
110
+ me.extend(me.style = {}, {
111
+ transform: _transform,
112
+ transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
113
+ transitionDuration: _prefixStyle('transitionDuration'),
114
+ transformOrigin: _prefixStyle('transformOrigin')
115
+ });
116
+
117
+ me.hasClass = function (e, c) {
118
+ var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
119
+ return re.test(e.className);
120
+ };
121
+
122
+ me.addClass = function (e, c) {
123
+ if ( me.hasClass(e, c) ) {
124
+ return;
125
+ }
126
+
127
+ var newclass = e.className.split(' ');
128
+ newclass.push(c);
129
+ e.className = newclass.join(' ');
130
+ };
131
+
132
+ me.removeClass = function (e, c) {
133
+ if ( !me.hasClass(e, c) ) {
134
+ return;
135
+ }
136
+
137
+ var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
138
+ e.className = e.className.replace(re, '');
139
+ };
140
+
141
+ me.offset = function (el) {
142
+ var left = -el.offsetLeft,
143
+ top = -el.offsetTop;
144
+
145
+ // jshint -W084
146
+ while (el = el.offsetParent) {
147
+ left -= el.offsetLeft;
148
+ top -= el.offsetTop;
149
+ }
150
+ // jshint +W084
151
+
152
+ return {
153
+ left: left,
154
+ top: top
155
+ };
156
+ };
157
+
158
+ me.extend(me.eventType = {}, {
159
+ touchstart: 1,
160
+ touchmove: 1,
161
+ touchend: 1,
162
+
163
+ mousedown: 2,
164
+ mousemove: 2,
165
+ mouseup: 2,
166
+
167
+ MSPointerDown: 3,
168
+ MSPointerMove: 3,
169
+ MSPointerUp: 3
170
+ });
171
+
172
+ me.extend(me.ease = {}, {
173
+ quadratic: {
174
+ style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
175
+ fn: function (k) {
176
+ return k * ( 2 - k );
177
+ }
178
+ },
179
+ circular: {
180
+ 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)
181
+ fn: function (k) {
182
+ return Math.sqrt( 1 - ( --k * k ) );
183
+ }
184
+ },
185
+ back: {
186
+ style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
187
+ fn: function (k) {
188
+ var b = 4;
189
+ return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
190
+ }
191
+ },
192
+ bounce: {
193
+ style: '',
194
+ fn: function (k) {
195
+ if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
196
+ return 7.5625 * k * k;
197
+ } else if ( k < ( 2 / 2.75 ) ) {
198
+ return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
199
+ } else if ( k < ( 2.5 / 2.75 ) ) {
200
+ return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
201
+ } else {
202
+ return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
203
+ }
204
+ }
205
+ },
206
+ elastic: {
207
+ style: '',
208
+ fn: function (k) {
209
+ var f = 0.22,
210
+ e = 0.4;
211
+
212
+ if ( k === 0 ) { return 0; }
213
+ if ( k == 1 ) { return 1; }
214
+
215
+ return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
216
+ }
217
+ }
218
+ });
219
+
220
+ me.tap = function (e, eventName) {
221
+ var ev = document.createEvent('Event');
222
+ ev.initEvent(eventName, true, true);
223
+ ev.pageX = e.pageX;
224
+ ev.pageY = e.pageY;
225
+ e.target.dispatchEvent(ev);
226
+ };
227
+
228
+ me.click = function (e) {
229
+ var target = e.target,
230
+ ev;
231
+
232
+ if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
233
+ ev = document.createEvent('MouseEvents');
234
+ ev.initMouseEvent('click', true, true, e.view, 1,
235
+ target.screenX, target.screenY, target.clientX, target.clientY,
236
+ e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
237
+ 0, null);
238
+
239
+ ev._constructed = true;
240
+ target.dispatchEvent(ev);
241
+ }
242
+ };
243
+
244
+ return me;
245
+ })();
246
+
247
+ function IScroll (el, options) {
248
+ this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
249
+ this.scroller = this.wrapper.children[0];
250
+ this.scrollerStyle = this.scroller.style; // cache style for better performance
251
+
252
+ this.options = {
253
+
254
+ resizeIndicator: true,
255
+
256
+ mouseWheelSpeed: 20,
257
+
258
+ snapThreshold: 0.334,
259
+
260
+ // INSERT POINT: OPTIONS
261
+
262
+ startX: 0,
263
+ startY: 0,
264
+ scrollY: true,
265
+ directionLockThreshold: 5,
266
+ momentum: true,
267
+
268
+ bounce: true,
269
+ bounceTime: 600,
270
+ bounceEasing: '',
271
+
272
+ preventDefault: true,
273
+
274
+ HWCompositing: true,
275
+ useTransition: true,
276
+ useTransform: true
277
+ };
278
+
279
+ for ( var i in options ) {
280
+ this.options[i] = options[i];
281
+ }
282
+
283
+ // Normalize options
284
+ this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
285
+
286
+ this.options.useTransition = utils.hasTransition && this.options.useTransition;
287
+ this.options.useTransform = utils.hasTransform && this.options.useTransform;
288
+
289
+ this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
290
+ this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
291
+
292
+ // If you want eventPassthrough I have to lock one of the axes
293
+ this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
294
+ this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
295
+
296
+ // With eventPassthrough we also need lockDirection mechanism
297
+ this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
298
+ this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
299
+
300
+ this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
301
+
302
+ this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
303
+
304
+ if ( this.options.tap === true ) {
305
+ this.options.tap = 'tap';
306
+ }
307
+
308
+ this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
309
+
310
+ if ( this.options.probeType == 3 ) {
311
+ this.options.useTransition = false; }
312
+
313
+ // INSERT POINT: NORMALIZATION
314
+
315
+ // Some defaults
316
+ this.x = 0;
317
+ this.y = 0;
318
+ this.directionX = 0;
319
+ this.directionY = 0;
320
+ this._events = {};
321
+
322
+ // INSERT POINT: DEFAULTS
323
+
324
+ this._init();
325
+ this.refresh();
326
+
327
+ this.scrollTo(this.options.startX, this.options.startY);
328
+ this.enable();
329
+ }
330
+
331
+ IScroll.prototype = {
332
+ version: '5.0.4',
333
+
334
+ _init: function () {
335
+ this._initEvents();
336
+
337
+ if ( this.options.scrollbars || this.options.indicators ) {
338
+ this._initIndicators();
339
+ }
340
+
341
+ if ( this.options.mouseWheel ) {
342
+ this._initWheel();
343
+ }
344
+
345
+ if ( this.options.snap ) {
346
+ this._initSnap();
347
+ }
348
+
349
+ if ( this.options.keyBindings ) {
350
+ this._initKeys();
351
+ }
352
+
353
+ // INSERT POINT: _init
354
+
355
+ },
356
+
357
+ destroy: function () {
358
+ this._initEvents(true);
359
+
360
+ this._execEvent('destroy');
361
+ },
362
+
363
+ _transitionEnd: function (e) {
364
+ if ( e.target != this.scroller ) {
365
+ return;
366
+ }
367
+
368
+ this._transitionTime(0);
369
+ if ( !this.resetPosition(this.options.bounceTime) ) {
370
+ this._execEvent('scrollEnd');
371
+ }
372
+ },
373
+
374
+ _start: function (e) {
375
+ // React to left mouse button only
376
+ if ( utils.eventType[e.type] != 1 ) {
377
+ if ( e.button !== 0 ) {
378
+ return;
379
+ }
380
+ }
381
+
382
+ if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
383
+ return;
384
+ }
385
+
386
+ if ( this.options.preventDefault && !utils.isAndroidBrowser ) {
387
+ e.preventDefault(); // This seems to break default Android browser
388
+ }
389
+
390
+ var point = e.touches ? e.touches[0] : e,
391
+ pos;
392
+
393
+ this.initiated = utils.eventType[e.type];
394
+ this.moved = false;
395
+ this.distX = 0;
396
+ this.distY = 0;
397
+ this.directionX = 0;
398
+ this.directionY = 0;
399
+ this.directionLocked = 0;
400
+
401
+ this._transitionTime();
402
+
403
+ this.isAnimating = false;
404
+ this.startTime = utils.getTime();
405
+
406
+ if ( this.options.useTransition && this.isInTransition ) {
407
+ pos = this.getComputedPosition();
408
+
409
+ this._translate(Math.round(pos.x), Math.round(pos.y));
410
+ this.isInTransition = false;
411
+ }
412
+
413
+ this.startX = this.x;
414
+ this.startY = this.y;
415
+ this.absStartX = this.x;
416
+ this.absStartY = this.y;
417
+ this.pointX = point.pageX;
418
+ this.pointY = point.pageY;
419
+
420
+ this._execEvent('scrollStart');
421
+ },
422
+
423
+ _move: function (e) {
424
+ if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
425
+ return;
426
+ }
427
+
428
+ if ( this.options.preventDefault ) { // increases performance on Android? TODO: check!
429
+ e.preventDefault();
430
+ }
431
+
432
+ var point = e.touches ? e.touches[0] : e,
433
+ deltaX = this.hasHorizontalScroll ? point.pageX - this.pointX : 0,
434
+ deltaY = this.hasVerticalScroll ? point.pageY - this.pointY : 0,
435
+ timestamp = utils.getTime(),
436
+ newX, newY,
437
+ absDistX, absDistY;
438
+
439
+ this.pointX = point.pageX;
440
+ this.pointY = point.pageY;
441
+
442
+ this.distX += deltaX;
443
+ this.distY += deltaY;
444
+ absDistX = Math.abs(this.distX);
445
+ absDistY = Math.abs(this.distY);
446
+
447
+ // We need to move at least 10 pixels for the scrolling to initiate
448
+ if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
449
+ return;
450
+ }
451
+
452
+ // If you are scrolling in one direction lock the other
453
+ if ( !this.directionLocked && !this.options.freeScroll ) {
454
+ if ( absDistX > absDistY + this.options.directionLockThreshold ) {
455
+ this.directionLocked = 'h'; // lock horizontally
456
+ } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
457
+ this.directionLocked = 'v'; // lock vertically
458
+ } else {
459
+ this.directionLocked = 'n'; // no lock
460
+ }
461
+ }
462
+
463
+ if ( this.directionLocked == 'h' ) {
464
+ if ( this.options.eventPassthrough == 'vertical' ) {
465
+ e.preventDefault();
466
+ } else if ( this.options.eventPassthrough == 'horizontal' ) {
467
+ this.initiated = false;
468
+ return;
469
+ }
470
+
471
+ deltaY = 0;
472
+ } else if ( this.directionLocked == 'v' ) {
473
+ if ( this.options.eventPassthrough == 'horizontal' ) {
474
+ e.preventDefault();
475
+ } else if ( this.options.eventPassthrough == 'vertical' ) {
476
+ this.initiated = false;
477
+ return;
478
+ }
479
+
480
+ deltaX = 0;
481
+ }
482
+
483
+ newX = this.x + deltaX;
484
+ newY = this.y + deltaY;
485
+
486
+ // Slow down if outside of the boundaries
487
+ if ( newX > 0 || newX < this.maxScrollX ) {
488
+ newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
489
+ }
490
+ if ( newY > 0 || newY < this.maxScrollY ) {
491
+ newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
492
+ }
493
+
494
+ this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
495
+ this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
496
+
497
+ this.moved = true;
498
+
499
+ this._translate(newX, newY);
500
+
501
+ /* REPLACE START: _move */
502
+ if ( timestamp - this.startTime > 300 ) {
503
+ this.startTime = timestamp;
504
+ this.startX = this.x;
505
+ this.startY = this.y;
506
+
507
+ if ( this.options.probeType == 1 ) {
508
+ this._execEvent('scroll');
509
+ }
510
+ }
511
+
512
+ if ( this.options.probeType > 1 ) {
513
+ this._execEvent('scroll');
514
+ }
515
+ /* REPLACE END: _move */
516
+
517
+ },
518
+
519
+ _end: function (e) {
520
+ if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
521
+ return;
522
+ }
523
+
524
+ if ( this.options.preventDefault ) {
525
+ e.preventDefault(); // TODO: check if needed
526
+ }
527
+
528
+ var point = e.changedTouches ? e.changedTouches[0] : e,
529
+ momentumX,
530
+ momentumY,
531
+ duration = utils.getTime() - this.startTime,
532
+ newX = Math.round(this.x),
533
+ newY = Math.round(this.y),
534
+ distanceX = Math.abs(newX - this.startX),
535
+ distanceY = Math.abs(newY - this.startY),
536
+ time = 0,
537
+ easing = '';
538
+
539
+ this.scrollTo(newX, newY); // ensures that the last position is rounded
540
+
541
+ this.isInTransition = 0;
542
+ this.initiated = 0;
543
+ this.endTime = utils.getTime();
544
+
545
+ // reset if we are outside of the boundaries
546
+ if ( this.resetPosition(this.options.bounceTime) ) {
547
+ return;
548
+ }
549
+
550
+ // we scrolled less than 10 pixels
551
+ if ( !this.moved ) {
552
+ if ( this.options.tap ) {
553
+ utils.tap(e, this.options.tap);
554
+ }
555
+
556
+ if ( this.options.click ) {
557
+ utils.click(e);
558
+ }
559
+
560
+ return;
561
+ }
562
+
563
+ if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
564
+ this._execEvent('flick');
565
+ return;
566
+ }
567
+
568
+ // start momentum animation if needed
569
+ if ( this.options.momentum && duration < 300 ) {
570
+ momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0) : { destination: newX, duration: 0 };
571
+ momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0) : { destination: newY, duration: 0 };
572
+ newX = momentumX.destination;
573
+ newY = momentumY.destination;
574
+ time = Math.max(momentumX.duration, momentumY.duration);
575
+ this.isInTransition = 1;
576
+ }
577
+
578
+ if ( this.options.snap ) {
579
+ var snap = this._nearestSnap(newX, newY);
580
+ this.currentPage = snap;
581
+ newX = snap.x;
582
+ newY = snap.y;
583
+ time = this.options.snapSpeed || Math.max(
584
+ Math.max(
585
+ Math.min(distanceX, 1000),
586
+ Math.min(distanceX, 1000)
587
+ ), 300);
588
+
589
+ this.directionX = 0;
590
+ this.directionY = 0;
591
+ easing = this.options.bounceEasing;
592
+ }
593
+
594
+ if ( newX != this.x || newY != this.y ) {
595
+ // change easing function when scroller goes out of the boundaries
596
+ if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
597
+ easing = utils.ease.quadratic;
598
+ }
599
+
600
+ this.scrollTo(newX, newY, time, easing);
601
+ return;
602
+ }
603
+
604
+ this._execEvent('scrollEnd');
605
+ },
606
+
607
+ _resize: function () {
608
+ var that = this;
609
+
610
+ clearTimeout(this.resizeTimeout);
611
+
612
+ this.resizeTimeout = setTimeout(function () {
613
+ that.refresh();
614
+ }, this.options.resizePolling);
615
+ },
616
+
617
+ resetPosition: function (time) {
618
+ var x = this.x,
619
+ y = this.y;
620
+
621
+ time = time || 0;
622
+
623
+ if ( !this.hasHorizontalScroll || this.x > 0 ) {
624
+ x = 0;
625
+ } else if ( this.x < this.maxScrollX ) {
626
+ x = this.maxScrollX;
627
+ }
628
+
629
+ if ( !this.hasVerticalScroll || this.y > 0 ) {
630
+ y = 0;
631
+ } else if ( this.y < this.maxScrollY ) {
632
+ y = this.maxScrollY;
633
+ }
634
+
635
+ if ( x == this.x && y == this.y ) {
636
+ return false;
637
+ }
638
+
639
+ this.scrollTo(x, y, time, this.options.bounceEasing);
640
+
641
+ return true;
642
+ },
643
+
644
+ disable: function () {
645
+ // Cancel scrolling
646
+ this.isInTransition = 0; // CS
647
+ this.initiated = 0; // CS
648
+ this.endTime = utils.getTime(); // CS
649
+
650
+ this.enabled = false;
651
+ },
652
+
653
+ enable: function () {
654
+ this.enabled = true;
655
+ },
656
+
657
+ refresh: function () {
658
+ var rf = this.wrapper.offsetHeight; // Force reflow
659
+
660
+ this.wrapperWidth = this.wrapper.clientWidth;
661
+ this.wrapperHeight = this.wrapper.clientHeight;
662
+
663
+ /* REPLACE START: refresh */
664
+
665
+ this.scrollerWidth = this.scroller.offsetWidth;
666
+ this.scrollerHeight = this.scroller.offsetHeight;
667
+
668
+ /* REPLACE END: refresh */
669
+
670
+ this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
671
+ this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
672
+
673
+ this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
674
+ this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
675
+
676
+ if ( !this.hasHorizontalScroll ) {
677
+ this.maxScrollX = 0;
678
+ this.scrollerWidth = this.wrapperWidth;
679
+ }
680
+
681
+ if ( !this.hasVerticalScroll ) {
682
+ this.maxScrollY = 0;
683
+ this.scrollerHeight = this.wrapperHeight;
684
+ }
685
+
686
+ this.endTime = 0;
687
+ this.directionX = 0;
688
+ this.directionY = 0;
689
+
690
+ this.wrapperOffset = utils.offset(this.wrapper);
691
+
692
+ this._execEvent('refresh');
693
+
694
+ this.resetPosition();
695
+
696
+ if ( this.options.snap ) {
697
+ var snap = this._nearestSnap(this.x, this.y);
698
+ if ( this.x == snap.x && this.y == snap.y ) {
699
+ return;
700
+ }
701
+
702
+ this.currentPage = snap;
703
+ this.scrollTo(snap.x, snap.y);
704
+ }
705
+ },
706
+
707
+ on: function (type, fn) {
708
+ if ( !this._events[type] ) {
709
+ this._events[type] = [];
710
+ }
711
+
712
+ this._events[type].push(fn);
713
+ },
714
+
715
+ _execEvent: function (type, event) {
716
+ if ( !this._events[type] ) {
717
+ return;
718
+ }
719
+
720
+ var i = 0,
721
+ l = this._events[type].length;
722
+
723
+ if ( !l ) {
724
+ return;
725
+ }
726
+
727
+ for ( ; i < l; i++ ) {
728
+ this._events[type][i].call(this, event);
729
+ }
730
+ },
731
+
732
+ scrollBy: function (x, y, time, easing) {
733
+ x = this.x + x;
734
+ y = this.y + y;
735
+ time = time || 0;
736
+
737
+ this.scrollTo(x, y, time, easing);
738
+ },
739
+
740
+ scrollTo: function (x, y, time, easing) {
741
+ easing = easing || utils.ease.circular;
742
+
743
+ if ( !time || (this.options.useTransition && easing.style) ) {
744
+ this._transitionTimingFunction(easing.style);
745
+ this._transitionTime(time);
746
+ this._translate(x, y);
747
+ } else {
748
+ this._animate(x, y, time, easing.fn);
749
+ }
750
+ },
751
+
752
+ scrollToElement: function (el, time, offsetX, offsetY, easing) {
753
+ el = el.nodeType ? el : this.scroller.querySelector(el);
754
+
755
+ if ( !el ) {
756
+ return;
757
+ }
758
+
759
+ var pos = utils.offset(el);
760
+
761
+ pos.left -= this.wrapperOffset.left;
762
+ pos.top -= this.wrapperOffset.top;
763
+
764
+ // if offsetX/Y are true we center the element to the screen
765
+ if ( offsetX === true ) {
766
+ offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
767
+ }
768
+ if ( offsetY === true ) {
769
+ offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
770
+ }
771
+
772
+ pos.left -= offsetX || 0;
773
+ pos.top -= offsetY || 0;
774
+
775
+ pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
776
+ pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;
777
+
778
+ time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(pos.left)*2, Math.abs(pos.top)*2) : time;
779
+
780
+ this.scrollTo(pos.left, pos.top, time, easing);
781
+ },
782
+
783
+ _transitionTime: function (time) {
784
+ time = time || 0;
785
+ this.scrollerStyle[utils.style.transitionDuration] = time + 'ms';
786
+
787
+
788
+ if ( this.indicator1 ) {
789
+ this.indicator1.transitionTime(time);
790
+ }
791
+
792
+ if ( this.indicator2 ) {
793
+ this.indicator2.transitionTime(time);
794
+ }
795
+
796
+ // INSERT POINT: _transitionTime
797
+
798
+ },
799
+
800
+ _transitionTimingFunction: function (easing) {
801
+ this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
802
+
803
+
804
+ if ( this.indicator1 ) {
805
+ this.indicator1.transitionTimingFunction(easing);
806
+ }
807
+
808
+ if ( this.indicator2 ) {
809
+ this.indicator2.transitionTimingFunction(easing);
810
+ }
811
+
812
+
813
+ // INSERT POINT: _transitionTimingFunction
814
+
815
+ },
816
+
817
+ _translate: function (x, y) {
818
+ if ( this.options.useTransform ) {
819
+
820
+ /* REPLACE START: _translate */
821
+
822
+ this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
823
+
824
+ /* REPLACE END: _translate */
825
+
826
+ } else {
827
+ x = Math.round(x);
828
+ y = Math.round(y);
829
+ this.scrollerStyle.left = x + 'px';
830
+ this.scrollerStyle.top = y + 'px';
831
+ }
832
+
833
+ this.x = x;
834
+ this.y = y;
835
+
836
+
837
+ if ( this.indicator1 ) { // usually the vertical
838
+ this.indicator1.updatePosition();
839
+ }
840
+
841
+ if ( this.indicator2 ) {
842
+ this.indicator2.updatePosition();
843
+ }
844
+
845
+ // INSERT POINT: _translate
846
+
847
+ },
848
+
849
+ _initEvents: function (remove) {
850
+ var eventType = remove ? utils.removeEvent : utils.addEvent,
851
+ target = this.options.bindToWrapper ? this.wrapper : window;
852
+
853
+ eventType(window, 'orientationchange', this);
854
+ eventType(window, 'resize', this);
855
+
856
+ eventType(this.wrapper, 'mousedown', this);
857
+ eventType(document, 'mousemove', this);
858
+ eventType(document, 'mousecancel', this);
859
+ eventType(document, 'mouseup', this);
860
+
861
+ if ( utils.hasPointer ) {
862
+ eventType(this.wrapper, 'MSPointerDown', this);
863
+ eventType(target, 'MSPointerMove', this);
864
+ eventType(target, 'MSPointerCancel', this);
865
+ eventType(target, 'MSPointerUp', this);
866
+ }
867
+
868
+ if ( utils.hasTouch ) {
869
+ eventType(this.wrapper, 'touchstart', this);
870
+ eventType(target, 'touchmove', this);
871
+ eventType(target, 'touchcancel', this);
872
+ eventType(target, 'touchend', this);
873
+ }
874
+
875
+ eventType(this.scroller, 'transitionend', this);
876
+ eventType(this.scroller, 'webkitTransitionEnd', this);
877
+ eventType(this.scroller, 'oTransitionEnd', this);
878
+ eventType(this.scroller, 'MSTransitionEnd', this);
879
+ },
880
+
881
+ getComputedPosition: function () {
882
+ var matrix = window.getComputedStyle(this.scroller, null),
883
+ x, y;
884
+
885
+ if ( this.options.useTransform ) {
886
+ matrix = matrix[utils.style.transform].split(')')[0].split(', ');
887
+ x = +(matrix[12] || matrix[4]);
888
+ y = +(matrix[13] || matrix[5]);
889
+ } else {
890
+ x = +matrix.left.replace(/[^-\d]/g, '');
891
+ y = +matrix.top.replace(/[^-\d]/g, '');
892
+ }
893
+
894
+ return { x: x, y: y };
895
+ },
896
+
897
+ _initIndicators: function () {
898
+ var interactive = this.options.interactiveScrollbars,
899
+ defaultScrollbars = typeof this.options.scrollbars != 'object',
900
+ customStyle = typeof this.options.scrollbars != 'string',
901
+ indicator1,
902
+ indicator2;
903
+
904
+ if ( this.options.scrollbars ) {
905
+ // Vertical scrollbar
906
+ if ( this.options.scrollY ) {
907
+ indicator1 = {
908
+ el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
909
+ interactive: interactive,
910
+ defaultScrollbars: true,
911
+ customStyle: customStyle,
912
+ resize: this.options.resizeIndicator,
913
+ listenX: false
914
+ };
915
+
916
+ this.wrapper.appendChild(indicator1.el);
917
+ }
918
+
919
+ // Horizontal scrollbar
920
+ if ( this.options.scrollX ) {
921
+ indicator2 = {
922
+ el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
923
+ interactive: interactive,
924
+ defaultScrollbars: true,
925
+ customStyle: customStyle,
926
+ resize: this.options.resizeIndicator,
927
+ listenY: false
928
+ };
929
+
930
+ this.wrapper.appendChild(indicator2.el);
931
+ }
932
+ } else {
933
+ indicator1 = this.options.indicators.length ? this.options.indicators[0] : this.options.indicators;
934
+ indicator2 = this.options.indicators[1] && this.options.indicators[1];
935
+ }
936
+
937
+ if ( indicator1 ) {
938
+ this.indicator1 = new Indicator(this, indicator1);
939
+ }
940
+
941
+ if ( indicator2 ) {
942
+ this.indicator2 = new Indicator(this, indicator2);
943
+ }
944
+
945
+ this.on('refresh', function () {
946
+ if ( this.indicator1 ) {
947
+ this.indicator1.refresh();
948
+ }
949
+
950
+ if ( this.indicator2 ) {
951
+ this.indicator2.refresh();
952
+ }
953
+ });
954
+
955
+ this.on('destroy', function () {
956
+ if ( this.indicator1 ) {
957
+ this.indicator1.destroy();
958
+ this.indicator1 = null;
959
+ }
960
+
961
+ if ( this.indicator2 ) {
962
+ this.indicator2.destroy();
963
+ this.indicator2 = null;
964
+ }
965
+ });
966
+ },
967
+
968
+ _initWheel: function () {
969
+ utils.addEvent(this.wrapper, 'wheel', this);
970
+ utils.addEvent(this.wrapper, 'mousewheel', this);
971
+ utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
972
+
973
+ this.on('destroy', function () {
974
+ utils.removeEvent(this.wrapper, 'wheel', this);
975
+ utils.removeEvent(this.wrapper, 'mousewheel', this);
976
+ utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
977
+ });
978
+ },
979
+
980
+ _wheel: function (e) {
981
+ if ( !this.enabled ) {
982
+ return;
983
+ }
984
+
985
+ var wheelDeltaX, wheelDeltaY,
986
+ newX, newY,
987
+ that = this;
988
+
989
+ // Execute the scrollEnd event after 400ms the wheel stopped scrolling
990
+ clearTimeout(this.wheelTimeout);
991
+ this.wheelTimeout = setTimeout(function () {
992
+ that._execEvent('scrollEnd');
993
+ }, 400);
994
+
995
+ e.preventDefault();
996
+ e.stopPropagation();
997
+
998
+ if ( 'deltaX' in e ) {
999
+ wheelDeltaX = -e.deltaX;
1000
+ wheelDeltaY = -e.deltaY;
1001
+
1002
+ // Checke whether deltaMode is DOM_DELTA_LINE
1003
+ if (e.deltaMode === 1) {
1004
+ wheelDeltaX = wheelDeltaX / 3 * this.options.mouseWheelSpeed;
1005
+ wheelDeltaY = wheelDeltaY / 3 * this.options.mouseWheelSpeed;
1006
+ }
1007
+ } else if ( 'wheelDeltaX' in e ) {
1008
+ wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
1009
+ wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
1010
+ } else if ( 'wheelDelta' in e ) {
1011
+ wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
1012
+ } else if ( 'detail' in e ) {
1013
+ wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
1014
+ } else {
1015
+ return;
1016
+ }
1017
+
1018
+ wheelDeltaX *= this.options.invertWheelDirection;
1019
+ wheelDeltaY *= this.options.invertWheelDirection;
1020
+
1021
+ if ( !this.hasVerticalScroll ) {
1022
+ wheelDeltaX = wheelDeltaY;
1023
+ }
1024
+
1025
+ newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
1026
+ newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
1027
+
1028
+ if ( newX > 0 ) {
1029
+ newX = 0;
1030
+ } else if ( newX < this.maxScrollX ) {
1031
+ newX = this.maxScrollX;
1032
+ }
1033
+
1034
+ if ( newY > 0 ) {
1035
+ newY = 0;
1036
+
1037
+ } else if ( newY < this.maxScrollY ) {
1038
+ newY = this.maxScrollY;
1039
+ }
1040
+
1041
+ this.scrollTo(newX, newY, 0);
1042
+
1043
+ if ( this.options.probeType > 1 ) {
1044
+ this._execEvent('scroll');
1045
+ }
1046
+
1047
+ this._execEvent(wheelDeltaY > 0 ? 'mousewheelup' : 'mousewheeldown'); // CS
1048
+ // INSERT POINT: _wheel
1049
+ },
1050
+
1051
+ _initSnap: function () {
1052
+ this.currentPage = {};
1053
+
1054
+ if ( typeof this.options.snap == 'string' ) {
1055
+ this.options.snap = this.scroller.querySelectorAll(this.options.snap);
1056
+ }
1057
+
1058
+ this.on('refresh', function () {
1059
+ var i = 0, l,
1060
+ m = 0, n,
1061
+ cx, cy,
1062
+ x = 0, y,
1063
+ stepX = this.options.snapStepX || this.wrapperWidth,
1064
+ stepY = this.options.snapStepY || this.wrapperHeight,
1065
+ el;
1066
+
1067
+ this.pages = [];
1068
+
1069
+ if ( this.options.snap === true ) {
1070
+ cx = Math.round( stepX / 2 );
1071
+ cy = Math.round( stepY / 2 );
1072
+
1073
+ while ( x > -this.scrollerWidth ) {
1074
+ this.pages[i] = [];
1075
+ l = 0;
1076
+ y = 0;
1077
+
1078
+ while ( y > -this.scrollerHeight ) {
1079
+ this.pages[i][l] = {
1080
+ x: Math.max(x, this.maxScrollX),
1081
+ y: Math.max(y, this.maxScrollY),
1082
+ width: stepX,
1083
+ height: stepY,
1084
+ cx: x - cx,
1085
+ cy: y - cy
1086
+ };
1087
+
1088
+ y -= stepY;
1089
+ l++;
1090
+ }
1091
+
1092
+ x -= stepX;
1093
+ i++;
1094
+ }
1095
+ } else {
1096
+ el = this.options.snap;
1097
+ l = el.length;
1098
+ n = -1;
1099
+
1100
+ for ( ; i < l; i++ ) {
1101
+ if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
1102
+ m = 0;
1103
+ n++;
1104
+ }
1105
+
1106
+ if ( !this.pages[m] ) {
1107
+ this.pages[m] = [];
1108
+ }
1109
+
1110
+ x = Math.max(-el[i].offsetLeft, this.maxScrollX);
1111
+ y = Math.max(-el[i].offsetTop, this.maxScrollY);
1112
+ cx = x - Math.round(el[i].offsetWidth / 2);
1113
+ cy = y - Math.round(el[i].offsetHeight / 2);
1114
+
1115
+ this.pages[m][n] = {
1116
+ x: x,
1117
+ y: y,
1118
+ width: el[i].offsetWidth,
1119
+ height: el[i].offsetHeight,
1120
+ cx: cx,
1121
+ cy: cy
1122
+ };
1123
+
1124
+ if ( x > this.maxScrollX ) {
1125
+ m++;
1126
+ }
1127
+ }
1128
+ }
1129
+
1130
+ this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
1131
+
1132
+ // Update snap threshold if needed
1133
+ if ( this.options.snapThreshold % 1 === 0 ) {
1134
+ this.snapThresholdX = this.options.snapThreshold;
1135
+ this.snapThresholdY = this.options.snapThreshold;
1136
+ } else {
1137
+ this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
1138
+ this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
1139
+ }
1140
+ });
1141
+
1142
+ this.on('flick', function () {
1143
+ var time = this.options.snapSpeed || Math.max(
1144
+ Math.max(
1145
+ Math.min(Math.abs(this.x - this.startX), 1000),
1146
+ Math.min(Math.abs(this.y - this.startY), 1000)
1147
+ ), 300);
1148
+
1149
+ this.goToPage(
1150
+ this.currentPage.pageX + this.directionX,
1151
+ this.currentPage.pageY + this.directionY,
1152
+ time
1153
+ );
1154
+ });
1155
+ },
1156
+
1157
+ _nearestSnap: function (x, y) {
1158
+ var i = 0,
1159
+ l = this.pages.length,
1160
+ m = 0;
1161
+
1162
+ // Check if we exceeded the snap threshold
1163
+ if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
1164
+ Math.abs(y - this.absStartY) < this.snapThresholdY ) {
1165
+ return this.currentPage;
1166
+ }
1167
+
1168
+ if ( x > 0 ) {
1169
+ x = 0;
1170
+ } else if ( x < this.maxScrollX ) {
1171
+ x = this.maxScrollX;
1172
+ }
1173
+
1174
+ if ( y > 0 ) {
1175
+ y = 0;
1176
+ } else if ( y < this.maxScrollY ) {
1177
+ y = this.maxScrollY;
1178
+ }
1179
+
1180
+ for ( ; i < l; i++ ) {
1181
+ if ( x >= this.pages[i][0].cx ) {
1182
+ x = this.pages[i][0].x;
1183
+ break;
1184
+ }
1185
+ }
1186
+
1187
+ l = this.pages[i].length;
1188
+
1189
+ for ( ; m < l; m++ ) {
1190
+ if ( y >= this.pages[0][m].cy ) {
1191
+ y = this.pages[0][m].y;
1192
+ break;
1193
+ }
1194
+ }
1195
+
1196
+ if ( i == this.currentPage.pageX ) {
1197
+ i += this.directionX;
1198
+
1199
+ if ( i < 0 ) {
1200
+ i = 0;
1201
+ } else if ( i >= this.pages.length ) {
1202
+ i = this.pages.length - 1;
1203
+ }
1204
+
1205
+ x = this.pages[i][0].x;
1206
+ }
1207
+
1208
+ if ( m == this.currentPage.pageY ) {
1209
+ m += this.directionY;
1210
+
1211
+ if ( m < 0 ) {
1212
+ m = 0;
1213
+ } else if ( m >= this.pages[0].length ) {
1214
+ m = this.pages[0].length - 1;
1215
+ }
1216
+
1217
+ y = this.pages[0][m].y;
1218
+ }
1219
+
1220
+ return {
1221
+ x: x,
1222
+ y: y,
1223
+ pageX: i,
1224
+ pageY: m
1225
+ };
1226
+ },
1227
+
1228
+ goToPage: function (x, y, time, easing) {
1229
+ easing = easing || this.options.bounceEasing;
1230
+
1231
+ if ( x >= this.pages.length ) {
1232
+ x = this.pages.length - 1;
1233
+ } else if ( x < 0 ) {
1234
+ x = 0;
1235
+ }
1236
+
1237
+ if ( y >= this.pages[0].length ) {
1238
+ y = this.pages[0].length - 1;
1239
+ } else if ( y < 0 ) {
1240
+ y = 0;
1241
+ }
1242
+
1243
+ var posX = this.pages[x][y].x,
1244
+ posY = this.pages[x][y].y;
1245
+
1246
+ time = time === undefined ? this.options.snapSpeed || Math.max(
1247
+ Math.max(
1248
+ Math.min(Math.abs(posX - this.x), 1000),
1249
+ Math.min(Math.abs(posY - this.y), 1000)
1250
+ ), 300) : time;
1251
+
1252
+ this.currentPage = {
1253
+ x: posX,
1254
+ y: posY,
1255
+ pageX: x,
1256
+ pageY: y
1257
+ };
1258
+
1259
+ this.scrollTo(posX, posY, time, easing);
1260
+ },
1261
+
1262
+ next: function (time, easing) {
1263
+ var x = this.currentPage.pageX,
1264
+ y = this.currentPage.pageY;
1265
+
1266
+ x++;
1267
+
1268
+ if ( x >= this.pages.length && this.hasVerticalScroll ) {
1269
+ x = 0;
1270
+ y++;
1271
+ }
1272
+
1273
+ this.goToPage(x, y, time, easing);
1274
+ },
1275
+
1276
+ prev: function (time, easing) {
1277
+ var x = this.currentPage.pageX,
1278
+ y = this.currentPage.pageY;
1279
+
1280
+ x--;
1281
+
1282
+ if ( x < 0 && this.hasVerticalScroll ) {
1283
+ x = 0;
1284
+ y--;
1285
+ }
1286
+
1287
+ this.goToPage(x, y, time, easing);
1288
+ },
1289
+
1290
+ _initKeys: function (e) {
1291
+ // default key bindings
1292
+ var keys = {
1293
+ pageUp: 33,
1294
+ pageDown: 34,
1295
+ end: 35,
1296
+ home: 36,
1297
+ left: 37,
1298
+ up: 38,
1299
+ right: 39,
1300
+ down: 40
1301
+ };
1302
+ var i;
1303
+
1304
+ // if you give me characters I give you keycode
1305
+ if ( typeof this.options.keyBindings == 'object' ) {
1306
+ for ( i in this.options.keyBindings ) {
1307
+ if ( typeof this.options.keyBindings[i] == 'string' ) {
1308
+ this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);
1309
+ }
1310
+ }
1311
+ } else {
1312
+ this.options.keyBindings = {};
1313
+ }
1314
+
1315
+ for ( i in keys ) {
1316
+ this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
1317
+ }
1318
+
1319
+ utils.addEvent(window, 'keydown', this);
1320
+
1321
+ this.on('destroy', function () {
1322
+ utils.removeEvent(window, 'keydown', this);
1323
+ });
1324
+ },
1325
+
1326
+ _key: function (e) {
1327
+ var keyboardEvent = null;
1328
+
1329
+ if ( !this.enabled ) {
1330
+ return;
1331
+ }
1332
+
1333
+ var snap = this.options.snap, // we are using this alot, better to cache it
1334
+ newX = snap ? this.currentPage.pageX : this.x,
1335
+ newY = snap ? this.currentPage.pageY : this.y,
1336
+ now = utils.getTime(),
1337
+ prevTime = this.keyTime || 0,
1338
+ acceleration = 0.250,
1339
+ pos;
1340
+
1341
+ if ( this.options.useTransition && this.isInTransition ) {
1342
+ pos = this.getComputedPosition();
1343
+
1344
+ this._translate(Math.round(pos.x), Math.round(pos.y));
1345
+ this.isInTransition = false;
1346
+ }
1347
+
1348
+ this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
1349
+
1350
+ switch ( e.keyCode ) {
1351
+ case this.options.keyBindings.pageUp:
1352
+ if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
1353
+ newX += snap ? 1 : this.wrapperWidth;
1354
+ } else {
1355
+ newY += snap ? 1 : this.wrapperHeight;
1356
+ keyboardEvent = 'keyboardup'; // CS
1357
+ }
1358
+ break;
1359
+ case this.options.keyBindings.pageDown:
1360
+ if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
1361
+ newX -= snap ? 1 : this.wrapperWidth;
1362
+ } else {
1363
+ newY -= snap ? 1 : this.wrapperHeight;
1364
+ keyboardEvent = 'keyboarddown'; // CS
1365
+ }
1366
+ break;
1367
+ case this.options.keyBindings.end:
1368
+ newX = snap ? this.pages.length-1 : this.maxScrollX;
1369
+ newY = snap ? this.pages[0].length-1 : this.maxScrollY;
1370
+ keyboardEvent = 'keyboardhintdown'; // CS
1371
+ break;
1372
+ case this.options.keyBindings.home:
1373
+ newX = 0;
1374
+ newY = 0;
1375
+ keyboardEvent = 'keyboardhintup'; // CS
1376
+ break;
1377
+ case this.options.keyBindings.left:
1378
+ newX += snap ? -1 : 5 + this.keyAcceleration>>0;
1379
+ break;
1380
+ case this.options.keyBindings.up:
1381
+ newY += snap ? 1 : 5 + this.keyAcceleration>>0;
1382
+ keyboardEvent = 'keyboardup'; // CS
1383
+ break;
1384
+ case this.options.keyBindings.right:
1385
+ newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
1386
+ break;
1387
+ case this.options.keyBindings.down:
1388
+ newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
1389
+ keyboardEvent = 'keyboarddown'; // CS
1390
+ break;
1391
+ }
1392
+
1393
+ if ( snap ) {
1394
+ this.goToPage(newX, newY);
1395
+ return;
1396
+ }
1397
+
1398
+ if ( newX > 0 ) {
1399
+ newX = 0;
1400
+ this.keyAcceleration = 0;
1401
+ } else if ( newX < this.maxScrollX ) {
1402
+ newX = this.maxScrollX;
1403
+ this.keyAcceleration = 0;
1404
+ }
1405
+
1406
+ if ( newY > 0 ) {
1407
+ newY = 0;
1408
+ this.keyAcceleration = 0;
1409
+ } else if ( newY < this.maxScrollY ) {
1410
+ newY = this.maxScrollY;
1411
+ this.keyAcceleration = 0;
1412
+ }
1413
+
1414
+ if (keyboardEvent) { this._execEvent(keyboardEvent, e); } // CS
1415
+
1416
+ this.scrollTo(newX, newY, 0);
1417
+
1418
+ this.keyTime = now;
1419
+
1420
+ if (this.enabled) { this._execEvent('afterkeyboard'); } // CS
1421
+ },
1422
+
1423
+ _animate: function (destX, destY, duration, easingFn) {
1424
+ var that = this,
1425
+ startX = this.x,
1426
+ startY = this.y,
1427
+ startTime = utils.getTime(),
1428
+ destTime = startTime + duration;
1429
+
1430
+ function step () {
1431
+ var now = utils.getTime(),
1432
+ newX, newY,
1433
+ easing;
1434
+
1435
+ if ( now >= destTime ) {
1436
+ that.isAnimating = false;
1437
+ that._translate(destX, destY);
1438
+
1439
+ if ( !that.resetPosition(that.options.bounceTime) ) {
1440
+ that._execEvent('scrollEnd');
1441
+ }
1442
+
1443
+ return;
1444
+ }
1445
+
1446
+ now = ( now - startTime ) / duration;
1447
+ easing = easingFn(now);
1448
+ newX = ( destX - startX ) * easing + startX;
1449
+ newY = ( destY - startY ) * easing + startY;
1450
+ that._translate(newX, newY);
1451
+
1452
+ if ( that.isAnimating ) {
1453
+ rAF(step);
1454
+ }
1455
+
1456
+ if ( that.options.probeType == 3 ) {
1457
+ that._execEvent('scroll');
1458
+ }
1459
+ }
1460
+
1461
+ this.isAnimating = true;
1462
+ step();
1463
+ },
1464
+
1465
+ handleEvent: function (e) {
1466
+ switch ( e.type ) {
1467
+ case 'touchstart':
1468
+ case 'MSPointerDown':
1469
+ case 'mousedown':
1470
+ this._start(e);
1471
+ break;
1472
+ case 'touchmove':
1473
+ case 'MSPointerMove':
1474
+ case 'mousemove':
1475
+ this._move(e);
1476
+ break;
1477
+ case 'touchend':
1478
+ case 'MSPointerUp':
1479
+ case 'mouseup':
1480
+ case 'touchcancel':
1481
+ case 'MSPointerCancel':
1482
+ case 'mousecancel':
1483
+ this._end(e);
1484
+ break;
1485
+ case 'orientationchange':
1486
+ case 'resize':
1487
+ this._resize();
1488
+ break;
1489
+ case 'transitionend':
1490
+ case 'webkitTransitionEnd':
1491
+ case 'oTransitionEnd':
1492
+ case 'MSTransitionEnd':
1493
+ this._transitionEnd(e);
1494
+ break;
1495
+ case 'wheel':
1496
+ case 'DOMMouseScroll':
1497
+ case 'mousewheel':
1498
+ this._wheel(e);
1499
+ break;
1500
+ case 'keydown':
1501
+ this._key(e);
1502
+ break;
1503
+ }
1504
+ }
1505
+ };
1506
+ function createDefaultScrollbar (direction, interactive, type) {
1507
+ var scrollbar = document.createElement('div'),
1508
+ indicator = document.createElement('div');
1509
+
1510
+ if ( type === true ) {
1511
+ scrollbar.style.cssText = 'position:absolute;z-index:9999';
1512
+ 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';
1513
+ }
1514
+
1515
+ indicator.className = 'iScrollIndicator';
1516
+
1517
+ if ( direction == 'h' ) {
1518
+ if ( type === true ) {
1519
+ scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
1520
+ indicator.style.height = '100%';
1521
+ }
1522
+ scrollbar.className = 'iScrollHorizontalScrollbar';
1523
+ } else {
1524
+ if ( type === true ) {
1525
+ scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
1526
+ indicator.style.width = '100%';
1527
+ }
1528
+ scrollbar.className = 'iScrollVerticalScrollbar';
1529
+ }
1530
+
1531
+ if ( !interactive ) {
1532
+ scrollbar.style.pointerEvents = 'none';
1533
+ }
1534
+
1535
+ scrollbar.appendChild(indicator);
1536
+
1537
+ return scrollbar;
1538
+ }
1539
+
1540
+ function Indicator (scroller, options) {
1541
+ this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
1542
+ this.indicator = this.wrapper.children[0];
1543
+ this.indicatorStyle = this.indicator.style;
1544
+ this.scroller = scroller;
1545
+
1546
+ this.options = {
1547
+ listenX: true,
1548
+ listenY: true,
1549
+ interactive: false,
1550
+ resize: true,
1551
+ defaultScrollbars: false,
1552
+ speedRatioX: 0,
1553
+ speedRatioY: 0
1554
+ };
1555
+
1556
+ for ( var i in options ) {
1557
+ this.options[i] = options[i];
1558
+ }
1559
+
1560
+ this.sizeRatioX = 1;
1561
+ this.sizeRatioY = 1;
1562
+ this.maxPosX = 0;
1563
+ this.maxPosY = 0;
1564
+
1565
+ if ( this.options.interactive ) {
1566
+ utils.addEvent(this.indicator, 'touchstart', this);
1567
+ utils.addEvent(this.indicator, 'MSPointerDown', this);
1568
+ utils.addEvent(this.indicator, 'mousedown', this);
1569
+
1570
+ utils.addEvent(window, 'touchend', this);
1571
+ utils.addEvent(window, 'MSPointerUp', this);
1572
+ utils.addEvent(window, 'mouseup', this);
1573
+ }
1574
+ }
1575
+
1576
+ Indicator.prototype = {
1577
+ handleEvent: function (e) {
1578
+ switch ( e.type ) {
1579
+ case 'touchstart':
1580
+ case 'MSPointerDown':
1581
+ case 'mousedown':
1582
+ this._start(e);
1583
+ break;
1584
+ case 'touchmove':
1585
+ case 'MSPointerMove':
1586
+ case 'mousemove':
1587
+ this._move(e);
1588
+ break;
1589
+ case 'touchend':
1590
+ case 'MSPointerUp':
1591
+ case 'mouseup':
1592
+ case 'touchcancel':
1593
+ case 'MSPointerCancel':
1594
+ case 'mousecancel':
1595
+ this._end(e);
1596
+ break;
1597
+ }
1598
+ },
1599
+
1600
+ destroy: function () {
1601
+ if ( this.options.interactive ) {
1602
+ utils.removeEvent(this.indicator, 'touchstart', this);
1603
+ utils.removeEvent(this.indicator, 'MSPointerDown', this);
1604
+ utils.removeEvent(this.indicator, 'mousedown', this);
1605
+
1606
+ utils.removeEvent(window, 'touchmove', this);
1607
+ utils.removeEvent(window, 'MSPointerMove', this);
1608
+ utils.removeEvent(window, 'mousemove', this);
1609
+
1610
+ utils.removeEvent(window, 'touchend', this);
1611
+ utils.removeEvent(window, 'MSPointerUp', this);
1612
+ utils.removeEvent(window, 'mouseup', this);
1613
+ }
1614
+
1615
+ if ( this.options.defaultScrollbars ) {
1616
+ this.wrapper.parentNode.removeChild(this.wrapper);
1617
+ }
1618
+ },
1619
+
1620
+ _start: function (e) {
1621
+ var point = e.touches ? e.touches[0] : e;
1622
+
1623
+ e.preventDefault();
1624
+ e.stopPropagation();
1625
+
1626
+ this.transitionTime(0);
1627
+
1628
+ this.initiated = true;
1629
+ this.moved = false;
1630
+ this.lastPointX = point.pageX;
1631
+ this.lastPointY = point.pageY;
1632
+
1633
+ this.startTime = utils.getTime();
1634
+
1635
+ utils.addEvent(window, 'touchmove', this);
1636
+ utils.addEvent(window, 'MSPointerMove', this);
1637
+ utils.addEvent(window, 'mousemove', this);
1638
+
1639
+ this.scroller._execEvent('scrollStart');
1640
+ },
1641
+
1642
+ _move: function (e) {
1643
+ var point = e.touches ? e.touches[0] : e,
1644
+ deltaX, deltaY,
1645
+ newX, newY,
1646
+ timestamp = utils.getTime();
1647
+
1648
+ this.moved = true;
1649
+
1650
+ deltaX = point.pageX - this.lastPointX;
1651
+ this.lastPointX = point.pageX;
1652
+
1653
+ deltaY = point.pageY - this.lastPointY;
1654
+ this.lastPointY = point.pageY;
1655
+
1656
+ newX = this.x + deltaX;
1657
+ newY = this.y + deltaY;
1658
+
1659
+ this._pos(newX, newY);
1660
+
1661
+ e.preventDefault();
1662
+ e.stopPropagation();
1663
+ },
1664
+
1665
+ _end: function (e) {
1666
+ if ( !this.initiated ) {
1667
+ return;
1668
+ }
1669
+
1670
+ this.initiated = false;
1671
+
1672
+ e.preventDefault();
1673
+ e.stopPropagation();
1674
+
1675
+ utils.removeEvent(window, 'touchmove', this);
1676
+ utils.removeEvent(window, 'MSPointerMove', this);
1677
+ utils.removeEvent(window, 'mousemove', this);
1678
+
1679
+ if ( this.moved ) {
1680
+ this.scroller._execEvent('scrollEnd');
1681
+ }
1682
+ },
1683
+
1684
+ transitionTime: function (time) {
1685
+ time = time || 0;
1686
+ this.indicatorStyle[utils.style.transitionDuration] = time + 'ms';
1687
+ },
1688
+
1689
+ transitionTimingFunction: function (easing) {
1690
+ this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
1691
+ },
1692
+
1693
+ refresh: function () {
1694
+ this.transitionTime(0);
1695
+
1696
+ if ( this.options.listenX && !this.options.listenY ) {
1697
+ this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
1698
+ } else if ( this.options.listenY && !this.options.listenX ) {
1699
+ this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
1700
+ } else {
1701
+ this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
1702
+ }
1703
+
1704
+ if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
1705
+ utils.addClass(this.wrapper, 'iScrollBothScrollbars');
1706
+ utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
1707
+
1708
+ if ( this.options.defaultScrollbars && this.options.customStyle ) {
1709
+ if ( this.options.listenX ) {
1710
+ this.wrapper.style.right = '8px';
1711
+ } else {
1712
+ this.wrapper.style.bottom = '8px';
1713
+ }
1714
+ }
1715
+ } else {
1716
+ utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
1717
+ utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
1718
+
1719
+ if ( this.options.defaultScrollbars && this.options.customStyle ) {
1720
+ if ( this.options.listenX ) {
1721
+ this.wrapper.style.right = '2px';
1722
+ } else {
1723
+ this.wrapper.style.bottom = '2px';
1724
+ }
1725
+ }
1726
+ }
1727
+
1728
+ var r = this.wrapper.offsetHeight; // force refresh
1729
+
1730
+ if ( this.options.listenX ) {
1731
+ this.wrapperWidth = this.wrapper.clientWidth;
1732
+ if ( this.options.resize ) {
1733
+ this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / this.scroller.scrollerWidth), 8);
1734
+ this.indicatorStyle.width = this.indicatorWidth + 'px';
1735
+ } else {
1736
+ this.indicatorWidth = this.indicator.clientWidth;
1737
+ }
1738
+ this.maxPosX = this.wrapperWidth - this.indicatorWidth;
1739
+ this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
1740
+ }
1741
+
1742
+ if ( this.options.listenY ) {
1743
+ this.wrapperHeight = this.wrapper.clientHeight;
1744
+ if ( this.options.resize ) {
1745
+ this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / this.scroller.scrollerHeight), 8);
1746
+ this.indicatorStyle.height = this.indicatorHeight + 'px';
1747
+ } else {
1748
+ this.indicatorHeight = this.indicator.clientHeight;
1749
+ }
1750
+
1751
+ this.maxPosY = this.wrapperHeight - this.indicatorHeight;
1752
+ this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
1753
+ }
1754
+
1755
+ this.updatePosition();
1756
+ },
1757
+
1758
+ updatePosition: function () {
1759
+ var x = Math.round(this.sizeRatioX * this.scroller.x) || 0,
1760
+ y = Math.round(this.sizeRatioY * this.scroller.y) || 0;
1761
+
1762
+ if ( !this.options.ignoreBoundaries ) {
1763
+ if ( x < 0 ) {
1764
+ x = 0;
1765
+ } else if ( x > this.maxPosX ) {
1766
+ x = this.maxPosX;
1767
+ }
1768
+
1769
+ if ( y < 0 ) {
1770
+ y = 0;
1771
+ } else if ( y > this.maxPosY ) {
1772
+ y = this.maxPosY;
1773
+ }
1774
+ }
1775
+
1776
+ this.x = x;
1777
+ this.y = y;
1778
+
1779
+ if ( this.scroller.options.useTransform ) {
1780
+ this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
1781
+ } else {
1782
+ this.indicatorStyle.left = x + 'px';
1783
+ this.indicatorStyle.top = y + 'px';
1784
+ }
1785
+ },
1786
+
1787
+ _pos: function (x, y) {
1788
+ if ( x < 0 ) {
1789
+ x = 0;
1790
+ } else if ( x > this.maxPosX ) {
1791
+ x = this.maxPosX;
1792
+ }
1793
+
1794
+ if ( y < 0 ) {
1795
+ y = 0;
1796
+ } else if ( y > this.maxPosY ) {
1797
+ y = this.maxPosY;
1798
+ }
1799
+
1800
+ x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
1801
+ y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
1802
+
1803
+ this.scroller.scrollTo(x, y);
1804
+ }
1805
+ };
1806
+
1807
+ IScroll.ease = utils.ease;
1808
+
1809
+ return IScroll;
1810
+
1811
+ })(window, document, Math);