Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('event-focus', function (Y, NAME) {
2
 
3
/**
4
 * Adds bubbling and delegation support to DOM events focus and blur.
5
 *
6
 * @module event
7
 * @submodule event-focus
8
 */
9
var Event    = Y.Event,
10
 
11
    YLang    = Y.Lang,
12
 
13
    isString = YLang.isString,
14
 
15
    arrayIndex = Y.Array.indexOf,
16
 
17
    useActivate = (function() {
18
 
19
        // Changing the structure of this test, so that it doesn't use inline JS in HTML,
20
        // which throws an exception in Win8 packaged apps, due to additional security restrictions:
21
        // http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences
22
 
23
        var supported = false,
24
            doc = Y.config.doc,
25
            p;
26
 
27
        if (doc) {
28
 
29
            p = doc.createElement("p");
30
            p.setAttribute("onbeforeactivate", ";");
31
 
32
            // onbeforeactivate is a function in IE8+.
33
            // onbeforeactivate is a string in IE6,7 (unfortunate, otherwise we could have just checked for function below).
34
            // onbeforeactivate is a function in IE10, in a Win8 App environment (no exception running the test).
35
 
36
            // onbeforeactivate is undefined in Webkit/Gecko.
37
            // onbeforeactivate is a function in Webkit/Gecko if it's a supported event (e.g. onclick).
38
 
39
            supported = (p.onbeforeactivate !== undefined);
40
        }
41
 
42
        return supported;
43
    }());
44
 
45
function define(type, proxy, directEvent) {
46
    var nodeDataKey = '_' + type + 'Notifiers';
47
 
48
    Y.Event.define(type, {
49
 
50
        _useActivate : useActivate,
51
 
52
        _attach: function (el, notifier, delegate) {
53
            if (Y.DOM.isWindow(el)) {
54
                return Event._attach([type, function (e) {
55
                    notifier.fire(e);
56
                }, el]);
57
            } else {
58
                return Event._attach(
59
                    [proxy, this._proxy, el, this, notifier, delegate],
60
                    { capture: true });
61
            }
62
        },
63
 
64
        _proxy: function (e, notifier, delegate) {
65
            var target        = e.target,
66
                currentTarget = e.currentTarget,
67
                notifiers     = target.getData(nodeDataKey),
68
                yuid          = Y.stamp(currentTarget._node),
69
                defer         = (useActivate || target !== currentTarget),
70
                directSub;
71
 
72
            notifier.currentTarget = (delegate) ? target : currentTarget;
73
            notifier.container     = (delegate) ? currentTarget : null;
74
 
75
            // Maintain a list to handle subscriptions from nested
76
            // containers div#a>div#b>input #a.on(focus..) #b.on(focus..),
77
            // use one focus or blur subscription that fires notifiers from
78
            // #b then #a to emulate bubble sequence.
79
            if (!notifiers) {
80
                notifiers = {};
81
                target.setData(nodeDataKey, notifiers);
82
 
83
                // only subscribe to the element's focus if the target is
84
                // not the current target (
85
                if (defer) {
86
                    directSub = Event._attach(
87
                        [directEvent, this._notify, target._node]).sub;
88
                    directSub.once = true;
89
                }
90
            } else {
91
                // In old IE, defer is always true.  In capture-phase browsers,
92
                // The delegate subscriptions will be encountered first, which
93
                // will establish the notifiers data and direct subscription
94
                // on the node.  If there is also a direct subscription to the
95
                // node's focus/blur, it should not call _notify because the
96
                // direct subscription from the delegate sub(s) exists, which
97
                // will call _notify.  So this avoids _notify being called
98
                // twice, unnecessarily.
99
                defer = true;
100
            }
101
 
102
            if (!notifiers[yuid]) {
103
                notifiers[yuid] = [];
104
            }
105
 
106
            notifiers[yuid].push(notifier);
107
 
108
            if (!defer) {
109
                this._notify(e);
110
            }
111
        },
112
 
113
        _notify: function (e, container) {
114
            var currentTarget = e.currentTarget,
115
                notifierData  = currentTarget.getData(nodeDataKey),
116
                axisNodes     = currentTarget.ancestors(),
117
                doc           = currentTarget.get('ownerDocument'),
118
                delegates     = [],
119
                                // Used to escape loops when there are no more
120
                                // notifiers to consider
121
                count         = notifierData ?
122
                                    Y.Object.keys(notifierData).length :
123
                                    0,
124
                target, notifiers, notifier, yuid, match, tmp, i, len, sub, ret;
125
 
126
            // clear the notifications list (mainly for delegation)
127
            currentTarget.clearData(nodeDataKey);
128
 
129
            // Order the delegate subs by their placement in the parent axis
130
            axisNodes.push(currentTarget);
131
            // document.get('ownerDocument') returns null
132
            // which we'll use to prevent having duplicate Nodes in the list
133
            if (doc) {
134
                axisNodes.unshift(doc);
135
            }
136
 
137
            // ancestors() returns the Nodes from top to bottom
138
            axisNodes._nodes.reverse();
139
 
140
            if (count) {
141
                // Store the count for step 2
142
                tmp = count;
143
                axisNodes.some(function (node) {
144
                    var yuid      = Y.stamp(node),
145
                        notifiers = notifierData[yuid],
146
                        i, len;
147
 
148
                    if (notifiers) {
149
                        count--;
150
                        for (i = 0, len = notifiers.length; i < len; ++i) {
151
                            if (notifiers[i].handle.sub.filter) {
152
                                delegates.push(notifiers[i]);
153
                            }
154
                        }
155
                    }
156
 
157
                    return !count;
158
                });
159
                count = tmp;
160
            }
161
 
162
            // Walk up the parent axis, notifying direct subscriptions and
163
            // testing delegate filters.
164
            while (count && (target = axisNodes.shift())) {
165
                yuid = Y.stamp(target);
166
 
167
                notifiers = notifierData[yuid];
168
 
169
                if (notifiers) {
170
                    for (i = 0, len = notifiers.length; i < len; ++i) {
171
                        notifier = notifiers[i];
172
                        sub      = notifier.handle.sub;
173
                        match    = true;
174
 
175
                        e.currentTarget = target;
176
 
177
                        if (sub.filter) {
178
                            match = sub.filter.apply(target,
179
                                [target, e].concat(sub.args || []));
180
 
181
                            // No longer necessary to test against this
182
                            // delegate subscription for the nodes along
183
                            // the parent axis.
184
                            delegates.splice(
185
                                arrayIndex(delegates, notifier), 1);
186
                        }
187
 
188
                        if (match) {
189
                            // undefined for direct subs
190
                            e.container = notifier.container;
191
                            ret = notifier.fire(e);
192
                        }
193
 
194
                        if (ret === false || e.stopped === 2) {
195
                            break;
196
                        }
197
                    }
198
 
199
                    delete notifiers[yuid];
200
                    count--;
201
                }
202
 
203
                if (e.stopped !== 2) {
204
                    // delegates come after subs targeting this specific node
205
                    // because they would not normally report until they'd
206
                    // bubbled to the container node.
207
                    for (i = 0, len = delegates.length; i < len; ++i) {
208
                        notifier = delegates[i];
209
                        sub = notifier.handle.sub;
210
 
211
                        if (sub.filter.apply(target,
212
                            [target, e].concat(sub.args || []))) {
213
 
214
                            e.container = notifier.container;
215
                            e.currentTarget = target;
216
                            ret = notifier.fire(e);
217
                        }
218
 
219
                        if (ret === false || e.stopped === 2 ||
220
                            // If e.stopPropagation() is called, notify any
221
                            // delegate subs from the same container, but break
222
                            // once the container changes. This emulates
223
                            // delegate() behavior for events like 'click' which
224
                            // won't notify delegates higher up the parent axis.
225
                            (e.stopped && delegates[i+1] &&
226
                             delegates[i+1].container !== notifier.container)) {
227
                            break;
228
                        }
229
                    }
230
                }
231
 
232
                if (e.stopped) {
233
                    break;
234
                }
235
            }
236
        },
237
 
238
        on: function (node, sub, notifier) {
239
            sub.handle = this._attach(node._node, notifier);
240
        },
241
 
242
        detach: function (node, sub) {
243
            sub.handle.detach();
244
        },
245
 
246
        delegate: function (node, sub, notifier, filter) {
247
            if (isString(filter)) {
248
                sub.filter = function (target) {
249
                    return Y.Selector.test(target._node, filter,
250
                        node === target ? null : node._node);
251
                };
252
            }
253
 
254
            sub.handle = this._attach(node._node, notifier, true);
255
        },
256
 
257
        detachDelegate: function (node, sub) {
258
            sub.handle.detach();
259
        }
260
    }, true);
261
}
262
 
263
// For IE, we need to defer to focusin rather than focus because
264
// `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
265
// el.onfocusin, doSomething, then el.onfocus.  All others support capture
266
// phase focus, which executes before doSomething.  To guarantee consistent
267
// behavior for this use case, IE's direct subscriptions are made against
268
// focusin so subscribers will be notified before js following el.focus() is
269
// executed.
270
if (useActivate) {
271
    //     name     capture phase       direct subscription
272
    define("focus", "beforeactivate",   "focusin");
273
    define("blur",  "beforedeactivate", "focusout");
274
} else {
275
    define("focus", "focus", "focus");
276
    define("blur",  "blur",  "blur");
277
}
278
 
279
 
280
}, '3.18.1', {"requires": ["event-synthetic"]});