wangyj18 9 gadi atpakaļ
vecāks
revīzija
4c37237ca3
2 mainītis faili ar 1115 papildinājumiem un 0 dzēšanām
  1. 1 0
      display-server/.project
  2. 1114 0
      display-server/web/res/js/base/iscroll/iscroll.js

+ 1 - 0
display-server/.project

@ -13,5 +13,6 @@
13 13
	</buildSpec>
14 14
	<natures>
15 15
		<nature>org.eclipse.jdt.core.javanature</nature>
16
		<nature>com.sysdeo.eclipse.tomcat.tomcatnature</nature>
16 17
	</natures>
17 18
</projectDescription>

+ 1114 - 0
display-server/web/res/js/base/iscroll/iscroll.js

@ -0,0 +1,1114 @@
1
/*!
2
 * iScroll v4.2.5 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org
3
 * Released under MIT license, http://cubiq.org/license
4
 */
5
define(function(require, exports, module){
6
	var doc = document;
7
	var m = Math,
8
	dummyStyle = doc.createElement('div').style,
9
	vendor = (function () {
10
		var vendors = 't,webkitT,MozT,msT,OT'.split(','),
11
			t,
12
			i = 0,
13
			l = vendors.length;
14

15
		for ( ; i < l; i++ ) {
16
			t = vendors[i] + 'ransform';
17
			if ( t in dummyStyle ) {
18
				return vendors[i].substr(0, vendors[i].length - 1);
19
			}
20
		}
21

22
		return false;
23
	})(),
24
	cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '',
25

26
	// Style properties
27
	transform = prefixStyle('transform'),
28
	transitionProperty = prefixStyle('transitionProperty'),
29
	transitionDuration = prefixStyle('transitionDuration'),
30
	transformOrigin = prefixStyle('transformOrigin'),
31
	transitionTimingFunction = prefixStyle('transitionTimingFunction'),
32
	transitionDelay = prefixStyle('transitionDelay'),
33

34
    // Browser capabilities
35
	isAndroid = (/android/gi).test(navigator.appVersion),
36
	isIDevice = (/iphone|ipad/gi).test(navigator.appVersion),
37
	isTouchPad = (/hp-tablet/gi).test(navigator.appVersion),
38

39
    has3d = prefixStyle('perspective') in dummyStyle,
40
    hasTouch = 'ontouchstart' in window && !isTouchPad,
41
    hasTransform = vendor !== false,
42
    hasTransitionEnd = prefixStyle('transition') in dummyStyle,
43

44
	RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
45
	START_EV = hasTouch ? 'touchstart' : 'mousedown',
46
	MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
47
	END_EV = hasTouch ? 'touchend' : 'mouseup',
48
	CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
49
	TRNEND_EV = (function () {
50
		if ( vendor === false ) return false;
51

52
		var transitionEnd = {
53
				''			: 'transitionend',
54
				'webkit'	: 'webkitTransitionEnd',
55
				'Moz'		: 'transitionend',
56
				'O'			: 'otransitionend',
57
				'ms'		: 'MSTransitionEnd'
58
			};
59

60
		return transitionEnd[vendor];
61
	})(),
62

63
	nextFrame = (function() {
64
		return window.requestAnimationFrame ||
65
			window.webkitRequestAnimationFrame ||
66
			window.mozRequestAnimationFrame ||
67
			window.oRequestAnimationFrame ||
68
			window.msRequestAnimationFrame ||
69
			function(callback) { return setTimeout(callback, 1); };
70
	})(),
71
	cancelFrame = (function () {
72
		return window.cancelRequestAnimationFrame ||
73
			window.webkitCancelAnimationFrame ||
74
			window.webkitCancelRequestAnimationFrame ||
75
			window.mozCancelRequestAnimationFrame ||
76
			window.oCancelRequestAnimationFrame ||
77
			window.msCancelRequestAnimationFrame ||
78
			clearTimeout;
79
	})(),
80

81
	// Helpers
82
	translateZ = has3d ? ' translateZ(0)' : '',
83

84
	// Constructor
85
	iScroll = function (el, options) {
86
		var that = this,
87
			i;
88

89
		that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
90
		that.wrapper.style.overflow = 'hidden';
91
		that.scroller = that.wrapper.children[0];
92

93
		// Default options
94
		that.options = {
95
			hScroll: true,
96
			vScroll: true,
97
			x: 0,
98
			y: 0,
99
			bounce: true,
100
			bounceLock: false,
101
			momentum: true,
102
			lockDirection: true,
103
			useTransform: true,
104
			useTransition: false,
105
			topOffset: 0,
106
			checkDOMChanges: false,		// Experimental
107
			handleClick: true,
108

109
			// Scrollbar
110
			hScrollbar: true,
111
			vScrollbar: true,
112
			fixedScrollbar: isAndroid,
113
			hideScrollbar: isIDevice,
114
			fadeScrollbar: isIDevice && has3d,
115
			scrollbarClass: '',
116

117
			// Zoom
118
			zoom: false,
119
			zoomMin: 1,
120
			zoomMax: 4,
121
			doubleTapZoom: 2,
122
			wheelAction: 'scroll',
123

124
			// Snap
125
			snap: false,
126
			snapThreshold: 1,
127

128
			// Events
129
			onRefresh: null,
130
			//阻止默认事件
131
			//onBeforeScrollStart: function (e) { e.preventDefault(); },
132
			onBeforeScrollStart: function (e) {
133
				var target = e.target;
134
				while (target.nodeType != 1){
135
					target = target.parentNode;
136
				}
137
				if (target.tagName != "SELECT" && target.tagName != "INPUT" && target.tagName != "TEXTAREA")
138
				e.preventDefault();
139
			},
140
			onScrollStart: null,
141
			onBeforeScrollMove: null,
142
			onScrollMove: null,
143
			onBeforeScrollEnd: null,
144
			onScrollEnd: null,
145
			onTouchEnd: null,
146
			onDestroy: null,
147
			onZoomStart: null,
148
			onZoom: null,
149
			onZoomEnd: null
150
		};
151

152
		// User defined options
153
		for (i in options) that.options[i] = options[i];
154

155
		// Set starting position
156
		that.x = that.options.x;
157
		that.y = that.options.y;
158

159
		// Normalize options
160
		that.options.useTransform = hasTransform && that.options.useTransform;
161
		that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
162
		that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
163
		that.options.zoom = that.options.useTransform && that.options.zoom;
164
		that.options.useTransition = hasTransitionEnd && that.options.useTransition;
165

166
		// Helpers FIX ANDROID BUG!
167
		// translate3d and scale doesn't work together!
168
		// Ignoring 3d ONLY WHEN YOU SET that.options.zoom
169
		if ( that.options.zoom && isAndroid ){
170
			translateZ = '';
171
		}
172

173
		// Set some default styles
174
		that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left';
175
		that.scroller.style[transitionDuration] = '0';
176
		that.scroller.style[transformOrigin] = '0 0';
177
		if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)';
178

179
		if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ;
180
		else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
181

182
		if (that.options.useTransition) that.options.fixedScrollbar = true;
183

184
		that.refresh();
185

186
		that._bind(RESIZE_EV, window);
187
		that._bind(START_EV);
188
		if (!hasTouch) {
189
			if (that.options.wheelAction != 'none') {
190
				that._bind('DOMMouseScroll');
191
				that._bind('mousewheel');
192
			}
193
		}
194

195
		if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
196
			that._checkDOMChanges();
197
		}, 500);
