2
YUI 3.10.3 (build 2fb5187)
3
Copyright 2013 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
8
YUI.add('event-move', function (Y, NAME) {
11
* Adds lower level support for "gesturemovestart", "gesturemove" and "gesturemoveend" events, which can be used to create drag/drop
12
* interactions which work across touch and mouse input devices. They correspond to "touchstart", "touchmove" and "touchend" on a touch input
13
* device, and "mousedown", "mousemove", "mouseup" on a mouse based input device.
15
* <p>Documentation for the gesturemove triplet of events can be found on the <a href="../classes/YUI.html#event_gesturemove">YUI</a> global,
16
* along with the other supported events.</p>
20
YUI().use('event-move', function (Y) {
21
Y.one('#myNode').on('gesturemovestart', function (e) {
22
Y.log('gesturemovestart Fired.');
24
Y.one('#myNode').on('gesturemove', function (e) {
25
Y.log('gesturemove Fired.');
27
Y.one('#myNode').on('gesturemoveend', function (e) {
28
Y.log('gesturemoveend Fired.');
32
* @module event-gestures
33
* @submodule event-move
37
var GESTURE_MAP = Y.Event._GESTURE_MAP,
39
start: GESTURE_MAP.start,
41
move: GESTURE_MAP.move
47
GESTURE_MOVE = "gesture" + MOVE,
48
GESTURE_MOVE_END = GESTURE_MOVE + END,
49
GESTURE_MOVE_START = GESTURE_MOVE + START,
51
_MOVE_START_HANDLE = "_msh",
53
_MOVE_END_HANDLE = "_meh",
55
_DEL_MOVE_START_HANDLE = "_dmsh",
56
_DEL_MOVE_HANDLE = "_dmh",
57
_DEL_MOVE_END_HANDLE = "_dmeh",
63
MIN_DISTANCE = "minDistance",
64
PREVENT_DEFAULT = "preventDefault",
66
OWNER_DOCUMENT = "ownerDocument",
68
CURRENT_TARGET = "currentTarget",
71
NODE_TYPE = "nodeType",
72
SUPPORTS_POINTER = Y.config.win && ("msPointerEnabled" in Y.config.win.navigator),
73
MS_TOUCH_ACTION_COUNT = 'msTouchActionCount',
74
MS_INIT_TOUCH_ACTION = 'msInitTouchAction',
76
_defArgsProcessor = function(se, args, delegate) {
77
var iConfig = (delegate) ? 4 : 3,
78
config = (args.length > iConfig) ? Y.merge(args.splice(iConfig,1)[0]) : {};
80
if (!(PREVENT_DEFAULT in config)) {
81
config[PREVENT_DEFAULT] = se.PREVENT_DEFAULT;
87
_getRoot = function(node, subscriber) {
88
return subscriber._extra.root || (node.get(NODE_TYPE) === 9) ? node : node.get(OWNER_DOCUMENT);
91
//Checks to see if the node is the document, and if it is, returns the documentElement.
92
_checkDocumentElem = function(node) {
93
var elem = node.getDOMNode();
94
if (node.compareTo(Y.config.doc) && elem.documentElement) {
95
return elem.documentElement;
102
_normTouchFacade = function(touchFacade, touch, params) {
103
touchFacade.pageX = touch.pageX;
104
touchFacade.pageY = touch.pageY;
105
touchFacade.screenX = touch.screenX;
106
touchFacade.screenY = touch.screenY;
107
touchFacade.clientX = touch.clientX;
108
touchFacade.clientY = touch.clientY;
109
touchFacade[TARGET] = touchFacade[TARGET] || touch[TARGET];
110
touchFacade[CURRENT_TARGET] = touchFacade[CURRENT_TARGET] || touch[CURRENT_TARGET];
112
touchFacade[BUTTON] = (params && params[BUTTON]) || 1; // default to left (left as per vendors, not W3C which is 0)
116
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.
118
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.
120
_setTouchActions = function (node) {
121
var elem = _checkDocumentElem(node) || node.getDOMNode(),
122
num = node.getData(MS_TOUCH_ACTION_COUNT);
124
//Checks to see if msTouchAction is supported.
125
if (SUPPORTS_POINTER) {
128
node.setData(MS_INIT_TOUCH_ACTION, elem.style.msTouchAction);
130
elem.style.msTouchAction = Y.Event._DEFAULT_TOUCH_ACTION;
132
node.setData(MS_TOUCH_ACTION_COUNT, num);
137
Resets the element's -ms-touch-action property back to the original value, This is called on detach() and detachDelegate().
139
_unsetTouchActions = function (node) {
140
var elem = _checkDocumentElem(node) || node.getDOMNode(),
141
num = node.getData(MS_TOUCH_ACTION_COUNT),
142
initTouchAction = node.getData(MS_INIT_TOUCH_ACTION);
144
if (SUPPORTS_POINTER) {
146
node.setData(MS_TOUCH_ACTION_COUNT, num);
147
if (num === 0 && elem.style.msTouchAction !== initTouchAction) {
148
elem.style.msTouchAction = initTouchAction;
153
_prevent = function(e, preventDefault) {
154
if (preventDefault) {
155
// preventDefault is a boolean or a function
156
if (!preventDefault.call || preventDefault(e)) {
162
define = Y.Event.define;
163
Y.Event._DEFAULT_TOUCH_ACTION = 'none';
166
* Sets up a "gesturemovestart" event, that is fired on touch devices in response to a single finger "touchstart",
167
* and on mouse based devices in response to a "mousedown". The subscriber can specify the minimum time
168
* and distance thresholds which should be crossed before the "gesturemovestart" is fired and for the mouse,
169
* which button should initiate a "gesturemovestart". This event can also be listened for using node.delegate().
171
* <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler,
172
* however if you want to pass the context and arguments as additional signature arguments to on/delegate,
173
* 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>
175
* @event gesturemovestart
177
* @param type {string} "gesturemovestart"
178
* @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.
179
* @param cfg {Object} Optional. An object which specifies:
182
* <dt>minDistance (defaults to 0)</dt>
183
* <dd>The minimum distance threshold which should be crossed before the gesturemovestart is fired</dd>
184
* <dt>minTime (defaults to 0)</dt>
185
* <dd>The minimum time threshold for which the finger/mouse should be help down before the gesturemovestart is fired</dd>
186
* <dt>button (no default)</dt>
187
* <dd>In the case of a mouse input device, if the event should only be fired for a specific mouse button.</dd>
188
* <dt>preventDefault (defaults to false)</dt>
189
* <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
190
* 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>
193
* @return {EventHandle} the detach handle
196
define(GESTURE_MOVE_START, {
198
on: function (node, subscriber, ce) {
200
//Set -ms-touch-action on IE10 and set preventDefault to true
201
_setTouchActions(node);
203
subscriber[_MOVE_START_HANDLE] = node.on(EVENT[START],
211
delegate : function(node, subscriber, ce, filter) {
215
subscriber[_DEL_MOVE_START_HANDLE] = node.delegate(EVENT[START],
217
se._onStart(e, node, subscriber, ce, true);
222
detachDelegate : function(node, subscriber, ce, filter) {
223
var handle = subscriber[_DEL_MOVE_START_HANDLE];
227
subscriber[_DEL_MOVE_START_HANDLE] = null;
230
_unsetTouchActions(node);
233
detach: function (node, subscriber, ce) {
234
var startHandle = subscriber[_MOVE_START_HANDLE];
237
startHandle.detach();
238
subscriber[_MOVE_START_HANDLE] = null;
241
_unsetTouchActions(node);
244
processArgs : function(args, delegate) {
245
var params = _defArgsProcessor(this, args, delegate);
247
if (!(MIN_TIME in params)) {
248
params[MIN_TIME] = this.MIN_TIME;
251
if (!(MIN_DISTANCE in params)) {
252
params[MIN_DISTANCE] = this.MIN_DISTANCE;
258
_onStart : function(e, node, subscriber, ce, delegate) {
261
node = e[CURRENT_TARGET];
264
var params = subscriber._extra,
266
minTime = params[MIN_TIME],
267
minDistance = params[MIN_DISTANCE],
268
button = params.button,
269
preventDefault = params[PREVENT_DEFAULT],
270
root = _getRoot(node, subscriber),
274
if (e.touches.length === 1) {
275
_normTouchFacade(e, e.touches[0], params);
280
fireStart = (button === undefined) || (button === e.button);
283
Y.log("gesturemovestart: params = button:" + button + ", minTime = " + minTime + ", minDistance = " + minDistance, "event-gestures");
287
_prevent(e, preventDefault);
289
if (minTime === 0 || minDistance === 0) {
290
Y.log("gesturemovestart: No minTime or minDistance. Firing immediately", "event-gestures");
291
this._start(e, node, ce, params);
295
startXY = [e.pageX, e.pageY];
299
Y.log("gesturemovestart: minTime specified. Setup timer.", "event-gestures");
300
Y.log("gesturemovestart: initialTime for minTime = " + new Date().getTime(), "event-gestures");
302
params._ht = Y.later(minTime, this, this._start, [e, node, ce, params]);
304
params._hme = root.on(EVENT[END], Y.bind(function() {
305
this._cancel(params);
309
if (minDistance > 0) {
311
Y.log("gesturemovestart: minDistance specified. Setup native mouse/touchmove listener to measure distance.", "event-gestures");
312
Y.log("gesturemovestart: initialXY for minDistance = " + startXY, "event-gestures");
314
params._hm = root.on(EVENT[MOVE], Y.bind(function(em) {
315
if (Math.abs(em.pageX - startXY[0]) > minDistance || Math.abs(em.pageY - startXY[1]) > minDistance) {
316
Y.log("gesturemovestart: minDistance hit.", "event-gestures");
317
this._start(e, node, ce, params);
325
_cancel : function(params) {
331
params._hme.detach();
340
_start : function(e, node, ce, params) {
343
this._cancel(params);
346
e.type = GESTURE_MOVE_START;
348
Y.log("gesturemovestart: Firing start: " + new Date().getTime(), "event-gestures");
350
node.setData(_MOVE_START, e);
356
PREVENT_DEFAULT : false
360
* Sets up a "gesturemove" event, that is fired on touch devices in response to a single finger "touchmove",
361
* and on mouse based devices in response to a "mousemove".
363
* <p>By default this event is only fired when the same node
364
* has received a "gesturemovestart" event. The subscriber can set standAlone to true, in the configuration properties,
365
* if they want to listen for this event without an initial "gesturemovestart".</p>
367
* <p>By default this event sets up it's internal "touchmove" and "mousemove" DOM listeners on the document element. The subscriber
368
* can set the root configuration property, to specify which node to attach DOM listeners to, if different from the document.</p>
370
* <p>This event can also be listened for using node.delegate().</p>
372
* <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler,
373
* however if you want to pass the context and arguments as additional signature arguments to on/delegate,
374
* 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>
378
* @param type {string} "gesturemove"
379
* @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.
380
* @param cfg {Object} Optional. An object which specifies:
382
* <dt>standAlone (defaults to false)</dt>
383
* <dd>true, if the subscriber should be notified even if a "gesturemovestart" has not occured on the same node.</dd>
384
* <dt>root (defaults to document)</dt>
385
* <dd>The node to which the internal DOM listeners should be attached.</dd>
386
* <dt>preventDefault (defaults to false)</dt>
387
* <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>
390
* @return {EventHandle} the detach handle
392
define(GESTURE_MOVE, {
394
on : function (node, subscriber, ce) {
396
_setTouchActions(node);
397
var root = _getRoot(node, subscriber, EVENT[MOVE]),
399
moveHandle = root.on(EVENT[MOVE],
406
subscriber[_MOVE_HANDLE] = moveHandle;
410
delegate : function(node, subscriber, ce, filter) {
414
subscriber[_DEL_MOVE_HANDLE] = node.delegate(EVENT[MOVE],
416
se._onMove(e, node, subscriber, ce, true);
421
detach : function (node, subscriber, ce) {
422
var moveHandle = subscriber[_MOVE_HANDLE];
426
subscriber[_MOVE_HANDLE] = null;
429
_unsetTouchActions(node);
432
detachDelegate : function(node, subscriber, ce, filter) {
433
var handle = subscriber[_DEL_MOVE_HANDLE];
437
subscriber[_DEL_MOVE_HANDLE] = null;
440
_unsetTouchActions(node);
444
processArgs : function(args, delegate) {
445
return _defArgsProcessor(this, args, delegate);
448
_onMove : function(e, node, subscriber, ce, delegate) {
451
node = e[CURRENT_TARGET];
454
var fireMove = subscriber._extra.standAlone || node.getData(_MOVE_START),
455
preventDefault = subscriber._extra.preventDefault;
457
Y.log("onMove initial fireMove check:" + fireMove,"event-gestures");
462
if (e.touches.length === 1) {
463
_normTouchFacade(e, e.touches[0]);
471
_prevent(e, preventDefault);
473
Y.log("onMove second fireMove check:" + fireMove,"event-gestures");
475
e.type = GESTURE_MOVE;
481
PREVENT_DEFAULT : false
485
* Sets up a "gesturemoveend" event, that is fired on touch devices in response to a single finger "touchend",
486
* and on mouse based devices in response to a "mouseup".
488
* <p>By default this event is only fired when the same node
489
* has received a "gesturemove" or "gesturemovestart" event. The subscriber can set standAlone to true, in the configuration properties,
490
* if they want to listen for this event without a preceding "gesturemovestart" or "gesturemove".</p>
492
* <p>By default this event sets up it's internal "touchend" and "mouseup" DOM listeners on the document element. The subscriber
493
* can set the root configuration property, to specify which node to attach DOM listeners to, if different from the document.</p>
495
* <p>This event can also be listened for using node.delegate().</p>
497
* <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler,
498
* however if you want to pass the context and arguments as additional signature arguments to on/delegate,
499
* 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>
502
* @event gesturemoveend
504
* @param type {string} "gesturemoveend"
505
* @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mouseup or touchend.changedTouches[0]).
506
* @param cfg {Object} Optional. An object which specifies:
508
* <dt>standAlone (defaults to false)</dt>
509
* <dd>true, if the subscriber should be notified even if a "gesturemovestart" or "gesturemove" has not occured on the same node.</dd>
510
* <dt>root (defaults to document)</dt>
511
* <dd>The node to which the internal DOM listeners should be attached.</dd>
512
* <dt>preventDefault (defaults to false)</dt>
513
* <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>
516
* @return {EventHandle} the detach handle
518
define(GESTURE_MOVE_END, {
520
on : function (node, subscriber, ce) {
521
_setTouchActions(node);
522
var root = _getRoot(node, subscriber),
524
endHandle = root.on(EVENT[END],
531
subscriber[_MOVE_END_HANDLE] = endHandle;
534
delegate : function(node, subscriber, ce, filter) {
538
subscriber[_DEL_MOVE_END_HANDLE] = node.delegate(EVENT[END],
540
se._onEnd(e, node, subscriber, ce, true);
545
detachDelegate : function(node, subscriber, ce, filter) {
546
var handle = subscriber[_DEL_MOVE_END_HANDLE];
550
subscriber[_DEL_MOVE_END_HANDLE] = null;
553
_unsetTouchActions(node);
557
detach : function (node, subscriber, ce) {
558
var endHandle = subscriber[_MOVE_END_HANDLE];
562
subscriber[_MOVE_END_HANDLE] = null;
565
_unsetTouchActions(node);
568
processArgs : function(args, delegate) {
569
return _defArgsProcessor(this, args, delegate);
572
_onEnd : function(e, node, subscriber, ce, delegate) {
575
node = e[CURRENT_TARGET];
578
var fireMoveEnd = subscriber._extra.standAlone || node.getData(_MOVE) || node.getData(_MOVE_START),
579
preventDefault = subscriber._extra.preventDefault;
583
if (e.changedTouches) {
584
if (e.changedTouches.length === 1) {
585
_normTouchFacade(e, e.changedTouches[0]);
593
_prevent(e, preventDefault);
595
e.type = GESTURE_MOVE_END;
598
node.clearData(_MOVE_START);
599
node.clearData(_MOVE);
604
PREVENT_DEFAULT : false
608
}, '3.10.3', {"requires": ["node-base", "event-touch", "event-synthetic"]});