Browse Source

筛选条件的滚动,以及在微信中定位被遮挡的问题

luyanan 7 years ago
parent
commit
f228bf7541
3 changed files with 1181 additions and 42 deletions
  1. 18 5
      css/share.css
  2. 60 37
      e/search.html
  3. 1103 0
      js/public/iscroll.js

+ 18 - 5
css/share.css

@ -313,7 +313,8 @@ ul.mui-table-view>li:last-child:after{background: none;}
313 313
314 314
.infocon.madiaBlock .h3Font{font-size:13px;line-height:22px;color:#666666;}
315 315
/*搜索*/
316
.searchBox{position:fixed;top:0;width:100%;max-width:640px;height:42px;background:#ff9900;overflow:hidden;z-index:3;}
316
.fixedBlock{position:fixed;top:0;width:100%;max-width:640px;z-index:3;}
317
.searchBox{position:relative;height:42px;background:#ff9900;overflow:hidden;}
317 318
.searchBox input.form-control[type='search']{border-color:#ff9900;background:#FFFFFF;vertical-align:middle;text-align: left;width:98%;height: 30px; border-radius:4px; font-size:12px; line-height:16px;margin:6px auto;}
318 319
.searchBox input.form-control[type='search']:focus{outline:none;box-shadow:none;border-color:#ff9900;}
319 320
.searchboxNewT{padding-right:34px;}
@ -322,11 +323,23 @@ ul.mui-table-view>li:last-child:after{background: none;}
322 323
.icon-filter{background-position:0 0;}
323 324
.rightnav .badge{position: absolute;right:4px;top:-1px;padding:1px 4px;background:#FFFFFF;color:#FF9900;}
324 325
/*筛选条件*/
325
.filterCon{padding-left: 65px;}
326
.filterCon .toptit{height: 42px;line-height: 42px;font-size:16px;background: #ff9900;color: #FFFFFF;text-align: center;}
326
.filterCon{position:relative;width: 85%;max-width:435px;left: 65px;height: 100%;}
327
.filterCon .toptit{position: absolute; z-index: 2;top: 0;right: 0;width:100%;height: 42px;
328
		line-height: 42px;font-size:16px;background: #ff9900;color: #FFFFFF;text-align: center;}
327 329
.filterListNew{ padding:14px 14px 8px;}
328 330
.mmenu.mmenu-horizontal ul.filterUl{width: 100%;float: none;}
329 331
.mmenu li{border: none;}
332
#wrapper {position: absolute;z-index: 1;top: 42px;bottom: 40px;right: 0;width:100%;overflow: hidden;}
333
334
#scroller {position: absolute;z-index: 1;width: 100%;
335
	-webkit-transform: translateZ(0);
336
	-moz-transform: translateZ(0);
337
	-ms-transform: translateZ(0);
338
	-o-transform: translateZ(0);
339
	transform: translateZ(0);
340
	-webkit-touch-callout: none;
341
}
342
330 343
.midCon{padding-bottom: 45px;}
331 344
.filterUl{height: 80px;padding:0;margin:14px 0 0;margin-right: -2%; overflow: hidden;}
332 345
.filterUl.filterUlactive{height: auto;}
@ -345,11 +358,11 @@ ul.mui-table-view>li:last-child:after{background: none;}
345 358
.rightbtn .unfoldtr:after{ border:solid transparent;border-bottom-color:#fff;border-width:5px;content:" ";position:absolute;bottom:100%;left:20px;}
346 359
.rightbtn .unfoldtr:before{border:solid transparent;border-bottom-color:#ccc;border-width:7px;content:" ";position:absolute;bottom:100%;left:18px;}
347 360
348
.submitBtn{position: fixed;width:84%;bottom:0;max-width:435px;}
361
.submitBtn{position: absolute;z-index: 2;bottom: 0;right: 0;bottom:0;width:100%;}
349 362
.submitBtn>span{display: inline-block;line-height:40px;color:#FFFFFF;width: 50%;text-align: center;background:#ffb649;}
350 363
.submitBtn>span:last-child{background:#FF7600;}
351 364
/*导航栏 */
352
.tabBox{position: fixed;top:42px;width:100%;max-width:640px;z-index:3;height:40px; }
365
.tabBox{height:40px; }
353 366
.swiper-wrapper-tab .swiper-slide-tab {line-height:40px;font-size: 15px;text-align: center;background: #fff;width:auto;padding:0 5%;}
354 367
.swiper-wrapper-tab .swiper-slide-tab:after { position: absolute; top: auto; right: auto; bottom: 0; left: 0; z-index: 2; display: block; width: 100%; height: 1px; content: ''; background-color: #dcdcdc; -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-transform: scaleY(.5) }
355 368
.swiper-wrapper-tab .swiper-slide-tab.active-tab{color:#ff9900; }

+ 60 - 37
e/search.html

@ -14,33 +14,52 @@
14 14
<script type="text/javascript" src="../js/jquery-1.11.1.js"></script>
15 15
<script type="text/javascript" src="../js/public/swiper.min.js"></script>
16 16
<script type="text/javascript" src="../js/public/shareCom.js"></script>	
17
<script type="text/javascript" src="../js/public/iscroll.js"></script>	
17 18
<script type="text/javascript" src="../js/public/jquery.mmenu.js"></script>	
18 19
<script type="text/javascript">
19 20
	$(function() {
20
		 $("nav#menu").mmenu();
21
		$("nav#menu").mmenu();
22
		var myscrollFil;
23
	    function loaded(){
24
	        setTimeout(function(){
25
	            myscrollFil=new iScroll("wrapper",{
26
	            	mouseWheel: true,
27
					onScrollMove:function(){
28
						myscrollFil.refresh()
29
					}
30
	            });
31
	            
32
	        },100 );
33
	    }
34
	    window.addEventListener("load",loaded,false);
35
		document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
21 36
	});
37
	
22 38
</script>
39

23 40
</head>
24 41

25 42
<body>
26 43
<div class="contentBody2" id="page">
27
	<div class="searchBox">
28
		<form action="" onsubmit="return false;" id="searB" class="searchboxNewT">
29
      		<input type="search" class="form-control" placeholder="请输入关键词" id="searchval" />
30
      	</form>
31
        <a href="#menu" class="rightnav" id="sele">
32
			<div class="serchicon icon-filter"><span class="badge" id="seler"></span></div>筛选
33
		</a>
34
    </div>
35
    <div class="tabBox">
36
		<div class="swiper-container-tab">
37
			<div class="swiper-wrapper swiper-wrapper-tab">
38
				<div class="swiper-slide swiper-slide-tab active-tab" data-tab="1">找专家</div>
39
				<div class="swiper-slide swiper-slide-tab" data-tab="6">找企业</div>
40
				<div class="swiper-slide swiper-slide-tab" data-tab="2">找资源</div>
41
				<div class="swiper-slide swiper-slide-tab" data-tab="4">找专利</div>
42
				<div class="swiper-slide swiper-slide-tab" data-tab="5">找论文</div>
43
				<div class="swiper-slide swiper-slide-tab" data-tab="3">找文</div>
44
	<div class="fixedBlock">
45
		<div class="searchBox">
46
			<form action="" onsubmit="return false;" id="searB" class="searchboxNewT">
47
	      		<input type="search" class="form-control" placeholder="请输入关键词" id="searchval" />
48
	      	</form>
49
	        <a href="#menu" class="rightnav" id="sele">
50
				<div class="serchicon icon-filter"><span class="badge" id="seler"></span></div>筛选
51
			</a>
52
	    </div>
53
	    <div class="tabBox">
54
			<div class="swiper-container-tab">
55
				<div class="swiper-wrapper swiper-wrapper-tab">
56
					<div class="swiper-slide swiper-slide-tab active-tab" data-tab="1">找专家</div>
57
					<div class="swiper-slide swiper-slide-tab" data-tab="6">找企业</div>
58
					<div class="swiper-slide swiper-slide-tab" data-tab="2">找资源</div>
59
					<div class="swiper-slide swiper-slide-tab" data-tab="4">找专利</div>
60
					<div class="swiper-slide swiper-slide-tab" data-tab="5">找文</div>
61
					<div class="swiper-slide swiper-slide-tab" data-tab="3">找文章</div>
62
				</div>
44 63
			</div>
45 64
		</div>
46 65
	</div>
@ -91,24 +110,26 @@
91 110
	<nav id="menu">
92 111
		<div class="filterCon">
93 112
			<h1 class="toptit">“找专家”</h1>
94
			<div class="midCon">
95
				<div class="filterListNew">
96
					<div class="rightbtn">所在城市<span class="spantext">不限</span><em class="foldtr"></em></div>
97
					<ul class="filterUl fourUl" id="address">
98
						
99
			       	</ul>
100
				</div>
101
				<div class="filterListNew">
102
					<div class="rightbtn">学术领域<span class="spantext">不限</span><em class="foldtr"></em></div>
103
					<ul class="filterUl threeUl" id="subject">
104
						
105
			       	</ul>
106
				</div>
107
				<div class="filterListNew">
108
					<div class="rightbtn">行业领域<span class="spantext">不限</span><em class="foldtr"></em></div>
109
					<ul class="filterUl fourUl" id="industry">
110
						
111
			       	</ul>
113
			<div id="wrapper">
114
				<div class="midCon" id="scroller">
115
					<div class="filterListNew">
116
						<div class="rightbtn">所在城市<span class="spantext">不限</span><em class="foldtr"></em></div>
117
						<ul class="filterUl fourUl" id="address">
118
							
119
				       	</ul>
120
					</div>
121
					<div class="filterListNew">
122
						<div class="rightbtn">学术领域<span class="spantext">不限</span><em class="foldtr"></em></div>
123
						<ul class="filterUl threeUl" id="subject">
124
							
125
				       	</ul>
126
					</div>
127
					<div class="filterListNew">
128
						<div class="rightbtn">行业领域<span class="spantext">不限</span><em class="foldtr"></em></div>
129
						<ul class="filterUl threeUl" id="industry">
130
							
131
				       	</ul>
132
					</div>
112 133
				</div>
113 134
			</div>
114 135
			<div class="submitBtn clearfix">
@ -119,7 +140,9 @@
119 140
	</nav>
120 141
</div>
121 142
<script src="../js/search_h5.js" type="text/javascript" charset="utf-8"></script>
122

143
<script type="text/javascript">
144
145
</script>
123 146
</body>
124 147

125 148
</html>

+ 1103 - 0
js/public/iscroll.js

@ -0,0 +1,1103 @@
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
(function(window, doc){
6
var m = Math,
7
	dummyStyle = doc.createElement('div').style,
8
	vendor = (function () {
9
		var vendors = 't,webkitT,MozT,msT,OT'.split(','),
10
			t,
11
			i = 0,
12
			l = vendors.length;
13

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

127
			// Events
128
			onRefresh: null,
129
			onBeforeScrollStart: function (e) { e.preventDefault(); },
130
			onScrollStart: null,
131
			onBeforeScrollMove: null,
132
			onScrollMove: null,
133
			onBeforeScrollEnd: null,
134
			onScrollEnd: null,
135
			onTouchEnd: null,
136
			onDestroy: null,
137
			onZoomStart: null,
138
			onZoom: null,
139
			onZoomEnd: null
140
		};
141

142
		// User defined options
143
		for (i in options) that.options[i] = options[i];
144
		
145
		// Set starting position
146
		that.x = that.options.x;
147
		that.y = that.options.y;
148

149
		// Normalize options
150
		that.options.useTransform = hasTransform && that.options.useTransform;
151
		that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
152
		that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
153
		that.options.zoom = that.options.useTransform && that.options.zoom;
154
		that.options.useTransition = hasTransitionEnd && that.options.useTransition;
155

156
		// Helpers FIX ANDROID BUG!
157
		// translate3d and scale doesn't work together!
158
		// Ignoring 3d ONLY WHEN YOU SET that.options.zoom
159
		if ( that.options.zoom && isAndroid ){
160
			translateZ = '';
161
		}
162
		
163
		// Set some default styles
164
		that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left';
165
		that.scroller.style[transitionDuration] = '0';
166
		that.scroller.style[transformOrigin] = '0 0';
167
		if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)';
168
		
169
		if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ;
170
		else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
171

172
		if (that.options.useTransition) that.options.fixedScrollbar = true;
173

174
		that.refresh();
175

176
		that._bind(RESIZE_EV, window);
177
		that._bind(START_EV);
178
		if (!hasTouch) {
179
			if (that.options.wheelAction != 'none') {
180
				that._bind('DOMMouseScroll');
181
				that._bind('mousewheel');
182
			}
183
		}
184

185
		if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
186
			that._checkDOMChanges();
187
		}, 500);
188
	};
189

190
// Prototype
191
iScroll.prototype = {
192
	enabled: true,
193
	x: 0,
194
	y: 0,
195
	steps: [],
196
	scale: 1,
197
	currPageX: 0, currPageY: 0,
198
	pagesX: [], pagesY: [],
199
	aniTime: null,
200
	wheelZoomCount: 0,
201
	
202
	handleEvent: function (e) {
203
		var that = this;
204
		switch(e.type) {
205
			case START_EV:
206
				if (!hasTouch && e.button !== 0) return;
207
				that._start(e);
208
				break;
209
			case MOVE_EV: that._move(e); break;
210
			case END_EV:
211
			case CANCEL_EV: that._end(e); break;
212
			case RESIZE_EV: that._resize(); break;
213
			case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break;
214
			case TRNEND_EV: that._transitionEnd(e); break;
215
		}
216
	},
217
	
218
	_checkDOMChanges: function () {
219
		if (this.moved || this.zoomed || this.animating ||
220
			(this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return;
221

222
		this.refresh();
223
	},
224
	
225
	_scrollbar: function (dir) {
226
		var that = this,
227
			bar;
228

229
		if (!that[dir + 'Scrollbar']) {
230
			if (that[dir + 'ScrollbarWrapper']) {
231
				if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = '';
232
				that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']);
233
				that[dir + 'ScrollbarWrapper'] = null;
234
				that[dir + 'ScrollbarIndicator'] = null;
235
			}
236

237
			return;
238
		}
239

240
		if (!that[dir + 'ScrollbarWrapper']) {
241
			// Create the scrollbar wrapper
242
			bar = doc.createElement('div');
243

244
			if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase();
245
			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');
246
			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');
247

248
			that.wrapper.appendChild(bar);
249
			that[dir + 'ScrollbarWrapper'] = bar;
250

251
			// Create the scrollbar indicator
252
			bar = doc.createElement('div');
253
			if (!that.options.scrollbarClass) {
254
				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';
255
			}
256
			
257
			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;
258
			if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)';
259

260
			that[dir + 'ScrollbarWrapper'].appendChild(bar);
261
			that[dir + 'ScrollbarIndicator'] = bar;
262
		}
263

264
		if (dir == 'h') {
265
			that.hScrollbarSize = that.hScrollbarWrapper.clientWidth;
266
			that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8);
267
			that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px';
268
			that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize;
269
			that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX;
270
		} else {
271
			that.vScrollbarSize = that.vScrollbarWrapper.clientHeight;
272
			that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8);
273
			that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px';
274
			that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize;
275
			that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY;
276
		}
277

278
		// Reset position
279
		that._scrollbarPos(dir, true);
280
	},
281
	
282
	_resize: function () {
283
		var that = this;
284
		setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0);
285
	},
286
	
287
	_pos: function (x, y) {
288
		if (this.zoomed) return;
289

290
		x = this.hScroll ? x : 0;
291
		y = this.vScroll ? y : 0;
292

293
		if (this.options.useTransform) {
294
			this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ;
295
		} else {
296
			x = m.round(x);
297
			y = m.round(y);
298
			this.scroller.style.left = x + 'px';
299
			this.scroller.style.top = y + 'px';
300
		}
301

302
		this.x = x;
303
		this.y = y;
304

305
		this._scrollbarPos('h');
306
		this._scrollbarPos('v');
307
	},
308

309
	_scrollbarPos: function (dir, hidden) {
310
		var that = this,
311
			pos = dir == 'h' ? that.x : that.y,
312
			size;
313

314
		if (!that[dir + 'Scrollbar']) return;
315

316
		pos = that[dir + 'ScrollbarProp'] * pos;
317

318
		if (pos < 0) {
319
			if (!that.options.fixedScrollbar) {
320
				size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3);
321
				if (size < 8) size = 8;
322
				that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
323
			}
324
			pos = 0;
325
		} else if (pos > that[dir + 'ScrollbarMaxScroll']) {
326
			if (!that.options.fixedScrollbar) {
327
				size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3);
328
				if (size < 8) size = 8;
329
				that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
330
				pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size);
331
			} else {
332
				pos = that[dir + 'ScrollbarMaxScroll'];
333
			}
334
		}
335

336
		that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0';
337
		that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1';
338
		that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ;
339
	},
340
	
341
	_start: function (e) {
342
		var that = this,
343
			point = hasTouch ? e.touches[0] : e,
344
			matrix, x, y,
345
			c1, c2;
346

347
		if (!that.enabled) return;
348

349
		if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
350

351
		if (that.options.useTransition || that.options.zoom) that._transitionTime(0);
352

353
		that.moved = false;
354
		that.animating = false;
355
		that.zoomed = false;
356
		that.distX = 0;
357
		that.distY = 0;
358
		that.absDistX = 0;
359
		that.absDistY = 0;
360
		that.dirX = 0;
361
		that.dirY = 0;
362

363
		// Gesture start
364
		if (that.options.zoom && hasTouch && e.touches.length > 1) {
365
			c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX);
366
			c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY);
367
			that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2);
368

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

372
			if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
373
		}
374

375
		if (that.options.momentum) {
376
			if (that.options.useTransform) {
377
				// Very lame general purpose alternative to CSSMatrix
378
				matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(',');
379
				x = +(matrix[12] || matrix[4]);
380
				y = +(matrix[13] || matrix[5]);
381
			} else {
382
				x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '');
383
				y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '');
384
			}
385
			
386
			if (x != that.x || y != that.y) {
387
				if (that.options.useTransition) that._unbind(TRNEND_EV);
388
				else cancelFrame(that.aniTime);
389
				that.steps = [];
390
				that._pos(x, y);
391
				if (that.options.onScrollEnd) that.options.onScrollEnd.call(that);
392
			}
393
		}
394

395
		that.absStartX = that.x;	// Needed by snap threshold
396
		that.absStartY = that.y;
397

398
		that.startX = that.x;
399
		that.startY = that.y;
400
		that.pointX = point.pageX;
401
		that.pointY = point.pageY;
402

403
		that.startTime = e.timeStamp || Date.now();
404

405
		if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
406

407
		that._bind(MOVE_EV, window);
408
		that._bind(END_EV, window);
409
		that._bind(CANCEL_EV, window);
410
	},
411
	
412
	_move: function (e) {
413
		var that = this,
414
			point = hasTouch ? e.touches[0] : e,
415
			deltaX = point.pageX - that.pointX,
416
			deltaY = point.pageY - that.pointY,
417
			newX = that.x + deltaX,
418
			newY = that.y + deltaY,
419
			c1, c2, scale,
420
			timestamp = e.timeStamp || Date.now();
421

422
		if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
423

424
		// Zoom
425
		if (that.options.zoom && hasTouch && e.touches.length > 1) {
426
			c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX);
427
			c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY);
428
			that.touchesDist = m.sqrt(c1*c1+c2*c2);
429

430
			that.zoomed = true;
431

432
			scale = 1 / that.touchesDistStart * that.touchesDist * this.scale;
433

434
			if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin);
435
			else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale);
436

437
			that.lastScale = scale / this.scale;
438

439
			newX = this.originX - this.originX * that.lastScale + this.x;
440
			newY = this.originY - this.originY * that.lastScale + this.y;
441

442
			this.scroller.style[top] = newY + 'px';
443

444
			if (that.options.onZoom) that.options.onZoom.call(that, e);
445
			return;
446
		}
447

448
		that.pointX = point.pageX;
449
		that.pointY = point.pageY;
450

451
		// Slow down if outside of the boundaries
452
		if (newX > 0 || newX < that.maxScrollX) {
453
			newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
454
		}
455
		if (newY > that.minScrollY || newY < that.maxScrollY) {
456
			newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY;
457
		}
458

459
		that.distX += deltaX;
460
		that.distY += deltaY;
461
		that.absDistX = m.abs(that.distX);
462
		that.absDistY = m.abs(that.distY);
463

464
		if (that.absDistX < 6 && that.absDistY < 6) {
465
			return;
466
		}
467

468
		// Lock direction
469
		if (that.options.lockDirection) {
470
			if (that.absDistX > that.absDistY + 5) {
471
				newY = that.y;
472
				deltaY = 0;
473
			} else if (that.absDistY > that.absDistX + 5) {
474
				newX = that.x;
475
				deltaX = 0;
476
			}
477
		}
478

479
		that.moved = true;
480
		that._pos(newX, newY);
481
		that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
482
		that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
483

484
		if (timestamp - that.startTime > 300) {
485
			that.startTime = timestamp;
486
			that.startX = that.x;
487
			that.startY = that.y;
488
		}
489
		
490
		if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
491
	},