198
	};
199

200
// Prototype
201
iScroll.prototype = {
202
	enabled: true,
203
	x: 0,
204
	y: 0,
205
	steps: [],
206
	scale: 1,
207
	currPageX: 0, currPageY: 0,
208
	pagesX: [], pagesY: [],
209
	aniTime: null,
210
	wheelZoomCount: 0,
211

212
	handleEvent: function (e) {
213
		var that = this;
214
		switch(e.type) {
215
			case START_EV:
216
				if (!hasTouch && e.button !== 0) return;
217
				that._start(e);
218
				break;
219
			case MOVE_EV: that._move(e); break;
220
			case END_EV:
221
			case CANCEL_EV: that._end(e); break;
222
			case RESIZE_EV: that._resize(); break;
223
			case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break;
224
			case TRNEND_EV: that._transitionEnd(e); break;
225
		}
226
	},
227

228
	_checkDOMChanges: function () {
229
		if (this.moved || this.zoomed || this.animating ||
230
			(this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return;
231

232
		this.refresh();
233
	},
234

235
	_scrollbar: function (dir) {
236
		var that = this,
237
			bar;
238

239
		if (!that[dir + 'Scrollbar']) {
240
			if (that[dir + 'ScrollbarWrapper']) {
241
				if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = '';
242
				that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']);
243
				that[dir + 'ScrollbarWrapper'] = null;
244
				that[dir + 'ScrollbarIndicator'] = null;
245
			}
246

247
			return;
248
		}
249

250
		if (!that[dir + 'ScrollbarWrapper']) {
251
			// Create the scrollbar wrapper
252
			bar = doc.createElement('div');
253

254
			if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase();
255
			else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px');
256

257
			bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1');
258

259
			that.wrapper.appendChild(bar);
260
			that[dir + 'ScrollbarWrapper'] = bar;
261

262
			// Create the scrollbar indicator
263
			bar = doc.createElement('div');
264
			if (!that.options.scrollbarClass) {
265
				bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px';
266
			}
267
			bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ;
268
			if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)';
269

270
			that[dir + 'ScrollbarWrapper'].appendChild(bar);
271
			that[dir + 'ScrollbarIndicator'] = bar;
272
		}
273

274
		if (dir == 'h') {
275
			that.hScrollbarSize = that.hScrollbarWrapper.clientWidth;
276
			that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8);
277
			that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px';
278
			that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize;
279
			that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX;
280
		} else {
281
			that.vScrollbarSize = that.vScrollbarWrapper.clientHeight;
282
			that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8);
283
			that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px';
284
			that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize;
285
			that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY;
286
		}
287

288
		// Reset position
289
		that._scrollbarPos(dir, true);
290
	},
