Subversion Repositories SmartDukaan

Rev

Rev 20685 | Details | Compare with Previous | Last modification | View Log | RSS feed

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