avalon-rails 1.4.6.0.20150915133100 → 1.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|