492
	
493
	_end: function (e) {
494
		if (hasTouch && e.touches.length !== 0) return;
495

496
		var that = this,
497
			point = hasTouch ? e.changedTouches[0] : e,
498
			target, ev,
499
			momentumX = { dist:0, time:0 },
500
			momentumY = { dist:0, time:0 },
501
			duration = (e.timeStamp || Date.now()) - that.startTime,
502
			newPosX = that.x,
503
			newPosY = that.y,
504
			distX, distY,
505
			newDuration,
506
			snap,
507
			scale;
508

509
		that._unbind(MOVE_EV, window);
510
		that._unbind(END_EV, window);
511
		that._unbind(CANCEL_EV, window);
512

513
		if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
514

515
		if (that.zoomed) {
516
			scale = that.scale * that.lastScale;
517
			scale = Math.max(that.options.zoomMin, scale);
518
			scale = Math.min(that.options.zoomMax, scale);
519
			that.lastScale = scale / that.scale;
520
			that.scale = scale;
521

522
			that.x = that.originX - that.originX * that.lastScale + that.x;
523
			that.y = that.originY - that.originY * that.lastScale + that.y;
524
			
525
			that.scroller.style[transitionDuration] = '200ms';
526
			that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ;
527
			
528
			that.zoomed = false;
529
			that.refresh();
530

531
			if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
532
			return;
533
		}
534

535
		if (!that.moved) {
536
			if (hasTouch) {
537
				if (that.doubleTapTimer && that.options.zoom) {
538
					// Double tapped
539
					clearTimeout(that.doubleTapTimer);
540
					that.doubleTapTimer = null;
541
					if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
542
					that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1);
543
					if (that.options.onZoomEnd) {
544
						setTimeout(function() {
545
							that.options.onZoomEnd.call(that, e);
546
						}, 200); // 200 is default zoom duration
547
					}
548
				} else if (this.options.handleClick) {
549
					that.doubleTapTimer = setTimeout(function () {
550
						that.doubleTapTimer = null;
551

552
						// Find the last touched element
553
						target = point.target;
554
						while (target.nodeType != 1) target = target.parentNode;
555

556
						if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
557
							ev = doc.createEvent('MouseEvents');
558
							ev.initMouseEvent('click', true, true, e.view, 1,
559
								point.screenX, point.screenY, point.clientX, point.clientY,
560
								e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
561
								0, null);
562
							ev._fake = true;
563
							target.dispatchEvent(ev);
564
						}
565
					}, that.options.zoom ? 250 : 0);
566
				}
567
			}