291

292
	_resize: function () {
293
		var that = this;
294
		setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0);
295
	},
296

297
	_pos: function (x, y) {
298
		if (this.zoomed) return;
299

300
		x = this.hScroll ? x : 0;
301
		y = this.vScroll ? y : 0;
302

303
		if (this.options.useTransform) {
304
			this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ;
305
		} else {
306
			x = m.round(x);
307
			y = m.round(y);
308
			this.scroller.style.left = x + 'px';
309
			this.scroller.style.top = y + 'px';
310
		}
311

312
		this.x = x;
313
		this.y = y;
314

315
		this._scrollbarPos('h');
316
		this._scrollbarPos('v');
317
	},
318

319
	_scrollbarPos: function (dir, hidden) {
320
		var that = this,
321
			pos = dir == 'h' ? that.x : that.y,
322
			size;
323

324
		if (!that[dir + 'Scrollbar']) return;
325

326
		pos = that[dir + 'ScrollbarProp'] * pos;
327

328
		if (pos < 0) {
329
			if (!that.options.fixedScrollbar) {
330
				size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3);
331
				if (size < 8) size = 8;
332
				that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
333
			}
334
			pos = 0;
335
		} else if (pos > that[dir + 'ScrollbarMaxScroll']) {
336
			if (!that.options.fixedScrollbar) {
337
				size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3);
338
				if (size < 8) size = 8;
339
				that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
340
				pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size);
341
			} else {
342
				pos = that[dir + 'ScrollbarMaxScroll'];
343
			}
344
		}
345

346
		that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0';
347
		that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1';
348
		that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ;
349
	},
350

351
	_start: function (e) {
352
		var that = this,
353
			point = hasTouch ? e.touches[0] : e,
354
			matrix, x, y,
355
			c1, c2;
356

357
		if (!that.enabled) return;
358

359
		if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
360

361
		if (that.options.useTransition || that.options.zoom) that._transitionTime(0);
362

363
		that.moved = false;
364
		that.animating = false;
365
		that.zoomed = false;
366
		that.distX = 0;
367
		that.distY = 0;
368
		that.absDistX = 0;
369
		that.absDistY = 0;
370
		that.dirX = 0;
371
		that.dirY = 0;
372

373
		// Gesture start
374
		if (that.options.zoom && hasTouch && e.touches.length > 1) {
375
			c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX);
376
			c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY);
377
			that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2);
378

379
			that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x;
380
			that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y;
381

382
			if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
383
		}
384

385
		if (that.options.momentum) {
386
			if (that.options.useTransform) {
387
				// Very lame general purpose alternative to CSSMatrix
388
				matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(',');
389
				x = +(matrix[12] || matrix[4]);
390
				y = +(matrix[13] || matrix[5]);
391
			} else {
392
				x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '');
393
				y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '');
394
			}
395

