3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('event-focus', function(Y) {
10
* Adds bubbling and delegation support to DOM events focus and blur.
13
* @submodule event-focus
17
isString = YLang.isString,
18
useActivate = YLang.isFunction(
19
Y.DOM.create('<p onbeforeactivate=";"/>').onbeforeactivate);
21
function define(type, proxy, directEvent) {
22
var nodeDataKey = '_' + type + 'Notifiers';
24
Y.Event.define(type, {
26
_attach: function (el, notifier, delegate) {
27
if (Y.DOM.isWindow(el)) {
28
return Event._attach([type, function (e) {
33
[proxy, this._proxy, el, this, notifier, delegate],
38
_proxy: function (e, notifier, delegate) {
40
notifiers = node.getData(nodeDataKey),
41
yuid = Y.stamp(e.currentTarget._node),
42
defer = (useActivate || e.target !== e.currentTarget),
43
sub = notifier.handle.sub,
44
filterArgs = [node, e].concat(sub.args || []),
47
notifier.currentTarget = (delegate) ? node : e.currentTarget;
48
notifier.container = (delegate) ? e.currentTarget : null;
50
if (!sub.filter || sub.filter.apply(node, filterArgs)) {
51
// Maintain a list to handle subscriptions from nested
52
// containers div#a>div#b>input #a.on(focus..) #b.on(focus..),
53
// use one focus or blur subscription that fires notifiers from
54
// #b then #a to emulate bubble sequence.
57
node.setData(nodeDataKey, notifiers);
59
// only subscribe to the element's focus if the target is
60
// not the current target (
62
directSub = Event._attach(
63
[directEvent, this._notify, node._node]).sub;
64
directSub.once = true;
68
if (!notifiers[yuid]) {
72
notifiers[yuid].push(notifier);
80
_notify: function (e, container) {
81
var node = e.currentTarget,
82
notifiers = node.getData(nodeDataKey),
83
// document.get('ownerDocument') returns null
84
doc = node.get('ownerDocument') || node,
90
// Walk up the parent axis until the origin node,
91
while (target && target !== doc) {
92
nots.push.apply(nots, notifiers[Y.stamp(target)] || []);
93
target = target.get('parentNode');
95
nots.push.apply(nots, notifiers[Y.stamp(doc)] || []);
97
for (i = 0, len = nots.length; i < len; ++i) {
99
e.currentTarget = nots[i].currentTarget;
101
if (notifier.container) {
102
e.container = notifier.container;
108
// clear the notifications list (mainly for delegation)
109
node.clearData(nodeDataKey);
113
on: function (node, sub, notifier) {
114
sub.onHandle = this._attach(node._node, notifier);
117
detach: function (node, sub) {
118
sub.onHandle.detach();
121
delegate: function (node, sub, notifier, filter) {
122
if (isString(filter)) {
123
sub.filter = Y.delegate.compileFilter(filter);
126
sub.delegateHandle = this._attach(node._node, notifier, true);
129
detachDelegate: function (node, sub) {
130
sub.delegateHandle.detach();
135
// For IE, we need to defer to focusin rather than focus because
136
// `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
137
// el.onfocusin, doSomething, then el.onfocus. All others support capture
138
// phase focus, which executes before doSomething. To guarantee consistent
139
// behavior for this use case, IE's direct subscriptions are made against
140
// focusin so subscribers will be notified before js following el.focus() is
143
// name capture phase direct subscription
144
define("focus", "beforeactivate", "focusin");
145
define("blur", "beforedeactivate", "focusout");
147
define("focus", "focus", "focus");
148
define("blur", "blur", "blur");
152
}, '3.4.1' ,{requires:['event-synthetic']});