568

569
			that._resetPos(400);
570

571
			if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
572
			return;
573
		}
574

575
		if (duration < 300 && that.options.momentum) {
576
			momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
577
			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;
578

579
			newPosX = that.x + momentumX.dist;
580
			newPosY = that.y + momentumY.dist;
581

582
			if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
583
			if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
584
		}
585

586
		if (momentumX.dist || momentumY.dist) {
587
			newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
588

589
			// Do we need to snap?
590
			if (that.options.snap) {
591
				distX = newPosX - that.absStartX;
592
				distY = newPosY - that.absStartY;
593
				if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); }
594
				else {
595
					snap = that._snap(newPosX, newPosY);
596
					newPosX = snap.x;
597
					newPosY = snap.y;
598
					newDuration = m.max(snap.time, newDuration);
599
				}
600
			}
601

602
			that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration);
603

604
			if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
605
			return;
606
		}
607

608
		// Do we need to snap?
609
		if (that.options.snap) {
610
			distX = newPosX - that.absStartX;
611
			distY = newPosY - that.absStartY;
612
			if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200);
613
			else {
614
				snap = that._snap(that.x, that.y);
615
				if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time);
616
			}
617

618
			if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
619
			return;
620
		}
621

622
		that._resetPos(200);
623
		if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