396
			if (x != that.x || y != that.y) {
397
				if (that.options.useTransition) that._unbind(TRNEND_EV);
398
				else cancelFrame(that.aniTime);
399
				that.steps = [];
400
				that._pos(x, y);
401
				if (that.options.onScrollEnd) that.options.onScrollEnd.call(that);
402
			}
403
		}
404

405
		that.absStartX = that.x;	// Needed by snap threshold
406
		that.absStartY = that.y;
407

408
		that.startX = that.x;
409
		that.startY = that.y;
410
		that.pointX = point.pageX;
411
		that.pointY = point.pageY;
412

413
		that.startTime = e.timeStamp || Date.now();
414

415
		if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
416

417
		that._bind(MOVE_EV, window);
418
		that._bind(END_EV, window);
419
		that._bind(CANCEL_EV, window);
420
	},
421

422
	_move: function (e) {
423
		var that = this,
424
			point = hasTouch ? e.touches[0] : e,
425
			deltaX = point.pageX - that.pointX,
426
			deltaY = point.pageY - that.pointY,
427
			newX = that.x + deltaX,
428
			newY = that.y + deltaY,
429
			c1, c2, scale,
430
			timestamp = e.timeStamp || Date.now();
431

432
		if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
433

434
		// Zoom
435
		if (that.options.zoom && hasTouch && e.touches.length > 1) {
436
			c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX);
437
			c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY);
438
			that.touchesDist = m.sqrt(c1*c1+c2*c2);
439

440
			that.zoomed = true;
441

442
			scale = 1 / that.touchesDistStart * that.touchesDist * this.scale;
443

444
			if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin);
445
			else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale);
446

447
			that.lastScale = scale / this.scale;
448

449
			newX = this.originX - this.originX * that.lastScale + this.x;
450
			newY = this.originY - this.originY * that.lastScale + this.y;
451

452
			this.scroller.style[transform] = 'translate(' + newX + 'px,' + newY + 'px) scale(' + scale + ')' + translateZ;
453

454
			if (that.options.onZoom) that.options.onZoom.call(that, e);
455
			return;
456
		}
457

458
		that.pointX = point.pageX;
459
		that.pointY = point.pageY;
460

461
		// Slow down if outside of the boundaries
462
		if (newX > 0 || newX < that.maxScrollX) {
463
			newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
464
		}
465
		if (newY > that.minScrollY || newY < that.maxScrollY) {
466
			newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY;
467
		}
468

469
		that.distX += deltaX;
470
		that.distY += deltaY;
471
		that.absDistX = m.abs(that.distX);
472
		that.absDistY = m.abs(that.distY);
473

474
		if (that.absDistX < 6 && that.absDistY < 6) {
475
			return;
476
		}
477

478
		// Lock direction
479
		if (that.options.lockDirection) {
480
			if (that.absDistX > that.absDistY + 5) {
481
				newY = that.y;
482
				deltaY = 0;
483
			} else if (that.absDistY > that.absDistX + 5) {
484
				newX = that.x;
485
				deltaX = 0;
486
			}
487
		}
488

489
		that.moved = true;
490
		that._pos(newX, newY);
491
		that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
492
		that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
493

494
		if (timestamp - that.startTime > 300) {
495
			that.startTime = timestamp;
496
			that.startX = that.x;
497
			that.startY = that.y;
498
		}
499

500
		if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
501
	},
502

