0
|
1 /*
|
|
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
|
|
3 Code licensed under the BSD License:
|
|
4 http://developer.yahoo.net/yui/license.txt
|
|
5 version: 2.8.0r4
|
|
6 */
|
|
7 /**
|
|
8 * Augments the Event Utility with a <code>delegate</code> method that
|
|
9 * facilitates easy creation of delegated event listeners. (Note: Using CSS
|
|
10 * selectors as the filtering criteria for delegated event listeners requires
|
|
11 * inclusion of the Selector Utility.)
|
|
12 *
|
|
13 * @module event-delegate
|
|
14 * @title Event Utility Event Delegation Module
|
|
15 * @namespace YAHOO.util
|
|
16 * @requires event
|
|
17 */
|
|
18
|
|
19 (function () {
|
|
20
|
|
21 var Event = YAHOO.util.Event,
|
|
22 Lang = YAHOO.lang,
|
|
23 delegates = [],
|
|
24
|
|
25
|
|
26 getMatch = function(el, selector, container) {
|
|
27
|
|
28 var returnVal;
|
|
29
|
|
30 if (!el || el === container) {
|
|
31 returnVal = false;
|
|
32 }
|
|
33 else {
|
|
34 returnVal = YAHOO.util.Selector.test(el, selector) ? el: getMatch(el.parentNode, selector, container);
|
|
35 }
|
|
36
|
|
37 return returnVal;
|
|
38
|
|
39 };
|
|
40
|
|
41
|
|
42 Lang.augmentObject(Event, {
|
|
43
|
|
44 /**
|
|
45 * Creates a delegate function used to call event listeners specified
|
|
46 * via the <code>YAHOO.util.Event.delegate</code> method.
|
|
47 *
|
|
48 * @method _createDelegate
|
|
49 *
|
|
50 * @param {Function} fn The method (event listener) to call.
|
|
51 * @param {Function|string} filter Function or CSS selector used to
|
|
52 * determine for what element(s) the event listener should be called.
|
|
53 * @param {Object} obj An arbitrary object that will be
|
|
54 * passed as a parameter to the listener.
|
|
55 * @param {Boolean|object} overrideContext If true, the value of the
|
|
56 * obj parameter becomes the execution context
|
|
57 * of the listener. If an object, this object
|
|
58 * becomes the execution context.
|
|
59 * @return {Function} Function that will call the event listener
|
|
60 * specified by the <code>YAHOO.util.Event.delegate</code> method.
|
|
61 * @private
|
|
62 * @for Event
|
|
63 * @static
|
|
64 */
|
|
65 _createDelegate: function (fn, filter, obj, overrideContext) {
|
|
66
|
|
67 return function (event) {
|
|
68
|
|
69 var container = this,
|
|
70 target = Event.getTarget(event),
|
|
71 selector = filter,
|
|
72
|
|
73 // The user might have specified the document object
|
|
74 // as the delegation container, in which case it is not
|
|
75 // nessary to scope the provided CSS selector(s) to the
|
|
76 // delegation container
|
|
77 bDocument = (container.nodeType === 9),
|
|
78
|
|
79 matchedEl,
|
|
80 context,
|
|
81 sID,
|
|
82 sIDSelector;
|
|
83
|
|
84
|
|
85 if (Lang.isFunction(filter)) {
|
|
86 matchedEl = filter(target);
|
|
87 }
|
|
88 else if (Lang.isString(filter)) {
|
|
89
|
|
90 if (!bDocument) {
|
|
91
|
|
92 sID = container.id;
|
|
93
|
|
94 if (!sID) {
|
|
95 sID = Event.generateId(container);
|
|
96 }
|
|
97
|
|
98 // Scope all selectors to the container
|
|
99 sIDSelector = ("#" + sID + " ");
|
|
100 selector = (sIDSelector + filter).replace(/,/gi, ("," + sIDSelector));
|
|
101
|
|
102 }
|
|
103
|
|
104
|
|
105 if (YAHOO.util.Selector.test(target, selector)) {
|
|
106 matchedEl = target;
|
|
107 }
|
|
108 else if (YAHOO.util.Selector.test(target, ((selector.replace(/,/gi, " *,")) + " *"))) {
|
|
109
|
|
110 // The target is a descendant of an element matching
|
|
111 // the selector, so crawl up to find the ancestor that
|
|
112 // matches the selector
|
|
113
|
|
114 matchedEl = getMatch(target, selector, container);
|
|
115
|
|
116 }
|
|
117
|
|
118 }
|
|
119
|
|
120
|
|
121 if (matchedEl) {
|
|
122
|
|
123 // The default context for delegated listeners is the
|
|
124 // element that matched the filter.
|
|
125
|
|
126 context = matchedEl;
|
|
127
|
|
128 if (overrideContext) {
|
|
129 if (overrideContext === true) {
|
|
130 context = obj;
|
|
131 } else {
|
|
132 context = overrideContext;
|
|
133 }
|
|
134 }
|
|
135
|
|
136 // Call the listener passing in the container and the
|
|
137 // element that matched the filter in case the user
|
|
138 // needs those.
|
|
139
|
|
140 return fn.call(context, event, matchedEl, container, obj);
|
|
141
|
|
142 }
|
|
143
|
|
144 };
|
|
145
|
|
146 },
|
|
147
|
|
148
|
|
149 /**
|
|
150 * Appends a delegated event listener. Delegated event listeners
|
|
151 * receive three arguments by default: the DOM event, the element
|
|
152 * specified by the filtering function or CSS selector, and the
|
|
153 * container element (the element to which the event listener is
|
|
154 * bound). (Note: Using the delegate method requires the event-delegate
|
|
155 * module. Using CSS selectors as the filtering criteria for delegated
|
|
156 * event listeners requires inclusion of the Selector Utility.)
|
|
157 *
|
|
158 * @method delegate
|
|
159 *
|
|
160 * @param {String|HTMLElement|Array|NodeList} container An id, an element
|
|
161 * reference, or a collection of ids and/or elements to assign the
|
|
162 * listener to.
|
|
163 * @param {String} type The type of event listener to append
|
|
164 * @param {Function} fn The method the event invokes
|
|
165 * @param {Function|string} filter Function or CSS selector used to
|
|
166 * determine for what element(s) the event listener should be called.
|
|
167 * When a function is specified, the function should return an
|
|
168 * HTML element. Using a CSS Selector requires the inclusion of the
|
|
169 * CSS Selector Utility.
|
|
170 * @param {Object} obj An arbitrary object that will be
|
|
171 * passed as a parameter to the listener
|
|
172 * @param {Boolean|object} overrideContext If true, the value of the obj parameter becomes
|
|
173 * the execution context of the listener. If an
|
|
174 * object, this object becomes the execution
|
|
175 * context.
|
|
176 * @return {Boolean} Returns true if the action was successful or defered,
|
|
177 * false if one or more of the elements
|
|
178 * could not have the listener attached,
|
|
179 * or if the operation throws an exception.
|
|
180 * @static
|
|
181 * @for Event
|
|
182 */
|
|
183 delegate: function (container, type, fn, filter, obj, overrideContext) {
|
|
184
|
|
185 var sType = type,
|
|
186 fnMouseDelegate,
|
|
187 fnDelegate;
|
|
188
|
|
189
|
|
190 if (Lang.isString(filter) && !YAHOO.util.Selector) {
|
|
191 YAHOO.log("Using a CSS selector to define the filtering criteria for a delegated listener requires the Selector Utility.", "error", "Event");
|
|
192 return false;
|
|
193 }
|
|
194
|
|
195
|
|
196 if (type == "mouseenter" || type == "mouseleave") {
|
|
197
|
|
198 if (!Event._createMouseDelegate) {
|
|
199 YAHOO.log("Delegating a " + type + " event requires the event-mouseenter module.", "error", "Event");
|
|
200 return false;
|
|
201 }
|
|
202
|
|
203 // Look up the real event--either mouseover or mouseout
|
|
204 sType = Event._getType(type);
|
|
205
|
|
206 fnMouseDelegate = Event._createMouseDelegate(fn, obj, overrideContext);
|
|
207
|
|
208 fnDelegate = Event._createDelegate(function (event, matchedEl, container) {
|
|
209
|
|
210 return fnMouseDelegate.call(matchedEl, event, container);
|
|
211
|
|
212 }, filter, obj, overrideContext);
|
|
213
|
|
214 }
|
|
215 else {
|
|
216
|
|
217 fnDelegate = Event._createDelegate(fn, filter, obj, overrideContext);
|
|
218
|
|
219 }
|
|
220
|
|
221 delegates.push([container, sType, fn, fnDelegate]);
|
|
222
|
|
223 return Event.on(container, sType, fnDelegate);
|
|
224
|
|
225 },
|
|
226
|
|
227
|
|
228 /**
|
|
229 * Removes a delegated event listener.
|
|
230 *
|
|
231 * @method removeDelegate
|
|
232 *
|
|
233 * @param {String|HTMLElement|Array|NodeList} container An id, an element
|
|
234 * reference, or a collection of ids and/or elements to remove
|
|
235 * the listener from.
|
|
236 * @param {String} type The type of event to remove.
|
|
237 * @param {Function} fn The method the event invokes. If fn is
|
|
238 * undefined, then all event listeners for the type of event are
|
|
239 * removed.
|
|
240 * @return {boolean} Returns true if the unbind was successful, false
|
|
241 * otherwise.
|
|
242 * @static
|
|
243 * @for Event
|
|
244 */
|
|
245 removeDelegate: function (container, type, fn) {
|
|
246
|
|
247 var sType = type,
|
|
248 returnVal = false,
|
|
249 index,
|
|
250 cacheItem;
|
|
251
|
|
252 // Look up the real event--either mouseover or mouseout
|
|
253 if (type == "mouseenter" || type == "mouseleave") {
|
|
254 sType = Event._getType(type);
|
|
255 }
|
|
256
|
|
257 index = Event._getCacheIndex(delegates, container, sType, fn);
|
|
258
|
|
259 if (index >= 0) {
|
|
260 cacheItem = delegates[index];
|
|
261 }
|
|
262
|
|
263
|
|
264 if (container && cacheItem) {
|
|
265
|
|
266 returnVal = Event.removeListener(cacheItem[0], cacheItem[1], cacheItem[3]);
|
|
267
|
|
268 if (returnVal) {
|
|
269 delete delegates[index][2];
|
|
270 delete delegates[index][3];
|
|
271 delegates.splice(index, 1);
|
|
272 }
|
|
273
|
|
274 }
|
|
275
|
|
276 return returnVal;
|
|
277
|
|
278 }
|
|
279
|
|
280 });
|
|
281
|
|
282 }());
|
|
283 YAHOO.register("event-delegate", YAHOO.util.Event, {version: "2.8.0r4", build: "2449"});
|