2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('event-focus', function(Y) {
11 * Adds bubbling and delegation support to DOM events focus and blur.
14 * @submodule event-focus
18 isString = YLang.isString,
19 useActivate = YLang.isFunction(
20 Y.DOM.create('<p onbeforeactivate=";"/>').onbeforeactivate);
22 function define(type, proxy, directEvent) {
23 var nodeDataKey = '_' + type + 'Notifiers';
25 Y.Event.define(type, {
27 _attach: function (el, notifier, delegate) {
28 if (Y.DOM.isWindow(el)) {
29 return Event._attach([type, function (e) {
34 [proxy, this._proxy, el, this, notifier, delegate],
39 _proxy: function (e, notifier, delegate) {
41 notifiers = node.getData(nodeDataKey),
42 yuid = Y.stamp(e.currentTarget._node),
43 defer = (useActivate || e.target !== e.currentTarget),
44 sub = notifier.handle.sub,
45 filterArgs = [node, e].concat(sub.args || []),
48 notifier.currentTarget = (delegate) ? node : e.currentTarget;
49 notifier.container = (delegate) ? e.currentTarget : null;
51 if (!sub.filter || sub.filter.apply(node, filterArgs)) {
52 // Maintain a list to handle subscriptions from nested
53 // containers div#a>div#b>input #a.on(focus..) #b.on(focus..),
54 // use one focus or blur subscription that fires notifiers from
55 // #b then #a to emulate bubble sequence.
58 node.setData(nodeDataKey, notifiers);
60 // only subscribe to the element's focus if the target is
61 // not the current target (
63 directSub = Event._attach(
64 [directEvent, this._notify, node._node]).sub;
65 directSub.once = true;
69 if (!notifiers[yuid]) {
73 notifiers[yuid].push(notifier);
81 _notify: function (e, container) {
82 var node = e.currentTarget,
83 notifiers = node.getData(nodeDataKey),
84 // document.get('ownerDocument') returns null
85 doc = node.get('ownerDocument') || node,
91 // Walk up the parent axis until the origin node,
92 while (target && target !== doc) {
93 nots.push.apply(nots, notifiers[Y.stamp(target)] || []);
94 target = target.get('parentNode');
96 nots.push.apply(nots, notifiers[Y.stamp(doc)] || []);
98 for (i = 0, len = nots.length; i < len; ++i) {
100 e.currentTarget = nots[i].currentTarget;
102 if (notifier.container) {
103 e.container = notifier.container;
111 // clear the notifications list (mainly for delegation)
112 node.clearData(nodeDataKey);
116 on: function (node, sub, notifier) {
117 sub.onHandle = this._attach(node._node, notifier);
120 detach: function (node, sub) {
121 sub.onHandle.detach();
124 delegate: function (node, sub, notifier, filter) {
125 if (isString(filter)) {
126 sub.filter = Y.delegate.compileFilter(filter);
129 sub.delegateHandle = this._attach(node._node, notifier, true);
132 detachDelegate: function (node, sub) {
133 sub.delegateHandle.detach();
138 // For IE, we need to defer to focusin rather than focus because
139 // `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
140 // el.onfocusin, doSomething, then el.onfocus. All others support capture
141 // phase focus, which executes before doSomething. To guarantee consistent
142 // behavior for this use case, IE's direct subscriptions are made against
143 // focusin so subscribers will be notified before js following el.focus() is
146 // name capture phase direct subscription
147 define("focus", "beforeactivate", "focusin");
148 define("blur", "beforedeactivate", "focusout");
150 define("focus", "focus", "focus");
151 define("blur", "blur", "blur");
155 }, '3.3.0' ,{requires:['event-synthetic']});