624
	},
625
	
626
	_resetPos: function (time) {
627
		var that = this,
628
			resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
629
			resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
630

631
		if (resetX == that.x && resetY == that.y) {
632
			if (that.moved) {
633
				that.moved = false;
634
				if (that.options.onScrollEnd) that.options.onScrollEnd.call(that);		// Execute custom code on scroll end
635
			}
636

637
			if (that.hScrollbar && that.options.hideScrollbar) {
638
				if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms';
639
				that.hScrollbarWrapper.style.opacity = '0';
640
			}
641
			if (that.vScrollbar && that.options.hideScrollbar) {
642
				if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms';
643
				that.vScrollbarWrapper.style.opacity = '0';
644
			}
645

646
			return;
647
		}
648

649
		that.scrollTo(resetX, resetY, time || 0);
650
	},
651

652
	_wheel: function (e) {
653
		var that = this,
654
			wheelDeltaX, wheelDeltaY,
655
			deltaX, deltaY,
656
			deltaScale;
657

658
		if ('wheelDeltaX' in e) {
659
			wheelDeltaX = e.wheelDeltaX / 12;
660
			wheelDeltaY = e.wheelDeltaY / 12;
661
		} else if('wheelDelta' in e) {
662
			wheelDeltaX = wheelDeltaY = e.wheelDelta / 12;
663
		} else if ('detail' in e) {
664
			wheelDeltaX = wheelDeltaY = -e.detail * 3;
665
		} else {
666
			return;
667
		}
668
		
669
		if (that.options.wheelAction == 'zoom') {
670
			deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0));