503
	_end: function (e) {
504
		if (hasTouch && e.touches.length !== 0) return;
505

506
		var that = this,
507
			point = hasTouch ? e.changedTouches[0] : e,
508
			target, ev,
509
			momentumX = { dist:0, time:0 },
510
			momentumY = { dist:0, time:0 },
511
			duration = (e.timeStamp || Date.now()) - that.startTime,
512
			newPosX = that.x,
513
			newPosY = that.y,
514
			distX, distY,
515
			newDuration,
516
			snap,
517
			scale;
518

519
		that._unbind(MOVE_EV, window);
520
		that._unbind(END_EV, window);
521
		that._unbind(CANCEL_EV, window);
522

523
		if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
524

525
		if (that.zoomed) {
526
			scale = that.scale * that.lastScale;
527
			scale = Math.max(that.options.zoomMin, scale);
528
			scale = Math.min(that.options.zoomMax, scale);
529
			that.lastScale = scale / that.scale;
530
			that.scale = scale;
531

532
			that.x = that.originX - that.originX * that.lastScale + that.x;
533
			that.y = that.originY - that.originY * that.lastScale + that.y;
534

535
			that.scroller.style[transitionDuration] = '200ms';
536
			that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ;
537

538
			that.zoomed = false;
539
			that.refresh();
540

541
			if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
542
			return;
543
		}
544

545
		if (!that.moved) {
546
			if (hasTouch) {
547
				if (that.doubleTapTimer && that.options.zoom) {
548
					// Double tapped
549
					clearTimeout(that.doubleTapTimer);
550
					that.doubleTapTimer = null;
551
					if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
552
					that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1);
553
					if (that.options.onZoomEnd) {
554
						setTimeout(function() {
555
							that.options.onZoomEnd.call(that, e);
556
						}, 200); // 200 is default zoom duration
557
					}
558
				} else if (this.options.handleClick) {
559
					that.doubleTapTimer = setTimeout(function () {
560
						that.doubleTapTimer = null;
561

562
						// Find the last touched element
563
						target = point.target;
564
						while (target.nodeType != 1) target = target.parentNode;
565

566
						if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
567
							ev = doc.createEvent('MouseEvents');
568
							ev.initMouseEvent('click', true, true, e.view, 1,
569
								point.screenX, point.screenY, point.clientX, point.clientY,
570
								e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
571
								0, null);
572
							ev._fake = true;
573
							target.dispatchEvent(ev);
574
						}
575
					}, that.options.zoom ? 250 : 0);
576
				}
577
			}
578

579
			that._resetPos(400);
580

581
			if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
582
			return;
583
		}
584

585
		if (duration < 300 && that.options.momentum) {
586
			momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
587
			momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY;
588

589
			newPosX = that.x + momentumX.dist;
590
			newPosY = that.y + momentumY.dist;
591

592
			if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
593
			if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
594
		}
595

596
		if (momentumX.dist || momentumY.dist) {
597
			newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
598

599
			// Do we need to snap?
600
			if (that.options.snap) {
601
				distX = newPosX - that.absStartX;
602
				distY = newPosY - that.absStartY;
603
				if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); }
604
				else {
605
					snap = that._snap(newPosX, newPosY);
606
					newPosX = snap.x;
607
					newPosY = snap.y;
608
					newDuration = m.max(snap.time, newDuration);
609
				}
610
			}
611

612
			that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration);
613

614
			if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
615
			return;
616
		}
617

618
		// Do we need to snap?
619
		if (that.options.snap) {
620
			distX = newPosX - that.absStartX;
621
			distY = newPosY - that.absStartY;
622
			if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200);
623
			else {
624
				snap = that._snap(that.x, that.y);
625
				if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time);
626
			}
627

628
			if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
629
			return;
630
		}
631

632
		that._resetPos(200);
633
		if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
634
	},
635

636
	_resetPos: function (time) {
637
		var that = this,
638
			resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
639
			resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
640

641
		if (resetX == that.x && resetY == that.y) {
642
			if (that.moved) {
643
				that.moved = false;
644
				if (that.options.onScrollEnd) that.options.onScrollEnd.call(that);		// Execute custom code on scroll end
645
			}
646

647
			if (that.hScrollbar && that.options.hideScrollbar) {
648
				if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms';
649
				that.hScrollbarWrapper.style.opacity = '0';
650
			}
651
			if (that.vScrollbar && that.options.hideScrollbar) {
652
				if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms';
653
				that.vScrollbarWrapper.style.opacity = '0';
654
			}
655

656
			return;
657
		}
658

659
		that.scrollTo(resetX, resetY, time || 0);
660
	},
661

662
	_wheel: function (e) {
663
		var that = this,
664
			wheelDeltaX, wheelDeltaY,
665
			deltaX, deltaY,
666
			deltaScale;
667

668
		if ('wheelDeltaX' in e) {
669
			wheelDeltaX = e.wheelDeltaX / 12;
670
			wheelDeltaY = e.wheelDeltaY / 12;
671
		} else if('wheelDelta' in e) {
672
			wheelDeltaX = wheelDeltaY = e.wheelDelta / 12;
673
		} else if ('detail' in e) {
674
			wheelDeltaX = wheelDeltaY = -e.detail * 3;
675
		} else {
676
			return;
677
		}
678

679
		if (that.options.wheelAction == 'zoom') {
680
			deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0));
681
			if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin;
682
			if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax;
683

684
			if (deltaScale != that.scale) {
685
				if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e);
686
				that.wheelZoomCount++;
687

688
				that.zoom(e.pageX, e.pageY, deltaScale, 400);
