|
1 YUI.add('event-move', function (Y, NAME) { |
|
2 |
|
3 /** |
|
4 * Adds lower level support for "gesturemovestart", "gesturemove" and "gesturemoveend" events, which can be used to create drag/drop |
|
5 * interactions which work across touch and mouse input devices. They correspond to "touchstart", "touchmove" and "touchend" on a touch input |
|
6 * device, and "mousedown", "mousemove", "mouseup" on a mouse based input device. |
|
7 * |
|
8 * <p>Documentation for the gesturemove triplet of events can be found on the <a href="../classes/YUI.html#event_gesturemove">YUI</a> global, |
|
9 * along with the other supported events.</p> |
|
10 |
|
11 @example |
|
12 |
|
13 YUI().use('event-move', function (Y) { |
|
14 Y.one('#myNode').on('gesturemovestart', function (e) { |
|
15 }); |
|
16 Y.one('#myNode').on('gesturemove', function (e) { |
|
17 }); |
|
18 Y.one('#myNode').on('gesturemoveend', function (e) { |
|
19 }); |
|
20 }); |
|
21 |
|
22 * @module event-gestures |
|
23 * @submodule event-move |
|
24 */ |
|
25 |
|
26 |
|
27 var GESTURE_MAP = Y.Event._GESTURE_MAP, |
|
28 EVENT = { |
|
29 start: GESTURE_MAP.start, |
|
30 end: GESTURE_MAP.end, |
|
31 move: GESTURE_MAP.move |
|
32 }, |
|
33 START = "start", |
|
34 MOVE = "move", |
|
35 END = "end", |
|
36 |
|
37 GESTURE_MOVE = "gesture" + MOVE, |
|
38 GESTURE_MOVE_END = GESTURE_MOVE + END, |
|
39 GESTURE_MOVE_START = GESTURE_MOVE + START, |
|
40 |
|
41 _MOVE_START_HANDLE = "_msh", |
|
42 _MOVE_HANDLE = "_mh", |
|
43 _MOVE_END_HANDLE = "_meh", |
|
44 |
|
45 _DEL_MOVE_START_HANDLE = "_dmsh", |
|
46 _DEL_MOVE_HANDLE = "_dmh", |
|
47 _DEL_MOVE_END_HANDLE = "_dmeh", |
|
48 |
|
49 _MOVE_START = "_ms", |
|
50 _MOVE = "_m", |
|
51 |
|
52 MIN_TIME = "minTime", |
|
53 MIN_DISTANCE = "minDistance", |
|
54 PREVENT_DEFAULT = "preventDefault", |
|
55 BUTTON = "button", |
|
56 OWNER_DOCUMENT = "ownerDocument", |
|
57 |
|
58 CURRENT_TARGET = "currentTarget", |
|
59 TARGET = "target", |
|
60 |
|
61 NODE_TYPE = "nodeType", |
|
62 SUPPORTS_POINTER = Y.config.win && ("msPointerEnabled" in Y.config.win.navigator), |
|
63 MS_TOUCH_ACTION_COUNT = 'msTouchActionCount', |
|
64 MS_INIT_TOUCH_ACTION = 'msInitTouchAction', |
|
65 |
|
66 _defArgsProcessor = function(se, args, delegate) { |
|
67 var iConfig = (delegate) ? 4 : 3, |
|
68 config = (args.length > iConfig) ? Y.merge(args.splice(iConfig,1)[0]) : {}; |
|
69 |
|
70 if (!(PREVENT_DEFAULT in config)) { |
|
71 config[PREVENT_DEFAULT] = se.PREVENT_DEFAULT; |
|
72 } |
|
73 |
|
74 return config; |
|
75 }, |
|
76 |
|
77 _getRoot = function(node, subscriber) { |
|
78 return subscriber._extra.root || (node.get(NODE_TYPE) === 9) ? node : node.get(OWNER_DOCUMENT); |
|
79 }, |
|
80 |
|
81 //Checks to see if the node is the document, and if it is, returns the documentElement. |
|
82 _checkDocumentElem = function(node) { |
|
83 var elem = node.getDOMNode(); |
|
84 if (node.compareTo(Y.config.doc) && elem.documentElement) { |
|
85 return elem.documentElement; |
|
86 } |
|
87 else { |
|
88 return false; |
|
89 } |
|
90 }, |
|
91 |
|
92 _normTouchFacade = function(touchFacade, touch, params) { |
|
93 touchFacade.pageX = touch.pageX; |
|
94 touchFacade.pageY = touch.pageY; |
|
95 touchFacade.screenX = touch.screenX; |
|
96 touchFacade.screenY = touch.screenY; |
|
97 touchFacade.clientX = touch.clientX; |
|
98 touchFacade.clientY = touch.clientY; |
|
99 touchFacade[TARGET] = touchFacade[TARGET] || touch[TARGET]; |
|
100 touchFacade[CURRENT_TARGET] = touchFacade[CURRENT_TARGET] || touch[CURRENT_TARGET]; |
|
101 |
|
102 touchFacade[BUTTON] = (params && params[BUTTON]) || 1; // default to left (left as per vendors, not W3C which is 0) |
|
103 }, |
|
104 |
|
105 /* |
|
106 In IE10 touch mode, gestures will not work properly unless the -ms-touch-action CSS property is set to something other than 'auto'. Read http://msdn.microsoft.com/en-us/library/windows/apps/hh767313.aspx for more info. To get around this, we set -ms-touch-action: none which is the same as e.preventDefault() on touch environments. This tells the browser to fire DOM events for all touch events, and not perform any default behavior. |
|
107 |
|
108 The user can over-ride this by setting a more lenient -ms-touch-action property on a node (such as pan-x, pan-y, etc.) via CSS when subscribing to the 'gesturemovestart' event. |
|
109 */ |
|
110 _setTouchActions = function (node) { |
|
111 var elem = _checkDocumentElem(node) || node.getDOMNode(), |
|
112 num = node.getData(MS_TOUCH_ACTION_COUNT); |
|
113 |
|
114 //Checks to see if msTouchAction is supported. |
|
115 if (SUPPORTS_POINTER) { |
|
116 if (!num) { |
|
117 num = 0; |
|
118 node.setData(MS_INIT_TOUCH_ACTION, elem.style.msTouchAction); |
|
119 } |
|
120 elem.style.msTouchAction = Y.Event._DEFAULT_TOUCH_ACTION; |
|
121 num++; |
|
122 node.setData(MS_TOUCH_ACTION_COUNT, num); |
|
123 } |
|
124 }, |
|
125 |
|
126 /* |
|
127 Resets the element's -ms-touch-action property back to the original value, This is called on detach() and detachDelegate(). |
|
128 */ |
|
129 _unsetTouchActions = function (node) { |
|
130 var elem = _checkDocumentElem(node) || node.getDOMNode(), |
|
131 num = node.getData(MS_TOUCH_ACTION_COUNT), |
|
132 initTouchAction = node.getData(MS_INIT_TOUCH_ACTION); |
|
133 |
|
134 if (SUPPORTS_POINTER) { |
|
135 num--; |
|
136 node.setData(MS_TOUCH_ACTION_COUNT, num); |
|
137 if (num === 0 && elem.style.msTouchAction !== initTouchAction) { |
|
138 elem.style.msTouchAction = initTouchAction; |
|
139 } |
|
140 } |
|
141 }, |
|
142 |
|
143 _prevent = function(e, preventDefault) { |
|
144 if (preventDefault) { |
|
145 // preventDefault is a boolean or a function |
|
146 if (!preventDefault.call || preventDefault(e)) { |
|
147 e.preventDefault(); |
|
148 } |
|
149 } |
|
150 }, |
|
151 |
|
152 define = Y.Event.define; |
|
153 Y.Event._DEFAULT_TOUCH_ACTION = 'none'; |
|
154 |
|
155 /** |
|
156 * Sets up a "gesturemovestart" event, that is fired on touch devices in response to a single finger "touchstart", |
|
157 * and on mouse based devices in response to a "mousedown". The subscriber can specify the minimum time |
|
158 * and distance thresholds which should be crossed before the "gesturemovestart" is fired and for the mouse, |
|
159 * which button should initiate a "gesturemovestart". This event can also be listened for using node.delegate(). |
|
160 * |
|
161 * <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler, |
|
162 * however if you want to pass the context and arguments as additional signature arguments to on/delegate, |
|
163 * you need to provide a null value for the configuration object, e.g: <code>node.on("gesturemovestart", fn, null, context, arg1, arg2, arg3)</code></p> |
|
164 * |
|
165 * @event gesturemovestart |
|
166 * @for YUI |
|
167 * @param type {string} "gesturemovestart" |
|
168 * @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mousedown or touchstart.touches[0]) which contains position co-ordinates. |
|
169 * @param cfg {Object} Optional. An object which specifies: |
|
170 * |
|
171 * <dl> |
|
172 * <dt>minDistance (defaults to 0)</dt> |
|
173 * <dd>The minimum distance threshold which should be crossed before the gesturemovestart is fired</dd> |
|
174 * <dt>minTime (defaults to 0)</dt> |
|
175 * <dd>The minimum time threshold for which the finger/mouse should be help down before the gesturemovestart is fired</dd> |
|
176 * <dt>button (no default)</dt> |
|
177 * <dd>In the case of a mouse input device, if the event should only be fired for a specific mouse button.</dd> |
|
178 * <dt>preventDefault (defaults to false)</dt> |
|
179 * <dd>Can be set to true/false to prevent default behavior as soon as the touchstart or mousedown is received (that is before minTime or minDistance thresholds are crossed, and so before the gesturemovestart listener is notified) so that things like text selection and context popups (on touch devices) can be |
|
180 * prevented. This property can also be set to a function, which returns true or false, based on the event facade passed to it (for example, DragDrop can determine if the target is a valid handle or not before preventing default).</dd> |
|
181 * </dl> |
|
182 * |
|
183 * @return {EventHandle} the detach handle |
|
184 */ |
|
185 |
|
186 define(GESTURE_MOVE_START, { |
|
187 |
|
188 on: function (node, subscriber, ce) { |
|
189 |
|
190 //Set -ms-touch-action on IE10 and set preventDefault to true |
|
191 _setTouchActions(node); |
|
192 |
|
193 subscriber[_MOVE_START_HANDLE] = node.on(EVENT[START], |
|
194 this._onStart, |
|
195 this, |
|
196 node, |
|
197 subscriber, |
|
198 ce); |
|
199 }, |
|
200 |
|
201 delegate : function(node, subscriber, ce, filter) { |
|
202 |
|
203 var se = this; |
|
204 |
|
205 subscriber[_DEL_MOVE_START_HANDLE] = node.delegate(EVENT[START], |
|
206 function(e) { |
|
207 se._onStart(e, node, subscriber, ce, true); |
|
208 }, |
|
209 filter); |
|
210 }, |
|
211 |
|
212 detachDelegate : function(node, subscriber, ce, filter) { |
|
213 var handle = subscriber[_DEL_MOVE_START_HANDLE]; |
|
214 |
|
215 if (handle) { |
|
216 handle.detach(); |
|
217 subscriber[_DEL_MOVE_START_HANDLE] = null; |
|
218 } |
|
219 |
|
220 _unsetTouchActions(node); |
|
221 }, |
|
222 |
|
223 detach: function (node, subscriber, ce) { |
|
224 var startHandle = subscriber[_MOVE_START_HANDLE]; |
|
225 |
|
226 if (startHandle) { |
|
227 startHandle.detach(); |
|
228 subscriber[_MOVE_START_HANDLE] = null; |
|
229 } |
|
230 |
|
231 _unsetTouchActions(node); |
|
232 }, |
|
233 |
|
234 processArgs : function(args, delegate) { |
|
235 var params = _defArgsProcessor(this, args, delegate); |
|
236 |
|
237 if (!(MIN_TIME in params)) { |
|
238 params[MIN_TIME] = this.MIN_TIME; |
|
239 } |
|
240 |
|
241 if (!(MIN_DISTANCE in params)) { |
|
242 params[MIN_DISTANCE] = this.MIN_DISTANCE; |
|
243 } |
|
244 |
|
245 return params; |
|
246 }, |
|
247 |
|
248 _onStart : function(e, node, subscriber, ce, delegate) { |
|
249 |
|
250 if (delegate) { |
|
251 node = e[CURRENT_TARGET]; |
|
252 } |
|
253 |
|
254 var params = subscriber._extra, |
|
255 fireStart = true, |
|
256 minTime = params[MIN_TIME], |
|
257 minDistance = params[MIN_DISTANCE], |
|
258 button = params.button, |
|
259 preventDefault = params[PREVENT_DEFAULT], |
|
260 root = _getRoot(node, subscriber), |
|
261 startXY; |
|
262 |
|
263 if (e.touches) { |
|
264 if (e.touches.length === 1) { |
|
265 _normTouchFacade(e, e.touches[0], params); |
|
266 } else { |
|
267 fireStart = false; |
|
268 } |
|
269 } else { |
|
270 fireStart = (button === undefined) || (button === e.button); |
|
271 } |
|
272 |
|
273 |
|
274 if (fireStart) { |
|
275 |
|
276 _prevent(e, preventDefault); |
|
277 |
|
278 if (minTime === 0 || minDistance === 0) { |
|
279 this._start(e, node, ce, params); |
|
280 |
|
281 } else { |
|
282 |
|
283 startXY = [e.pageX, e.pageY]; |
|
284 |
|
285 if (minTime > 0) { |
|
286 |
|
287 |
|
288 params._ht = Y.later(minTime, this, this._start, [e, node, ce, params]); |
|
289 |
|
290 params._hme = root.on(EVENT[END], Y.bind(function() { |
|
291 this._cancel(params); |
|
292 }, this)); |
|
293 } |
|
294 |
|
295 if (minDistance > 0) { |
|
296 |
|
297 |
|
298 params._hm = root.on(EVENT[MOVE], Y.bind(function(em) { |
|
299 if (Math.abs(em.pageX - startXY[0]) > minDistance || Math.abs(em.pageY - startXY[1]) > minDistance) { |
|
300 this._start(e, node, ce, params); |
|
301 } |
|
302 }, this)); |
|
303 } |
|
304 } |
|
305 } |
|
306 }, |
|
307 |
|
308 _cancel : function(params) { |
|
309 if (params._ht) { |
|
310 params._ht.cancel(); |
|
311 params._ht = null; |
|
312 } |
|
313 if (params._hme) { |
|
314 params._hme.detach(); |
|
315 params._hme = null; |
|
316 } |
|
317 if (params._hm) { |
|
318 params._hm.detach(); |
|
319 params._hm = null; |
|
320 } |
|
321 }, |
|
322 |
|
323 _start : function(e, node, ce, params) { |
|
324 |
|
325 if (params) { |
|
326 this._cancel(params); |
|
327 } |
|
328 |
|
329 e.type = GESTURE_MOVE_START; |
|
330 |
|
331 |
|
332 node.setData(_MOVE_START, e); |
|
333 ce.fire(e); |
|
334 }, |
|
335 |
|
336 MIN_TIME : 0, |
|
337 MIN_DISTANCE : 0, |
|
338 PREVENT_DEFAULT : false |
|
339 }); |
|
340 |
|
341 /** |
|
342 * Sets up a "gesturemove" event, that is fired on touch devices in response to a single finger "touchmove", |
|
343 * and on mouse based devices in response to a "mousemove". |
|
344 * |
|
345 * <p>By default this event is only fired when the same node |
|
346 * has received a "gesturemovestart" event. The subscriber can set standAlone to true, in the configuration properties, |
|
347 * if they want to listen for this event without an initial "gesturemovestart".</p> |
|
348 * |
|
349 * <p>By default this event sets up it's internal "touchmove" and "mousemove" DOM listeners on the document element. The subscriber |
|
350 * can set the root configuration property, to specify which node to attach DOM listeners to, if different from the document.</p> |
|
351 * |
|
352 * <p>This event can also be listened for using node.delegate().</p> |
|
353 * |
|
354 * <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler, |
|
355 * however if you want to pass the context and arguments as additional signature arguments to on/delegate, |
|
356 * you need to provide a null value for the configuration object, e.g: <code>node.on("gesturemove", fn, null, context, arg1, arg2, arg3)</code></p> |
|
357 * |
|
358 * @event gesturemove |
|
359 * @for YUI |
|
360 * @param type {string} "gesturemove" |
|
361 * @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mousemove or touchmove.touches[0]) which contains position co-ordinates. |
|
362 * @param cfg {Object} Optional. An object which specifies: |
|
363 * <dl> |
|
364 * <dt>standAlone (defaults to false)</dt> |
|
365 * <dd>true, if the subscriber should be notified even if a "gesturemovestart" has not occured on the same node.</dd> |
|
366 * <dt>root (defaults to document)</dt> |
|
367 * <dd>The node to which the internal DOM listeners should be attached.</dd> |
|
368 * <dt>preventDefault (defaults to false)</dt> |
|
369 * <dd>Can be set to true/false to prevent default behavior as soon as the touchmove or mousemove is received. As with gesturemovestart, can also be set to function which returns true/false based on the event facade passed to it.</dd> |
|
370 * </dl> |
|
371 * |
|
372 * @return {EventHandle} the detach handle |
|
373 */ |
|
374 define(GESTURE_MOVE, { |
|
375 |
|
376 on : function (node, subscriber, ce) { |
|
377 |
|
378 _setTouchActions(node); |
|
379 var root = _getRoot(node, subscriber, EVENT[MOVE]), |
|
380 |
|
381 moveHandle = root.on(EVENT[MOVE], |
|
382 this._onMove, |
|
383 this, |
|
384 node, |
|
385 subscriber, |
|
386 ce); |
|
387 |
|
388 subscriber[_MOVE_HANDLE] = moveHandle; |
|
389 |
|
390 }, |
|
391 |
|
392 delegate : function(node, subscriber, ce, filter) { |
|
393 |
|
394 var se = this; |
|
395 |
|
396 subscriber[_DEL_MOVE_HANDLE] = node.delegate(EVENT[MOVE], |
|
397 function(e) { |
|
398 se._onMove(e, node, subscriber, ce, true); |
|
399 }, |
|
400 filter); |
|
401 }, |
|
402 |
|
403 detach : function (node, subscriber, ce) { |
|
404 var moveHandle = subscriber[_MOVE_HANDLE]; |
|
405 |
|
406 if (moveHandle) { |
|
407 moveHandle.detach(); |
|
408 subscriber[_MOVE_HANDLE] = null; |
|
409 } |
|
410 |
|
411 _unsetTouchActions(node); |
|
412 }, |
|
413 |
|
414 detachDelegate : function(node, subscriber, ce, filter) { |
|
415 var handle = subscriber[_DEL_MOVE_HANDLE]; |
|
416 |
|
417 if (handle) { |
|
418 handle.detach(); |
|
419 subscriber[_DEL_MOVE_HANDLE] = null; |
|
420 } |
|
421 |
|
422 _unsetTouchActions(node); |
|
423 |
|
424 }, |
|
425 |
|
426 processArgs : function(args, delegate) { |
|
427 return _defArgsProcessor(this, args, delegate); |
|
428 }, |
|
429 |
|
430 _onMove : function(e, node, subscriber, ce, delegate) { |
|
431 |
|
432 if (delegate) { |
|
433 node = e[CURRENT_TARGET]; |
|
434 } |
|
435 |
|
436 var fireMove = subscriber._extra.standAlone || node.getData(_MOVE_START), |
|
437 preventDefault = subscriber._extra.preventDefault; |
|
438 |
|
439 |
|
440 if (fireMove) { |
|
441 |
|
442 if (e.touches) { |
|
443 if (e.touches.length === 1) { |
|
444 _normTouchFacade(e, e.touches[0]); |
|
445 } else { |
|
446 fireMove = false; |
|
447 } |
|
448 } |
|
449 |
|
450 if (fireMove) { |
|
451 |
|
452 _prevent(e, preventDefault); |
|
453 |
|
454 |
|
455 e.type = GESTURE_MOVE; |
|
456 ce.fire(e); |
|
457 } |
|
458 } |
|
459 }, |
|
460 |
|
461 PREVENT_DEFAULT : false |
|
462 }); |
|
463 |
|
464 /** |
|
465 * Sets up a "gesturemoveend" event, that is fired on touch devices in response to a single finger "touchend", |
|
466 * and on mouse based devices in response to a "mouseup". |
|
467 * |
|
468 * <p>By default this event is only fired when the same node |
|
469 * has received a "gesturemove" or "gesturemovestart" event. The subscriber can set standAlone to true, in the configuration properties, |
|
470 * if they want to listen for this event without a preceding "gesturemovestart" or "gesturemove".</p> |
|
471 * |
|
472 * <p>By default this event sets up it's internal "touchend" and "mouseup" DOM listeners on the document element. The subscriber |
|
473 * can set the root configuration property, to specify which node to attach DOM listeners to, if different from the document.</p> |
|
474 * |
|
475 * <p>This event can also be listened for using node.delegate().</p> |
|
476 * |
|
477 * <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler, |
|
478 * however if you want to pass the context and arguments as additional signature arguments to on/delegate, |
|
479 * you need to provide a null value for the configuration object, e.g: <code>node.on("gesturemoveend", fn, null, context, arg1, arg2, arg3)</code></p> |
|
480 * |
|
481 * |
|
482 * @event gesturemoveend |
|
483 * @for YUI |
|
484 * @param type {string} "gesturemoveend" |
|
485 * @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mouseup or touchend.changedTouches[0]). |
|
486 * @param cfg {Object} Optional. An object which specifies: |
|
487 * <dl> |
|
488 * <dt>standAlone (defaults to false)</dt> |
|
489 * <dd>true, if the subscriber should be notified even if a "gesturemovestart" or "gesturemove" has not occured on the same node.</dd> |
|
490 * <dt>root (defaults to document)</dt> |
|
491 * <dd>The node to which the internal DOM listeners should be attached.</dd> |
|
492 * <dt>preventDefault (defaults to false)</dt> |
|
493 * <dd>Can be set to true/false to prevent default behavior as soon as the touchend or mouseup is received. As with gesturemovestart, can also be set to function which returns true/false based on the event facade passed to it.</dd> |
|
494 * </dl> |
|
495 * |
|
496 * @return {EventHandle} the detach handle |
|
497 */ |
|
498 define(GESTURE_MOVE_END, { |
|
499 |
|
500 on : function (node, subscriber, ce) { |
|
501 _setTouchActions(node); |
|
502 var root = _getRoot(node, subscriber), |
|
503 |
|
504 endHandle = root.on(EVENT[END], |
|
505 this._onEnd, |
|
506 this, |
|
507 node, |
|
508 subscriber, |
|
509 ce); |
|
510 |
|
511 subscriber[_MOVE_END_HANDLE] = endHandle; |
|
512 }, |
|
513 |
|
514 delegate : function(node, subscriber, ce, filter) { |
|
515 |
|
516 var se = this; |
|
517 |
|
518 subscriber[_DEL_MOVE_END_HANDLE] = node.delegate(EVENT[END], |
|
519 function(e) { |
|
520 se._onEnd(e, node, subscriber, ce, true); |
|
521 }, |
|
522 filter); |
|
523 }, |
|
524 |
|
525 detachDelegate : function(node, subscriber, ce, filter) { |
|
526 var handle = subscriber[_DEL_MOVE_END_HANDLE]; |
|
527 |
|
528 if (handle) { |
|
529 handle.detach(); |
|
530 subscriber[_DEL_MOVE_END_HANDLE] = null; |
|
531 } |
|
532 |
|
533 _unsetTouchActions(node); |
|
534 |
|
535 }, |
|
536 |
|
537 detach : function (node, subscriber, ce) { |
|
538 var endHandle = subscriber[_MOVE_END_HANDLE]; |
|
539 |
|
540 if (endHandle) { |
|
541 endHandle.detach(); |
|
542 subscriber[_MOVE_END_HANDLE] = null; |
|
543 } |
|
544 |
|
545 _unsetTouchActions(node); |
|
546 }, |
|
547 |
|
548 processArgs : function(args, delegate) { |
|
549 return _defArgsProcessor(this, args, delegate); |
|
550 }, |
|
551 |
|
552 _onEnd : function(e, node, subscriber, ce, delegate) { |
|
553 |
|
554 if (delegate) { |
|
555 node = e[CURRENT_TARGET]; |
|
556 } |
|
557 |
|
558 var fireMoveEnd = subscriber._extra.standAlone || node.getData(_MOVE) || node.getData(_MOVE_START), |
|
559 preventDefault = subscriber._extra.preventDefault; |
|
560 |
|
561 if (fireMoveEnd) { |
|
562 |
|
563 if (e.changedTouches) { |
|
564 if (e.changedTouches.length === 1) { |
|
565 _normTouchFacade(e, e.changedTouches[0]); |
|
566 } else { |
|
567 fireMoveEnd = false; |
|
568 } |
|
569 } |
|
570 |
|
571 if (fireMoveEnd) { |
|
572 |
|
573 _prevent(e, preventDefault); |
|
574 |
|
575 e.type = GESTURE_MOVE_END; |
|
576 ce.fire(e); |
|
577 |
|
578 node.clearData(_MOVE_START); |
|
579 node.clearData(_MOVE); |
|
580 } |
|
581 } |
|
582 }, |
|
583 |
|
584 PREVENT_DEFAULT : false |
|
585 }); |
|
586 |
|
587 |
|
588 }, '@VERSION@', {"requires": ["node-base", "event-touch", "event-synthetic"]}); |