671
			if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin;
672
			if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax;
673
			
674
			if (deltaScale != that.scale) {
675
				if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e);
676
				that.wheelZoomCount++;
677
				
678
				that.zoom(e.pageX, e.pageY, deltaScale, 400);
679
				
680
				setTimeout(function() {
681
					that.wheelZoomCount--;
682
					if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
683
				}, 400);
684
			}
685
			
686
			return;
687
		}
688
		
689
		deltaX = that.x + wheelDeltaX;
690
		deltaY = that.y + wheelDeltaY;
691

692
		if (deltaX > 0) deltaX = 0;
693
		else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX;
694

695
		if (deltaY > that.minScrollY) deltaY = that.minScrollY;
696
		else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY;
697
    
698
		if (that.maxScrollY < 0) {
699
			that.scrollTo(deltaX, deltaY, 0);
700
		}
701
	},
702
	
703
	_transitionEnd: function (e) {
704
		var that = this;
705

706
		if (e.target != that.scroller) return;
707

708
		that._unbind(TRNEND_EV);
709
		
710
		that._startAni();
711
	},
712

713

714
	/**
715
	*
716
	* Utilities
717
	*
718
	*/
719
	_startAni: function () {
720
		var that = this,
721
			startX = that.x, startY = that.y,
722
			startTime = Date.now(),
723
			step, easeOut,
724
			animate;
725

726
		if (that.animating) return;
727
		
728
		if (!that.steps.length) {
729
			that._resetPos(400);
730
			return;
731
		}
732
		
733
		step = that.steps.shift();
734
		
735
		if (step.x == startX && step.y == startY) step.time = 0;
736

737
		that.animating = true;
738
		that.moved = true;
739
		
740
		if (that.options.useTransition) {
741
			that._transitionTime(step.time);
742
			that._pos(step.x, step.y);
743
			that.animating = false;
744
			if (step.time) that._bind(TRNEND_EV);
745
			else that._resetPos(0);
746
			return;
747
		}
748

749
		animate = function () {
750
			var now = Date.now(),
751
				newX, newY;
752

753
			if (now >= startTime + step.time) {
754
				that._pos(step.x, step.y);
755
				that.animating = false;
756
				if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that);			// Execute custom code on animation end
757
				that._startAni();
758
				return;
759
			}
760

761
			now = (now - startTime) / step.time - 1;
762
			easeOut = m.sqrt(1 - now * now);
763
			newX = (step.x - startX) * easeOut + startX;
764
			newY = (step.y - startY) * easeOut + startY;
765
			that._pos(newX, newY);
766
			if (that.animating) that.aniTime = nextFrame(animate);
767
		};