689

690
				setTimeout(function() {
691
					that.wheelZoomCount--;
692
					if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
693
				}, 400);
694
			}
695

696
			return;
697
		}
698

699
		deltaX = that.x + wheelDeltaX;
700
		deltaY = that.y + wheelDeltaY;
701

702
		if (deltaX > 0) deltaX = 0;
703
		else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX;
704

705
		if (deltaY > that.minScrollY) deltaY = that.minScrollY;
706
		else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY;
707

708
		if (that.maxScrollY < 0) {
709
			that.scrollTo(deltaX, deltaY, 0);
710
		}
711
	},
712

713
	_transitionEnd: function (e) {
714
		var that = this;
715

716
		if (e.target != that.scroller) return;
717

718
		that._unbind(TRNEND_EV);
719

720
		that._startAni();
721
	},
722

723

724
	/**
725
	*
726
	* Utilities
727
	*
728
	*/
729
	_startAni: function () {
730
		var that = this,
731
			startX = that.x, startY = that.y,
732
			startTime = Date.now(),
733
			step, easeOut,
734
			animate;
735

736
		if (that.animating) return;
737

738
		if (!that.steps.length) {
739
			that._resetPos(400);
740
			return;
741
		}
742

743
		step = that.steps.shift();
744

745
		if (step.x == startX && step.y == startY) step.time = 0;
746

747
		that.animating = true;
748
		that.moved = true;
749

750
		if (that.options.useTransition) {
751
			that._transitionTime(step.time);
752
			that._pos(step.x, step.y);
753
			that.animating = false;
754
			if (step.time) that._bind(TRNEND_EV);
755
			else that._resetPos(0);
756
			return;
757
		}
758

759
		animate = function () {
760
			var now = Date.now(),
761
				newX, newY;
762

763
			if (now >= startTime + step.time) {
764
				that._pos(step.x, step.y);
765
				that.animating = false;
766
				if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that);			// Execute custom code on animation end
767
				that._startAni();
768
				return;
769
			}
770

771
			now = (now - startTime) / step.time - 1;
772
			easeOut = m.sqrt(1 - now * now);
773
			newX = (step.x - startX) * easeOut + startX;
774
			newY = (step.y - startY) * easeOut + startY;
775
			that._pos(newX, newY);
776
			if (that.animating) that.aniTime = nextFrame(animate);
777
		};
778

779
		animate();
780
	},
781

782
	_transitionTime: function (time) {
783
		time += 'ms';
784
		this.scroller.style[transitionDuration] = time;
785
		if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time;
786
		if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time;
787
	},
788

789
	_momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
790
		var deceleration = 0.0006,
791
			speed = m.abs(dist) / time,
792
			newDist = (speed * speed) / (2 * deceleration),
793
			newTime = 0, outsideDist = 0;
794

795
		// Proportinally reduce speed if we are outside of the boundaries
796
		if (dist > 0 && newDist > maxDistUpper) {
797
			outsideDist = size / (6 / (newDist / speed * deceleration));
798
			maxDistUpper = maxDistUpper + outsideDist;
799
			speed = speed * maxDistUpper / newDist;
800
			newDist = maxDistUpper;
801
		} else if (dist < 0 && newDist > maxDistLower) {
802
			outsideDist = size / (6 / (newDist / speed * deceleration));
803
			maxDistLower = maxDistLower + outsideDist;
804
			speed = speed * maxDistLower / newDist;
805
			newDist = maxDistLower;
806
		}
807

808
		newDist = newDist * (dist < 0 ? -1 : 1);
809
		newTime = speed / deceleration;
810

811
		return { dist: newDist, time: m.round(newTime) };
812
	},
813

814
	_offset: function (el) {
815
		var left = -el.offsetLeft,
816
			top = -el.offsetTop;
817

818
		while (el = el.offsetParent) {
819
			left -= el.offsetLeft;
820
			top -= el.offsetTop;
821
		}
822

823
		if (el != this.wrapper) {
824
			left *= this.scale;
825
			top *= this.scale;
826
		}
827

828
		return { left: left, top: top };
829
	},
830

