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