768

769
		animate();
770
	},
771

772
	_transitionTime: function (time) {
773
		time += 'ms';
774
		this.scroller.style[transitionDuration] = time;
775
		if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time;
776
		if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time;
777
	},
778

779
	_momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
780
		var deceleration = 0.0006,
781
			speed = m.abs(dist) / time,
782
			newDist = (speed * speed) / (2 * deceleration),
783
			newTime = 0, outsideDist = 0;
784

785
		// Proportinally reduce speed if we are outside of the boundaries
786
		if (dist > 0 && newDist > maxDistUpper) {
787
			outsideDist = size / (6 / (newDist / speed * deceleration));
788
			maxDistUpper = maxDistUpper + outsideDist;
789
			speed = speed * maxDistUpper / newDist;
790
			newDist = maxDistUpper;
791
		} else if (dist < 0 && newDist > maxDistLower) {
792
			outsideDist = size / (6 / (newDist / speed * deceleration));
793
			maxDistLower = maxDistLower + outsideDist;
794
			speed = speed * maxDistLower / newDist;
795
			newDist = maxDistLower;
796
		}
797

798
		newDist = newDist * (dist < 0 ? -1 : 1);
799
		newTime = speed / deceleration;
800

801
		return { dist: newDist, time: m.round(newTime) };