831
	_snap: function (x, y) {
832
		var that = this,
833
			i, l,
834
			page, time,
835
			sizeX, sizeY;
836

837
		// Check page X
838
		page = that.pagesX.length - 1;
839
		for (i=0, l=that.pagesX.length; i<l; i++) {
840
			if (x >= that.pagesX[i]) {
841
				page = i;
842
				break;
843
			}
844
		}
845
		if (page == that.currPageX && page > 0 && that.dirX < 0) page--;
846
		x = that.pagesX[page];
847
		sizeX = m.abs(x - that.pagesX[that.currPageX]);
848
		sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0;
849
		that.currPageX = page;
850

851
		// Check page Y
852
		page = that.pagesY.length-1;
853
		for (i=0; i<page; i++) {
854
			if (y >= that.pagesY[i]) {
855
				page = i;
856
				break;
857
			}
858
		}
859
		if (page == that.currPageY && page > 0 && that.dirY < 0) page--;
860
		y = that.pagesY[page];
861
		sizeY = m.abs(y - that.pagesY[that.currPageY]);
862
		sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0;
863
		that.currPageY = page;
864

865
		// Snap with constant speed (proportional duration)
866
		time = m.round(m.max(sizeX, sizeY)) || 200;
867

868
		return { x: x, y: y, time: time };
869
	},
870

871
	_bind: function (type, el, bubble) {
872
		(el || this.scroller).addEventListener(type, this, !!bubble);
873
	},
874

875
	_unbind: function (type, el, bubble) {
876
		(el || this.scroller).removeEventListener(type, this, !!bubble);
877
	},
878

879

880
	/**
881
	*
882
	* Public methods
883
	*
884
	*/
885
	destroy: function () {
886
		var that = this;
887

888
		that.scroller.style[transform] = '';
889

890
		// Remove the scrollbars
891
		that.hScrollbar = false;
892
		that.vScrollbar = false;
893
		that._scrollbar('h');
894
		that._scrollbar('v');
895

896
		// Remove the event listeners
897
		that._unbind(RESIZE_EV, window);
898
		that._unbind(START_EV);
899
		that._unbind(MOVE_EV, window);
900
		that._unbind(END_EV, window);
901
		that._unbind(CANCEL_EV, window);
902

903
		if (!that.options.hasTouch) {
904
			that._unbind('DOMMouseScroll');
905
			that._unbind('mousewheel');
906
		}
907

908
		if (that.options.useTransition) that._unbind(TRNEND_EV);
909

910
		if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime);
911

912
		if (that.options.onDestroy) that.options.onDestroy.call(that);
913
	},
914

915
	refresh: function () {
916
		var that = this,
917
			offset,
918
			i, l,
919
			els,
920
			pos = 0,
921
			page = 0;
922

923
		if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin;
924
		that.wrapperW = that.wrapper.clientWidth || 1;
925
		that.wrapperH = that.wrapper.clientHeight || 1;
926

927
		that.minScrollY = -that.options.topOffset || 0;
928
		that.scrollerW = m.round(that.scroller.offsetWidth * that.scale);
929
		that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale);
930
		that.maxScrollX = that.wrapperW - that.scrollerW;
931
		that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY;
932
		that.dirX = 0;
933
		that.dirY = 0;
934

935
		if (that.options.onRefresh) that.options.onRefresh.call(that);
936

937
		that.hScroll = that.options.hScroll && that.maxScrollX < 0;
938
		that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
939

940
		that.hScrollbar = that.hScroll && that.options.hScrollbar;
941
		that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH;
942

943
		offset = that._offset(that.wrapper);
944
		that.wrapperOffsetLeft = -offset.left;
945
		that.wrapperOffsetTop = -offset.top;
946

947
		// Prepare snap
948
		if (typeof that.options.snap == 'string') {
949
			that.pagesX = [];
950
			that.pagesY = [];
951
			els = that.scroller.querySelectorAll(that.options.snap);
952
			for (i=0, l=els.length; i<l; i++) {
953
				pos = that._offset(els[i]);
954
				pos.left += that.wrapperOffsetLeft;
955
				pos.top += that.wrapperOffsetTop;
956
				that.pagesX[i] = pos.left < that.maxScrollX ? that.maxScrollX : pos.left * that.scale;
957
				that.pagesY[i] = pos.top < that.maxScrollY ? that.maxScrollY : pos.top * that.scale;
958
			}
959
		} else if (that.options.snap) {
960
			that.pagesX = [];
961
			while (pos >= that.maxScrollX) {
962
				that.pagesX[page] = pos;
963
				pos = pos - that.wrapperW;
964
				page++;
965
			}
966
			if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1];
967

968
			pos = 0;
