author | Giulio Cesare Solaroli <giulio.cesare@solaroli.it> | 2011-10-03 16:04:12 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@solaroli.it> | 2011-10-03 16:04:12 (UTC) |
commit | 541bb378ddece2eab135a8066a16994e94436dea (patch) (unidiff) | |
tree | ff160ea3e26f7fe07fcfd401387c5a0232ca715e /frontend/beta/js/YUI/event.js | |
parent | 1bf431fd3d45cbdf4afa3e12afefe5d24f4d3bc7 (diff) | |
parent | ecad5e895831337216544e81f1a467e0c68c4a6a (diff) | |
download | clipperz-541bb378ddece2eab135a8066a16994e94436dea.zip clipperz-541bb378ddece2eab135a8066a16994e94436dea.tar.gz clipperz-541bb378ddece2eab135a8066a16994e94436dea.tar.bz2 |
Merge pull request #1 from gcsolaroli/master
First version of the restructured repository
Diffstat (limited to 'frontend/beta/js/YUI/event.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/beta/js/YUI/event.js | 1738 |
1 files changed, 1738 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI/event.js b/frontend/beta/js/YUI/event.js new file mode 100644 index 0000000..7bfac3b --- a/dev/null +++ b/frontend/beta/js/YUI/event.js | |||
@@ -0,0 +1,1738 @@ | |||
1 | /* | ||
2 | Copyright (c) 2006, Yahoo! Inc. All rights reserved. | ||
3 | Code licensed under the BSD License: | ||
4 | http://developer.yahoo.net/yui/license.txt | ||
5 | version: 0.12.0 | ||
6 | */ | ||
7 | |||
8 | /** | ||
9 | * The CustomEvent class lets you define events for your application | ||
10 | * that can be subscribed to by one or more independent component. | ||
11 | * | ||
12 | * @param {String} type The type of event, which is passed to the callback | ||
13 | * when the event fires | ||
14 | * @param {Object} oScope The context the event will fire from. "this" will | ||
15 | * refer to this object in the callback. Default value: | ||
16 | * the window object. The listener can override this. | ||
17 | * @param {boolean} silent pass true to prevent the event from writing to | ||
18 | * the log system | ||
19 | * @namespace YAHOO.util | ||
20 | * @class CustomEvent | ||
21 | * @constructor | ||
22 | */ | ||
23 | YAHOO.util.CustomEvent = function(type, oScope, silent, signature) { | ||
24 | |||
25 | /** | ||
26 | * The type of event, returned to subscribers when the event fires | ||
27 | * @property type | ||
28 | * @type string | ||
29 | */ | ||
30 | this.type = type; | ||
31 | |||
32 | /** | ||
33 | * The scope the the event will fire from by default. Defaults to the window | ||
34 | * obj | ||
35 | * @property scope | ||
36 | * @type object | ||
37 | */ | ||
38 | this.scope = oScope || window; | ||
39 | |||
40 | /** | ||
41 | * By default all custom events are logged in the debug build, set silent | ||
42 | * to true to disable logging for this event. | ||
43 | * @property silent | ||
44 | * @type boolean | ||
45 | */ | ||
46 | this.silent = silent; | ||
47 | |||
48 | /** | ||
49 | * Custom events support two styles of arguments provided to the event | ||
50 | * subscribers. | ||
51 | * <ul> | ||
52 | * <li>YAHOO.util.CustomEvent.LIST: | ||
53 | * <ul> | ||
54 | * <li>param1: event name</li> | ||
55 | * <li>param2: array of arguments sent to fire</li> | ||
56 | * <li>param3: <optional> a custom object supplied by the subscriber</li> | ||
57 | * </ul> | ||
58 | * </li> | ||
59 | * <li>YAHOO.util.CustomEvent.FLAT | ||
60 | * <ul> | ||
61 | * <li>param1: the first argument passed to fire. If you need to | ||
62 | * pass multiple parameters, use and array or object literal</li> | ||
63 | * <li>param2: <optional> a custom object supplied by the subscriber</li> | ||
64 | * </ul> | ||
65 | * </li> | ||
66 | * </ul> | ||
67 | * @property signature | ||
68 | * @type int | ||
69 | */ | ||
70 | this.signature = signature || YAHOO.util.CustomEvent.LIST; | ||
71 | |||
72 | /** | ||
73 | * The subscribers to this event | ||
74 | * @property subscribers | ||
75 | * @type Subscriber[] | ||
76 | */ | ||
77 | this.subscribers = []; | ||
78 | |||
79 | if (!this.silent) { | ||
80 | } | ||
81 | |||
82 | var onsubscribeType = "_YUICEOnSubscribe"; | ||
83 | |||
84 | // Only add subscribe events for events that are not generated by | ||
85 | // CustomEvent | ||
86 | if (type !== onsubscribeType) { | ||
87 | |||
88 | /** | ||
89 | * Custom events provide a custom event that fires whenever there is | ||
90 | * a new subscriber to the event. This provides an opportunity to | ||
91 | * handle the case where there is a non-repeating event that has | ||
92 | * already fired has a new subscriber. | ||
93 | * | ||
94 | * @event subscribeEvent | ||
95 | * @type YAHOO.util.CustomEvent | ||
96 | * @param {Function} fn The function to execute | ||
97 | * @param {Object} obj An object to be passed along when the event | ||
98 | * fires | ||
99 | * @param {boolean|Object} override If true, the obj passed in becomes | ||
100 | * the execution scope of the listener. | ||
101 | * if an object, that object becomes the | ||
102 | * the execution scope. | ||
103 | */ | ||
104 | this.subscribeEvent = | ||
105 | new YAHOO.util.CustomEvent(onsubscribeType, this, true); | ||
106 | |||
107 | } | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * Subscriber listener sigature constant. The LIST type returns three | ||
112 | * parameters: the event type, the array of args passed to fire, and | ||
113 | * the optional custom object | ||
114 | * @property YAHOO.util.CustomEvent.LIST | ||
115 | * @static | ||
116 | * @type int | ||
117 | */ | ||
118 | YAHOO.util.CustomEvent.LIST = 0; | ||
119 | |||
120 | /** | ||
121 | * Subscriber listener sigature constant. The FLAT type returns two | ||
122 | * parameters: the first argument passed to fire and the optional | ||
123 | * custom object | ||
124 | * @property YAHOO.util.CustomEvent.FLAT | ||
125 | * @static | ||
126 | * @type int | ||
127 | */ | ||
128 | YAHOO.util.CustomEvent.FLAT = 1; | ||
129 | |||
130 | YAHOO.util.CustomEvent.prototype = { | ||
131 | |||
132 | /** | ||
133 | * Subscribes the caller to this event | ||
134 | * @method subscribe | ||
135 | * @param {Function} fn The function to execute | ||
136 | * @param {Object} obj An object to be passed along when the event | ||
137 | * fires | ||
138 | * @param {boolean|Object} override If true, the obj passed in becomes | ||
139 | * the execution scope of the listener. | ||
140 | * if an object, that object becomes the | ||
141 | * the execution scope. | ||
142 | */ | ||
143 | subscribe: function(fn, obj, override) { | ||
144 | if (this.subscribeEvent) { | ||
145 | this.subscribeEvent.fire(fn, obj, override); | ||
146 | } | ||
147 | |||
148 | this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) ); | ||
149 | }, | ||
150 | |||
151 | /** | ||
152 | * Unsubscribes the caller from this event | ||
153 | * @method unsubscribe | ||
154 | * @param {Function} fn The function to execute | ||
155 | * @param {Object} obj The custom object passed to subscribe (optional) | ||
156 | * @return {boolean} True if the subscriber was found and detached. | ||
157 | */ | ||
158 | unsubscribe: function(fn, obj) { | ||
159 | var found = false; | ||
160 | for (var i=0, len=this.subscribers.length; i<len; ++i) { | ||
161 | var s = this.subscribers[i]; | ||
162 | if (s && s.contains(fn, obj)) { | ||
163 | this._delete(i); | ||
164 | found = true; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | return found; | ||
169 | }, | ||
170 | |||
171 | /** | ||
172 | * Notifies the subscribers. The callback functions will be executed | ||
173 | * from the scope specified when the event was created, and with the | ||
174 | * following parameters: | ||
175 | * <ul> | ||
176 | * <li>The type of event</li> | ||
177 | * <li>All of the arguments fire() was executed with as an array</li> | ||
178 | * <li>The custom object (if any) that was passed into the subscribe() | ||
179 | * method</li> | ||
180 | * </ul> | ||
181 | * @method fire | ||
182 | * @param {Object*} arguments an arbitrary set of parameters to pass to | ||
183 | * the handler. | ||
184 | */ | ||
185 | fire: function() { | ||
186 | var len=this.subscribers.length; | ||
187 | if (!len && this.silent) { | ||
188 | return true; | ||
189 | } | ||
190 | |||
191 | var args=[], ret=true, i; | ||
192 | |||
193 | for (i=0; i<arguments.length; ++i) { | ||
194 | args.push(arguments[i]); | ||
195 | } | ||
196 | |||
197 | var argslength = args.length; | ||
198 | |||
199 | if (!this.silent) { | ||
200 | } | ||
201 | |||
202 | for (i=0; i<len; ++i) { | ||
203 | var s = this.subscribers[i]; | ||
204 | if (s) { | ||
205 | if (!this.silent) { | ||
206 | } | ||
207 | |||
208 | var scope = s.getScope(this.scope); | ||
209 | |||
210 | if (this.signature == YAHOO.util.CustomEvent.FLAT) { | ||
211 | var param = null; | ||
212 | if (args.length > 0) { | ||
213 | param = args[0]; | ||
214 | } | ||
215 | ret = s.fn.call(scope, param, s.obj); | ||
216 | } else { | ||
217 | ret = s.fn.call(scope, this.type, args, s.obj); | ||
218 | } | ||
219 | if (false === ret) { | ||
220 | if (!this.silent) { | ||
221 | } | ||
222 | |||
223 | //break; | ||
224 | return false; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | return true; | ||
230 | }, | ||
231 | |||
232 | /** | ||
233 | * Removes all listeners | ||
234 | * @method unsubscribeAll | ||
235 | */ | ||
236 | unsubscribeAll: function() { | ||
237 | for (var i=0, len=this.subscribers.length; i<len; ++i) { | ||
238 | this._delete(len - 1 - i); | ||
239 | } | ||
240 | }, | ||
241 | |||
242 | /** | ||
243 | * @method _delete | ||
244 | * @private | ||
245 | */ | ||
246 | _delete: function(index) { | ||
247 | var s = this.subscribers[index]; | ||
248 | if (s) { | ||
249 | delete s.fn; | ||
250 | delete s.obj; | ||
251 | } | ||
252 | |||
253 | // delete this.subscribers[index]; | ||
254 | this.subscribers.splice(index, 1); | ||
255 | }, | ||
256 | |||
257 | /** | ||
258 | * @method toString | ||
259 | */ | ||
260 | toString: function() { | ||
261 | return "CustomEvent: " + "'" + this.type + "', " + | ||
262 | "scope: " + this.scope; | ||
263 | |||
264 | } | ||
265 | }; | ||
266 | |||
267 | ///////////////////////////////////////////////////////////////////// | ||
268 | |||
269 | /** | ||
270 | * Stores the subscriber information to be used when the event fires. | ||
271 | * @param {Function} fn The function to execute | ||
272 | * @param {Object} obj An object to be passed along when the event fires | ||
273 | * @param {boolean} override If true, the obj passed in becomes the execution | ||
274 | * scope of the listener | ||
275 | * @class Subscriber | ||
276 | * @constructor | ||
277 | */ | ||
278 | YAHOO.util.Subscriber = function(fn, obj, override) { | ||
279 | |||
280 | /** | ||
281 | * The callback that will be execute when the event fires | ||
282 | * @property fn | ||
283 | * @type function | ||
284 | */ | ||
285 | this.fn = fn; | ||
286 | |||
287 | /** | ||
288 | * An optional custom object that will passed to the callback when | ||
289 | * the event fires | ||
290 | * @property obj | ||
291 | * @type object | ||
292 | */ | ||
293 | this.obj = obj || null; | ||
294 | |||
295 | /** | ||
296 | * The default execution scope for the event listener is defined when the | ||
297 | * event is created (usually the object which contains the event). | ||
298 | * By setting override to true, the execution scope becomes the custom | ||
299 | * object passed in by the subscriber. If override is an object, that | ||
300 | * object becomes the scope. | ||
301 | * @property override | ||
302 | * @type boolean|object | ||
303 | */ | ||
304 | this.override = override; | ||
305 | |||
306 | }; | ||
307 | |||
308 | /** | ||
309 | * Returns the execution scope for this listener. If override was set to true | ||
310 | * the custom obj will be the scope. If override is an object, that is the | ||
311 | * scope, otherwise the default scope will be used. | ||
312 | * @method getScope | ||
313 | * @param {Object} defaultScope the scope to use if this listener does not | ||
314 | * override it. | ||
315 | */ | ||
316 | YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) { | ||
317 | if (this.override) { | ||
318 | if (this.override === true) { | ||
319 | return this.obj; | ||
320 | } else { | ||
321 | return this.override; | ||
322 | } | ||
323 | } | ||
324 | return defaultScope; | ||
325 | }; | ||
326 | |||
327 | /** | ||
328 | * Returns true if the fn and obj match this objects properties. | ||
329 | * Used by the unsubscribe method to match the right subscriber. | ||
330 | * | ||
331 | * @method contains | ||
332 | * @param {Function} fn the function to execute | ||
333 | * @param {Object} obj an object to be passed along when the event fires | ||
334 | * @return {boolean} true if the supplied arguments match this | ||
335 | * subscriber's signature. | ||
336 | */ | ||
337 | YAHOO.util.Subscriber.prototype.contains = function(fn, obj) { | ||
338 | if (obj) { | ||
339 | return (this.fn == fn && this.obj == obj); | ||
340 | } else { | ||
341 | return (this.fn == fn); | ||
342 | } | ||
343 | }; | ||
344 | |||
345 | /** | ||
346 | * @method toString | ||
347 | */ | ||
348 | YAHOO.util.Subscriber.prototype.toString = function() { | ||
349 | return "Subscriber { obj: " + (this.obj || "") + | ||
350 | ", override: " + (this.override || "no") + " }"; | ||
351 | }; | ||
352 | |||
353 | /** | ||
354 | * The Event Utility provides utilities for managing DOM Events and tools | ||
355 | * for building event systems | ||
356 | * | ||
357 | * @module event | ||
358 | * @title Event Utility | ||
359 | * @namespace YAHOO.util | ||
360 | * @requires yahoo | ||
361 | */ | ||
362 | |||
363 | // The first instance of Event will win if it is loaded more than once. | ||
364 | if (!YAHOO.util.Event) { | ||
365 | |||
366 | /** | ||
367 | * The event utility provides functions to add and remove event listeners, | ||
368 | * event cleansing. It also tries to automatically remove listeners it | ||
369 | * registers during the unload event. | ||
370 | * | ||
371 | * @class Event | ||
372 | * @static | ||
373 | */ | ||
374 | YAHOO.util.Event = function() { | ||
375 | |||
376 | /** | ||
377 | * True after the onload event has fired | ||
378 | * @property loadComplete | ||
379 | * @type boolean | ||
380 | * @static | ||
381 | * @private | ||
382 | */ | ||
383 | var loadComplete = false; | ||
384 | |||
385 | /** | ||
386 | * Cache of wrapped listeners | ||
387 | * @property listeners | ||
388 | * @type array | ||
389 | * @static | ||
390 | * @private | ||
391 | */ | ||
392 | var listeners = []; | ||
393 | |||
394 | /** | ||
395 | * User-defined unload function that will be fired before all events | ||
396 | * are detached | ||
397 | * @property unloadListeners | ||
398 | * @type array | ||
399 | * @static | ||
400 | * @private | ||
401 | */ | ||
402 | var unloadListeners = []; | ||
403 | |||
404 | /** | ||
405 | * Cache of DOM0 event handlers to work around issues with DOM2 events | ||
406 | * in Safari | ||
407 | * @property legacyEvents | ||
408 | * @static | ||
409 | * @private | ||
410 | */ | ||
411 | var legacyEvents = []; | ||
412 | |||
413 | /** | ||
414 | * Listener stack for DOM0 events | ||
415 | * @property legacyHandlers | ||
416 | * @static | ||
417 | * @private | ||
418 | */ | ||
419 | var legacyHandlers = []; | ||
420 | |||
421 | /** | ||
422 | * The number of times to poll after window.onload. This number is | ||
423 | * increased if additional late-bound handlers are requested after | ||
424 | * the page load. | ||
425 | * @property retryCount | ||
426 | * @static | ||
427 | * @private | ||
428 | */ | ||
429 | var retryCount = 0; | ||
430 | |||
431 | /** | ||
432 | * onAvailable listeners | ||
433 | * @property onAvailStack | ||
434 | * @static | ||
435 | * @private | ||
436 | */ | ||
437 | var onAvailStack = []; | ||
438 | |||
439 | /** | ||
440 | * Lookup table for legacy events | ||
441 | * @property legacyMap | ||
442 | * @static | ||
443 | * @private | ||
444 | */ | ||
445 | var legacyMap = []; | ||
446 | |||
447 | /** | ||
448 | * Counter for auto id generation | ||
449 | * @property counter | ||
450 | * @static | ||
451 | * @private | ||
452 | */ | ||
453 | var counter = 0; | ||
454 | |||
455 | return { // PREPROCESS | ||
456 | |||
457 | /** | ||
458 | * The number of times we should look for elements that are not | ||
459 | * in the DOM at the time the event is requested after the document | ||
460 | * has been loaded. The default is 200@amp;50 ms, so it will poll | ||
461 | * for 10 seconds or until all outstanding handlers are bound | ||
462 | * (whichever comes first). | ||
463 | * @property POLL_RETRYS | ||
464 | * @type int | ||
465 | * @static | ||
466 | * @final | ||
467 | */ | ||
468 | POLL_RETRYS: 200, | ||
469 | |||
470 | /** | ||
471 | * The poll interval in milliseconds | ||
472 | * @property POLL_INTERVAL | ||
473 | * @type int | ||
474 | * @static | ||
475 | * @final | ||
476 | */ | ||
477 | POLL_INTERVAL: 20, | ||
478 | |||
479 | /** | ||
480 | * Element to bind, int constant | ||
481 | * @property EL | ||
482 | * @type int | ||
483 | * @static | ||
484 | * @final | ||
485 | */ | ||
486 | EL: 0, | ||
487 | |||
488 | /** | ||
489 | * Type of event, int constant | ||
490 | * @property TYPE | ||
491 | * @type int | ||
492 | * @static | ||
493 | * @final | ||
494 | */ | ||
495 | TYPE: 1, | ||
496 | |||
497 | /** | ||
498 | * Function to execute, int constant | ||
499 | * @property FN | ||
500 | * @type int | ||
501 | * @static | ||
502 | * @final | ||
503 | */ | ||
504 | FN: 2, | ||
505 | |||
506 | /** | ||
507 | * Function wrapped for scope correction and cleanup, int constant | ||
508 | * @property WFN | ||
509 | * @type int | ||
510 | * @static | ||
511 | * @final | ||
512 | */ | ||
513 | WFN: 3, | ||
514 | |||
515 | /** | ||
516 | * Object passed in by the user that will be returned as a | ||
517 | * parameter to the callback, int constant | ||
518 | * @property OBJ | ||
519 | * @type int | ||
520 | * @static | ||
521 | * @final | ||
522 | */ | ||
523 | OBJ: 3, | ||
524 | |||
525 | /** | ||
526 | * Adjusted scope, either the element we are registering the event | ||
527 | * on or the custom object passed in by the listener, int constant | ||
528 | * @property ADJ_SCOPE | ||
529 | * @type int | ||
530 | * @static | ||
531 | * @final | ||
532 | */ | ||
533 | ADJ_SCOPE: 4, | ||
534 | |||
535 | /** | ||
536 | * Safari detection is necessary to work around the preventDefault | ||
537 | * bug that makes it so you can't cancel a href click from the | ||
538 | * handler. There is not a capabilities check we can use here. | ||
539 | * @property isSafari | ||
540 | * @private | ||
541 | * @static | ||
542 | */ | ||
543 | isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent), | ||
544 | |||
545 | /** | ||
546 | * IE detection needed to properly calculate pageX and pageY. | ||
547 | * capabilities checking didn't seem to work because another | ||
548 | * browser that does not provide the properties have the values | ||
549 | * calculated in a different manner than IE. | ||
550 | * @property isIE | ||
551 | * @private | ||
552 | * @static | ||
553 | */ | ||
554 | isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && | ||
555 | navigator.userAgent.match(/msie/gi)), | ||
556 | |||
557 | /** | ||
558 | * poll handle | ||
559 | * @property _interval | ||
560 | * @private | ||
561 | */ | ||
562 | _interval: null, | ||
563 | |||
564 | /** | ||
565 | * @method startInterval | ||
566 | * @static | ||
567 | * @private | ||
568 | */ | ||
569 | startInterval: function() { | ||
570 | if (!this._interval) { | ||
571 | var self = this; | ||
572 | var callback = function() { self._tryPreloadAttach(); }; | ||
573 | this._interval = setInterval(callback, this.POLL_INTERVAL); | ||
574 | // this.timeout = setTimeout(callback, i); | ||
575 | } | ||
576 | }, | ||
577 | |||
578 | /** | ||
579 | * Executes the supplied callback when the item with the supplied | ||
580 | * id is found. This is meant to be used to execute behavior as | ||
581 | * soon as possible as the page loads. If you use this after the | ||
582 | * initial page load it will poll for a fixed time for the element. | ||
583 | * The number of times it will poll and the frequency are | ||
584 | * configurable. By default it will poll for 10 seconds. | ||
585 | * | ||
586 | * @method onAvailable | ||
587 | * | ||
588 | * @param {string} p_id the id of the element to look for. | ||
589 | * @param {function} p_fn what to execute when the element is found. | ||
590 | * @param {object} p_obj an optional object to be passed back as | ||
591 | * a parameter to p_fn. | ||
592 | * @param {boolean} p_override If set to true, p_fn will execute | ||
593 | * in the scope of p_obj | ||
594 | * | ||
595 | * @static | ||
596 | */ | ||
597 | onAvailable: function(p_id, p_fn, p_obj, p_override) { | ||
598 | onAvailStack.push( { id: p_id, | ||
599 | fn: p_fn, | ||
600 | obj: p_obj, | ||
601 | override: p_override, | ||
602 | checkReady: false } ); | ||
603 | |||
604 | retryCount = this.POLL_RETRYS; | ||
605 | this.startInterval(); | ||
606 | }, | ||
607 | |||
608 | /** | ||
609 | * Works the same way as onAvailable, but additionally checks the | ||
610 | * state of sibling elements to determine if the content of the | ||
611 | * available element is safe to modify. | ||
612 | * | ||
613 | * @method onContentReady | ||
614 | * | ||
615 | * @param {string} p_id the id of the element to look for. | ||
616 | * @param {function} p_fn what to execute when the element is ready. | ||
617 | * @param {object} p_obj an optional object to be passed back as | ||
618 | * a parameter to p_fn. | ||
619 | * @param {boolean} p_override If set to true, p_fn will execute | ||
620 | * in the scope of p_obj | ||
621 | * | ||
622 | * @static | ||
623 | */ | ||
624 | onContentReady: function(p_id, p_fn, p_obj, p_override) { | ||
625 | onAvailStack.push( { id: p_id, | ||
626 | fn: p_fn, | ||
627 | obj: p_obj, | ||
628 | override: p_override, | ||
629 | checkReady: true } ); | ||
630 | |||
631 | retryCount = this.POLL_RETRYS; | ||
632 | this.startInterval(); | ||
633 | }, | ||
634 | |||
635 | /** | ||
636 | * Appends an event handler | ||
637 | * | ||
638 | * @method addListener | ||
639 | * | ||
640 | * @param {Object} el The html element to assign the | ||
641 | * event to | ||
642 | * @param {String} sType The type of event to append | ||
643 | * @param {Function} fn The method the event invokes | ||
644 | * @param {Object} obj An arbitrary object that will be | ||
645 | * passed as a parameter to the handler | ||
646 | * @param {boolean} override If true, the obj passed in becomes | ||
647 | * the execution scope of the listener | ||
648 | * @return {boolean} True if the action was successful or defered, | ||
649 | * false if one or more of the elements | ||
650 | * could not have the event bound to it. | ||
651 | * @static | ||
652 | */ | ||
653 | addListener: function(el, sType, fn, obj, override) { | ||
654 | |||
655 | if (!fn || !fn.call) { | ||
656 | return false; | ||
657 | } | ||
658 | |||
659 | // The el argument can be an array of elements or element ids. | ||
660 | if ( this._isValidCollection(el)) { | ||
661 | var ok = true; | ||
662 | for (var i=0,len=el.length; i<len; ++i) { | ||
663 | ok = this.on(el[i], | ||
664 | sType, | ||
665 | fn, | ||
666 | obj, | ||
667 | override) && ok; | ||
668 | } | ||
669 | return ok; | ||
670 | |||
671 | } else if (typeof el == "string") { | ||
672 | var oEl = this.getEl(el); | ||
673 | // If the el argument is a string, we assume it is | ||
674 | // actually the id of the element. If the page is loaded | ||
675 | // we convert el to the actual element, otherwise we | ||
676 | // defer attaching the event until onload event fires | ||
677 | |||
678 | // check to see if we need to delay hooking up the event | ||
679 | // until after the page loads. | ||
680 | if (oEl) { | ||
681 | el = oEl; | ||
682 | } else { | ||
683 | // defer adding the event until the element is available | ||
684 | this.onAvailable(el, function() { | ||
685 | YAHOO.util.Event.on(el, sType, fn, obj, override); | ||
686 | }); | ||
687 | |||
688 | return true; | ||
689 | } | ||
690 | } | ||
691 | |||
692 | // Element should be an html element or an array if we get | ||
693 | // here. | ||
694 | if (!el) { | ||
695 | return false; | ||
696 | } | ||
697 | |||
698 | // we need to make sure we fire registered unload events | ||
699 | // prior to automatically unhooking them. So we hang on to | ||
700 | // these instead of attaching them to the window and fire the | ||
701 | // handles explicitly during our one unload event. | ||
702 | if ("unload" == sType && obj !== this) { | ||
703 | unloadListeners[unloadListeners.length] = | ||
704 | [el, sType, fn, obj, override]; | ||
705 | return true; | ||
706 | } | ||
707 | |||
708 | // if the user chooses to override the scope, we use the custom | ||
709 | // object passed in, otherwise the executing scope will be the | ||
710 | // HTML element that the event is registered on | ||
711 | var scope = el; | ||
712 | if (override) { | ||
713 | if (override === true) { | ||
714 | scope = obj; | ||
715 | } else { | ||
716 | scope = override; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | // wrap the function so we can return the obj object when | ||
721 | // the event fires; | ||
722 | var wrappedFn = function(e) { | ||
723 | return fn.call(scope, YAHOO.util.Event.getEvent(e), | ||
724 | obj); | ||
725 | }; | ||
726 | |||
727 | var li = [el, sType, fn, wrappedFn, scope]; | ||
728 | var index = listeners.length; | ||
729 | // cache the listener so we can try to automatically unload | ||
730 | listeners[index] = li; | ||
731 | |||
732 | if (this.useLegacyEvent(el, sType)) { | ||
733 | var legacyIndex = this.getLegacyIndex(el, sType); | ||
734 | |||
735 | // Add a new dom0 wrapper if one is not detected for this | ||
736 | // element | ||
737 | if ( legacyIndex == -1 || | ||
738 | el != legacyEvents[legacyIndex][0] ) { | ||
739 | |||
740 | legacyIndex = legacyEvents.length; | ||
741 | legacyMap[el.id + sType] = legacyIndex; | ||
742 | |||
743 | // cache the signature for the DOM0 event, and | ||
744 | // include the existing handler for the event, if any | ||
745 | legacyEvents[legacyIndex] = | ||
746 | [el, sType, el["on" + sType]]; | ||
747 | legacyHandlers[legacyIndex] = []; | ||
748 | |||
749 | el["on" + sType] = | ||
750 | function(e) { | ||
751 | YAHOO.util.Event.fireLegacyEvent( | ||
752 | YAHOO.util.Event.getEvent(e), legacyIndex); | ||
753 | }; | ||
754 | } | ||
755 | |||
756 | // add a reference to the wrapped listener to our custom | ||
757 | // stack of events | ||
758 | //legacyHandlers[legacyIndex].push(index); | ||
759 | legacyHandlers[legacyIndex].push(li); | ||
760 | |||
761 | } else { | ||
762 | this._simpleAdd(el, sType, wrappedFn, false); | ||
763 | } | ||
764 | |||
765 | return true; | ||
766 | |||
767 | }, | ||
768 | |||
769 | /** | ||
770 | * When using legacy events, the handler is routed to this object | ||
771 | * so we can fire our custom listener stack. | ||
772 | * @method fireLegacyEvent | ||
773 | * @static | ||
774 | * @private | ||
775 | */ | ||
776 | fireLegacyEvent: function(e, legacyIndex) { | ||
777 | var ok = true; | ||
778 | |||
779 | var le = legacyHandlers[legacyIndex]; | ||
780 | for (var i=0,len=le.length; i<len; ++i) { | ||
781 | var li = le[i]; | ||
782 | if ( li && li[this.WFN] ) { | ||
783 | var scope = li[this.ADJ_SCOPE]; | ||
784 | var ret = li[this.WFN].call(scope, e); | ||
785 | ok = (ok && ret); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | return ok; | ||
790 | }, | ||
791 | |||
792 | /** | ||
793 | * Returns the legacy event index that matches the supplied | ||
794 | * signature | ||
795 | * @method getLegacyIndex | ||
796 | * @static | ||
797 | * @private | ||
798 | */ | ||
799 | getLegacyIndex: function(el, sType) { | ||
800 | var key = this.generateId(el) + sType; | ||
801 | if (typeof legacyMap[key] == "undefined") { | ||
802 | return -1; | ||
803 | } else { | ||
804 | return legacyMap[key]; | ||
805 | } | ||
806 | }, | ||
807 | |||
808 | /** | ||
809 | * Logic that determines when we should automatically use legacy | ||
810 | * events instead of DOM2 events. | ||
811 | * @method useLegacyEvent | ||
812 | * @static | ||
813 | * @private | ||
814 | */ | ||
815 | useLegacyEvent: function(el, sType) { | ||
816 | if (!el.addEventListener && !el.attachEvent) { | ||
817 | return true; | ||
818 | } else if (this.isSafari) { | ||
819 | if ("click" == sType || "dblclick" == sType) { | ||
820 | return true; | ||
821 | } | ||
822 | } | ||
823 | return false; | ||
824 | }, | ||
825 | |||
826 | /** | ||
827 | * Removes an event handler | ||
828 | * | ||
829 | * @method removeListener | ||
830 | * | ||
831 | * @param {Object} el the html element or the id of the element to | ||
832 | * assign the event to. | ||
833 | * @param {String} sType the type of event to remove. | ||
834 | * @param {Function} fn the method the event invokes. If fn is | ||
835 | * undefined, then all event handlers for the type of event are | ||
836 | * removed. | ||
837 | * @return {boolean} true if the unbind was successful, false | ||
838 | * otherwise. | ||
839 | * @static | ||
840 | */ | ||
841 | removeListener: function(el, sType, fn) { | ||
842 | var i, len; | ||
843 | |||
844 | // The el argument can be a string | ||
845 | if (typeof el == "string") { | ||
846 | el = this.getEl(el); | ||
847 | // The el argument can be an array of elements or element ids. | ||
848 | } else if ( this._isValidCollection(el)) { | ||
849 | var ok = true; | ||
850 | for (i=0,len=el.length; i<len; ++i) { | ||
851 | ok = ( this.removeListener(el[i], sType, fn) && ok ); | ||
852 | } | ||
853 | return ok; | ||
854 | } | ||
855 | |||
856 | if (!fn || !fn.call) { | ||
857 | //return false; | ||
858 | return this.purgeElement(el, false, sType); | ||
859 | } | ||
860 | |||
861 | if ("unload" == sType) { | ||
862 | |||
863 | for (i=0, len=unloadListeners.length; i<len; i++) { | ||
864 | var li = unloadListeners[i]; | ||
865 | if (li && | ||
866 | li[0] == el && | ||
867 | li[1] == sType && | ||
868 | li[2] == fn) { | ||
869 | unloadListeners.splice(i, 1); | ||
870 | return true; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | return false; | ||
875 | } | ||
876 | |||
877 | var cacheItem = null; | ||
878 | |||
879 | // The index is a hidden parameter; needed to remove it from | ||
880 | // the method signature because it was tempting users to | ||
881 | // try and take advantage of it, which is not possible. | ||
882 | var index = arguments[3]; | ||
883 | |||
884 | if ("undefined" == typeof index) { | ||
885 | index = this._getCacheIndex(el, sType, fn); | ||
886 | } | ||
887 | |||
888 | if (index >= 0) { | ||
889 | cacheItem = listeners[index]; | ||
890 | } | ||
891 | |||
892 | if (!el || !cacheItem) { | ||
893 | return false; | ||
894 | } | ||
895 | |||
896 | if (this.useLegacyEvent(el, sType)) { | ||
897 | var legacyIndex = this.getLegacyIndex(el, sType); | ||
898 | var llist = legacyHandlers[legacyIndex]; | ||
899 | if (llist) { | ||
900 | for (i=0, len=llist.length; i<len; ++i) { | ||
901 | li = llist[i]; | ||
902 | if (li && | ||
903 | li[this.EL] == el && | ||
904 | li[this.TYPE] == sType && | ||
905 | li[this.FN] == fn) { | ||
906 | llist.splice(i, 1); | ||
907 | break; | ||
908 | } | ||
909 | } | ||
910 | } | ||
911 | |||
912 | } else { | ||
913 | this._simpleRemove(el, sType, cacheItem[this.WFN], false); | ||
914 | } | ||
915 | |||
916 | // removed the wrapped handler | ||
917 | delete listeners[index][this.WFN]; | ||
918 | delete listeners[index][this.FN]; | ||
919 | listeners.splice(index, 1); | ||
920 | |||
921 | return true; | ||
922 | |||
923 | }, | ||
924 | |||
925 | /** | ||
926 | * Returns the event's target element | ||
927 | * @method getTarget | ||
928 | * @param {Event} ev the event | ||
929 | * @param {boolean} resolveTextNode when set to true the target's | ||
930 | * parent will be returned if the target is a | ||
931 | * text node. @deprecated, the text node is | ||
932 | * now resolved automatically | ||
933 | * @return {HTMLElement} the event's target | ||
934 | * @static | ||
935 | */ | ||
936 | getTarget: function(ev, resolveTextNode) { | ||
937 | var t = ev.target || ev.srcElement; | ||
938 | return this.resolveTextNode(t); | ||
939 | }, | ||
940 | |||
941 | /** | ||
942 | * In some cases, some browsers will return a text node inside | ||
943 | * the actual element that was targeted. This normalizes the | ||
944 | * return value for getTarget and getRelatedTarget. | ||
945 | * @method resolveTextNode | ||
946 | * @param {HTMLElement} node node to resolve | ||
947 | * @return {HTMLElement} the normized node | ||
948 | * @static | ||
949 | */ | ||
950 | resolveTextNode: function(node) { | ||
951 | // if (node && node.nodeName && | ||
952 | // "#TEXT" == node.nodeName.toUpperCase()) { | ||
953 | if (node && 3 == node.nodeType) { | ||
954 | return node.parentNode; | ||
955 | } else { | ||
956 | return node; | ||
957 | } | ||
958 | }, | ||
959 | |||
960 | /** | ||
961 | * Returns the event's pageX | ||
962 | * @method getPageX | ||
963 | * @param {Event} ev the event | ||
964 | * @return {int} the event's pageX | ||
965 | * @static | ||
966 | */ | ||
967 | getPageX: function(ev) { | ||
968 | var x = ev.pageX; | ||
969 | if (!x && 0 !== x) { | ||
970 | x = ev.clientX || 0; | ||
971 | |||
972 | if ( this.isIE ) { | ||
973 | x += this._getScrollLeft(); | ||
974 | } | ||
975 | } | ||
976 | |||
977 | return x; | ||
978 | }, | ||
979 | |||
980 | /** | ||
981 | * Returns the event's pageY | ||
982 | * @method getPageY | ||
983 | * @param {Event} ev the event | ||
984 | * @return {int} the event's pageY | ||
985 | * @static | ||
986 | */ | ||
987 | getPageY: function(ev) { | ||
988 | var y = ev.pageY; | ||
989 | if (!y && 0 !== y) { | ||
990 | y = ev.clientY || 0; | ||
991 | |||
992 | if ( this.isIE ) { | ||
993 | y += this._getScrollTop(); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | return y; | ||
998 | }, | ||
999 | |||
1000 | /** | ||
1001 | * Returns the pageX and pageY properties as an indexed array. | ||
1002 | * @method getXY | ||
1003 | * @type int[] | ||
1004 | * @static | ||
1005 | */ | ||
1006 | getXY: function(ev) { | ||
1007 | return [this.getPageX(ev), this.getPageY(ev)]; | ||
1008 | }, | ||
1009 | |||
1010 | /** | ||
1011 | * Returns the event's related target | ||
1012 | * @method getRelatedTarget | ||
1013 | * @param {Event} ev the event | ||
1014 | * @return {HTMLElement} the event's relatedTarget | ||
1015 | * @static | ||
1016 | */ | ||
1017 | getRelatedTarget: function(ev) { | ||
1018 | var t = ev.relatedTarget; | ||
1019 | if (!t) { | ||
1020 | if (ev.type == "mouseout") { | ||
1021 | t = ev.toElement; | ||
1022 | } else if (ev.type == "mouseover") { | ||
1023 | t = ev.fromElement; | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | return this.resolveTextNode(t); | ||
1028 | }, | ||
1029 | |||
1030 | /** | ||
1031 | * Returns the time of the event. If the time is not included, the | ||
1032 | * event is modified using the current time. | ||
1033 | * @method getTime | ||
1034 | * @param {Event} ev the event | ||
1035 | * @return {Date} the time of the event | ||
1036 | * @static | ||
1037 | */ | ||
1038 | getTime: function(ev) { | ||
1039 | if (!ev.time) { | ||
1040 | var t = new Date().getTime(); | ||
1041 | try { | ||
1042 | ev.time = t; | ||
1043 | } catch(e) { | ||
1044 | return t; | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | return ev.time; | ||
1049 | }, | ||
1050 | |||
1051 | /** | ||
1052 | * Convenience method for stopPropagation + preventDefault | ||
1053 | * @method stopEvent | ||
1054 | * @param {Event} ev the event | ||
1055 | * @static | ||
1056 | */ | ||
1057 | stopEvent: function(ev) { | ||
1058 | this.stopPropagation(ev); | ||
1059 | this.preventDefault(ev); | ||
1060 | }, | ||
1061 | |||
1062 | /** | ||
1063 | * Stops event propagation | ||
1064 | * @method stopPropagation | ||
1065 | * @param {Event} ev the event | ||
1066 | * @static | ||
1067 | */ | ||
1068 | stopPropagation: function(ev) { | ||
1069 | if (ev.stopPropagation) { | ||
1070 | ev.stopPropagation(); | ||
1071 | } else { | ||
1072 | ev.cancelBubble = true; | ||
1073 | } | ||
1074 | }, | ||
1075 | |||
1076 | /** | ||
1077 | * Prevents the default behavior of the event | ||
1078 | * @method preventDefault | ||
1079 | * @param {Event} ev the event | ||
1080 | * @static | ||
1081 | */ | ||
1082 | preventDefault: function(ev) { | ||
1083 | if (ev.preventDefault) { | ||
1084 | ev.preventDefault(); | ||
1085 | } else { | ||
1086 | ev.returnValue = false; | ||
1087 | } | ||
1088 | }, | ||
1089 | |||
1090 | /** | ||
1091 | * Finds the event in the window object, the caller's arguments, or | ||
1092 | * in the arguments of another method in the callstack. This is | ||
1093 | * executed automatically for events registered through the event | ||
1094 | * manager, so the implementer should not normally need to execute | ||
1095 | * this function at all. | ||
1096 | * @method getEvent | ||
1097 | * @param {Event} e the event parameter from the handler | ||
1098 | * @return {Event} the event | ||
1099 | * @static | ||
1100 | */ | ||
1101 | getEvent: function(e) { | ||
1102 | var ev = e || window.event; | ||
1103 | |||
1104 | if (!ev) { | ||
1105 | var c = this.getEvent.caller; | ||
1106 | while (c) { | ||
1107 | ev = c.arguments[0]; | ||
1108 | if (ev && Event == ev.constructor) { | ||
1109 | break; | ||
1110 | } | ||
1111 | c = c.caller; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | return ev; | ||
1116 | }, | ||
1117 | |||
1118 | /** | ||
1119 | * Returns the charcode for an event | ||
1120 | * @method getCharCode | ||
1121 | * @param {Event} ev the event | ||
1122 | * @return {int} the event's charCode | ||
1123 | * @static | ||
1124 | */ | ||
1125 | getCharCode: function(ev) { | ||
1126 | return ev.charCode || ev.keyCode || 0; | ||
1127 | }, | ||
1128 | |||
1129 | /** | ||
1130 | * Locating the saved event handler data by function ref | ||
1131 | * | ||
1132 | * @method _getCacheIndex | ||
1133 | * @static | ||
1134 | * @private | ||
1135 | */ | ||
1136 | _getCacheIndex: function(el, sType, fn) { | ||
1137 | for (var i=0,len=listeners.length; i<len; ++i) { | ||
1138 | var li = listeners[i]; | ||
1139 | if ( li && | ||
1140 | li[this.FN] == fn && | ||
1141 | li[this.EL] == el && | ||
1142 | li[this.TYPE] == sType ) { | ||
1143 | return i; | ||
1144 | } | ||
1145 | } | ||
1146 | |||
1147 | return -1; | ||
1148 | }, | ||
1149 | |||
1150 | /** | ||
1151 | * Generates an unique ID for the element if it does not already | ||
1152 | * have one. | ||
1153 | * @method generateId | ||
1154 | * @param el the element to create the id for | ||
1155 | * @return {string} the resulting id of the element | ||
1156 | * @static | ||
1157 | */ | ||
1158 | generateId: function(el) { | ||
1159 | var id = el.id; | ||
1160 | |||
1161 | if (!id) { | ||
1162 | id = "yuievtautoid-" + counter; | ||
1163 | ++counter; | ||
1164 | el.id = id; | ||
1165 | } | ||
1166 | |||
1167 | return id; | ||
1168 | }, | ||
1169 | |||
1170 | /** | ||
1171 | * We want to be able to use getElementsByTagName as a collection | ||
1172 | * to attach a group of events to. Unfortunately, different | ||
1173 | * browsers return different types of collections. This function | ||
1174 | * tests to determine if the object is array-like. It will also | ||
1175 | * fail if the object is an array, but is empty. | ||
1176 | * @method _isValidCollection | ||
1177 | * @param o the object to test | ||
1178 | * @return {boolean} true if the object is array-like and populated | ||
1179 | * @static | ||
1180 | * @private | ||
1181 | */ | ||
1182 | _isValidCollection: function(o) { | ||
1183 | // this.logger.debug(o.constructor.toString()) | ||
1184 | // this.logger.debug(typeof o) | ||
1185 | |||
1186 | return ( o && // o is something | ||
1187 | o.length && // o is indexed | ||
1188 | typeof o != "string" && // o is not a string | ||
1189 | !o.tagName && // o is not an HTML element | ||
1190 | !o.alert && // o is not a window | ||
1191 | typeof o[0] != "undefined" ); | ||
1192 | |||
1193 | }, | ||
1194 | |||
1195 | /** | ||
1196 | * @private | ||
1197 | * @property elCache | ||
1198 | * DOM element cache | ||
1199 | * @static | ||
1200 | */ | ||
1201 | elCache: {}, | ||
1202 | |||
1203 | /** | ||
1204 | * We cache elements bound by id because when the unload event | ||
1205 | * fires, we can no longer use document.getElementById | ||
1206 | * @method getEl | ||
1207 | * @static | ||
1208 | * @private | ||
1209 | */ | ||
1210 | getEl: function(id) { | ||
1211 | return document.getElementById(id); | ||
1212 | }, | ||
1213 | |||
1214 | /** | ||
1215 | * Clears the element cache | ||
1216 | * @deprecated Elements are not cached any longer | ||
1217 | * @method clearCache | ||
1218 | * @static | ||
1219 | * @private | ||
1220 | */ | ||
1221 | clearCache: function() { }, | ||
1222 | |||
1223 | /** | ||
1224 | * hook up any deferred listeners | ||
1225 | * @method _load | ||
1226 | * @static | ||
1227 | * @private | ||
1228 | */ | ||
1229 | _load: function(e) { | ||
1230 | loadComplete = true; | ||
1231 | var EU = YAHOO.util.Event; | ||
1232 | // Remove the listener to assist with the IE memory issue, but not | ||
1233 | // for other browsers because FF 1.0x does not like it. | ||
1234 | if (this.isIE) { | ||
1235 | EU._simpleRemove(window, "load", EU._load); | ||
1236 | } | ||
1237 | }, | ||
1238 | |||
1239 | /** | ||
1240 | * Polling function that runs before the onload event fires, | ||
1241 | * attempting to attach to DOM Nodes as soon as they are | ||
1242 | * available | ||
1243 | * @method _tryPreloadAttach | ||
1244 | * @static | ||
1245 | * @private | ||
1246 | */ | ||
1247 | _tryPreloadAttach: function() { | ||
1248 | |||
1249 | if (this.locked) { | ||
1250 | return false; | ||
1251 | } | ||
1252 | |||
1253 | this.locked = true; | ||
1254 | |||
1255 | // keep trying until after the page is loaded. We need to | ||
1256 | // check the page load state prior to trying to bind the | ||
1257 | // elements so that we can be certain all elements have been | ||
1258 | // tested appropriately | ||
1259 | var tryAgain = !loadComplete; | ||
1260 | if (!tryAgain) { | ||
1261 | tryAgain = (retryCount > 0); | ||
1262 | } | ||
1263 | |||
1264 | // onAvailable | ||
1265 | var notAvail = []; | ||
1266 | for (var i=0,len=onAvailStack.length; i<len ; ++i) { | ||
1267 | var item = onAvailStack[i]; | ||
1268 | if (item) { | ||
1269 | var el = this.getEl(item.id); | ||
1270 | |||
1271 | if (el) { | ||
1272 | // The element is available, but not necessarily ready | ||
1273 | |||
1274 | if ( !item.checkReady || | ||
1275 | loadComplete || | ||
1276 | el.nextSibling || | ||
1277 | (document && document.body) ) { | ||
1278 | |||
1279 | var scope = el; | ||
1280 | if (item.override) { | ||
1281 | if (item.override === true) { | ||
1282 | scope = item.obj; | ||
1283 | } else { | ||
1284 | scope = item.override; | ||
1285 | } | ||
1286 | } | ||
1287 | item.fn.call(scope, item.obj); | ||
1288 | delete onAvailStack[i]; | ||
1289 | } | ||
1290 | } else { | ||
1291 | notAvail.push(item); | ||
1292 | } | ||
1293 | } | ||
1294 | } | ||
1295 | |||
1296 | retryCount = (notAvail.length === 0) ? 0 : retryCount - 1; | ||
1297 | |||
1298 | if (tryAgain) { | ||
1299 | this.startInterval(); | ||
1300 | } else { | ||
1301 | clearInterval(this._interval); | ||
1302 | this._interval = null; | ||
1303 | } | ||
1304 | |||
1305 | this.locked = false; | ||
1306 | |||
1307 | return true; | ||
1308 | |||
1309 | }, | ||
1310 | |||
1311 | /** | ||
1312 | * Removes all listeners attached to the given element via addListener. | ||
1313 | * Optionally, the node's children can also be purged. | ||
1314 | * Optionally, you can specify a specific type of event to remove. | ||
1315 | * @method purgeElement | ||
1316 | * @param {HTMLElement} el the element to purge | ||
1317 | * @param {boolean} recurse recursively purge this element's children | ||
1318 | * as well. Use with caution. | ||
1319 | * @param {string} sType optional type of listener to purge. If | ||
1320 | * left out, all listeners will be removed | ||
1321 | * @static | ||
1322 | */ | ||
1323 | purgeElement: function(el, recurse, sType) { | ||
1324 | var elListeners = this.getListeners(el, sType); | ||
1325 | if (elListeners) { | ||
1326 | for (var i=0,len=elListeners.length; i<len ; ++i) { | ||
1327 | var l = elListeners[i]; | ||
1328 | // can't use the index on the changing collection | ||
1329 | //this.removeListener(el, l.type, l.fn, l.index); | ||
1330 | this.removeListener(el, l.type, l.fn); | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | if (recurse && el && el.childNodes) { | ||
1335 | for (i=0,len=el.childNodes.length; i<len ; ++i) { | ||
1336 | this.purgeElement(el.childNodes[i], recurse, sType); | ||
1337 | } | ||
1338 | } | ||
1339 | }, | ||
1340 | |||
1341 | /** | ||
1342 | * Returns all listeners attached to the given element via addListener. | ||
1343 | * Optionally, you can specify a specific type of event to return. | ||
1344 | * @method getListeners | ||
1345 | * @param el {HTMLElement} the element to inspect | ||
1346 | * @param sType {string} optional type of listener to return. If | ||
1347 | * left out, all listeners will be returned | ||
1348 | * @return {Object} the listener. Contains the following fields: | ||
1349 | * type: (string) the type of event | ||
1350 | * fn: (function) the callback supplied to addListener | ||
1351 | * obj: (object) the custom object supplied to addListener | ||
1352 | * adjust: (boolean) whether or not to adjust the default scope | ||
1353 | * index: (int) its position in the Event util listener cache | ||
1354 | * @static | ||
1355 | */ | ||
1356 | getListeners: function(el, sType) { | ||
1357 | var elListeners = []; | ||
1358 | if (listeners && listeners.length > 0) { | ||
1359 | for (var i=0,len=listeners.length; i<len ; ++i) { | ||
1360 | var l = listeners[i]; | ||
1361 | if ( l && l[this.EL] === el && | ||
1362 | (!sType || sType === l[this.TYPE]) ) { | ||
1363 | elListeners.push({ | ||
1364 | type: l[this.TYPE], | ||
1365 | fn: l[this.FN], | ||
1366 | obj: l[this.OBJ], | ||
1367 | adjust: l[this.ADJ_SCOPE], | ||
1368 | index: i | ||
1369 | }); | ||
1370 | } | ||
1371 | } | ||
1372 | } | ||
1373 | |||
1374 | return (elListeners.length) ? elListeners : null; | ||
1375 | }, | ||
1376 | |||
1377 | /** | ||
1378 | * Removes all listeners registered by pe.event. Called | ||
1379 | * automatically during the unload event. | ||
1380 | * @method _unload | ||
1381 | * @static | ||
1382 | * @private | ||
1383 | */ | ||
1384 | _unload: function(e) { | ||
1385 | |||
1386 | var EU = YAHOO.util.Event, i, j, l, len, index; | ||
1387 | |||
1388 | for (i=0,len=unloadListeners.length; i<len; ++i) { | ||
1389 | l = unloadListeners[i]; | ||
1390 | if (l) { | ||
1391 | var scope = window; | ||
1392 | if (l[EU.ADJ_SCOPE]) { | ||
1393 | if (l[EU.ADJ_SCOPE] === true) { | ||
1394 | scope = l[EU.OBJ]; | ||
1395 | } else { | ||
1396 | scope = l[EU.ADJ_SCOPE]; | ||
1397 | } | ||
1398 | } | ||
1399 | l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ] ); | ||
1400 | delete unloadListeners[i]; | ||
1401 | l=null; | ||
1402 | scope=null; | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | if (listeners && listeners.length > 0) { | ||
1407 | j = listeners.length; | ||
1408 | while (j) { | ||
1409 | index = j-1; | ||
1410 | l = listeners[index]; | ||
1411 | if (l) { | ||
1412 | EU.removeListener(l[EU.EL], l[EU.TYPE], | ||
1413 | l[EU.FN], index); | ||
1414 | } | ||
1415 | j = j - 1; | ||
1416 | } | ||
1417 | l=null; | ||
1418 | |||
1419 | EU.clearCache(); | ||
1420 | } | ||
1421 | |||
1422 | for (i=0,len=legacyEvents.length; i<len; ++i) { | ||
1423 | // dereference the element | ||
1424 | delete legacyEvents[i][0]; | ||
1425 | // delete the array item | ||
1426 | delete legacyEvents[i]; | ||
1427 | } | ||
1428 | |||
1429 | EU._simpleRemove(window, "unload", EU._unload); | ||
1430 | |||
1431 | }, | ||
1432 | |||
1433 | /** | ||
1434 | * Returns scrollLeft | ||
1435 | * @method _getScrollLeft | ||
1436 | * @static | ||
1437 | * @private | ||
1438 | */ | ||
1439 | _getScrollLeft: function() { | ||
1440 | return this._getScroll()[1]; | ||
1441 | }, | ||
1442 | |||
1443 | /** | ||
1444 | * Returns scrollTop | ||
1445 | * @method _getScrollTop | ||
1446 | * @static | ||
1447 | * @private | ||
1448 | */ | ||
1449 | _getScrollTop: function() { | ||
1450 | return this._getScroll()[0]; | ||
1451 | }, | ||
1452 | |||
1453 | /** | ||
1454 | * Returns the scrollTop and scrollLeft. Used to calculate the | ||
1455 | * pageX and pageY in Internet Explorer | ||
1456 | * @method _getScroll | ||
1457 | * @static | ||
1458 | * @private | ||
1459 | */ | ||
1460 | _getScroll: function() { | ||
1461 | var dd = document.documentElement, db = document.body; | ||
1462 | if (dd && (dd.scrollTop || dd.scrollLeft)) { | ||
1463 | return [dd.scrollTop, dd.scrollLeft]; | ||
1464 | } else if (db) { | ||
1465 | return [db.scrollTop, db.scrollLeft]; | ||
1466 | } else { | ||
1467 | return [0, 0]; | ||
1468 | } | ||
1469 | }, | ||
1470 | |||
1471 | /** | ||
1472 | * Adds a DOM event directly without the caching, cleanup, scope adj, etc | ||
1473 | * | ||
1474 | * @method _simpleAdd | ||
1475 | * @param {HTMLElement} el the element to bind the handler to | ||
1476 | * @param {string} sType the type of event handler | ||
1477 | * @param {function} fn the callback to invoke | ||
1478 | * @param {boolen} capture capture or bubble phase | ||
1479 | * @static | ||
1480 | * @private | ||
1481 | */ | ||
1482 | _simpleAdd: function () { | ||
1483 | if (window.addEventListener) { | ||
1484 | return function(el, sType, fn, capture) { | ||
1485 | el.addEventListener(sType, fn, (capture)); | ||
1486 | }; | ||
1487 | } else if (window.attachEvent) { | ||
1488 | return function(el, sType, fn, capture) { | ||
1489 | el.attachEvent("on" + sType, fn); | ||
1490 | }; | ||
1491 | } else { | ||
1492 | return function(){}; | ||
1493 | } | ||
1494 | }(), | ||
1495 | |||
1496 | /** | ||
1497 | * Basic remove listener | ||
1498 | * | ||
1499 | * @method _simpleRemove | ||
1500 | * @param {HTMLElement} el the element to bind the handler to | ||
1501 | * @param {string} sType the type of event handler | ||
1502 | * @param {function} fn the callback to invoke | ||
1503 | * @param {boolen} capture capture or bubble phase | ||
1504 | * @static | ||
1505 | * @private | ||
1506 | */ | ||
1507 | _simpleRemove: function() { | ||
1508 | if (window.removeEventListener) { | ||
1509 | return function (el, sType, fn, capture) { | ||
1510 | el.removeEventListener(sType, fn, (capture)); | ||
1511 | }; | ||
1512 | } else if (window.detachEvent) { | ||
1513 | return function (el, sType, fn) { | ||
1514 | el.detachEvent("on" + sType, fn); | ||
1515 | }; | ||
1516 | } else { | ||
1517 | return function(){}; | ||
1518 | } | ||
1519 | }() | ||
1520 | }; | ||
1521 | |||
1522 | }(); | ||
1523 | |||
1524 | (function() { | ||
1525 | var EU = YAHOO.util.Event; | ||
1526 | |||
1527 | /** | ||
1528 | * YAHOO.util.Event.on is an alias for addListener | ||
1529 | * @method on | ||
1530 | * @see addListener | ||
1531 | * @static | ||
1532 | */ | ||
1533 | EU.on = EU.addListener; | ||
1534 | |||
1535 | // YAHOO.mix(EU, YAHOO.util.EventProvider.prototype); | ||
1536 | // EU.createEvent("DOMContentReady"); | ||
1537 | // EU.subscribe("DOMContentReady", EU._load); | ||
1538 | |||
1539 | if (document && document.body) { | ||
1540 | EU._load(); | ||
1541 | } else { | ||
1542 | // EU._simpleAdd(document, "DOMContentLoaded", EU._load); | ||
1543 | EU._simpleAdd(window, "load", EU._load); | ||
1544 | } | ||
1545 | EU._simpleAdd(window, "unload", EU._unload); | ||
1546 | EU._tryPreloadAttach(); | ||
1547 | })(); | ||
1548 | } | ||
1549 | |||
1550 | /** | ||
1551 | * EventProvider is designed to be used with YAHOO.augment to wrap | ||
1552 | * CustomEvents in an interface that allows events to be subscribed to | ||
1553 | * and fired by name. This makes it possible for implementing code to | ||
1554 | * subscribe to an event that either has not been created yet, or will | ||
1555 | * not be created at all. | ||
1556 | * | ||
1557 | * @Class EventProvider | ||
1558 | */ | ||
1559 | YAHOO.util.EventProvider = function() { }; | ||
1560 | |||
1561 | YAHOO.util.EventProvider.prototype = { | ||
1562 | |||
1563 | /** | ||
1564 | * Private storage of custom events | ||
1565 | * @property __yui_events | ||
1566 | * @type Object[] | ||
1567 | * @private | ||
1568 | */ | ||
1569 | __yui_events: null, | ||
1570 | |||
1571 | /** | ||
1572 | * Private storage of custom event subscribers | ||
1573 | * @property __yui_subscribers | ||
1574 | * @type Object[] | ||
1575 | * @private | ||
1576 | */ | ||
1577 | __yui_subscribers: null, | ||
1578 | |||
1579 | /** | ||
1580 | * Subscribe to a CustomEvent by event type | ||
1581 | * | ||
1582 | * @method subscribe | ||
1583 | * @param p_type {string} the type, or name of the event | ||
1584 | * @param p_fn {function} the function to exectute when the event fires | ||
1585 | * @param p_obj | ||
1586 | * @param p_obj {Object} An object to be passed along when the event | ||
1587 | * fires | ||
1588 | * @param p_override {boolean} If true, the obj passed in becomes the | ||
1589 | * execution scope of the listener | ||
1590 | */ | ||
1591 | subscribe: function(p_type, p_fn, p_obj, p_override) { | ||
1592 | |||
1593 | this.__yui_events = this.__yui_events || {}; | ||
1594 | var ce = this.__yui_events[p_type]; | ||
1595 | |||
1596 | if (ce) { | ||
1597 | ce.subscribe(p_fn, p_obj, p_override); | ||
1598 | } else { | ||
1599 | this.__yui_subscribers = this.__yui_subscribers || {}; | ||
1600 | var subs = this.__yui_subscribers; | ||
1601 | if (!subs[p_type]) { | ||
1602 | subs[p_type] = []; | ||
1603 | } | ||
1604 | subs[p_type].push( | ||
1605 | { fn: p_fn, obj: p_obj, override: p_override } ); | ||
1606 | } | ||
1607 | }, | ||
1608 | |||
1609 | /** | ||
1610 | * Unsubscribes the from the specified event | ||
1611 | * @method unsubscribe | ||
1612 | * @param p_type {string} The type, or name of the event | ||
1613 | * @param p_fn {Function} The function to execute | ||
1614 | * @param p_obj {Object} The custom object passed to subscribe (optional) | ||
1615 | * @return {boolean} true if the subscriber was found and detached. | ||
1616 | */ | ||
1617 | unsubscribe: function(p_type, p_fn, p_obj) { | ||
1618 | this.__yui_events = this.__yui_events || {}; | ||
1619 | var ce = this.__yui_events[p_type]; | ||
1620 | if (ce) { | ||
1621 | return ce.unsubscribe(p_fn, p_obj); | ||
1622 | } else { | ||
1623 | return false; | ||
1624 | } | ||
1625 | }, | ||
1626 | |||
1627 | /** | ||
1628 | * Creates a new custom event of the specified type. If a custom event | ||
1629 | * by that name already exists, it will not be re-created. In either | ||
1630 | * case the custom event is returned. | ||
1631 | * | ||
1632 | * @method createEvent | ||
1633 | * | ||
1634 | * @param p_type {string} the type, or name of the event | ||
1635 | * @param p_config {object} optional config params. Valid properties are: | ||
1636 | * | ||
1637 | * <ul> | ||
1638 | * <li> | ||
1639 | * scope: defines the default execution scope. If not defined | ||
1640 | * the default scope will be this instance. | ||
1641 | * </li> | ||
1642 | * <li> | ||
1643 | * silent: if true, the custom event will not generate log messages. | ||
1644 | * This is false by default. | ||
1645 | * </li> | ||
1646 | * <li> | ||
1647 | * onSubscribeCallback: specifies a callback to execute when the | ||
1648 | * event has a new subscriber. This will fire immediately for | ||
1649 | * each queued subscriber if any exist prior to the creation of | ||
1650 | * the event. | ||
1651 | * </li> | ||
1652 | * </ul> | ||
1653 | * | ||
1654 | * @return {CustomEvent} the custom event | ||
1655 | * | ||
1656 | */ | ||
1657 | createEvent: function(p_type, p_config) { | ||
1658 | |||
1659 | this.__yui_events = this.__yui_events || {}; | ||
1660 | var opts = p_config || {}; | ||
1661 | var events = this.__yui_events; | ||
1662 | |||
1663 | if (events[p_type]) { | ||
1664 | } else { | ||
1665 | |||
1666 | var scope = opts.scope || this; | ||
1667 | var silent = opts.silent || null; | ||
1668 | |||
1669 | var ce = new YAHOO.util.CustomEvent(p_type, scope, silent, | ||
1670 | YAHOO.util.CustomEvent.FLAT); | ||
1671 | events[p_type] = ce; | ||
1672 | |||
1673 | if (opts.onSubscribeCallback) { | ||
1674 | ce.subscribeEvent.subscribe(opts.onSubscribeCallback); | ||
1675 | } | ||
1676 | |||
1677 | this.__yui_subscribers = this.__yui_subscribers || {}; | ||
1678 | var qs = this.__yui_subscribers[p_type]; | ||
1679 | |||
1680 | if (qs) { | ||
1681 | for (var i=0; i<qs.length; ++i) { | ||
1682 | ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override); | ||
1683 | } | ||
1684 | } | ||
1685 | } | ||
1686 | |||
1687 | return events[p_type]; | ||
1688 | }, | ||
1689 | |||
1690 | /** | ||
1691 | * Fire a custom event by name. The callback functions will be executed | ||
1692 | * from the scope specified when the event was created, and with the | ||
1693 | * following parameters: | ||
1694 | * <ul> | ||
1695 | * <li>The first argument fire() was executed with</li> | ||
1696 | * <li>The custom object (if any) that was passed into the subscribe() | ||
1697 | * method</li> | ||
1698 | * </ul> | ||
1699 | * @method fireEvent | ||
1700 | * @param p_type {string} the type, or name of the event | ||
1701 | * @param arguments {Object*} an arbitrary set of parameters to pass to | ||
1702 | * the handler. | ||
1703 | * @return {boolean} the return value from CustomEvent.fire, or null if | ||
1704 | * the custom event does not exist. | ||
1705 | */ | ||
1706 | fireEvent: function(p_type, arg1, arg2, etc) { | ||
1707 | |||
1708 | this.__yui_events = this.__yui_events || {}; | ||
1709 | var ce = this.__yui_events[p_type]; | ||
1710 | |||
1711 | if (ce) { | ||
1712 | var args = []; | ||
1713 | for (var i=1; i<arguments.length; ++i) { | ||
1714 | args.push(arguments[i]); | ||
1715 | } | ||
1716 | return ce.fire.apply(ce, args); | ||
1717 | } else { | ||
1718 | return null; | ||
1719 | } | ||
1720 | }, | ||
1721 | |||
1722 | /** | ||
1723 | * Returns true if the custom event of the provided type has been created | ||
1724 | * with createEvent. | ||
1725 | * @method hasEvent | ||
1726 | * @param type {string} the type, or name of the event | ||
1727 | */ | ||
1728 | hasEvent: function(type) { | ||
1729 | if (this.__yui_events) { | ||
1730 | if (this.__yui_events[type]) { | ||
1731 | return true; | ||
1732 | } | ||
1733 | } | ||
1734 | return false; | ||
1735 | } | ||
1736 | |||
1737 | }; | ||
1738 | |||