802
	},
803

804
	_offset: function (el) {
805
		var left = -el.offsetLeft,
806
			top = -el.offsetTop;
807
			
808
		while (el = el.offsetParent) {
809
			left -= el.offsetLeft;
810
			top -= el.offsetTop;
811
		}
812
		
813
		if (el != this.wrapper) {
814
			left *= this.scale;
815
			top *= this.scale;
816
		}
817

818
		return { left: left, top: top };
819
	},
820

821
	_snap: function (x, y) {
822
		var that = this,
823
			i, l,
824
			page, time,
825
			sizeX, sizeY;
826

827
		// Check page X
828
		page = that.pagesX.length - 1;
829
		for (i=0, l=that.pagesX.length; i<l; i++) {
830
			if (x >= that.pagesX[i]) {
831
				page = i;
832
				break;
833
			}
834
		}
835
		if (page == that.currPageX && page > 0 && that.dirX < 0) page--;
836
		x = that.pagesX[page];
837
		sizeX = m.abs(x - that.pagesX[that.currPageX]);
838
		sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0;
839
		that.currPageX = page;
840

841
		// Check page Y
842
		page = that.pagesY.length-1;
843
		for (i=0; i<page; i++) {
844
			if (y >= that.pagesY[i]) {
845
				page = i;
846
				break;
847
			}
848
		}
849
		if (page == that.currPageY && page > 0 && that.dirY < 0) page--;
850
		y = that.pagesY[page];
851
		sizeY = m.abs(y - that.pagesY[that.currPageY]);
852
		sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0;
853
		that.currPageY = page;
854

855
		// Snap with constant speed (proportional duration)
856
		time = m.round(m.max(sizeX, sizeY)) || 200;
857

858
		return { x: x, y: y, time: time };
859
	},
860

861
	_bind: function (type, el, bubble) {
862
		(el || this.scroller).addEventListener(type, this, !!bubble);
863
	},
864

865
	_unbind: function (type, el, bubble) {
866
		(el || this.scroller).removeEventListener(type, this, !!bubble);
867
	},
868

869

870
	/**
871
	*
872
	* Public methods
873
	*
874
	*/
875
	destroy: function () {
876
		var that = this;
877
		that.scroller.style[transform] = '';
878

879
		// Remove the scrollbars
880
		that.hScrollbar = false;
881
		that.vScrollbar = false;
882
		that._scrollbar('h');
883
		that._scrollbar('v');
884

885
		// Remove the event listeners
886
		that._unbind(RESIZE_EV, window);
887
		that._unbind(START_EV);
888
		that._unbind(MOVE_EV, window);
889
		that._unbind(END_EV, window);
890
		that._unbind(CANCEL_EV, window);
891
		
892
		if (!that.options.hasTouch) {
893
			that._unbind('DOMMouseScroll');
894
			that._unbind('mousewheel');
895
		}
896
		
897
		if (that.options.useTransition) that._unbind(TRNEND_EV);
898
		
899
		if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime);
900
		
901
		if (that.options.onDestroy) that.options.onDestroy.call(that);
902
	},
903

904
	refresh: function () {
905
		var that = this,
906
			offset,
907
			i, l,
908
			els,
909
			pos = 0,
910
			page = 0;
911

912
		if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin;
913
		that.wrapperW = that.wrapper.clientWidth || 1;
914
		that.wrapperH = that.wrapper.clientHeight || 1;
915

916
		that.minScrollY = -that.options.topOffset || 0;
917
		that.scrollerW = m.round(that.scroller.offsetWidth * that.scale);
918
		that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale);
919
		that.maxScrollX = that.wrapperW - that.scrollerW;
920
		that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY;
921
		that.dirX = 0;
922
		that.dirY = 0;
923

924
		if (that.options.onRefresh) that.options.onRefresh.call(that);
925

926
		that.hScroll = that.options.hScroll && that.maxScrollX < 0;
927
		that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
928

929
		that.hScrollbar = that.hScroll && that.options.hScrollbar;
930
		that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH;
931

932
		offset = that._offset(that.wrapper);
933
		that.wrapperOffsetLeft = -offset.left;
934
		that.wrapperOffsetTop = -offset.top;
935

936
		// Prepare snap