969
			page = 0;
970
			that.pagesY = [];
971
			while (pos >= that.maxScrollY) {
972
				that.pagesY[page] = pos;
973
				pos = pos - that.wrapperH;
974
				page++;
975
			}
976
			if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1];
977
		}
978

979
		// Prepare the scrollbars
980
		that._scrollbar('h');
981
		that._scrollbar('v');
982

983
		if (!that.zoomed) {
984
			that.scroller.style[transitionDuration] = '0';
985
			that._resetPos(400);
986
		}
987
	},
988

989
	scrollTo: function (x, y, time, relative) {
990
		var that = this,
991
			step = x,
992
			i, l;
993

994
		that.stop();
995

996
		if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
997

998
		for (i=0, l=step.length; i<l; i++) {
999
			if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
1000
			that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
1001
		}
1002

1003
		that._startAni();
1004
	},
1005

1006
	scrollToElement: function (el, time) {
1007
		var that = this, pos;
1008
		el = el.nodeType ? el : that.scroller.querySelector(el);
1009
		if (!el) return;
1010

1011
		pos = that._offset(el);
1012
		pos.left += that.wrapperOffsetLeft;
1013
		pos.top += that.wrapperOffsetTop;
1014

1015
		pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
1016
		pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
1017
		time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
1018

1019
		that.scrollTo(pos.left, pos.top, time);
1020
	},
1021

1022
	scrollToPage: function (pageX, pageY, time) {
1023
		var that = this, x, y;
1024

1025
		time = time === undefined ? 400 : time;
1026

1027
		if (that.options.onScrollStart) that.options.onScrollStart.call(that);
1028

1029
		if (that.options.snap) {
1030
			pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX;
1031
			pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY;
1032

1033
			pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX;
1034
			pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY;
1035

1036
			that.currPageX = pageX;
1037
			that.currPageY = pageY;
1038
			x = that.pagesX[pageX];
1039
			y = that.pagesY[pageY];
1040
		} else {
1041
			x = -that.wrapperW * pageX;
1042
			y = -that.wrapperH * pageY;
1043
			if (x < that.maxScrollX) x = that.maxScrollX;
1044
			if (y < that.maxScrollY) y = that.maxScrollY;
1045
		}
1046

1047
		that.scrollTo(x, y, time);
1048
	},
1049

1050
	disable: function () {
1051
		this.stop();
1052
		this._resetPos(0);
1053
		this.enabled = false;
1054

1055
		// If disabled after touchstart we make sure that there are no left over events
1056
		this._unbind(MOVE_EV, window);
1057
		this._unbind(END_EV, window);
1058
		this._unbind(CANCEL_EV, window);
1059
	},
1060

1061
	enable: function () {
1062
		this.enabled = true;
1063
	},
1064

1065
	stop: function () {
1066
		if (this.options.useTransition) this._unbind(TRNEND_EV);
1067
		else cancelFrame(this.aniTime);
1068
		this.steps = [];
1069
		this.moved = false;
1070
		this.animating = false;
1071
	},
1072

1073
	zoom: function (x, y, scale, time) {
1074
		var that = this,
1075
			relScale = scale / that.scale;
1076

1077
		if (!that.options.useTransform) return;
1078

1079
		that.zoomed = true;
1080
		time = time === undefined ? 200 : time;
1081
		x = x - that.wrapperOffsetLeft - that.x;
1082
		y = y - that.wrapperOffsetTop - that.y;
1083
		that.x = x - x * relScale + that.x;
1084
		that.y = y - y * relScale + that.y;
1085

1086
		that.scale = scale;
1087
		that.refresh();
1088

1089
		that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x;
1090
		that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
1091

1092
		that.scroller.style[transitionDuration] = time + 'ms';
1093
		that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ;
1094
		that.zoomed = false;
1095
	},
1096

1097
	isReady: function () {
1098
		return !this.moved && !this.zoomed && !this.animating;
1099
	}
1100
};
1101

1102
function prefixStyle (style) {
1103
	if ( vendor === '' ) return style;
1104

1105
	style = style.charAt(0).toUpperCase() + style.substr(1);
1106
	return vendor + style;
1107
}
1108

1109
dummyStyle = null;	// for the sake of it
1110

1111
/*if (typeof exports !== 'undefined') exports.iScroll = iScroll;
1112
else window.iScroll = iScroll;*/
1113
module.exports = iScroll;
1114
});