Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('event-tap', function (Y, NAME) {
2
 
3
/**
4
The tap module provides a gesture events, "tap", which normalizes user interactions
5
across touch and mouse or pointer based input devices.  This can be used by application developers
6
to build input device agnostic components which behave the same in response to either touch or mouse based
7
interaction.
8
 
9
'tap' is like a touchscreen 'click', only it requires much less finger-down time since it listens to touch events,
10
but reverts to mouse events if touch is not supported.
11
 
12
@example
13
 
14
    YUI().use('event-tap', function (Y) {
15
        Y.one('#my-button').on('tap', function (e) {
16
            Y.log('Button was tapped on');
17
        });
18
    });
19
 
20
@module event
21
@submodule event-tap
22
@author Andres Garza, matuzak and tilo mitra
23
@since 3.7.0
24
 
25
*/
26
var doc = Y.config.doc,
27
    GESTURE_MAP = Y.Event._GESTURE_MAP,
28
    EVT_START = GESTURE_MAP.start,
29
    EVT_TAP = 'tap',
30
    POINTER_EVENT_TEST = /pointer/i,
31
 
32
    HANDLES = {
33
        START: 'Y_TAP_ON_START_HANDLE',
34
        END: 'Y_TAP_ON_END_HANDLE',
35
        CANCEL: 'Y_TAP_ON_CANCEL_HANDLE'
36
    };
37
 
38
function detachHandles(subscription, handles) {
39
    handles = handles || Y.Object.values(HANDLES);
40
 
41
    Y.Array.each(handles, function (item) {
42
        var handle = subscription[item];
43
        if (handle) {
44
            handle.detach();
45
            subscription[item] = null;
46
        }
47
    });
48
 
49
}
50
 
51
 
52
/**
53
Sets up a "tap" event, that is fired on touch devices in response to a tap event (finger down, finder up).
54
This event can be used instead of listening for click events which have a 500ms delay on most touch devices.
55
This event can also be listened for using node.delegate().
56
 
57
@event tap
58
@param type {string} "tap"
59
@param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event.
60
@for Event
61
@return {EventHandle} the detach handle
62
*/
63
Y.Event.define(EVT_TAP, {
64
    publishConfig: {
65
        preventedFn: function (e) {
66
            var sub = e.target.once('click', function (click) {
67
                click.preventDefault();
68
            });
69
 
70
            // Make sure to detach the subscription during the next event loop
71
            // so this doesn't `preventDefault()` on the wrong click event.
72
            setTimeout(function () {
73
                sub.detach();
74
            //Setting this to `0` causes the detachment to occur before the click
75
            //comes in on Android 4.0.3-4.0.4. 100ms seems to be a reliable number here
76
            //that works across the board.
77
            }, 100);
78
        }
79
    },
80
 
81
    processArgs: function (args, isDelegate) {
82
 
83
        //if we return for the delegate use case, then the `filter` argument
84
        //returns undefined, and we have to get the filter from sub._extra[0] (ugly)
85
 
86
        if (!isDelegate) {
87
            var extra = args[3];
88
            // remove the extra arguments from the array as specified by
89
            // http://yuilibrary.com/yui/docs/event/synths.html
90
            args.splice(3,1);
91
            return extra;
92
        }
93
    },
94
    /**
95
    This function should set up the node that will eventually fire the event.
96
 
97
    Usage:
98
 
99
        node.on('tap', function (e) {
100
            Y.log('the node was tapped on');
101
        });
102
 
103
    @method on
104
    @param {Node} node
105
    @param {Array} subscription
106
    @param {Boolean} notifier
107
    @public
108
    @static
109
    **/
110
    on: function (node, subscription, notifier) {
111
        subscription[HANDLES.START] = node.on(EVT_START, this._start, this, node, subscription, notifier);
112
    },
113
 
114
    /**
115
    Detaches all event subscriptions set up by the event-tap module
116
 
117
    @method detach
118
    @param {Node} node
119
    @param {Array} subscription
120
    @param {Boolean} notifier
121
    @public
122
    @static
123
    **/
124
    detach: function (node, subscription, notifier) {
125
        detachHandles(subscription);
126
    },
127
 
128
    /**
129
    Event delegation for the 'tap' event. The delegated event will use a
130
    supplied selector or filtering function to test if the event references at least one
131
    node that should trigger the subscription callback.
132
 
133
    Usage:
134
 
135
        node.delegate('tap', function (e) {
136
            Y.log('li a inside node was tapped.');
137
        }, 'li a');
138
 
139
    @method delegate
140
    @param {Node} node
141
    @param {Array} subscription
142
    @param {Boolean} notifier
143
    @param {String | Function} filter
144
    @public
145
    @static
146
    **/
147
    delegate: function (node, subscription, notifier, filter) {
148
        subscription[HANDLES.START] = Y.delegate(EVT_START, function (e) {
149
            this._start(e, node, subscription, notifier, true);
150
        }, node, filter, this);
151
    },
152
 
153
    /**
154
    Detaches the delegated event subscriptions set up by the event-tap module.
155
    Only used if you use node.delegate(...) instead of node.on(...);
156
 
157
    @method detachDelegate
158
    @param {Node} node
159
    @param {Array} subscription
160
    @param {Boolean} notifier
161
    @public
162
    @static
163
    **/
164
    detachDelegate: function (node, subscription, notifier) {
165
        detachHandles(subscription);
166
    },
167
 
168
    /**
169
    Called when the monitor(s) are tapped on, either through touchstart or mousedown.
170
 
171
    @method _start
172
    @param {DOMEventFacade} event
173
    @param {Node} node
174
    @param {Array} subscription
175
    @param {Boolean} notifier
176
    @param {Boolean} delegate
177
    @protected
178
    @static
179
    **/
180
    _start: function (event, node, subscription, notifier, delegate) {
181
 
182
        var context = {
183
                canceled: false,
184
                eventType: event.type
185
            },
186
            preventMouse = subscription.preventMouse || false;
187
 
188
        //move ways to quit early to the top.
189
        // no right clicks
190
        if (event.button && event.button === 3) {
191
            return;
192
        }
193
 
194
        // for now just support a 1 finger count (later enhance via config)
195
        if (event.touches && event.touches.length !== 1) {
196
            return;
197
        }
198
 
199
        context.node = delegate ? event.currentTarget : node;
200
 
201
        //There is a double check in here to support event simulation tests, in which
202
        //event.touches can be undefined when simulating 'touchstart' on touch devices.
203
        if (event.touches) {
204
          context.startXY = [ event.touches[0].pageX, event.touches[0].pageY ];
205
        }
206
        else {
207
          context.startXY = [ event.pageX, event.pageY ];
208
        }
209
 
210
        //If `onTouchStart()` was called by a touch event, set up touch event subscriptions.
211
        //Otherwise, set up mouse/pointer event event subscriptions.
212
        if (event.touches) {
213
 
214
            subscription[HANDLES.END] = node.once('touchend', this._end, this, node, subscription, notifier, delegate, context);
215
            subscription[HANDLES.CANCEL] = node.once('touchcancel', this.detach, this, node, subscription, notifier, delegate, context);
216
 
217
            //Since this is a touch* event, there will be corresponding mouse events
218
            //that will be fired. We don't want these events to get picked up and fire
219
            //another `tap` event, so we'll set this variable to `true`.
220
            subscription.preventMouse = true;
221
        }
222
 
223
        //Only add these listeners if preventMouse is `false`
224
        //ie: not when touch events have already been subscribed to
225
        else if (context.eventType.indexOf('mouse') !== -1 && !preventMouse) {
226
            subscription[HANDLES.END] = node.once('mouseup', this._end, this, node, subscription, notifier, delegate, context);
227
            subscription[HANDLES.CANCEL] = node.once('mousecancel', this.detach, this, node, subscription, notifier, delegate, context);
228
        }
229
 
230
        //If a mouse event comes in after a touch event, it will go in here and
231
        //reset preventMouse to `true`.
232
        //If a mouse event comes in without a prior touch event, preventMouse will be
233
        //false in any case, so this block doesn't do anything.
234
        else if (context.eventType.indexOf('mouse') !== -1 && preventMouse) {
235
            subscription.preventMouse = false;
236
        }
237
 
238
        else if (POINTER_EVENT_TEST.test(context.eventType)) {
239
            subscription[HANDLES.END] = node.once(GESTURE_MAP.end, this._end, this, node, subscription, notifier, delegate, context);
240
            subscription[HANDLES.CANCEL] = node.once(GESTURE_MAP.cancel, this.detach, this, node, subscription, notifier, delegate, context);
241
        }
242
 
243
    },
244
 
245
 
246
    /**
247
    Called when the monitor(s) fires a touchend event (or the mouse equivalent).
248
    This method fires the 'tap' event if certain requirements are met.
249
 
250
    @method _end
251
    @param {DOMEventFacade} event
252
    @param {Node} node
253
    @param {Array} subscription
254
    @param {Boolean} notifier
255
    @param {Boolean} delegate
256
    @param {Object} context
257
    @protected
258
    @static
259
    **/
260
    _end: function (event, node, subscription, notifier, delegate, context) {
261
        var startXY = context.startXY,
262
            endXY,
263
            clientXY,
264
            sensitivity = 15;
265
 
266
        if (subscription._extra && subscription._extra.sensitivity >= 0) {
267
            sensitivity = subscription._extra.sensitivity;
268
        }
269
 
270
        //There is a double check in here to support event simulation tests, in which
271
        //event.touches can be undefined when simulating 'touchstart' on touch devices.
272
        if (event.changedTouches) {
273
          endXY = [ event.changedTouches[0].pageX, event.changedTouches[0].pageY ];
274
          clientXY = [event.changedTouches[0].clientX, event.changedTouches[0].clientY];
275
        }
276
        else {
277
          endXY = [ event.pageX, event.pageY ];
278
          clientXY = [event.clientX, event.clientY];
279
        }
280
 
281
        // make sure mouse didn't move
282
        if (Math.abs(endXY[0] - startXY[0]) <= sensitivity && Math.abs(endXY[1] - startXY[1]) <= sensitivity) {
283
 
284
            event.type = EVT_TAP;
285
            event.pageX = endXY[0];
286
            event.pageY = endXY[1];
287
            event.clientX = clientXY[0];
288
            event.clientY = clientXY[1];
289
            event.currentTarget = context.node;
290
 
291
            notifier.fire(event);
292
        }
293
 
294
        detachHandles(subscription, [HANDLES.END, HANDLES.CANCEL]);
295
    }
296
});
297
 
298
 
299
}, '3.18.1', {"requires": ["node-base", "event-base", "event-touch", "event-synthetic"]});