937
		if (typeof that.options.snap == 'string') {
938
			that.pagesX = [];
939
			that.pagesY = [];
940
			els = that.scroller.querySelectorAll(that.options.snap);
941
			for (i=0, l=els.length; i<l; i++) {
942
				pos = that._offset(els[i]);
943
				pos.left += that.wrapperOffsetLeft;
944
				pos.top += that.wrapperOffsetTop;
945
				that.pagesX[i] = pos.left < that.maxScrollX ? that.maxScrollX : pos.left * that.scale;
946
				that.pagesY[i] = pos.top < that.maxScrollY ? that.maxScrollY : pos.top * that.scale;
947
			}
948
		} else if (that.options.snap) {
949
			that.pagesX = [];
950
			while (pos >= that.maxScrollX) {
951
				that.pagesX[page] = pos;
952
				pos = pos - that.wrapperW;
953
				page++;
954
			}
955
			if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1];
956

957
			pos = 0;
958
			page = 0;
959
			that.pagesY = [];
960
			while (pos >= that.maxScrollY) {
961
				that.pagesY[page] = pos;
962
				pos = pos - that.wrapperH;
963
				page++;
964
			}
965
			if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1];
966
		}
967

968
		// Prepare the scrollbars
969
		that._scrollbar('h');
970
		that._scrollbar('v');
971

972
		if (!that.zoomed) {
973
			that.scroller.style[transitionDuration] = '0';
974
			that._resetPos(400);
975
		}
976
	},
977

978
	scrollTo: function (x, y, time, relative) {
979
		var that = this,
980
			step = x,
981
			i, l;
982

983
		that.stop();
984

985
		if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
986
		
987
		for (i=0, l=step.length; i<l; i++) {
988
			if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
989
			that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
990
		}
991

992
		that._startAni();
993
	},
994

995
	scrollToElement: function (el, time) {
996
		var that = this, pos;
997
		el = el.nodeType ? el : that.scroller.querySelector(el);
998
		if (!el) return;
999

1000
		pos = that._offset(el);
1001
		pos.left += that.wrapperOffsetLeft;
1002
		pos.top += that.wrapperOffsetTop;
1003

1004
		pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
1005
		pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
1006
		time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
1007

1008
		that.scrollTo(pos.left, pos.top, time);
1009
	},
1010

1011
	scrollToPage: function (pageX, pageY, time) {
1012
		var that = this, x, y;
1013
		
1014
		time = time === undefined ? 400 : time;
1015

1016
		if (that.options.onScrollStart) that.options.onScrollStart.call(that);
1017

1018
		if (that.options.snap) {
1019
			pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX;
1020
			pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY;
1021

1022
			pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX;
1023
			pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY;
1024

1025
			that.currPageX = pageX;
1026
			that.currPageY = pageY;
1027
			x = that.pagesX[pageX];
1028
			y = that.pagesY[pageY];
1029
		} else {
1030
			x = -that.wrapperW * pageX;
1031
			y = -that.wrapperH * pageY;
1032
			if (x < that.maxScrollX) x = that.maxScrollX;
1033
			if (y < that.maxScrollY) y = that.maxScrollY;
1034
		}
1035

1036
		that.scrollTo(x, y, time);
1037
	},
1038

1039
	disable: function () {
1040
		this.stop();
1041
		this._resetPos(0);
1042
		this.enabled = false;
1043

1044
		// If disabled after touchstart we make sure that there are no left over events
1045
		this._unbind(MOVE_EV, window);
1046
		this._unbind(END_EV, window);
1047
		this._unbind(CANCEL_EV, window);
1048
	},
1049
	
1050
	enable: function () {
1051
		this.enabled = true;
1052
	},
1053
	
1054
	stop: function () {
1055
		if (this.options.useTransition) this._unbind(TRNEND_EV);
1056
		else cancelFrame(this.aniTime);
1057
		this.steps = [];
1058
		this.moved = false;
1059
		this.animating = false;
1060
	},
1061
	
1062
	zoom: function (x, y, scale, time) {
1063
		var that = this,
1064
			relScale = scale / that.scale;
1065

1066
		if (!that.options.useTransform) return;
1067

1068
		that.zoomed = true;
1069
		time = time === undefined ? 200 : time;
1070
		x = x - that.wrapperOffsetLeft - that.x;
1071
		y = y - that.wrapperOffsetTop - that.y;
1072
		that.x = x - x * relScale + that.x;
1073
		that.y = y - y * relScale + that.y;
1074

1075
		that.scale = scale;
1076
		that.refresh();
1077

1078
		that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x;
1079
		that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
1080

1081
		that.scroller.style[transitionDuration] = time + 'ms';
1082
		that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ;
1083
		that.zoomed = false;
1084
	},
1085
	
1086
	isReady: function () {
1087
		return !this.moved && !this.zoomed && !this.animating;
1088
	}
1089
};
1090

1091
function prefixStyle (style) {
1092
	if ( vendor === '' ) return style;
1093

1094
	style = style.charAt(0).toUpperCase() + style.substr(1);
1095
	return vendor + style;
1096
}
1097

1098
dummyStyle = null;	// for the sake of it
1099

1100
if (typeof exports !== 'undefined') exports.iScroll = iScroll;
1101
else window.iScroll = iScroll;
1102

1103
})(window, document);