avalon-rails 1.4.6.0.20150915133100 → 1.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/lib/avalon-rails/version.rb +1 -1
- data/vendor/assets/javascripts/avalon.js +83 -76
- data/vendor/assets/javascripts/avalon.min.js +3 -3
- data/vendor/assets/javascripts/avalon.mobile.js +604 -229
- data/vendor/assets/javascripts/avalon.mobile.min.js +3 -3
- data/vendor/assets/javascripts/avalon.mobile.old.js +622 -243
- data/vendor/assets/javascripts/avalon.mobile.shim.js +592 -227
- data/vendor/assets/javascripts/avalon.modern.js +65 -62
- data/vendor/assets/javascripts/avalon.modern.min.js +2 -2
- data/vendor/assets/javascripts/avalon.modern.shim.js +53 -60
- data/vendor/assets/javascripts/avalon.shim.js +70 -74
- metadata +7 -7
@@ -5,7 +5,7 @@
|
|
5
5
|
http://weibo.com/jslouvre/
|
6
6
|
|
7
7
|
Released under the MIT license
|
8
|
-
avalon.mobile.shim.js 1.
|
8
|
+
avalon.mobile.shim.js 1.4.7 built in 2015.10.13
|
9
9
|
==================================================*/
|
10
10
|
(function(global, factory) {
|
11
11
|
|
@@ -59,9 +59,6 @@ function createMap() {
|
|
59
59
|
}
|
60
60
|
|
61
61
|
var subscribers = "$" + expose
|
62
|
-
var otherRequire = window.require
|
63
|
-
var otherDefine = window.define
|
64
|
-
var innerRequire
|
65
62
|
var stopRepeatAssign = false
|
66
63
|
var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach
|
67
64
|
var rcomplexType = /^(?:object|array)$/
|
@@ -172,12 +169,12 @@ avalon.nextTick = new function () {// jshint ignore:line
|
|
172
169
|
/*********************************************************************
|
173
170
|
* avalon的静态方法定义区 *
|
174
171
|
**********************************************************************/
|
175
|
-
avalon.init = function(el) {
|
172
|
+
avalon.init = function (el) {
|
176
173
|
this[0] = this.element = el
|
177
174
|
}
|
178
175
|
avalon.fn = avalon.prototype = avalon.init.prototype
|
179
176
|
|
180
|
-
avalon.type = function(obj) { //取得目标的类型
|
177
|
+
avalon.type = function (obj) { //取得目标的类型
|
181
178
|
if (obj == null) {
|
182
179
|
return String(obj)
|
183
180
|
}
|
@@ -187,25 +184,25 @@ avalon.type = function(obj) { //取得目标的类型
|
|
187
184
|
typeof obj
|
188
185
|
}
|
189
186
|
|
190
|
-
var isFunction = function(fn) {
|
187
|
+
var isFunction = function (fn) {
|
191
188
|
return serialize.call(fn) === "[object Function]"
|
192
189
|
}
|
193
190
|
|
194
191
|
avalon.isFunction = isFunction
|
195
192
|
|
196
|
-
avalon.isWindow = function(obj) {
|
193
|
+
avalon.isWindow = function (obj) {
|
197
194
|
return rwindow.test(serialize.call(obj))
|
198
195
|
}
|
199
196
|
|
200
197
|
/*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/
|
201
198
|
|
202
|
-
avalon.isPlainObject = function(obj) {
|
199
|
+
avalon.isPlainObject = function (obj) {
|
203
200
|
// 简单的 typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通不过
|
204
201
|
return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto
|
205
202
|
}
|
206
203
|
|
207
204
|
//与jQuery.extend方法,可用于浅拷贝,深拷贝
|
208
|
-
avalon.mix = avalon.fn.mix = function() {
|
205
|
+
avalon.mix = avalon.fn.mix = function () {
|
209
206
|
var options, name, src, copy, copyIsArray, clone,
|
210
207
|
target = arguments[0] || {},
|
211
208
|
i = 1,
|
@@ -267,15 +264,15 @@ function _number(a, len) { //用于模拟slice, splice的效果
|
|
267
264
|
avalon.mix({
|
268
265
|
rword: rword,
|
269
266
|
subscribers: subscribers,
|
270
|
-
version: 1.
|
267
|
+
version: 1.47,
|
271
268
|
ui: {},
|
272
269
|
log: log,
|
273
|
-
slice: function(nodes, start, end) {
|
270
|
+
slice: function (nodes, start, end) {
|
274
271
|
return aslice.call(nodes, start, end)
|
275
272
|
},
|
276
273
|
noop: noop,
|
277
274
|
/*如果不用Error对象封装一下,str在控制台下可能会乱码*/
|
278
|
-
error: function(str, e) {
|
275
|
+
error: function (str, e) {
|
279
276
|
throw new (e || Error)(str)// jshint ignore:line
|
280
277
|
},
|
281
278
|
/*将一个以空格或逗号隔开的字符串或数组,转换成一个键值都为1的对象*/
|
@@ -290,7 +287,7 @@ avalon.mix({
|
|
290
287
|
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
|
291
288
|
avalon.range(0)
|
292
289
|
=> []*/
|
293
|
-
range: function(start, end, step) { // 用于生成整数数组
|
290
|
+
range: function (start, end, step) { // 用于生成整数数组
|
294
291
|
step || (step = 1)
|
295
292
|
if (end == null) {
|
296
293
|
end = start || 0
|
@@ -307,34 +304,30 @@ avalon.mix({
|
|
307
304
|
},
|
308
305
|
eventHooks: {},
|
309
306
|
/*绑定事件*/
|
310
|
-
bind: function(el, type, fn, phase) {
|
307
|
+
bind: function (el, type, fn, phase) {
|
311
308
|
var hooks = avalon.eventHooks
|
312
309
|
var hook = hooks[type]
|
313
310
|
if (typeof hook === "object") {
|
314
|
-
type = hook.type
|
315
|
-
|
316
|
-
|
317
|
-
}
|
311
|
+
type = hook.type || type
|
312
|
+
phase = hook.phase || !!phase
|
313
|
+
fn = hook.fn ? hook.fn(el, fn) : fn
|
318
314
|
}
|
319
|
-
|
320
|
-
el.addEventListener(type, fn, !!phase)
|
315
|
+
el.addEventListener(type, fn, phase)
|
321
316
|
return fn
|
322
317
|
},
|
323
318
|
/*卸载事件*/
|
324
|
-
unbind: function(el, type, fn, phase) {
|
319
|
+
unbind: function (el, type, fn, phase) {
|
325
320
|
var hooks = avalon.eventHooks
|
326
321
|
var hook = hooks[type]
|
327
322
|
var callback = fn || noop
|
328
323
|
if (typeof hook === "object") {
|
329
|
-
type = hook.type
|
330
|
-
|
331
|
-
fn = hook.deel(el, type, fn, false)
|
332
|
-
}
|
324
|
+
type = hook.type || type
|
325
|
+
phase = hook.phase || !!phase
|
333
326
|
}
|
334
|
-
el.removeEventListener(type, callback,
|
327
|
+
el.removeEventListener(type, callback, phase)
|
335
328
|
},
|
336
329
|
/*读写删除元素节点的样式*/
|
337
|
-
css: function(node, name, value) {
|
330
|
+
css: function (node, name, value) {
|
338
331
|
if (node instanceof avalon) {
|
339
332
|
node = node[0]
|
340
333
|
}
|
@@ -361,7 +354,7 @@ avalon.mix({
|
|
361
354
|
}
|
362
355
|
},
|
363
356
|
/*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/
|
364
|
-
each: function(obj, fn) {
|
357
|
+
each: function (obj, fn) {
|
365
358
|
if (obj) { //排除null, undefined
|
366
359
|
var i = 0
|
367
360
|
if (isArrayLike(obj)) {
|
@@ -379,12 +372,12 @@ avalon.mix({
|
|
379
372
|
}
|
380
373
|
},
|
381
374
|
//收集元素的data-{{prefix}}-*属性,并转换为对象
|
382
|
-
getWidgetData: function(elem, prefix) {
|
375
|
+
getWidgetData: function (elem, prefix) {
|
383
376
|
var raw = avalon(elem).data()
|
384
377
|
var result = {}
|
385
378
|
for (var i in raw) {
|
386
379
|
if (i.indexOf(prefix) === 0) {
|
387
|
-
result[i.replace(prefix, "").replace(/\w/, function(a) {
|
380
|
+
result[i.replace(prefix, "").replace(/\w/, function (a) {
|
388
381
|
return a.toLowerCase()
|
389
382
|
})] = raw[i]
|
390
383
|
}
|
@@ -393,17 +386,17 @@ avalon.mix({
|
|
393
386
|
},
|
394
387
|
Array: {
|
395
388
|
/*只有当前数组不存在此元素时只添加它*/
|
396
|
-
ensure: function(target, item) {
|
389
|
+
ensure: function (target, item) {
|
397
390
|
if (target.indexOf(item) === -1) {
|
398
391
|
return target.push(item)
|
399
392
|
}
|
400
393
|
},
|
401
394
|
/*移除数组中指定位置的元素,返回布尔表示成功与否*/
|
402
|
-
removeAt: function(target, index) {
|
395
|
+
removeAt: function (target, index) {
|
403
396
|
return !!target.splice(index, 1).length
|
404
397
|
},
|
405
398
|
/*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/
|
406
|
-
remove: function(target, item) {
|
399
|
+
remove: function (target, item) {
|
407
400
|
var index = target.indexOf(item)
|
408
401
|
if (~index)
|
409
402
|
return avalon.Array.removeAt(target, index)
|
@@ -635,7 +628,7 @@ if (DOC.onmousewheel === void 0) {
|
|
635
628
|
chrome wheel deltaY 下100 上-100 */
|
636
629
|
eventHooks.mousewheel = {
|
637
630
|
type: "wheel",
|
638
|
-
|
631
|
+
fn: function (elem, fn) {
|
639
632
|
return function (e) {
|
640
633
|
e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120
|
641
634
|
e.wheelDeltaX = 0
|
@@ -675,11 +668,7 @@ function escapeRegExp(target) {
|
|
675
668
|
}
|
676
669
|
|
677
670
|
var plugins = {
|
678
|
-
|
679
|
-
var flag = innerRequire && builtin
|
680
|
-
window.require = flag ? innerRequire : otherRequire
|
681
|
-
window.define = flag ? innerRequire.define : otherDefine
|
682
|
-
},
|
671
|
+
|
683
672
|
interpolate: function (array) {
|
684
673
|
openTag = array[0]
|
685
674
|
closeTag = array[1]
|
@@ -919,7 +908,7 @@ function modelFactory(source, $special, $model) {
|
|
919
908
|
return name in this.$model
|
920
909
|
})
|
921
910
|
/* jshint ignore:end */
|
922
|
-
for (
|
911
|
+
for (i in EventBus) {
|
923
912
|
hideProperty($vmodel, i, EventBus[i])
|
924
913
|
}
|
925
914
|
|
@@ -1527,7 +1516,7 @@ function injectDisposeQueue(data, list) {
|
|
1527
1516
|
var elem = data.element
|
1528
1517
|
if (!data.uuid) {
|
1529
1518
|
if (elem.nodeType !== 1) {
|
1530
|
-
data.uuid = data.type + (
|
1519
|
+
data.uuid = data.type + getUid(elem.parentNode)+ "-"+ (++disposeCount)
|
1531
1520
|
} else {
|
1532
1521
|
data.uuid = data.name + "-" + getUid(elem)
|
1533
1522
|
}
|
@@ -2642,7 +2631,7 @@ function scanExpr(str) {
|
|
2642
2631
|
}
|
2643
2632
|
value = str.slice(start, stop)
|
2644
2633
|
if (value) { //处理{{ }}插值表达式
|
2645
|
-
tokens.push(getToken(value
|
2634
|
+
tokens.push(getToken(value))
|
2646
2635
|
}
|
2647
2636
|
start = stop + closeTag.length
|
2648
2637
|
} while (1)
|
@@ -2657,11 +2646,10 @@ function scanExpr(str) {
|
|
2657
2646
|
return tokens
|
2658
2647
|
}
|
2659
2648
|
|
2660
|
-
function scanText(textNode, vmodels
|
2661
|
-
var bindings = []
|
2662
|
-
tokens = scanExpr(textNode.data)
|
2649
|
+
function scanText(textNode, vmodels) {
|
2650
|
+
var bindings = [], tokens = scanExpr(textNode.data)
|
2663
2651
|
if (tokens.length) {
|
2664
|
-
for (var i = 0; token = tokens[i++]; ) {
|
2652
|
+
for (var i = 0, token; token = tokens[i++]; ) {
|
2665
2653
|
var node = DOC.createTextNode(token.value) //将文本转换为文本节点,并替换原来的文本节点
|
2666
2654
|
if (token.expr) {
|
2667
2655
|
token.value = token.value.replace(roneTime, function () {
|
@@ -2674,7 +2662,6 @@ function scanText(textNode, vmodels, index) {
|
|
2674
2662
|
token.type = "html"
|
2675
2663
|
return ""
|
2676
2664
|
})// jshint ignore:line
|
2677
|
-
token.pos = index * 1000 + i
|
2678
2665
|
bindings.push(token) //收集带有插值表达式的文本
|
2679
2666
|
}
|
2680
2667
|
avalonFragment.appendChild(node)
|
@@ -3138,7 +3125,6 @@ var TimerID, ribbon = []
|
|
3138
3125
|
}
|
3139
3126
|
|
3140
3127
|
var watchValueInTimer = noop
|
3141
|
-
var rmsinput = /text|password|hidden/
|
3142
3128
|
new function() { // jshint ignore:line
|
3143
3129
|
try { //#272 IE9-IE11, firefox
|
3144
3130
|
var setters = {}
|
@@ -3146,7 +3132,7 @@ new function() { // jshint ignore:line
|
|
3146
3132
|
var bproto = HTMLTextAreaElement.prototype
|
3147
3133
|
function newSetter(value) { // jshint ignore:line
|
3148
3134
|
setters[this.tagName].call(this, value)
|
3149
|
-
if (
|
3135
|
+
if (!this.msFocus && this.avalonSetter && this.oldValue !== value) {
|
3150
3136
|
this.avalonSetter()
|
3151
3137
|
}
|
3152
3138
|
}
|
@@ -3200,7 +3186,7 @@ duplexBinding.INPUT = function(element, evaluator, data) {
|
|
3200
3186
|
}
|
3201
3187
|
//当model变化时,它就会改变value的值
|
3202
3188
|
data.handler = function() {
|
3203
|
-
var val = data.pipe(evaluator(), data, "set")
|
3189
|
+
var val = data.pipe(evaluator(), data, "set")
|
3204
3190
|
if (val !== element.oldValue) {
|
3205
3191
|
element.value = element.oldValue = val
|
3206
3192
|
}
|
@@ -3263,10 +3249,11 @@ duplexBinding.INPUT = function(element, evaluator, data) {
|
|
3263
3249
|
bound("blur", function() {
|
3264
3250
|
element.msFocus = false
|
3265
3251
|
})
|
3266
|
-
if (
|
3267
|
-
|
3252
|
+
if (!/^(file|button|reset|submit|checkbox|radio)$/.test(element.type)) {
|
3253
|
+
element.avalonSetter = updateVModel //#765
|
3254
|
+
watchValueInTimer(function () {
|
3268
3255
|
if (root.contains(element)) {
|
3269
|
-
if (!element.msFocus &&
|
3256
|
+
if (!element.msFocus && data.oldValue !== element.value) {
|
3270
3257
|
updateVModel()
|
3271
3258
|
}
|
3272
3259
|
} else if (!element.msRetain) {
|
@@ -3274,11 +3261,9 @@ duplexBinding.INPUT = function(element, evaluator, data) {
|
|
3274
3261
|
}
|
3275
3262
|
})
|
3276
3263
|
}
|
3277
|
-
|
3278
|
-
element.avalonSetter = updateVModel
|
3279
3264
|
}
|
3280
3265
|
|
3281
|
-
|
3266
|
+
|
3282
3267
|
avalon.injectBinding(data)
|
3283
3268
|
callback.call(element, element.value)
|
3284
3269
|
}
|
@@ -3490,6 +3475,9 @@ bindingHandlers.repeat = function (data, vmodels) {
|
|
3490
3475
|
}
|
3491
3476
|
}
|
3492
3477
|
|
3478
|
+
data.handler = noop
|
3479
|
+
avalon.injectBinding(data)
|
3480
|
+
|
3493
3481
|
var elem = data.element
|
3494
3482
|
if (elem.nodeType === 1) {
|
3495
3483
|
elem.removeAttribute(data.name)
|
@@ -3558,7 +3546,12 @@ bindingExecutors.repeat = function (method, pos, el) {
|
|
3558
3546
|
|
3559
3547
|
if (data.xtype === "array") {
|
3560
3548
|
if (old.length === neo.length) {
|
3561
|
-
|
3549
|
+
if (old !== neo && old.length > 0) {
|
3550
|
+
bindingExecutors.repeat.call(this, 'clear', pos, el)
|
3551
|
+
}
|
3552
|
+
else {
|
3553
|
+
return
|
3554
|
+
}
|
3562
3555
|
}
|
3563
3556
|
method = "add"
|
3564
3557
|
pos = 0
|
@@ -4066,9 +4059,9 @@ var filters = avalon.filters = {
|
|
4066
4059
|
$filter: function(val) {
|
4067
4060
|
for (var i = 1, n = arguments.length; i < n; i++) {
|
4068
4061
|
var array = arguments[i]
|
4069
|
-
var fn = avalon.filters[array
|
4062
|
+
var fn = avalon.filters[array[0]]
|
4070
4063
|
if (typeof fn === "function") {
|
4071
|
-
var arr = [val].concat(array)
|
4064
|
+
var arr = [val].concat(array.slice(1))
|
4072
4065
|
val = fn.apply(null, arr)
|
4073
4066
|
}
|
4074
4067
|
}
|
@@ -4384,183 +4377,555 @@ new function () {
|
|
4384
4377
|
})
|
4385
4378
|
}
|
4386
4379
|
|
4387
|
-
new function() {// jshint ignore:line
|
4388
|
-
var
|
4389
|
-
|
4390
|
-
|
4391
|
-
|
4392
|
-
|
4393
|
-
|
4394
|
-
|
4395
|
-
|
4396
|
-
var touchTimeout = null
|
4397
|
-
var longTapTimeout = null
|
4398
|
-
var dragDistance = 30
|
4399
|
-
var clickDuration = 750 //小于750ms是点击,长于它是长按或拖动
|
4400
|
-
var me = bindingHandlers.on
|
4401
|
-
|
4402
|
-
if (IEtouch) {
|
4403
|
-
touchNames = ["pointerdown", "pointermove", "pointerup", "pointercancel"]
|
4404
|
-
}
|
4405
|
-
if (IEMStouch) {
|
4406
|
-
touchNames = ["MSPointerDown", "MSPointerMove", "MSPointerUp", "MSPointerCancel"]
|
4407
|
-
}
|
4408
|
-
function isPrimaryTouch(event){
|
4409
|
-
return (event.pointerType === 'touch' || event.pointerType === event.MSPOINTER_TYPE_TOUCH) && event.isPrimary
|
4410
|
-
}
|
4411
|
-
|
4412
|
-
function isPointerEventType(e, type){
|
4413
|
-
return (e.type === 'pointer'+type || e.type.toLowerCase() === 'mspointer'+type)
|
4414
|
-
}
|
4415
|
-
|
4416
|
-
//判定滑动方向
|
4417
|
-
function swipeDirection(x1, x2, y1, y2) {
|
4418
|
-
return Math.abs(x1 - x2) >=
|
4419
|
-
Math.abs(y1 - y2) ? (x1 - x2 > 0 ? "left" : "right") : (y1 - y2 > 0 ? "up" : "down")
|
4420
|
-
}
|
4421
|
-
|
4422
|
-
function fireEvent(el, name, detail) {
|
4423
|
-
var event = document.createEvent("Events")
|
4424
|
-
event.initEvent(name, true, true)
|
4425
|
-
if (detail) {
|
4426
|
-
event.detail = detail
|
4427
|
-
}
|
4428
|
-
el.dispatchEvent(event)
|
4429
|
-
}
|
4430
|
-
|
4431
|
-
function onMouse(event) {
|
4432
|
-
var target = event.target,
|
4433
|
-
element = touchProxy.element
|
4434
|
-
|
4435
|
-
if (element && element !== target) {
|
4436
|
-
var type = target.type || '',
|
4437
|
-
targetTag = target.tagName.toLowerCase(),
|
4438
|
-
elementTag = element.tagName.toLowerCase()
|
4439
|
-
// 通过手机的“前往”提交表单时不可禁止默认行为;通过label focus input时也不可以阻止默认行为
|
4440
|
-
if ((targetTag === 'input' && elementTag === "label") || type === 'submit') {
|
4441
|
-
return false
|
4380
|
+
new function () { // jshint ignore:line
|
4381
|
+
var ua = navigator.userAgent.toLowerCase()
|
4382
|
+
//http://stackoverflow.com/questions/9038625/detect-if-device-is-ios
|
4383
|
+
function iOSversion() {
|
4384
|
+
//https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html
|
4385
|
+
//http://mp.weixin.qq.com/s?__biz=MzA3MDQ4MzQzMg==&mid=256900619&idx=1&sn=b29f84cff0b8d7b9742e5d8b3cd8f218&scene=1&srcid=1009F9l4gh9nZ7rcQJEhmf7Q#rd
|
4386
|
+
if (/iPad|iPhone|iPod/i.test(ua) && !window.MSStream) {
|
4387
|
+
if ("backdropFilter" in document.documentElement.style) {
|
4388
|
+
return 9
|
4442
4389
|
}
|
4443
|
-
if (
|
4444
|
-
|
4445
|
-
}
|
4446
|
-
|
4447
|
-
|
4448
|
-
|
4449
|
-
|
4450
|
-
|
4451
|
-
|
4452
|
-
|
4453
|
-
|
4454
|
-
|
4455
|
-
|
4456
|
-
|
4457
|
-
|
4458
|
-
|
4459
|
-
|
4460
|
-
|
4461
|
-
delta = now - (touchProxy.last || now)
|
4462
|
-
|
4463
|
-
if (_isPointerType && !isPrimaryTouch(event)) return
|
4464
|
-
if (touchProxy.x1 || touchProxy.y1) {
|
4465
|
-
touchProxy.x1 = undefined
|
4466
|
-
touchProxy.y1 = undefined
|
4467
|
-
}
|
4468
|
-
if (delta > 0 && delta <= 250) {
|
4469
|
-
touchProxy.isDoubleTap = true
|
4470
|
-
}
|
4471
|
-
touchProxy.x = firstTouch.pageX
|
4472
|
-
touchProxy.y = firstTouch.pageY
|
4473
|
-
touchProxy.mx = 0
|
4474
|
-
touchProxy.my = 0
|
4475
|
-
touchProxy.last = now
|
4476
|
-
touchProxy.element = element
|
4477
|
-
|
4478
|
-
longTapTimeout = setTimeout(function() {
|
4479
|
-
longTapTimeout = null
|
4480
|
-
fireEvent(element, "hold")
|
4481
|
-
fireEvent(element, "longtap")
|
4482
|
-
touchProxy = {}
|
4483
|
-
}, clickDuration)
|
4484
|
-
return true
|
4390
|
+
if (!!window.indexedDB) {
|
4391
|
+
return 8
|
4392
|
+
}
|
4393
|
+
if (!!window.SpeechSynthesisUtterance) {
|
4394
|
+
return 7
|
4395
|
+
}
|
4396
|
+
if (!!window.webkitAudioContext) {
|
4397
|
+
return 6
|
4398
|
+
}
|
4399
|
+
if (!!window.matchMedia) {
|
4400
|
+
return 5
|
4401
|
+
}
|
4402
|
+
if (!!window.history && 'pushState' in window.history) {
|
4403
|
+
return 4
|
4404
|
+
}
|
4405
|
+
return 3
|
4406
|
+
}
|
4407
|
+
return NaN
|
4485
4408
|
}
|
4486
|
-
|
4487
|
-
|
4488
|
-
|
4489
|
-
|
4490
|
-
|
4491
|
-
|
4492
|
-
|
4493
|
-
|
4494
|
-
|
4495
|
-
|
4496
|
-
|
4497
|
-
|
4498
|
-
|
4499
|
-
|
4500
|
-
|
4501
|
-
|
4502
|
-
|
4503
|
-
|
4504
|
-
|
4505
|
-
|
4506
|
-
|
4507
|
-
|
4508
|
-
|
4509
|
-
|
4510
|
-
|
4511
|
-
|
4512
|
-
|
4513
|
-
|
4514
|
-
|
4515
|
-
|
4516
|
-
|
4517
|
-
|
4518
|
-
|
4519
|
-
|
4520
|
-
|
4521
|
-
|
4522
|
-
|
4523
|
-
|
4524
|
-
|
4525
|
-
|
4526
|
-
|
4527
|
-
|
4528
|
-
|
4529
|
-
|
4530
|
-
|
4531
|
-
|
4532
|
-
|
4533
|
-
|
4534
|
-
|
4535
|
-
|
4536
|
-
|
4537
|
-
|
4538
|
-
|
4409
|
+
|
4410
|
+
var deviceIsAndroid = ua.indexOf('android') > 0
|
4411
|
+
var deviceIsIOS = iOSversion()
|
4412
|
+
var gestureHooks = avalon.gestureHooks = {
|
4413
|
+
pointers: {},
|
4414
|
+
start: function (event, callback) {
|
4415
|
+
|
4416
|
+
//touches是当前屏幕上所有触摸点的列表;
|
4417
|
+
//targetTouches是当前对象上所有触摸点的列表;
|
4418
|
+
//changedTouches是涉及当前事件的触摸点的列表。
|
4419
|
+
for (var i = 0; i < event.changedTouches.length; i++) {
|
4420
|
+
var touch = event.changedTouches[i]
|
4421
|
+
var pointer = {
|
4422
|
+
startTouch: mixTouchAttr({}, touch),
|
4423
|
+
startTime: Date.now(),
|
4424
|
+
status: 'tapping',
|
4425
|
+
element: event.target
|
4426
|
+
}
|
4427
|
+
gestureHooks.pointers[touch.identifier] = pointer;
|
4428
|
+
callback(pointer, touch)
|
4429
|
+
|
4430
|
+
}
|
4431
|
+
},
|
4432
|
+
move: function (event, callback) {
|
4433
|
+
for (var i = 0; i < event.changedTouches.length; i++) {
|
4434
|
+
var touch = event.changedTouches[i]
|
4435
|
+
var pointer = gestureHooks.pointers[touch.identifier]
|
4436
|
+
if (!pointer) {
|
4437
|
+
return
|
4438
|
+
}
|
4439
|
+
|
4440
|
+
if (!("lastTouch" in pointer)) {
|
4441
|
+
pointer.lastTouch = pointer.startTouch
|
4442
|
+
pointer.lastTime = pointer.startTime
|
4443
|
+
pointer.deltaX = pointer.deltaY = pointer.duration = pointer.distance = 0
|
4444
|
+
}
|
4445
|
+
|
4446
|
+
var time = Date.now() - pointer.lastTime
|
4447
|
+
|
4448
|
+
if (time > 0) {
|
4449
|
+
|
4450
|
+
var RECORD_DURATION = 70
|
4451
|
+
if (time > RECORD_DURATION) {
|
4452
|
+
time = RECORD_DURATION
|
4453
|
+
}
|
4454
|
+
if (pointer.duration + time > RECORD_DURATION) {
|
4455
|
+
pointer.duration = RECORD_DURATION - time
|
4456
|
+
}
|
4457
|
+
|
4458
|
+
|
4459
|
+
pointer.duration += time;
|
4460
|
+
pointer.lastTouch = mixTouchAttr({}, touch)
|
4461
|
+
|
4462
|
+
pointer.lastTime = Date.now()
|
4463
|
+
|
4464
|
+
pointer.deltaX = touch.clientX - pointer.startTouch.clientX
|
4465
|
+
pointer.deltaY = touch.clientY - pointer.startTouch.clientY
|
4466
|
+
var x = pointer.deltaX * pointer.deltaX
|
4467
|
+
var y = pointer.deltaY * pointer.deltaY
|
4468
|
+
pointer.distance = Math.sqrt(x + y)
|
4469
|
+
pointer.isVertical = x < y
|
4470
|
+
|
4471
|
+
callback(pointer, touch)
|
4472
|
+
}
|
4473
|
+
}
|
4474
|
+
},
|
4475
|
+
end: function (event, callback) {
|
4476
|
+
for (var i = 0; i < event.changedTouches.length; i++) {
|
4477
|
+
var touch = event.changedTouches[i],
|
4478
|
+
id = touch.identifier,
|
4479
|
+
pointer = gestureHooks.pointers[id]
|
4480
|
+
|
4481
|
+
if (!pointer)
|
4482
|
+
continue
|
4483
|
+
|
4484
|
+
callback(pointer, touch)
|
4485
|
+
|
4486
|
+
delete gestureHooks.pointers[id]
|
4487
|
+
}
|
4488
|
+
},
|
4489
|
+
fire: function (elem, type, props) {
|
4490
|
+
if (elem) {
|
4491
|
+
var event = document.createEvent('Events')
|
4492
|
+
event.initEvent(type, true, true)
|
4493
|
+
avalon.mix(event, props)
|
4494
|
+
elem.dispatchEvent(event)
|
4495
|
+
}
|
4496
|
+
},
|
4497
|
+
add: function (name, gesture) {
|
4498
|
+
function move(event) {
|
4499
|
+
gesture.touchmove(event)
|
4500
|
+
}
|
4501
|
+
|
4502
|
+
function end(event) {
|
4503
|
+
gesture.touchend(event)
|
4504
|
+
|
4505
|
+
document.removeEventListener('touchmove', move)
|
4506
|
+
|
4507
|
+
document.removeEventListener('touchend', end)
|
4508
|
+
|
4509
|
+
document.removeEventListener('touchcancel', cancel)
|
4510
|
+
|
4511
|
+
}
|
4512
|
+
|
4513
|
+
function cancel(event) {
|
4514
|
+
gesture.touchcancel(event)
|
4515
|
+
|
4516
|
+
document.removeEventListener('touchmove', move)
|
4517
|
+
|
4518
|
+
document.removeEventListener('touchend', end)
|
4519
|
+
|
4520
|
+
document.removeEventListener('touchcancel', cancel)
|
4521
|
+
|
4522
|
+
}
|
4523
|
+
|
4524
|
+
gesture.events.forEach(function (eventName) {
|
4525
|
+
avalon.eventHooks[eventName] = {
|
4526
|
+
fn: function (el, fn) {
|
4527
|
+
if (!el['touch-' + name]) {
|
4528
|
+
el['touch-' + name] = '1'
|
4529
|
+
el.addEventListener('touchstart', function (event) {
|
4530
|
+
gesture.touchstart(event)
|
4531
|
+
|
4532
|
+
document.addEventListener('touchmove', move)
|
4533
|
+
|
4534
|
+
document.addEventListener('touchend', end)
|
4535
|
+
|
4536
|
+
document.addEventListener('touchcancel', cancel)
|
4537
|
+
|
4538
|
+
})
|
4539
|
+
}
|
4540
|
+
return fn
|
4541
|
+
}
|
4539
4542
|
}
|
4543
|
+
})
|
4544
|
+
}
|
4545
|
+
}
|
4546
|
+
|
4547
|
+
|
4548
|
+
|
4549
|
+
var touchkeys = ['screenX', 'screenY', 'clientX', 'clientY', 'pageX', 'pageY']
|
4550
|
+
|
4551
|
+
// 复制 touch 对象上的有用属性到固定对象上
|
4552
|
+
function mixTouchAttr(target, source) {
|
4553
|
+
if (source) {
|
4554
|
+
touchkeys.forEach(function (key) {
|
4555
|
+
target[key] = source[key]
|
4556
|
+
})
|
4557
|
+
}
|
4558
|
+
return target
|
4559
|
+
}
|
4560
|
+
|
4561
|
+
var supportPointer = !!navigator.pointerEnabled || !!navigator.msPointerEnabled
|
4562
|
+
|
4563
|
+
if (supportPointer) { // 支持pointer的设备可用样式来取消click事件的300毫秒延迟
|
4564
|
+
root.style.msTouchAction = root.style.touchAction = 'none'
|
4565
|
+
}
|
4566
|
+
var tapGesture = {
|
4567
|
+
events: ['tap'],
|
4568
|
+
touchBoundary: 10,
|
4569
|
+
tapDelay: 200,
|
4570
|
+
needClick: function (target) {
|
4571
|
+
//判定是否使用原生的点击事件, 否则使用sendClick方法手动触发一个人工的点击事件
|
4572
|
+
switch (target.nodeName.toLowerCase()) {
|
4573
|
+
case 'button':
|
4574
|
+
case 'select':
|
4575
|
+
case 'textarea':
|
4576
|
+
if (target.disabled) {
|
4577
|
+
return true
|
4578
|
+
}
|
4579
|
+
|
4580
|
+
break;
|
4581
|
+
case 'input':
|
4582
|
+
// IOS6 pad 上选择文件,如果不是原生的click,弹出的选择界面尺寸错误
|
4583
|
+
if ((deviceIsIOS && target.type === 'file') || target.disabled) {
|
4584
|
+
return true
|
4585
|
+
}
|
4586
|
+
|
4587
|
+
break;
|
4588
|
+
case 'label':
|
4589
|
+
case 'iframe':
|
4590
|
+
case 'video':
|
4591
|
+
return true
|
4592
|
+
}
|
4593
|
+
|
4594
|
+
return false
|
4595
|
+
},
|
4596
|
+
needFocus: function (target) {
|
4597
|
+
switch (target.nodeName.toLowerCase()) {
|
4598
|
+
case 'textarea':
|
4599
|
+
case 'select': //实测android下select也需要
|
4600
|
+
return true;
|
4601
|
+
case 'input':
|
4602
|
+
switch (target.type) {
|
4603
|
+
case 'button':
|
4604
|
+
case 'checkbox':
|
4605
|
+
case 'file':
|
4606
|
+
case 'image':
|
4607
|
+
case 'radio':
|
4608
|
+
case 'submit':
|
4609
|
+
return false
|
4610
|
+
}
|
4611
|
+
//如果是只读或disabled状态,就无须获得焦点了
|
4612
|
+
return !target.disabled && !target.readOnly
|
4613
|
+
default:
|
4614
|
+
return false
|
4615
|
+
}
|
4616
|
+
},
|
4617
|
+
focus: function (targetElement) {
|
4618
|
+
var length;
|
4619
|
+
//在iOS7下, 对一些新表单元素(如date, datetime, time, month)调用focus方法会抛错,
|
4620
|
+
//幸好的是,我们可以改用setSelectionRange获取焦点, 将光标挪到文字的最后
|
4621
|
+
var type = targetElement.type
|
4622
|
+
if (deviceIsIOS && targetElement.setSelectionRange &&
|
4623
|
+
type.indexOf('date') !== 0 && type !== 'time' && type !== 'month') {
|
4624
|
+
length = targetElement.value.length
|
4625
|
+
targetElement.setSelectionRange(length, length)
|
4540
4626
|
} else {
|
4541
|
-
|
4627
|
+
targetElement.focus()
|
4542
4628
|
}
|
4629
|
+
},
|
4630
|
+
findControl: function (labelElement) {
|
4631
|
+
// 获取label元素所对应的表单元素
|
4632
|
+
// 可以能过control属性, getElementById, 或用querySelector直接找其内部第一表单元素实现
|
4633
|
+
if (labelElement.control !== undefined) {
|
4634
|
+
return labelElement.control
|
4635
|
+
}
|
4636
|
+
|
4637
|
+
if (labelElement.htmlFor) {
|
4638
|
+
return document.getElementById(labelElement.htmlFor)
|
4639
|
+
}
|
4640
|
+
|
4641
|
+
return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea')
|
4642
|
+
},
|
4643
|
+
fixTarget: function (target) {
|
4644
|
+
if (target.nodeType === 3) {
|
4645
|
+
return target.parentNode
|
4646
|
+
}
|
4647
|
+
if (window.SVGElementInstance && (target instanceof SVGElementInstance)) {
|
4648
|
+
return target.correspondingUseElement;
|
4649
|
+
}
|
4650
|
+
|
4651
|
+
return target
|
4652
|
+
},
|
4653
|
+
updateScrollParent: function (targetElement) {
|
4654
|
+
//如果事件源元素位于某一个有滚动条的祖父元素中,那么保持其scrollParent与scrollTop值
|
4655
|
+
var scrollParent = targetElement.tapScrollParent
|
4656
|
+
|
4657
|
+
if (!scrollParent || !scrollParent.contains(targetElement)) {
|
4658
|
+
var parentElement = targetElement
|
4659
|
+
do {
|
4660
|
+
if (parentElement.scrollHeight > parentElement.offsetHeight) {
|
4661
|
+
scrollParent = parentElement
|
4662
|
+
targetElement.tapScrollParent = parentElement
|
4663
|
+
break
|
4664
|
+
}
|
4665
|
+
|
4666
|
+
parentElement = parentElement.parentElement
|
4667
|
+
} while (parentElement)
|
4668
|
+
}
|
4669
|
+
|
4670
|
+
if (scrollParent) {
|
4671
|
+
scrollParent.lastScrollTop = scrollParent.scrollTop
|
4672
|
+
}
|
4673
|
+
},
|
4674
|
+
touchHasMoved: function (event) {
|
4675
|
+
// 判定是否发生移动,其阀值是10px
|
4676
|
+
var touch = event.changedTouches[0],
|
4677
|
+
boundary = tapGesture.touchBoundary
|
4678
|
+
return Math.abs(touch.pageX - tapGesture.touchStartX) > boundary ||
|
4679
|
+
Math.abs(touch.pageY - tapGesture.touchStartY) > boundary
|
4680
|
+
|
4681
|
+
},
|
4682
|
+
findType: function (targetElement) {
|
4683
|
+
// 安卓chrome浏览器上,模拟的 click 事件不能让 select 打开,故使用 mousedown 事件
|
4684
|
+
return deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select' ?
|
4685
|
+
'mousedown' : 'click'
|
4686
|
+
},
|
4687
|
+
sendClick: function (targetElement, event) {
|
4688
|
+
// 在click之前触发tap事件
|
4689
|
+
gestureHooks.fire(targetElement, 'tap', {
|
4690
|
+
touchEvent: event
|
4691
|
+
})
|
4692
|
+
var clickEvent, touch
|
4693
|
+
//某些安卓设备必须先移除焦点,之后模拟的click事件才能让新元素获取焦点
|
4694
|
+
if (document.activeElement && document.activeElement !== targetElement) {
|
4695
|
+
document.activeElement.blur()
|
4696
|
+
}
|
4697
|
+
|
4698
|
+
touch = event.changedTouches[0]
|
4699
|
+
// 手动触发点击事件,此时必须使用document.createEvent('MouseEvents')来创建事件
|
4700
|
+
// 及使用initMouseEvent来初始化它
|
4701
|
+
clickEvent = document.createEvent('MouseEvents')
|
4702
|
+
clickEvent.initMouseEvent(tapGesture.findType(targetElement), true, true, window, 1, touch.screenX,
|
4703
|
+
touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null)
|
4704
|
+
clickEvent.touchEvent = event
|
4705
|
+
targetElement.dispatchEvent(clickEvent)
|
4706
|
+
},
|
4707
|
+
touchstart: function (event) {
|
4708
|
+
//忽略多点触摸
|
4709
|
+
if (event.targetTouches.length !== 1) {
|
4710
|
+
return true
|
4711
|
+
}
|
4712
|
+
//修正事件源对象
|
4713
|
+
var targetElement = tapGesture.fixTarget(event.target)
|
4714
|
+
var touch = event.targetTouches[0]
|
4715
|
+
if (deviceIsIOS) {
|
4716
|
+
// 判断是否是点击文字,进行选择等操作,如果是,不需要模拟click
|
4717
|
+
var selection = window.getSelection();
|
4718
|
+
if (selection.rangeCount && !selection.isCollapsed) {
|
4719
|
+
return true
|
4720
|
+
}
|
4721
|
+
var id = touch.identifier
|
4722
|
+
//当 alert 或 confirm 时,点击其他地方,会触发touch事件,identifier相同,此事件应该被忽略
|
4723
|
+
if (id && isFinite(tapGesture.lastTouchIdentifier) && tapGesture.lastTouchIdentifier === id) {
|
4724
|
+
event.preventDefault()
|
4725
|
+
return false
|
4726
|
+
}
|
4727
|
+
|
4728
|
+
tapGesture.lastTouchIdentifier = id
|
4729
|
+
|
4730
|
+
tapGesture.updateScrollParent(targetElement)
|
4731
|
+
}
|
4732
|
+
//收集触摸点的信息
|
4733
|
+
tapGesture.status = "tapping"
|
4734
|
+
tapGesture.startTime = Date.now()
|
4735
|
+
tapGesture.element = targetElement
|
4736
|
+
tapGesture.pageX = touch.pageX
|
4737
|
+
tapGesture.pageY = touch.pageY
|
4738
|
+
// 如果点击太快,阻止双击带来的放大收缩行为
|
4739
|
+
if ((tapGesture.startTime - tapGesture.lastTime) < tapGesture.tapDelay) {
|
4740
|
+
event.preventDefault()
|
4741
|
+
}
|
4742
|
+
},
|
4743
|
+
touchmove: function (event) {
|
4744
|
+
if (tapGesture.status !== "tapping") {
|
4745
|
+
return true
|
4746
|
+
}
|
4747
|
+
// 如果事件源元素发生改变,或者发生了移动,那么就取消触发点击事件
|
4748
|
+
if (tapGesture.element !== tapGesture.fixTarget(event.target) ||
|
4749
|
+
tapGesture.touchHasMoved(event)) {
|
4750
|
+
tapGesture.status = tapGesture.element = 0
|
4751
|
+
}
|
4752
|
+
|
4753
|
+
},
|
4754
|
+
touchend: function (event) {
|
4755
|
+
var targetElement = tapGesture.element
|
4756
|
+
var now = Date.now()
|
4757
|
+
//如果是touchstart与touchend相隔太久,可以认为是长按,那么就直接返回
|
4758
|
+
//或者是在touchstart, touchmove阶段,判定其不该触发点击事件,也直接返回
|
4759
|
+
if (!targetElement || now - tapGesture.startTime > tapGesture.tapDelay) {
|
4760
|
+
return true
|
4761
|
+
}
|
4762
|
+
|
4763
|
+
|
4764
|
+
tapGesture.lastTime = now
|
4765
|
+
|
4766
|
+
var startTime = tapGesture.startTime
|
4767
|
+
tapGesture.status = tapGesture.startTime = 0
|
4768
|
+
|
4769
|
+
targetTagName = targetElement.tagName.toLowerCase()
|
4770
|
+
if (targetTagName === 'label') {
|
4771
|
+
//尝试触发label上可能绑定的tap事件
|
4772
|
+
gestureHooks.fire(targetElement, 'tap', {
|
4773
|
+
touchEvent: event
|
4774
|
+
})
|
4775
|
+
var forElement = tapGesture.findControl(targetElement)
|
4776
|
+
if (forElement) {
|
4777
|
+
tapGesture.focus(targetElement)
|
4778
|
+
targetElement = forElement
|
4779
|
+
}
|
4780
|
+
} else if (tapGesture.needFocus(targetElement)) {
|
4781
|
+
// 如果元素从touchstart到touchend经历时间过长,那么不应该触发点击事
|
4782
|
+
// 或者此元素是iframe中的input元素,那么它也无法获点焦点
|
4783
|
+
if ((now - startTime) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
|
4784
|
+
tapGesture.element = 0
|
4785
|
+
return false
|
4786
|
+
}
|
4787
|
+
|
4788
|
+
tapGesture.focus(targetElement)
|
4789
|
+
deviceIsAndroid && tapGesture.sendClick(targetElement, event)
|
4790
|
+
|
4791
|
+
return false
|
4792
|
+
}
|
4793
|
+
|
4794
|
+
if (deviceIsIOS) {
|
4795
|
+
//如果它的父容器的滚动条发生改变,那么应该识别为划动或拖动事件,不应该触发点击事件
|
4796
|
+
var scrollParent = targetElement.tapScrollParent;
|
4797
|
+
if (scrollParent && scrollParent.lastScrollTop !== scrollParent.scrollTop) {
|
4798
|
+
return true
|
4799
|
+
}
|
4800
|
+
}
|
4801
|
+
//如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click
|
4802
|
+
if (!tapGesture.needClick(targetElement)) {
|
4803
|
+
event.preventDefault()
|
4804
|
+
// 触发一次模拟的click
|
4805
|
+
tapGesture.sendClick(targetElement, event)
|
4806
|
+
}
|
4807
|
+
},
|
4808
|
+
touchcancel: function () {
|
4809
|
+
tapGesture.startTime = tapGesture.element = 0
|
4543
4810
|
}
|
4544
4811
|
}
|
4545
|
-
|
4546
|
-
|
4547
|
-
|
4548
|
-
|
4549
|
-
|
4550
|
-
|
4551
|
-
|
4552
|
-
|
4553
|
-
|
4554
|
-
|
4555
|
-
|
4556
|
-
|
4812
|
+
|
4813
|
+
gestureHooks.add("tap", tapGesture)
|
4814
|
+
|
4815
|
+
var pressGesture = {
|
4816
|
+
events: ['longtap', 'doubletap'],
|
4817
|
+
cancelPress: function (pointer) {
|
4818
|
+
clearTimeout(pointer.pressingHandler)
|
4819
|
+
pointer.pressingHandler = null
|
4820
|
+
},
|
4821
|
+
touchstart: function (event) {
|
4822
|
+
gestureHooks.start(event, function (pointer, touch) {
|
4823
|
+
pointer.pressingHandler = setTimeout(function () {
|
4824
|
+
if (pointer.status === 'tapping') {
|
4825
|
+
gestureHooks.fire(event.target, 'longtap', {
|
4826
|
+
touch: touch,
|
4827
|
+
touchEvent: event
|
4828
|
+
})
|
4829
|
+
}
|
4830
|
+
pressGesture.cancelPress(pointer)
|
4831
|
+
}, 500)
|
4832
|
+
if (event.changedTouches.length !== 1) {
|
4833
|
+
pointer.status = 0
|
4834
|
+
}
|
4835
|
+
})
|
4836
|
+
|
4837
|
+
},
|
4838
|
+
touchmove: function (event) {
|
4839
|
+
gestureHooks.move(event, function (pointer) {
|
4840
|
+
if (pointer.distance > 10 && pointer.pressingHandler) {
|
4841
|
+
pressGesture.cancelPress(pointer)
|
4842
|
+
if (pointer.status === 'tapping') {
|
4843
|
+
pointer.status = 'panning'
|
4844
|
+
}
|
4845
|
+
}
|
4846
|
+
})
|
4847
|
+
},
|
4848
|
+
touchend: function (event) {
|
4849
|
+
gestureHooks.end(event, function (pointer, touch) {
|
4850
|
+
pressGesture.cancelPress(pointer)
|
4851
|
+
if (pointer.status === 'tapping') {
|
4852
|
+
pointer.lastTime = Date.now()
|
4853
|
+
if (pressGesture.lastTap && pointer.lastTime - pressGesture.lastTap.lastTime < 300) {
|
4854
|
+
gestureHooks.fire(pointer.element, 'doubletap', {
|
4855
|
+
touch: touch,
|
4856
|
+
touchEvent: event
|
4857
|
+
})
|
4858
|
+
}
|
4859
|
+
|
4860
|
+
pressGesture.lastTap = pointer
|
4861
|
+
}
|
4862
|
+
})
|
4863
|
+
|
4864
|
+
},
|
4865
|
+
touchcancel: function (event) {
|
4866
|
+
gestureHooks.end(event, function (pointer) {
|
4867
|
+
pressGesture.cancelPress(pointer)
|
4868
|
+
})
|
4869
|
+
}
|
4557
4870
|
}
|
4558
|
-
|
4559
|
-
|
4560
|
-
|
4871
|
+
gestureHooks.add('press', pressGesture)
|
4872
|
+
|
4873
|
+
var swipeGesture = {
|
4874
|
+
events: ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown'],
|
4875
|
+
getAngle: function (x, y) {
|
4876
|
+
var r = Math.atan2(y, x) //radians
|
4877
|
+
var angle = Math.round(r * 180 / Math.PI) //degrees
|
4878
|
+
return angle < 0 ? 360 - Math.abs(angle) : angle
|
4879
|
+
},
|
4880
|
+
getDirection: function (x, y) {
|
4881
|
+
var angle = swipeGesture.getAngle(x, y)
|
4882
|
+
if ((angle <= 45) && (angle >= 0)) {
|
4883
|
+
return "left"
|
4884
|
+
} else if ((angle <= 360) && (angle >= 315)) {
|
4885
|
+
return "left"
|
4886
|
+
} else if ((angle >= 135) && (angle <= 225)) {
|
4887
|
+
return "right"
|
4888
|
+
} else if ((angle > 45) && (angle < 135)) {
|
4889
|
+
return "down"
|
4890
|
+
} else {
|
4891
|
+
return "up"
|
4892
|
+
}
|
4893
|
+
},
|
4894
|
+
touchstart: function (event) {
|
4895
|
+
gestureHooks.start(event, noop)
|
4896
|
+
},
|
4897
|
+
touchmove: function (event) {
|
4898
|
+
gestureHooks.move(event, noop)
|
4899
|
+
},
|
4900
|
+
touchend: function (event) {
|
4901
|
+
if (event.changedTouches.length !== 1) {
|
4902
|
+
return
|
4903
|
+
}
|
4904
|
+
gestureHooks.end(event, function (pointer, touch) {
|
4905
|
+
var isflick = (pointer.distance > 30 && pointer.distance / pointer.duration > 0.65)
|
4906
|
+
if (isflick) {
|
4907
|
+
var extra = {
|
4908
|
+
deltaX: pointer.deltaX,
|
4909
|
+
deltaY: pointer.deltaY,
|
4910
|
+
touch: touch,
|
4911
|
+
touchEvent: event,
|
4912
|
+
direction: swipeGesture.getDirection(pointer.deltaX, pointer.deltaY),
|
4913
|
+
isVertical: pointer.isVertical
|
4914
|
+
}
|
4915
|
+
var target = pointer.element
|
4916
|
+
gestureHooks.fire(target, 'swipe', extra)
|
4917
|
+
gestureHooks.fire(target, 'swipe' + extra.direction, extra)
|
4918
|
+
}
|
4919
|
+
})
|
4920
|
+
}
|
4921
|
+
}
|
4922
|
+
|
4923
|
+
swipeGesture.touchcancel = swipeGesture.touchend
|
4924
|
+
gestureHooks.add('swipe', swipeGesture)
|
4561
4925
|
|
4562
4926
|
//各种摸屏事件的示意图 http://quojs.tapquo.com/ http://touch.code.baidu.com/
|
4563
|
-
}// jshint ignore:line
|
4927
|
+
} // jshint ignore:line
|
4928
|
+
|
4564
4929
|
|
4565
4930
|
// Register as a named AMD module, since avalon can be concatenated with other
|
4566
4931
|
// files that may use define, but not via a proper concatenation script that
|