]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/event/event.js
Release 6.2.0beta4
[Github/sugarcrm.git] / include / javascript / yui / build / event / event.js
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 /**
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}  context 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 debugsystem
19  * @param {int}     signature the signature that the custom event subscriber
20  *                  will receive. YAHOO.util.CustomEvent.LIST or 
21  *                  YAHOO.util.CustomEvent.FLAT.  The default is
22  *                  YAHOO.util.CustomEvent.LIST.
23  * @param fireOnce {boolean} If configured to fire once, the custom event 
24  * will only notify subscribers a single time regardless of how many times 
25  * the event is fired.  In addition, new subscribers will be notified 
26  * immediately if the event has already been fired.
27  * @namespace YAHOO.util
28  * @class CustomEvent
29  * @constructor
30  */
31 YAHOO.util.CustomEvent = function(type, context, silent, signature, fireOnce) {
32
33     /**
34      * The type of event, returned to subscribers when the event fires
35      * @property type
36      * @type string
37      */
38     this.type = type;
39
40     /**
41      * The context the event will fire from by default. Defaults to the window obj.
42      * @property scope
43      * @type object
44      */
45     this.scope = context || window;
46
47     /**
48      * By default all custom events are logged in the debug build. Set silent to true 
49      * to disable debug output for this event.
50      * @property silent
51      * @type boolean
52      */
53     this.silent = silent;
54
55     /**
56      * If configured to fire once, the custom event will only notify subscribers
57      * a single time regardless of how many times the event is fired.  In addition,
58      * new subscribers will be notified immediately if the event has already been
59      * fired.
60      * @property fireOnce
61      * @type boolean
62      * @default false
63      */
64     this.fireOnce = fireOnce;
65
66     /**
67      * Indicates whether or not this event has ever been fired.
68      * @property fired
69      * @type boolean
70      * @default false
71      */
72     this.fired = false;
73
74     /**
75      * For fireOnce events the arguments the event was fired with are stored
76      * so that new subscribers get the proper payload.
77      * @property firedWith
78      * @type Array
79      */
80     this.firedWith = null;
81
82     /**
83      * Custom events support two styles of arguments provided to the event
84      * subscribers.  
85      * <ul>
86      * <li>YAHOO.util.CustomEvent.LIST: 
87      *   <ul>
88      *   <li>param1: event name</li>
89      *   <li>param2: array of arguments sent to fire</li>
90      *   <li>param3: <optional> a custom object supplied by the subscriber</li>
91      *   </ul>
92      * </li>
93      * <li>YAHOO.util.CustomEvent.FLAT
94      *   <ul>
95      *   <li>param1: the first argument passed to fire.  If you need to
96      *           pass multiple parameters, use and array or object literal</li>
97      *   <li>param2: <optional> a custom object supplied by the subscriber</li>
98      *   </ul>
99      * </li>
100      * </ul>
101      *   @property signature
102      *   @type int
103      */
104     this.signature = signature || YAHOO.util.CustomEvent.LIST;
105
106     /**
107      * The subscribers to this event
108      * @property subscribers
109      * @type Subscriber[]
110      */
111     this.subscribers = [];
112
113     if (!this.silent) {
114     }
115
116     var onsubscribeType = "_YUICEOnSubscribe";
117
118     // Only add subscribe events for events that are not generated by 
119     // CustomEvent
120     if (type !== onsubscribeType) {
121
122         /**
123          * Custom events provide a custom event that fires whenever there is
124          * a new subscriber to the event.  This provides an opportunity to
125          * handle the case where there is a non-repeating event that has
126          * already fired has a new subscriber.  
127          *
128          * @event subscribeEvent
129          * @type YAHOO.util.CustomEvent
130          * @param fn {Function} The function to execute
131          * @param obj <Object> An object to be passed along when the event fires. 
132          * Defaults to the custom event.
133          * @param override <boolean|Object> If true, the obj passed in becomes the 
134          * execution context of the listener. If an object, that object becomes 
135          * the execution context. Defaults to the custom event.
136          */
137         this.subscribeEvent = 
138                 new YAHOO.util.CustomEvent(onsubscribeType, this, true);
139
140     } 
141
142
143     /**
144      * In order to make it possible to execute the rest of the subscriber
145      * stack when one thows an exception, the subscribers exceptions are
146      * caught.  The most recent exception is stored in this property
147      * @property lastError
148      * @type Error
149      */
150     this.lastError = null;
151 };
152
153 /**
154  * Subscriber listener sigature constant.  The LIST type returns three
155  * parameters: the event type, the array of args passed to fire, and
156  * the optional custom object
157  * @property YAHOO.util.CustomEvent.LIST
158  * @static
159  * @type int
160  */
161 YAHOO.util.CustomEvent.LIST = 0;
162
163 /**
164  * Subscriber listener sigature constant.  The FLAT type returns two
165  * parameters: the first argument passed to fire and the optional 
166  * custom object
167  * @property YAHOO.util.CustomEvent.FLAT
168  * @static
169  * @type int
170  */
171 YAHOO.util.CustomEvent.FLAT = 1;
172
173 YAHOO.util.CustomEvent.prototype = {
174
175     /**
176      * Subscribes the caller to this event
177      * @method subscribe
178      * @param {Function} fn        The function to execute
179      * @param {Object}   obj       An object to be passed along when the event fires.
180      * overrideContext <boolean|Object> If true, the obj passed in becomes the execution 
181      * context of the listener. If an object, that object becomes the execution context.
182      */
183     subscribe: function(fn, obj, overrideContext) {
184
185         if (!fn) {
186 throw new Error("Invalid callback for subscriber to '" + this.type + "'");
187         }
188
189         if (this.subscribeEvent) {
190             this.subscribeEvent.fire(fn, obj, overrideContext);
191         }
192
193         var s = new YAHOO.util.Subscriber(fn, obj, overrideContext);
194
195         if (this.fireOnce && this.fired) {
196             this.notify(s, this.firedWith);
197         } else {
198             this.subscribers.push(s);
199         }
200     },
201
202     /**
203      * Unsubscribes subscribers.
204      * @method unsubscribe
205      * @param {Function} fn  The subscribed function to remove, if not supplied
206      *                       all will be removed
207      * @param {Object}   obj  The custom object passed to subscribe.  This is
208      *                        optional, but if supplied will be used to
209      *                        disambiguate multiple listeners that are the same
210      *                        (e.g., you subscribe many object using a function
211      *                        that lives on the prototype)
212      * @return {boolean} True if the subscriber was found and detached.
213      */
214     unsubscribe: function(fn, obj) {
215
216         if (!fn) {
217             return this.unsubscribeAll();
218         }
219
220         var found = false;
221         for (var i=0, len=this.subscribers.length; i<len; ++i) {
222             var s = this.subscribers[i];
223             if (s && s.contains(fn, obj)) {
224                 this._delete(i);
225                 found = true;
226             }
227         }
228
229         return found;
230     },
231
232     /**
233      * Notifies the subscribers.  The callback functions will be executed
234      * from the context specified when the event was created, and with the 
235      * following parameters:
236      *   <ul>
237      *   <li>The type of event</li>
238      *   <li>All of the arguments fire() was executed with as an array</li>
239      *   <li>The custom object (if any) that was passed into the subscribe() 
240      *       method</li>
241      *   </ul>
242      * @method fire 
243      * @param {Object*} arguments an arbitrary set of parameters to pass to 
244      *                            the handler.
245      * @return {boolean} false if one of the subscribers returned false, 
246      *                   true otherwise
247      */
248     fire: function() {
249
250         this.lastError = null;
251
252         var errors = [],
253             len=this.subscribers.length;
254
255
256         var args=[].slice.call(arguments, 0), ret=true, i, rebuild=false;
257
258         if (this.fireOnce) {
259             if (this.fired) {
260                 return true;
261             } else {
262                 this.firedWith = args;
263             }
264         }
265
266         this.fired = true;
267
268         if (!len && this.silent) {
269             return true;
270         }
271
272         if (!this.silent) {
273         }
274
275         // make a copy of the subscribers so that there are
276         // no index problems if one subscriber removes another.
277         var subs = this.subscribers.slice();
278
279         for (i=0; i<len; ++i) {
280             var s = subs[i];
281             if (!s) {
282                 rebuild=true;
283             } else {
284
285                 ret = this.notify(s, args);
286
287                 if (false === ret) {
288                     if (!this.silent) {
289                     }
290
291                     break;
292                 }
293             }
294         }
295
296         return (ret !== false);
297     },
298
299     notify: function(s, args) {
300
301         var ret, param=null, scope = s.getScope(this.scope),
302                  throwErrors = YAHOO.util.Event.throwErrors;
303
304         if (!this.silent) {
305         }
306
307         if (this.signature == YAHOO.util.CustomEvent.FLAT) {
308
309             if (args.length > 0) {
310                 param = args[0];
311             }
312
313             try {
314                 ret = s.fn.call(scope, param, s.obj);
315             } catch(e) {
316                 this.lastError = e;
317                 // errors.push(e);
318                 if (throwErrors) {
319                     throw e;
320                 }
321             }
322         } else {
323             try {
324                 ret = s.fn.call(scope, this.type, args, s.obj);
325             } catch(ex) {
326                 this.lastError = ex;
327                 if (throwErrors) {
328                     throw ex;
329                 }
330             }
331         }
332
333         return ret;
334     },
335
336     /**
337      * Removes all listeners
338      * @method unsubscribeAll
339      * @return {int} The number of listeners unsubscribed
340      */
341     unsubscribeAll: function() {
342         var l = this.subscribers.length, i;
343         for (i=l-1; i>-1; i--) {
344             this._delete(i);
345         }
346
347         this.subscribers=[];
348
349         return l;
350     },
351
352     /**
353      * @method _delete
354      * @private
355      */
356     _delete: function(index) {
357         var s = this.subscribers[index];
358         if (s) {
359             delete s.fn;
360             delete s.obj;
361         }
362
363         // this.subscribers[index]=null;
364         this.subscribers.splice(index, 1);
365     },
366
367     /**
368      * @method toString
369      */
370     toString: function() {
371          return "CustomEvent: " + "'" + this.type  + "', " + 
372              "context: " + this.scope;
373
374     }
375 };
376
377 /////////////////////////////////////////////////////////////////////
378
379 /**
380  * Stores the subscriber information to be used when the event fires.
381  * @param {Function} fn       The function to execute
382  * @param {Object}   obj      An object to be passed along when the event fires
383  * @param {boolean}  overrideContext If true, the obj passed in becomes the execution
384  *                            context of the listener
385  * @class Subscriber
386  * @constructor
387  */
388 YAHOO.util.Subscriber = function(fn, obj, overrideContext) {
389
390     /**
391      * The callback that will be execute when the event fires
392      * @property fn
393      * @type function
394      */
395     this.fn = fn;
396
397     /**
398      * An optional custom object that will passed to the callback when
399      * the event fires
400      * @property obj
401      * @type object
402      */
403     this.obj = YAHOO.lang.isUndefined(obj) ? null : obj;
404
405     /**
406      * The default execution context for the event listener is defined when the
407      * event is created (usually the object which contains the event).
408      * By setting overrideContext to true, the execution context becomes the custom
409      * object passed in by the subscriber.  If overrideContext is an object, that 
410      * object becomes the context.
411      * @property overrideContext
412      * @type boolean|object
413      */
414     this.overrideContext = overrideContext;
415
416 };
417
418 /**
419  * Returns the execution context for this listener.  If overrideContext was set to true
420  * the custom obj will be the context.  If overrideContext is an object, that is the
421  * context, otherwise the default context will be used.
422  * @method getScope
423  * @param {Object} defaultScope the context to use if this listener does not
424  *                              override it.
425  */
426 YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
427     if (this.overrideContext) {
428         if (this.overrideContext === true) {
429             return this.obj;
430         } else {
431             return this.overrideContext;
432         }
433     }
434     return defaultScope;
435 };
436
437 /**
438  * Returns true if the fn and obj match this objects properties.
439  * Used by the unsubscribe method to match the right subscriber.
440  *
441  * @method contains
442  * @param {Function} fn the function to execute
443  * @param {Object} obj an object to be passed along when the event fires
444  * @return {boolean} true if the supplied arguments match this 
445  *                   subscriber's signature.
446  */
447 YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
448     if (obj) {
449         return (this.fn == fn && this.obj == obj);
450     } else {
451         return (this.fn == fn);
452     }
453 };
454
455 /**
456  * @method toString
457  */
458 YAHOO.util.Subscriber.prototype.toString = function() {
459     return "Subscriber { obj: " + this.obj  + 
460            ", overrideContext: " +  (this.overrideContext || "no") + " }";
461 };
462
463 /**
464  * The Event Utility provides utilities for managing DOM Events and tools
465  * for building event systems
466  *
467  * @module event
468  * @title Event Utility
469  * @namespace YAHOO.util
470  * @requires yahoo
471  */
472
473 // The first instance of Event will win if it is loaded more than once.
474 // @TODO this needs to be changed so that only the state data that needs to
475 // be preserved is kept, while methods are overwritten/added as needed.
476 // This means that the module pattern can't be used.
477 if (!YAHOO.util.Event) {
478
479 /**
480  * The event utility provides functions to add and remove event listeners,
481  * event cleansing.  It also tries to automatically remove listeners it
482  * registers during the unload event.
483  *
484  * @class Event
485  * @static
486  */
487     YAHOO.util.Event = function() {
488
489         /**
490          * True after the onload event has fired
491          * @property loadComplete
492          * @type boolean
493          * @static
494          * @private
495          */
496         var loadComplete =  false,
497
498         /**
499          * Cache of wrapped listeners
500          * @property listeners
501          * @type array
502          * @static
503          * @private
504          */
505         listeners = [],
506
507
508         /**
509          * User-defined unload function that will be fired before all events
510          * are detached
511          * @property unloadListeners
512          * @type array
513          * @static
514          * @private
515          */
516         unloadListeners = [],
517
518         /**
519          * The number of times to poll after window.onload.  This number is
520          * increased if additional late-bound handlers are requested after
521          * the page load.
522          * @property retryCount
523          * @static
524          * @private
525          */
526         retryCount = 0,
527
528         /**
529          * onAvailable listeners
530          * @property onAvailStack
531          * @static
532          * @private
533          */
534         onAvailStack = [],
535
536         /**
537          * Counter for auto id generation
538          * @property counter
539          * @static
540          * @private
541          */
542         counter = 0,
543         
544         /**
545          * Normalized keycodes for webkit/safari
546          * @property webkitKeymap
547          * @type {int: int}
548          * @private
549          * @static
550          * @final
551          */
552          webkitKeymap = {
553             63232: 38, // up
554             63233: 40, // down
555             63234: 37, // left
556             63235: 39, // right
557             63276: 33, // page up
558             63277: 34, // page down
559             25: 9      // SHIFT-TAB (Safari provides a different key code in
560                        // this case, even though the shiftKey modifier is set)
561         },
562
563                 isIE = YAHOO.env.ua.ie,
564
565         // String constants used by the addFocusListener and removeFocusListener methods
566                 
567         FOCUSIN = "focusin",
568         FOCUSOUT = "focusout";
569
570         return {
571
572             /**
573              * The number of times we should look for elements that are not
574              * in the DOM at the time the event is requested after the document
575              * has been loaded.  The default is 500@amp;40 ms, so it will poll
576              * for 20 seconds or until all outstanding handlers are bound
577              * (whichever comes first).
578              * @property POLL_RETRYS
579              * @type int
580              * @static
581              * @final
582              */
583             POLL_RETRYS: 500,
584
585             /**
586              * The poll interval in milliseconds
587              * @property POLL_INTERVAL
588              * @type int
589              * @static
590              * @final
591              */
592             POLL_INTERVAL: 40,
593
594             /**
595              * Element to bind, int constant
596              * @property EL
597              * @type int
598              * @static
599              * @final
600              */
601             EL: 0,
602
603             /**
604              * Type of event, int constant
605              * @property TYPE
606              * @type int
607              * @static
608              * @final
609              */
610             TYPE: 1,
611
612             /**
613              * Function to execute, int constant
614              * @property FN
615              * @type int
616              * @static
617              * @final
618              */
619             FN: 2,
620
621             /**
622              * Function wrapped for context correction and cleanup, int constant
623              * @property WFN
624              * @type int
625              * @static
626              * @final
627              */
628             WFN: 3,
629
630             /**
631              * Object passed in by the user that will be returned as a 
632              * parameter to the callback, int constant.  Specific to
633              * unload listeners
634              * @property OBJ
635              * @type int
636              * @static
637              * @final
638              */
639             UNLOAD_OBJ: 3,
640
641             /**
642              * Adjusted context, either the element we are registering the event
643              * on or the custom object passed in by the listener, int constant
644              * @property ADJ_SCOPE
645              * @type int
646              * @static
647              * @final
648              */
649             ADJ_SCOPE: 4,
650
651             /**
652              * The original obj passed into addListener
653              * @property OBJ
654              * @type int
655              * @static
656              * @final
657              */
658             OBJ: 5,
659
660             /**
661              * The original context parameter passed into addListener
662              * @property OVERRIDE
663              * @type int
664              * @static
665              * @final
666              */
667             OVERRIDE: 6,
668
669             /**
670              * The original capture parameter passed into addListener
671              * @property CAPTURE
672              * @type int
673              * @static
674              * @final
675              */
676                         CAPTURE: 7,
677
678             /**
679              * addListener/removeListener can throw errors in unexpected scenarios.
680              * These errors are suppressed, the method returns false, and this property
681              * is set
682              * @property lastError
683              * @static
684              * @type Error
685              */
686             lastError: null,
687
688             /**
689              * Safari detection
690              * @property isSafari
691              * @private
692              * @static
693              * @deprecated use YAHOO.env.ua.webkit
694              */
695             isSafari: YAHOO.env.ua.webkit,
696             
697             /**
698              * webkit version
699              * @property webkit
700              * @type string
701              * @private
702              * @static
703              * @deprecated use YAHOO.env.ua.webkit
704              */
705             webkit: YAHOO.env.ua.webkit,
706             
707             /**
708              * IE detection 
709              * @property isIE
710              * @private
711              * @static
712              * @deprecated use YAHOO.env.ua.ie
713              */
714             isIE: isIE,
715
716             /**
717              * poll handle
718              * @property _interval
719              * @static
720              * @private
721              */
722             _interval: null,
723
724             /**
725              * document readystate poll handle
726              * @property _dri
727              * @static
728              * @private
729              */
730              _dri: null,
731
732
733             /**
734              * Map of special event types
735              * @property _specialTypes
736              * @static
737              * @private
738              */
739                         _specialTypes: {
740                                 focusin: (isIE ? "focusin" : "focus"),
741                                 focusout: (isIE ? "focusout" : "blur")
742                         },
743
744
745             /**
746              * True when the document is initially usable
747              * @property DOMReady
748              * @type boolean
749              * @static
750              */
751             DOMReady: false,
752
753             /**
754              * Errors thrown by subscribers of custom events are caught
755              * and the error message is written to the debug console.  If
756              * this property is set to true, it will also re-throw the
757              * error.
758              * @property throwErrors
759              * @type boolean
760              * @default false
761              */
762             throwErrors: false,
763
764
765             /**
766              * @method startInterval
767              * @static
768              * @private
769              */
770             startInterval: function() {
771                 if (!this._interval) {
772                     // var self = this;
773                     // var callback = function() { self._tryPreloadAttach(); };
774                     // this._interval = setInterval(callback, this.POLL_INTERVAL);
775                     this._interval = YAHOO.lang.later(this.POLL_INTERVAL, this, this._tryPreloadAttach, null, true);
776                 }
777             },
778
779             /**
780              * Executes the supplied callback when the item with the supplied
781              * id is found.  This is meant to be used to execute behavior as
782              * soon as possible as the page loads.  If you use this after the
783              * initial page load it will poll for a fixed time for the element.
784              * The number of times it will poll and the frequency are
785              * configurable.  By default it will poll for 10 seconds.
786              *
787              * <p>The callback is executed with a single parameter:
788              * the custom object parameter, if provided.</p>
789              *
790              * @method onAvailable
791              *
792              * @param {string||string[]}   id the id of the element, or an array
793              * of ids to look for.
794              * @param {function} fn what to execute when the element is found.
795              * @param {object}   obj an optional object to be passed back as
796              *                   a parameter to fn.
797              * @param {boolean|object}  overrideContext If set to true, fn will execute
798              *                   in the context of obj, if set to an object it
799              *                   will execute in the context of that object
800              * @param checkContent {boolean} check child node readiness (onContentReady)
801              * @static
802              */
803             onAvailable: function(id, fn, obj, overrideContext, checkContent) {
804
805                 var a = (YAHOO.lang.isString(id)) ? [id] : id;
806
807                 for (var i=0; i<a.length; i=i+1) {
808                     onAvailStack.push({id:         a[i], 
809                                        fn:         fn, 
810                                        obj:        obj, 
811                                        overrideContext:   overrideContext, 
812                                        checkReady: checkContent });
813                 }
814
815                 retryCount = this.POLL_RETRYS;
816
817                 this.startInterval();
818             },
819
820             /**
821              * Works the same way as onAvailable, but additionally checks the
822              * state of sibling elements to determine if the content of the
823              * available element is safe to modify.
824              *
825              * <p>The callback is executed with a single parameter:
826              * the custom object parameter, if provided.</p>
827              *
828              * @method onContentReady
829              *
830              * @param {string}   id the id of the element to look for.
831              * @param {function} fn what to execute when the element is ready.
832              * @param {object}   obj an optional object to be passed back as
833              *                   a parameter to fn.
834              * @param {boolean|object}  overrideContext If set to true, fn will execute
835              *                   in the context of obj.  If an object, fn will
836              *                   exectute in the context of that object
837              *
838              * @static
839              */
840             onContentReady: function(id, fn, obj, overrideContext) {
841                 this.onAvailable(id, fn, obj, overrideContext, true);
842             },
843
844             /**
845              * Executes the supplied callback when the DOM is first usable.  This
846              * will execute immediately if called after the DOMReady event has
847              * fired.   @todo the DOMContentReady event does not fire when the
848              * script is dynamically injected into the page.  This means the
849              * DOMReady custom event will never fire in FireFox or Opera when the
850              * library is injected.  It _will_ fire in Safari, and the IE 
851              * implementation would allow for us to fire it if the defered script
852              * is not available.  We want this to behave the same in all browsers.
853              * Is there a way to identify when the script has been injected 
854              * instead of included inline?  Is there a way to know whether the 
855              * window onload event has fired without having had a listener attached 
856              * to it when it did so?
857              *
858              * <p>The callback is a CustomEvent, so the signature is:</p>
859              * <p>type &lt;string&gt;, args &lt;array&gt;, customobject &lt;object&gt;</p>
860              * <p>For DOMReady events, there are no fire argments, so the
861              * signature is:</p>
862              * <p>"DOMReady", [], obj</p>
863              *
864              *
865              * @method onDOMReady
866              *
867              * @param {function} fn what to execute when the element is found.
868              * @param {object}   obj an optional object to be passed back as
869              *                   a parameter to fn.
870              * @param {boolean|object}  overrideContext If set to true, fn will execute
871              *                   in the context of obj, if set to an object it
872              *                   will execute in the context of that object
873              *
874              * @static
875              */
876             // onDOMReady: function(fn, obj, overrideContext) {
877             onDOMReady: function() {
878                 this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent, arguments);
879             },
880
881
882             /**
883              * Appends an event handler
884              *
885              * @method _addListener
886              *
887              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
888              *  reference, or a collection of ids and/or elements to assign the 
889              *  listener to.
890              * @param {String}   sType     The type of event to append
891              * @param {Function} fn        The method the event invokes
892              * @param {Object}   obj    An arbitrary object that will be 
893              *                             passed as a parameter to the handler
894              * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
895              *                             the execution context of the listener. If an
896              *                             object, this object becomes the execution
897              *                             context.
898              * @param {boolen}      capture capture or bubble phase
899              * @return {Boolean} True if the action was successful or defered,
900              *                        false if one or more of the elements 
901              *                        could not have the listener attached,
902              *                        or if the operation throws an exception.
903              * @private
904              * @static
905              */
906             _addListener: function(el, sType, fn, obj, overrideContext, bCapture) {
907
908                 if (!fn || !fn.call) {
909                     return false;
910                 }
911
912                 // The el argument can be an array of elements or element ids.
913                 if ( this._isValidCollection(el)) {
914                     var ok = true;
915                     for (var i=0,len=el.length; i<len; ++i) {
916                         ok = this.on(el[i], 
917                                        sType, 
918                                        fn, 
919                                        obj, 
920                                        overrideContext) && ok;
921                     }
922                     return ok;
923
924                 } else if (YAHOO.lang.isString(el)) {
925                     var oEl = this.getEl(el);
926                     // If the el argument is a string, we assume it is 
927                     // actually the id of the element.  If the page is loaded
928                     // we convert el to the actual element, otherwise we 
929                     // defer attaching the event until onload event fires
930
931                     // check to see if we need to delay hooking up the event 
932                     // until after the page loads.
933                     if (oEl) {
934                         el = oEl;
935                     } else {
936                         // defer adding the event until the element is available
937                         this.onAvailable(el, function() {
938                            YAHOO.util.Event._addListener(el, sType, fn, obj, overrideContext, bCapture);
939                         });
940
941                         return true;
942                     }
943                 }
944
945                 // Element should be an html element or an array if we get 
946                 // here.
947                 if (!el) {
948                     return false;
949                 }
950
951                 // we need to make sure we fire registered unload events 
952                 // prior to automatically unhooking them.  So we hang on to 
953                 // these instead of attaching them to the window and fire the
954                 // handles explicitly during our one unload event.
955                 if ("unload" == sType && obj !== this) {
956                     unloadListeners[unloadListeners.length] =
957                             [el, sType, fn, obj, overrideContext];
958                     return true;
959                 }
960
961
962                 // if the user chooses to override the context, we use the custom
963                 // object passed in, otherwise the executing context will be the
964                 // HTML element that the event is registered on
965                 var context = el;
966                 if (overrideContext) {
967                     if (overrideContext === true) {
968                         context = obj;
969                     } else {
970                         context = overrideContext;
971                     }
972                 }
973
974                 // wrap the function so we can return the obj object when
975                 // the event fires;
976                 var wrappedFn = function(e) {
977                         return fn.call(context, YAHOO.util.Event.getEvent(e, el), 
978                                 obj);
979                     };
980
981                 var li = [el, sType, fn, wrappedFn, context, obj, overrideContext, bCapture];
982                 var index = listeners.length;
983                 // cache the listener so we can try to automatically unload
984                 listeners[index] = li;
985
986                 try {
987                     this._simpleAdd(el, sType, wrappedFn, bCapture);
988                 } catch(ex) {
989                     // handle an error trying to attach an event.  If it fails
990                     // we need to clean up the cache
991                     this.lastError = ex;
992                     this.removeListener(el, sType, fn);
993                     return false;
994                 }
995
996                 return true;
997                 
998             },
999
1000             /**
1001              * Checks to see if the type requested is a special type 
1002                          * (as defined by the _specialTypes hash), and (if so) returns 
1003                          * the special type name.
1004              *
1005              * @method _getType
1006              *
1007              * @param {String}   sType     The type to look up
1008              * @private
1009              */
1010                         _getType: function (type) {
1011                         
1012                                 return this._specialTypes[type] || type;
1013                                 
1014                         },
1015
1016
1017             /**
1018              * Appends an event handler
1019              *
1020              * @method addListener
1021              *
1022              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1023              *  reference, or a collection of ids and/or elements to assign the 
1024              *  listener to.
1025              * @param {String}   sType     The type of event to append
1026              * @param {Function} fn        The method the event invokes
1027              * @param {Object}   obj    An arbitrary object that will be 
1028              *                             passed as a parameter to the handler
1029              * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1030              *                             the execution context of the listener. If an
1031              *                             object, this object becomes the execution
1032              *                             context.
1033              * @return {Boolean} True if the action was successful or defered,
1034              *                        false if one or more of the elements 
1035              *                        could not have the listener attached,
1036              *                        or if the operation throws an exception.
1037              * @static
1038              */
1039             addListener: function (el, sType, fn, obj, overrideContext) {
1040
1041                                 var capture = ((sType == FOCUSIN || sType == FOCUSOUT) && !YAHOO.env.ua.ie) ? true : false;
1042
1043                 return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
1044
1045                 },
1046
1047
1048             /**
1049              * Attaches a focusin event listener to the specified element for 
1050                          * the purpose of listening for the focus event on the element's 
1051              * descendants.
1052              * @method addFocusListener
1053              *
1054              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1055              *  reference, or a collection of ids and/or elements to assign the 
1056              *  listener to.
1057              * @param {Function} fn        The method the event invokes
1058              * @param {Object}   obj    An arbitrary object that will be 
1059              *                             passed as a parameter to the handler
1060              * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1061              *                             the execution context of the listener. If an
1062              *                             object, this object becomes the execution
1063              *                             context.
1064              * @return {Boolean} True if the action was successful or defered,
1065              *                        false if one or more of the elements 
1066              *                        could not have the listener attached,
1067              *                        or if the operation throws an exception.
1068              * @static
1069                         * @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
1070              */
1071             addFocusListener: function (el, fn, obj, overrideContext) {
1072                 return this.on(el, FOCUSIN, fn, obj, overrideContext);
1073             },          
1074
1075
1076             /**
1077              * Removes a focusin event listener to the specified element for 
1078                          * the purpose of listening for the focus event on the element's 
1079              * descendants.
1080              *
1081              * @method removeFocusListener
1082              *
1083              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1084              *  reference, or a collection of ids and/or elements to remove
1085              *  the listener from.
1086              * @param {Function} fn the method the event invokes.  If fn is
1087              *  undefined, then all event handlers for the type of event are 
1088              *  removed.
1089              * @return {boolean} true if the unbind was successful, false 
1090              *  otherwise.
1091              * @static
1092                  * @deprecated use YAHOO.util.Event.removeListener and specify "focusin" as the event type.
1093              */
1094             removeFocusListener: function (el, fn) { 
1095                 return this.removeListener(el, FOCUSIN, fn);
1096             },
1097
1098             /**
1099              * Attaches a focusout event listener to the specified element for 
1100                          * the purpose of listening for the blur event on the element's 
1101                          * descendants.
1102              *
1103              * @method addBlurListener
1104              *
1105              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1106              *  reference, or a collection of ids and/or elements to assign the 
1107              *  listener to.
1108              * @param {Function} fn        The method the event invokes
1109              * @param {Object}   obj    An arbitrary object that will be 
1110              *                             passed as a parameter to the handler
1111              * @param {Boolean|object}  overrideContext  If true, the obj passed in becomes
1112              *                             the execution context of the listener. If an
1113              *                             object, this object becomes the execution
1114              *                             context.
1115              * @return {Boolean} True if the action was successful or defered,
1116              *                        false if one or more of the elements 
1117              *                        could not have the listener attached,
1118              *                        or if the operation throws an exception.
1119              * @static
1120                  * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
1121              */
1122             addBlurListener: function (el, fn, obj, overrideContext) {
1123                 return this.on(el, FOCUSOUT, fn, obj, overrideContext);
1124             },          
1125
1126             /**
1127              * Removes a focusout event listener to the specified element for 
1128                          * the purpose of listening for the blur event on the element's 
1129                          * descendants.
1130              *
1131              * @method removeBlurListener
1132              *
1133              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1134              *  reference, or a collection of ids and/or elements to remove
1135              *  the listener from.
1136              * @param {Function} fn the method the event invokes.  If fn is
1137              *  undefined, then all event handlers for the type of event are 
1138              *  removed.
1139              * @return {boolean} true if the unbind was successful, false 
1140              *  otherwise.
1141              * @static
1142                  * @deprecated use YAHOO.util.Event.removeListener and specify "focusout" as the event type.
1143              */
1144             removeBlurListener: function (el, fn) { 
1145                 return this.removeListener(el, FOCUSOUT, fn);
1146             },
1147
1148             /**
1149              * Removes an event listener
1150              *
1151              * @method removeListener
1152              *
1153              * @param {String|HTMLElement|Array|NodeList} el An id, an element 
1154              *  reference, or a collection of ids and/or elements to remove
1155              *  the listener from.
1156              * @param {String} sType the type of event to remove.
1157              * @param {Function} fn the method the event invokes.  If fn is
1158              *  undefined, then all event handlers for the type of event are 
1159              *  removed.
1160              * @return {boolean} true if the unbind was successful, false 
1161              *  otherwise.
1162              * @static
1163              */
1164             removeListener: function(el, sType, fn) {
1165                 var i, len, li;
1166
1167                                 sType = this._getType(sType);
1168
1169                 // The el argument can be a string
1170                 if (typeof el == "string") {
1171                     el = this.getEl(el);
1172                 // The el argument can be an array of elements or element ids.
1173                 } else if ( this._isValidCollection(el)) {
1174                     var ok = true;
1175                     for (i=el.length-1; i>-1; i--) {
1176                         ok = ( this.removeListener(el[i], sType, fn) && ok );
1177                     }
1178                     return ok;
1179                 }
1180
1181                 if (!fn || !fn.call) {
1182                     //return false;
1183                     return this.purgeElement(el, false, sType);
1184                 }
1185
1186                 if ("unload" == sType) {
1187
1188                     for (i=unloadListeners.length-1; i>-1; i--) {
1189                         li = unloadListeners[i];
1190                         if (li && 
1191                             li[0] == el && 
1192                             li[1] == sType && 
1193                             li[2] == fn) {
1194                                 unloadListeners.splice(i, 1);
1195                                 // unloadListeners[i]=null;
1196                                 return true;
1197                         }
1198                     }
1199
1200                     return false;
1201                 }
1202
1203                 var cacheItem = null;
1204
1205                 // The index is a hidden parameter; needed to remove it from
1206                 // the method signature because it was tempting users to
1207                 // try and take advantage of it, which is not possible.
1208                 var index = arguments[3];
1209   
1210                 if ("undefined" === typeof index) {
1211                     index = this._getCacheIndex(listeners, el, sType, fn);
1212                 }
1213
1214                 if (index >= 0) {
1215                     cacheItem = listeners[index];
1216                 }
1217
1218                 if (!el || !cacheItem) {
1219                     return false;
1220                 }
1221
1222
1223                                 var bCapture = cacheItem[this.CAPTURE] === true ? true : false;
1224
1225                 try {
1226                     this._simpleRemove(el, sType, cacheItem[this.WFN], bCapture);
1227                 } catch(ex) {
1228                     this.lastError = ex;
1229                     return false;
1230                 }
1231
1232                 // removed the wrapped handler
1233                 delete listeners[index][this.WFN];
1234                 delete listeners[index][this.FN];
1235                 listeners.splice(index, 1);
1236                 // listeners[index]=null;
1237
1238                 return true;
1239
1240             },
1241
1242             /**
1243              * Returns the event's target element.  Safari sometimes provides
1244              * a text node, and this is automatically resolved to the text
1245              * node's parent so that it behaves like other browsers.
1246              * @method getTarget
1247              * @param {Event} ev the event
1248              * @param {boolean} resolveTextNode when set to true the target's
1249              *                  parent will be returned if the target is a 
1250              *                  text node.  @deprecated, the text node is
1251              *                  now resolved automatically
1252              * @return {HTMLElement} the event's target
1253              * @static
1254              */
1255             getTarget: function(ev, resolveTextNode) {
1256                 var t = ev.target || ev.srcElement;
1257                 return this.resolveTextNode(t);
1258             },
1259
1260             /**
1261              * In some cases, some browsers will return a text node inside
1262              * the actual element that was targeted.  This normalizes the
1263              * return value for getTarget and getRelatedTarget.
1264              * @method resolveTextNode
1265              * @param {HTMLElement} node node to resolve
1266              * @return {HTMLElement} the normized node
1267              * @static
1268              */
1269             resolveTextNode: function(n) {
1270                 try {
1271                     if (n && 3 == n.nodeType) {
1272                         return n.parentNode;
1273                     }
1274                 } catch(e) { }
1275
1276                 return n;
1277             },
1278
1279             /**
1280              * Returns the event's pageX
1281              * @method getPageX
1282              * @param {Event} ev the event
1283              * @return {int} the event's pageX
1284              * @static
1285              */
1286             getPageX: function(ev) {
1287                 var x = ev.pageX;
1288                 if (!x && 0 !== x) {
1289                     x = ev.clientX || 0;
1290
1291                     if ( this.isIE ) {
1292                         x += this._getScrollLeft();
1293                     }
1294                 }
1295
1296                 return x;
1297             },
1298
1299             /**
1300              * Returns the event's pageY
1301              * @method getPageY
1302              * @param {Event} ev the event
1303              * @return {int} the event's pageY
1304              * @static
1305              */
1306             getPageY: function(ev) {
1307                 var y = ev.pageY;
1308                 if (!y && 0 !== y) {
1309                     y = ev.clientY || 0;
1310
1311                     if ( this.isIE ) {
1312                         y += this._getScrollTop();
1313                     }
1314                 }
1315
1316
1317                 return y;
1318             },
1319
1320             /**
1321              * Returns the pageX and pageY properties as an indexed array.
1322              * @method getXY
1323              * @param {Event} ev the event
1324              * @return {[x, y]} the pageX and pageY properties of the event
1325              * @static
1326              */
1327             getXY: function(ev) {
1328                 return [this.getPageX(ev), this.getPageY(ev)];
1329             },
1330
1331             /**
1332              * Returns the event's related target 
1333              * @method getRelatedTarget
1334              * @param {Event} ev the event
1335              * @return {HTMLElement} the event's relatedTarget
1336              * @static
1337              */
1338             getRelatedTarget: function(ev) {
1339                 var t = ev.relatedTarget;
1340                 if (!t) {
1341                     if (ev.type == "mouseout") {
1342                         t = ev.toElement;
1343                     } else if (ev.type == "mouseover") {
1344                         t = ev.fromElement;
1345                     }
1346                 }
1347
1348                 return this.resolveTextNode(t);
1349             },
1350
1351             /**
1352              * Returns the time of the event.  If the time is not included, the
1353              * event is modified using the current time.
1354              * @method getTime
1355              * @param {Event} ev the event
1356              * @return {Date} the time of the event
1357              * @static
1358              */
1359             getTime: function(ev) {
1360                 if (!ev.time) {
1361                     var t = new Date().getTime();
1362                     try {
1363                         ev.time = t;
1364                     } catch(ex) { 
1365                         this.lastError = ex;
1366                         return t;
1367                     }
1368                 }
1369
1370                 return ev.time;
1371             },
1372
1373             /**
1374              * Convenience method for stopPropagation + preventDefault
1375              * @method stopEvent
1376              * @param {Event} ev the event
1377              * @static
1378              */
1379             stopEvent: function(ev) {
1380                 this.stopPropagation(ev);
1381                 this.preventDefault(ev);
1382             },
1383
1384             /**
1385              * Stops event propagation
1386              * @method stopPropagation
1387              * @param {Event} ev the event
1388              * @static
1389              */
1390             stopPropagation: function(ev) {
1391                 if (ev.stopPropagation) {
1392                     ev.stopPropagation();
1393                 } else {
1394                     ev.cancelBubble = true;
1395                 }
1396             },
1397
1398             /**
1399              * Prevents the default behavior of the event
1400              * @method preventDefault
1401              * @param {Event} ev the event
1402              * @static
1403              */
1404             preventDefault: function(ev) {
1405                 if (ev.preventDefault) {
1406                     ev.preventDefault();
1407                 } else {
1408                     ev.returnValue = false;
1409                 }
1410             },
1411              
1412             /**
1413              * Finds the event in the window object, the caller's arguments, or
1414              * in the arguments of another method in the callstack.  This is
1415              * executed automatically for events registered through the event
1416              * manager, so the implementer should not normally need to execute
1417              * this function at all.
1418              * @method getEvent
1419              * @param {Event} e the event parameter from the handler
1420              * @param {HTMLElement} boundEl the element the listener is attached to
1421              * @return {Event} the event 
1422              * @static
1423              */
1424             getEvent: function(e, boundEl) {
1425                 var ev = e || window.event;
1426
1427                 if (!ev) {
1428                     var c = this.getEvent.caller;
1429                     while (c) {
1430                         ev = c.arguments[0];
1431                         if (ev && Event == ev.constructor) {
1432                             break;
1433                         }
1434                         c = c.caller;
1435                     }
1436                 }
1437
1438                 return ev;
1439             },
1440
1441             /**
1442              * Returns the charcode for an event
1443              * @method getCharCode
1444              * @param {Event} ev the event
1445              * @return {int} the event's charCode
1446              * @static
1447              */
1448             getCharCode: function(ev) {
1449                 var code = ev.keyCode || ev.charCode || 0;
1450
1451                 // webkit key normalization
1452                 if (YAHOO.env.ua.webkit && (code in webkitKeymap)) {
1453                     code = webkitKeymap[code];
1454                 }
1455                 return code;
1456             },
1457
1458             /**
1459              * Locating the saved event handler data by function ref
1460              *
1461              * @method _getCacheIndex
1462              * @static
1463              * @private
1464              */
1465             _getCacheIndex: function(a, el, sType, fn) {
1466                 for (var i=0, l=a.length; i<l; i=i+1) {
1467                     var li = a[i];
1468                     if ( li                 && 
1469                          li[this.FN] == fn  && 
1470                          li[this.EL] == el  && 
1471                          li[this.TYPE] == sType ) {
1472                         return i;
1473                     }
1474                 }
1475
1476                 return -1;
1477             },
1478
1479             /**
1480              * Generates an unique ID for the element if it does not already 
1481              * have one.
1482              * @method generateId
1483              * @param el the element to create the id for
1484              * @return {string} the resulting id of the element
1485              * @static
1486              */
1487             generateId: function(el) {
1488                 var id = el.id;
1489
1490                 if (!id) {
1491                     id = "yuievtautoid-" + counter;
1492                     ++counter;
1493                     el.id = id;
1494                 }
1495
1496                 return id;
1497             },
1498
1499
1500             /**
1501              * We want to be able to use getElementsByTagName as a collection
1502              * to attach a group of events to.  Unfortunately, different 
1503              * browsers return different types of collections.  This function
1504              * tests to determine if the object is array-like.  It will also 
1505              * fail if the object is an array, but is empty.
1506              * @method _isValidCollection
1507              * @param o the object to test
1508              * @return {boolean} true if the object is array-like and populated
1509              * @static
1510              * @private
1511              */
1512             _isValidCollection: function(o) {
1513                 try {
1514                     return ( o                     && // o is something
1515                              typeof o !== "string" && // o is not a string
1516                              o.length              && // o is indexed
1517                              !o.tagName            && // o is not an HTML element
1518                              !o.alert              && // o is not a window
1519                              typeof o[0] !== "undefined" );
1520                 } catch(ex) {
1521                     return false;
1522                 }
1523
1524             },
1525
1526             /**
1527              * @private
1528              * @property elCache
1529              * DOM element cache
1530              * @static
1531              * @deprecated Elements are not cached due to issues that arise when
1532              * elements are removed and re-added
1533              */
1534             elCache: {},
1535
1536             /**
1537              * We cache elements bound by id because when the unload event 
1538              * fires, we can no longer use document.getElementById
1539              * @method getEl
1540              * @static
1541              * @private
1542              * @deprecated Elements are not cached any longer
1543              */
1544             getEl: function(id) {
1545                 return (typeof id === "string") ? document.getElementById(id) : id;
1546             },
1547
1548             /**
1549              * Clears the element cache
1550              * @deprecated Elements are not cached any longer
1551              * @method clearCache
1552              * @static
1553              * @private
1554              */
1555             clearCache: function() { },
1556
1557             /**
1558              * Custom event the fires when the dom is initially usable
1559              * @event DOMReadyEvent
1560              */
1561             DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", YAHOO, 0, 0, 1),
1562
1563             /**
1564              * hook up any deferred listeners
1565              * @method _load
1566              * @static
1567              * @private
1568              */
1569             _load: function(e) {
1570
1571                 if (!loadComplete) {
1572                     loadComplete = true;
1573                     var EU = YAHOO.util.Event;
1574
1575                     // Just in case DOMReady did not go off for some reason
1576                     EU._ready();
1577
1578                     // Available elements may not have been detected before the
1579                     // window load event fires. Try to find them now so that the
1580                     // the user is more likely to get the onAvailable notifications
1581                     // before the window load notification
1582                     EU._tryPreloadAttach();
1583
1584                 }
1585             },
1586
1587             /**
1588              * Fires the DOMReady event listeners the first time the document is
1589              * usable.
1590              * @method _ready
1591              * @static
1592              * @private
1593              */
1594             _ready: function(e) {
1595                 var EU = YAHOO.util.Event;
1596                 if (!EU.DOMReady) {
1597                     EU.DOMReady=true;
1598
1599                     // Fire the content ready custom event
1600                     EU.DOMReadyEvent.fire();
1601
1602                     // Remove the DOMContentLoaded (FF/Opera)
1603                     EU._simpleRemove(document, "DOMContentLoaded", EU._ready);
1604                 }
1605             },
1606
1607             /**
1608              * Polling function that runs before the onload event fires, 
1609              * attempting to attach to DOM Nodes as soon as they are 
1610              * available
1611              * @method _tryPreloadAttach
1612              * @static
1613              * @private
1614              */
1615             _tryPreloadAttach: function() {
1616
1617                 if (onAvailStack.length === 0) {
1618                     retryCount = 0;
1619                     if (this._interval) {
1620                         // clearInterval(this._interval);
1621                         this._interval.cancel();
1622                         this._interval = null;
1623                     } 
1624                     return;
1625                 }
1626
1627                 if (this.locked) {
1628                     return;
1629                 }
1630
1631                 if (this.isIE) {
1632                     // Hold off if DOMReady has not fired and check current
1633                     // readyState to protect against the IE operation aborted
1634                     // issue.
1635                     if (!this.DOMReady) {
1636                         this.startInterval();
1637                         return;
1638                     }
1639                 }
1640
1641                 this.locked = true;
1642
1643
1644                 // keep trying until after the page is loaded.  We need to 
1645                 // check the page load state prior to trying to bind the 
1646                 // elements so that we can be certain all elements have been 
1647                 // tested appropriately
1648                 var tryAgain = !loadComplete;
1649                 if (!tryAgain) {
1650                     tryAgain = (retryCount > 0 && onAvailStack.length > 0);
1651                 }
1652
1653                 // onAvailable
1654                 var notAvail = [];
1655
1656                 var executeItem = function (el, item) {
1657                     var context = el;
1658                     if (item.overrideContext) {
1659                         if (item.overrideContext === true) {
1660                             context = item.obj;
1661                         } else {
1662                             context = item.overrideContext;
1663                         }
1664                     }
1665                     item.fn.call(context, item.obj);
1666                 };
1667
1668                 var i, len, item, el, ready=[];
1669
1670                 // onAvailable onContentReady
1671                 for (i=0, len=onAvailStack.length; i<len; i=i+1) {
1672                     item = onAvailStack[i];
1673                     if (item) {
1674                         el = this.getEl(item.id);
1675                         if (el) {
1676                             if (item.checkReady) {
1677                                 if (loadComplete || el.nextSibling || !tryAgain) {
1678                                     ready.push(item);
1679                                     onAvailStack[i] = null;
1680                                 }
1681                             } else {
1682                                 executeItem(el, item);
1683                                 onAvailStack[i] = null;
1684                             }
1685                         } else {
1686                             notAvail.push(item);
1687                         }
1688                     }
1689                 }
1690                 
1691                 // make sure onContentReady fires after onAvailable
1692                 for (i=0, len=ready.length; i<len; i=i+1) {
1693                     item = ready[i];
1694                     executeItem(this.getEl(item.id), item);
1695                 }
1696
1697
1698                 retryCount--;
1699
1700                 if (tryAgain) {
1701                     for (i=onAvailStack.length-1; i>-1; i--) {
1702                         item = onAvailStack[i];
1703                         if (!item || !item.id) {
1704                             onAvailStack.splice(i, 1);
1705                         }
1706                     }
1707
1708                     this.startInterval();
1709                 } else {
1710                     if (this._interval) {
1711                         // clearInterval(this._interval);
1712                         this._interval.cancel();
1713                         this._interval = null;
1714                     }
1715                 }
1716
1717                 this.locked = false;
1718
1719             },
1720
1721             /**
1722              * Removes all listeners attached to the given element via addListener.
1723              * Optionally, the node's children can also be purged.
1724              * Optionally, you can specify a specific type of event to remove.
1725              * @method purgeElement
1726              * @param {HTMLElement} el the element to purge
1727              * @param {boolean} recurse recursively purge this element's children
1728              * as well.  Use with caution.
1729              * @param {string} sType optional type of listener to purge. If
1730              * left out, all listeners will be removed
1731              * @static
1732              */
1733             purgeElement: function(el, recurse, sType) {
1734                 var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1735                 var elListeners = this.getListeners(oEl, sType), i, len;
1736                 if (elListeners) {
1737                     for (i=elListeners.length-1; i>-1; i--) {
1738                         var l = elListeners[i];
1739                         this.removeListener(oEl, l.type, l.fn);
1740                     }
1741                 }
1742
1743                 if (recurse && oEl && oEl.childNodes) {
1744                     for (i=0,len=oEl.childNodes.length; i<len ; ++i) {
1745                         this.purgeElement(oEl.childNodes[i], recurse, sType);
1746                     }
1747                 }
1748             },
1749
1750             /**
1751              * Returns all listeners attached to the given element via addListener.
1752              * Optionally, you can specify a specific type of event to return.
1753              * @method getListeners
1754              * @param el {HTMLElement|string} the element or element id to inspect 
1755              * @param sType {string} optional type of listener to return. If
1756              * left out, all listeners will be returned
1757              * @return {Object} the listener. Contains the following fields:
1758              * &nbsp;&nbsp;type:   (string)   the type of event
1759              * &nbsp;&nbsp;fn:     (function) the callback supplied to addListener
1760              * &nbsp;&nbsp;obj:    (object)   the custom object supplied to addListener
1761              * &nbsp;&nbsp;adjust: (boolean|object)  whether or not to adjust the default context
1762              * &nbsp;&nbsp;scope: (boolean)  the derived context based on the adjust parameter
1763              * &nbsp;&nbsp;index:  (int)      its position in the Event util listener cache
1764              * @static
1765              */           
1766             getListeners: function(el, sType) {
1767                 var results=[], searchLists;
1768                 if (!sType) {
1769                     searchLists = [listeners, unloadListeners];
1770                 } else if (sType === "unload") {
1771                     searchLists = [unloadListeners];
1772                 } else {
1773                                         sType = this._getType(sType);
1774                     searchLists = [listeners];
1775                 }
1776
1777                 var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el;
1778
1779                 for (var j=0;j<searchLists.length; j=j+1) {
1780                     var searchList = searchLists[j];
1781                     if (searchList) {
1782                         for (var i=0,len=searchList.length; i<len ; ++i) {
1783                             var l = searchList[i];
1784                             if ( l  && l[this.EL] === oEl && 
1785                                     (!sType || sType === l[this.TYPE]) ) {
1786                                 results.push({
1787                                     type:   l[this.TYPE],
1788                                     fn:     l[this.FN],
1789                                     obj:    l[this.OBJ],
1790                                     adjust: l[this.OVERRIDE],
1791                                     scope:  l[this.ADJ_SCOPE],
1792                                     index:  i
1793                                 });
1794                             }
1795                         }
1796                     }
1797                 }
1798
1799                 return (results.length) ? results : null;
1800             },
1801
1802             /**
1803              * Removes all listeners registered by pe.event.  Called 
1804              * automatically during the unload event.
1805              * @method _unload
1806              * @static
1807              * @private
1808              */
1809             _unload: function(e) {
1810
1811                 var EU = YAHOO.util.Event, i, j, l, len, index,
1812                          ul = unloadListeners.slice(), context;
1813
1814                 // execute and clear stored unload listeners
1815                 for (i=0, len=unloadListeners.length; i<len; ++i) {
1816                     l = ul[i];
1817                     if (l) {
1818                         context = window;
1819                         if (l[EU.ADJ_SCOPE]) {
1820                             if (l[EU.ADJ_SCOPE] === true) {
1821                                 context = l[EU.UNLOAD_OBJ];
1822                             } else {
1823                                 context = l[EU.ADJ_SCOPE];
1824                             }
1825                         }
1826                         l[EU.FN].call(context, EU.getEvent(e, l[EU.EL]), l[EU.UNLOAD_OBJ] );
1827                         ul[i] = null;
1828                     }
1829                 }
1830
1831                 l = null;
1832                 context = null;
1833                 unloadListeners = null;
1834
1835                 // Remove listeners to handle IE memory leaks
1836                 // 2.5.0 listeners are removed for all browsers again.  FireFox preserves
1837                 // at least some listeners between page refreshes, potentially causing
1838                 // errors during page load (mouseover listeners firing before they
1839                 // should if the user moves the mouse at the correct moment).
1840                 if (listeners) {
1841                     for (j=listeners.length-1; j>-1; j--) {
1842                         l = listeners[j];
1843                         if (l) {
1844                             EU.removeListener(l[EU.EL], l[EU.TYPE], l[EU.FN], j);
1845                         } 
1846                     }
1847                     l=null;
1848                 }
1849
1850                 EU._simpleRemove(window, "unload", EU._unload);
1851
1852             },
1853
1854             /**
1855              * Returns scrollLeft
1856              * @method _getScrollLeft
1857              * @static
1858              * @private
1859              */
1860             _getScrollLeft: function() {
1861                 return this._getScroll()[1];
1862             },
1863
1864             /**
1865              * Returns scrollTop
1866              * @method _getScrollTop
1867              * @static
1868              * @private
1869              */
1870             _getScrollTop: function() {
1871                 return this._getScroll()[0];
1872             },
1873
1874             /**
1875              * Returns the scrollTop and scrollLeft.  Used to calculate the 
1876              * pageX and pageY in Internet Explorer
1877              * @method _getScroll
1878              * @static
1879              * @private
1880              */
1881             _getScroll: function() {
1882                 var dd = document.documentElement, db = document.body;
1883                 if (dd && (dd.scrollTop || dd.scrollLeft)) {
1884                     return [dd.scrollTop, dd.scrollLeft];
1885                 } else if (db) {
1886                     return [db.scrollTop, db.scrollLeft];
1887                 } else {
1888                     return [0, 0];
1889                 }
1890             },
1891             
1892             /**
1893              * Used by old versions of CustomEvent, restored for backwards
1894              * compatibility
1895              * @method regCE
1896              * @private
1897              * @static
1898              * @deprecated still here for backwards compatibility
1899              */
1900             regCE: function() {},
1901
1902             /**
1903              * Adds a DOM event directly without the caching, cleanup, context adj, etc
1904              *
1905              * @method _simpleAdd
1906              * @param {HTMLElement} el      the element to bind the handler to
1907              * @param {string}      sType   the type of event handler
1908              * @param {function}    fn      the callback to invoke
1909              * @param {boolen}      capture capture or bubble phase
1910              * @static
1911              * @private
1912              */
1913             _simpleAdd: function () {
1914                 if (window.addEventListener) {
1915                     return function(el, sType, fn, capture) {
1916                         el.addEventListener(sType, fn, (capture));
1917                     };
1918                 } else if (window.attachEvent) {
1919                     return function(el, sType, fn, capture) {
1920                         el.attachEvent("on" + sType, fn);
1921                     };
1922                 } else {
1923                     return function(){};
1924                 }
1925             }(),
1926
1927             /**
1928              * Basic remove listener
1929              *
1930              * @method _simpleRemove
1931              * @param {HTMLElement} el      the element to bind the handler to
1932              * @param {string}      sType   the type of event handler
1933              * @param {function}    fn      the callback to invoke
1934              * @param {boolen}      capture capture or bubble phase
1935              * @static
1936              * @private
1937              */
1938             _simpleRemove: function() {
1939                 if (window.removeEventListener) {
1940                     return function (el, sType, fn, capture) {
1941                         el.removeEventListener(sType, fn, (capture));
1942                     };
1943                 } else if (window.detachEvent) {
1944                     return function (el, sType, fn) {
1945                         el.detachEvent("on" + sType, fn);
1946                     };
1947                 } else {
1948                     return function(){};
1949                 }
1950             }()
1951         };
1952
1953     }();
1954
1955     (function() {
1956         var EU = YAHOO.util.Event;
1957
1958         /**
1959          * YAHOO.util.Event.on is an alias for addListener
1960          * @method on
1961          * @see addListener
1962          * @static
1963          */
1964         EU.on = EU.addListener;
1965
1966         /**
1967          * YAHOO.util.Event.onFocus is an alias for addFocusListener
1968          * @method onFocus
1969          * @see addFocusListener
1970          * @static
1971                  * @deprecated use YAHOO.util.Event.on and specify "focusin" as the event type.
1972          */
1973         EU.onFocus = EU.addFocusListener;
1974
1975         /**
1976          * YAHOO.util.Event.onBlur is an alias for addBlurListener
1977          * @method onBlur
1978          * @see addBlurListener
1979          * @static
1980                  * @deprecated use YAHOO.util.Event.on and specify "focusout" as the event type.
1981          */     
1982         EU.onBlur = EU.addBlurListener;
1983
1984 /*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
1985
1986         // Internet Explorer: use the readyState of a defered script.
1987         // This isolates what appears to be a safe moment to manipulate
1988         // the DOM prior to when the document's readyState suggests
1989         // it is safe to do so.
1990         if (EU.isIE) {
1991             if (self !== self.top) {
1992                 document.onreadystatechange = function() {
1993                     if (document.readyState == 'complete') {
1994                         document.onreadystatechange = null;
1995                         EU._ready();
1996                     }
1997                 };
1998             } else {
1999
2000                 // Process onAvailable/onContentReady items when the 
2001                 // DOM is ready.
2002                 YAHOO.util.Event.onDOMReady(
2003                         YAHOO.util.Event._tryPreloadAttach,
2004                         YAHOO.util.Event, true);
2005                 
2006                 var n = document.createElement('p');  
2007
2008                 EU._dri = setInterval(function() {
2009                     try {
2010                         // throws an error if doc is not ready
2011                         n.doScroll('left');
2012                         clearInterval(EU._dri);
2013                         EU._dri = null;
2014                         EU._ready();
2015                         n = null;
2016                     } catch (ex) { 
2017                     }
2018                 }, EU.POLL_INTERVAL); 
2019             }
2020
2021         // The document's readyState in Safari currently will
2022         // change to loaded/complete before images are loaded.
2023         } else if (EU.webkit && EU.webkit < 525) {
2024
2025             EU._dri = setInterval(function() {
2026                 var rs=document.readyState;
2027                 if ("loaded" == rs || "complete" == rs) {
2028                     clearInterval(EU._dri);
2029                     EU._dri = null;
2030                     EU._ready();
2031                 }
2032             }, EU.POLL_INTERVAL); 
2033
2034         // FireFox and Opera: These browsers provide a event for this
2035         // moment.  The latest WebKit releases now support this event.
2036         } else {
2037
2038             EU._simpleAdd(document, "DOMContentLoaded", EU._ready);
2039
2040         }
2041         /////////////////////////////////////////////////////////////
2042
2043
2044         EU._simpleAdd(window, "load", EU._load);
2045         EU._simpleAdd(window, "unload", EU._unload);
2046         EU._tryPreloadAttach();
2047     })();
2048
2049 }
2050 /**
2051  * EventProvider is designed to be used with YAHOO.augment to wrap 
2052  * CustomEvents in an interface that allows events to be subscribed to 
2053  * and fired by name.  This makes it possible for implementing code to
2054  * subscribe to an event that either has not been created yet, or will
2055  * not be created at all.
2056  *
2057  * @Class EventProvider
2058  */
2059 YAHOO.util.EventProvider = function() { };
2060
2061 YAHOO.util.EventProvider.prototype = {
2062
2063     /**
2064      * Private storage of custom events
2065      * @property __yui_events
2066      * @type Object[]
2067      * @private
2068      */
2069     __yui_events: null,
2070
2071     /**
2072      * Private storage of custom event subscribers
2073      * @property __yui_subscribers
2074      * @type Object[]
2075      * @private
2076      */
2077     __yui_subscribers: null,
2078     
2079     /**
2080      * Subscribe to a CustomEvent by event type
2081      *
2082      * @method subscribe
2083      * @param p_type     {string}   the type, or name of the event
2084      * @param p_fn       {function} the function to exectute when the event fires
2085      * @param p_obj      {Object}   An object to be passed along when the event 
2086      *                              fires
2087      * @param overrideContext {boolean}  If true, the obj passed in becomes the 
2088      *                              execution scope of the listener
2089      */
2090     subscribe: function(p_type, p_fn, p_obj, overrideContext) {
2091
2092         this.__yui_events = this.__yui_events || {};
2093         var ce = this.__yui_events[p_type];
2094
2095         if (ce) {
2096             ce.subscribe(p_fn, p_obj, overrideContext);
2097         } else {
2098             this.__yui_subscribers = this.__yui_subscribers || {};
2099             var subs = this.__yui_subscribers;
2100             if (!subs[p_type]) {
2101                 subs[p_type] = [];
2102             }
2103             subs[p_type].push(
2104                 { fn: p_fn, obj: p_obj, overrideContext: overrideContext } );
2105         }
2106     },
2107
2108     /**
2109      * Unsubscribes one or more listeners the from the specified event
2110      * @method unsubscribe
2111      * @param p_type {string}   The type, or name of the event.  If the type
2112      *                          is not specified, it will attempt to remove
2113      *                          the listener from all hosted events.
2114      * @param p_fn   {Function} The subscribed function to unsubscribe, if not
2115      *                          supplied, all subscribers will be removed.
2116      * @param p_obj  {Object}   The custom object passed to subscribe.  This is
2117      *                        optional, but if supplied will be used to
2118      *                        disambiguate multiple listeners that are the same
2119      *                        (e.g., you subscribe many object using a function
2120      *                        that lives on the prototype)
2121      * @return {boolean} true if the subscriber was found and detached.
2122      */
2123     unsubscribe: function(p_type, p_fn, p_obj) {
2124         this.__yui_events = this.__yui_events || {};
2125         var evts = this.__yui_events;
2126         if (p_type) {
2127             var ce = evts[p_type];
2128             if (ce) {
2129                 return ce.unsubscribe(p_fn, p_obj);
2130             }
2131         } else {
2132             var ret = true;
2133             for (var i in evts) {
2134                 if (YAHOO.lang.hasOwnProperty(evts, i)) {
2135                     ret = ret && evts[i].unsubscribe(p_fn, p_obj);
2136                 }
2137             }
2138             return ret;
2139         }
2140
2141         return false;
2142     },
2143     
2144     /**
2145      * Removes all listeners from the specified event.  If the event type
2146      * is not specified, all listeners from all hosted custom events will
2147      * be removed.
2148      * @method unsubscribeAll
2149      * @param p_type {string}   The type, or name of the event
2150      */
2151     unsubscribeAll: function(p_type) {
2152         return this.unsubscribe(p_type);
2153     },
2154
2155     /**
2156      * Creates a new custom event of the specified type.  If a custom event
2157      * by that name already exists, it will not be re-created.  In either
2158      * case the custom event is returned. 
2159      *
2160      * @method createEvent
2161      *
2162      * @param p_type {string} the type, or name of the event
2163      * @param p_config {object} optional config params.  Valid properties are:
2164      *
2165      *  <ul>
2166      *    <li>
2167      *      scope: defines the default execution scope.  If not defined
2168      *      the default scope will be this instance.
2169      *    </li>
2170      *    <li>
2171      *      silent: if true, the custom event will not generate log messages.
2172      *      This is false by default.
2173      *    </li>
2174      *    <li>
2175      *      fireOnce: if true, the custom event will only notify subscribers
2176      *      once regardless of the number of times the event is fired.  In
2177      *      addition, new subscribers will be executed immediately if the
2178      *      event has already fired.
2179      *      This is false by default.
2180      *    </li>
2181      *    <li>
2182      *      onSubscribeCallback: specifies a callback to execute when the
2183      *      event has a new subscriber.  This will fire immediately for
2184      *      each queued subscriber if any exist prior to the creation of
2185      *      the event.
2186      *    </li>
2187      *  </ul>
2188      *
2189      *  @return {CustomEvent} the custom event
2190      *
2191      */
2192     createEvent: function(p_type, p_config) {
2193
2194         this.__yui_events = this.__yui_events || {};
2195         var opts = p_config || {},
2196             events = this.__yui_events, ce;
2197
2198         if (events[p_type]) {
2199         } else {
2200
2201             ce = new YAHOO.util.CustomEvent(p_type, opts.scope || this, opts.silent,
2202                          YAHOO.util.CustomEvent.FLAT, opts.fireOnce);
2203
2204             events[p_type] = ce;
2205
2206             if (opts.onSubscribeCallback) {
2207                 ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
2208             }
2209
2210             this.__yui_subscribers = this.__yui_subscribers || {};
2211             var qs = this.__yui_subscribers[p_type];
2212
2213             if (qs) {
2214                 for (var i=0; i<qs.length; ++i) {
2215                     ce.subscribe(qs[i].fn, qs[i].obj, qs[i].overrideContext);
2216                 }
2217             }
2218         }
2219
2220         return events[p_type];
2221     },
2222
2223
2224    /**
2225      * Fire a custom event by name.  The callback functions will be executed
2226      * from the scope specified when the event was created, and with the 
2227      * following parameters:
2228      *   <ul>
2229      *   <li>The first argument fire() was executed with</li>
2230      *   <li>The custom object (if any) that was passed into the subscribe() 
2231      *       method</li>
2232      *   </ul>
2233      * @method fireEvent
2234      * @param p_type    {string}  the type, or name of the event
2235      * @param arguments {Object*} an arbitrary set of parameters to pass to 
2236      *                            the handler.
2237      * @return {boolean} the return value from CustomEvent.fire
2238      *                   
2239      */
2240     fireEvent: function(p_type) {
2241
2242         this.__yui_events = this.__yui_events || {};
2243         var ce = this.__yui_events[p_type];
2244
2245         if (!ce) {
2246             return null;
2247         }
2248
2249         var args = [];
2250         for (var i=1; i<arguments.length; ++i) {
2251             args.push(arguments[i]);
2252         }
2253         return ce.fire.apply(ce, args);
2254     },
2255
2256     /**
2257      * Returns true if the custom event of the provided type has been created
2258      * with createEvent.
2259      * @method hasEvent
2260      * @param type {string} the type, or name of the event
2261      */
2262     hasEvent: function(type) {
2263         if (this.__yui_events) {
2264             if (this.__yui_events[type]) {
2265                 return true;
2266             }
2267         }
2268         return false;
2269     }
2270
2271 };
2272
2273 (function() {
2274
2275     var Event = YAHOO.util.Event, Lang = YAHOO.lang;
2276
2277 /**
2278 * KeyListener is a utility that provides an easy interface for listening for
2279 * keydown/keyup events fired against DOM elements.
2280 * @namespace YAHOO.util
2281 * @class KeyListener
2282 * @constructor
2283 * @param {HTMLElement} attachTo The element or element ID to which the key 
2284 *                               event should be attached
2285 * @param {String}      attachTo The element or element ID to which the key
2286 *                               event should be attached
2287 * @param {Object}      keyData  The object literal representing the key(s) 
2288 *                               to detect. Possible attributes are 
2289 *                               shift(boolean), alt(boolean), ctrl(boolean) 
2290 *                               and keys(either an int or an array of ints 
2291 *                               representing keycodes).
2292 * @param {Function}    handler  The CustomEvent handler to fire when the 
2293 *                               key event is detected
2294 * @param {Object}      handler  An object literal representing the handler. 
2295 * @param {String}      event    Optional. The event (keydown or keyup) to 
2296 *                               listen for. Defaults automatically to keydown.
2297 *
2298 * @knownissue the "keypress" event is completely broken in Safari 2.x and below.
2299 *             the workaround is use "keydown" for key listening.  However, if
2300 *             it is desired to prevent the default behavior of the keystroke,
2301 *             that can only be done on the keypress event.  This makes key
2302 *             handling quite ugly.
2303 * @knownissue keydown is also broken in Safari 2.x and below for the ESC key.
2304 *             There currently is no workaround other than choosing another
2305 *             key to listen for.
2306 */
2307 YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {
2308     if (!attachTo) {
2309     } else if (!keyData) {
2310     } else if (!handler) {
2311     } 
2312     
2313     if (!event) {
2314         event = YAHOO.util.KeyListener.KEYDOWN;
2315     }
2316
2317     /**
2318     * The CustomEvent fired internally when a key is pressed
2319     * @event keyEvent
2320     * @private
2321     * @param {Object} keyData The object literal representing the key(s) to 
2322     *                         detect. Possible attributes are shift(boolean), 
2323     *                         alt(boolean), ctrl(boolean) and keys(either an 
2324     *                         int or an array of ints representing keycodes).
2325     */
2326     var keyEvent = new YAHOO.util.CustomEvent("keyPressed");
2327     
2328     /**
2329     * The CustomEvent fired when the KeyListener is enabled via the enable() 
2330     * function
2331     * @event enabledEvent
2332     * @param {Object} keyData The object literal representing the key(s) to 
2333     *                         detect. Possible attributes are shift(boolean), 
2334     *                         alt(boolean), ctrl(boolean) and keys(either an 
2335     *                         int or an array of ints representing keycodes).
2336     */
2337     this.enabledEvent = new YAHOO.util.CustomEvent("enabled");
2338
2339     /**
2340     * The CustomEvent fired when the KeyListener is disabled via the 
2341     * disable() function
2342     * @event disabledEvent
2343     * @param {Object} keyData The object literal representing the key(s) to 
2344     *                         detect. Possible attributes are shift(boolean), 
2345     *                         alt(boolean), ctrl(boolean) and keys(either an 
2346     *                         int or an array of ints representing keycodes).
2347     */
2348     this.disabledEvent = new YAHOO.util.CustomEvent("disabled");
2349
2350     if (Lang.isString(attachTo)) {
2351         attachTo = document.getElementById(attachTo); // No Dom util
2352     }
2353
2354     if (Lang.isFunction(handler)) {
2355         keyEvent.subscribe(handler);
2356     } else {
2357         keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);
2358     }
2359
2360     /**
2361     * Handles the key event when a key is pressed.
2362     * @method handleKeyPress
2363     * @param {DOMEvent} e   The keypress DOM event
2364     * @param {Object}   obj The DOM event scope object
2365     * @private
2366     */
2367     function handleKeyPress(e, obj) {
2368         if (! keyData.shift) {  
2369             keyData.shift = false; 
2370         }
2371         if (! keyData.alt) {    
2372             keyData.alt = false;
2373         }
2374         if (! keyData.ctrl) {
2375             keyData.ctrl = false;
2376         }
2377
2378         // check held down modifying keys first
2379         if (e.shiftKey == keyData.shift && 
2380             e.altKey   == keyData.alt &&
2381             e.ctrlKey  == keyData.ctrl) { // if we pass this, all modifiers match
2382             
2383             var dataItem, keys = keyData.keys, key;
2384
2385             if (YAHOO.lang.isArray(keys)) {
2386                 for (var i=0;i<keys.length;i++) {
2387                     dataItem = keys[i];
2388                     key = Event.getCharCode(e);
2389
2390                     if (dataItem == key) {
2391                         keyEvent.fire(key, e);
2392                         break;
2393                     }
2394                 }
2395             } else {
2396                 key = Event.getCharCode(e);
2397                 if (keys == key ) {
2398                     keyEvent.fire(key, e);
2399                 }
2400             }
2401         }
2402     }
2403
2404     /**
2405     * Enables the KeyListener by attaching the DOM event listeners to the 
2406     * target DOM element
2407     * @method enable
2408     */
2409     this.enable = function() {
2410         if (! this.enabled) {
2411             Event.on(attachTo, event, handleKeyPress);
2412             this.enabledEvent.fire(keyData);
2413         }
2414         /**
2415         * Boolean indicating the enabled/disabled state of the Tooltip
2416         * @property enabled
2417         * @type Boolean
2418         */
2419         this.enabled = true;
2420     };
2421
2422     /**
2423     * Disables the KeyListener by removing the DOM event listeners from the 
2424     * target DOM element
2425     * @method disable
2426     */
2427     this.disable = function() {
2428         if (this.enabled) {
2429             Event.removeListener(attachTo, event, handleKeyPress);
2430             this.disabledEvent.fire(keyData);
2431         }
2432         this.enabled = false;
2433     };
2434
2435     /**
2436     * Returns a String representation of the object.
2437     * @method toString
2438     * @return {String}  The string representation of the KeyListener
2439     */ 
2440     this.toString = function() {
2441         return "KeyListener [" + keyData.keys + "] " + attachTo.tagName + 
2442                 (attachTo.id ? "[" + attachTo.id + "]" : "");
2443     };
2444
2445 };
2446
2447 var KeyListener = YAHOO.util.KeyListener;
2448
2449 /**
2450  * Constant representing the DOM "keydown" event.
2451  * @property YAHOO.util.KeyListener.KEYDOWN
2452  * @static
2453  * @final
2454  * @type String
2455  */
2456 KeyListener.KEYDOWN = "keydown";
2457
2458 /**
2459  * Constant representing the DOM "keyup" event.
2460  * @property YAHOO.util.KeyListener.KEYUP
2461  * @static
2462  * @final
2463  * @type String
2464  */
2465 KeyListener.KEYUP = "keyup";
2466
2467 /**
2468  * keycode constants for a subset of the special keys
2469  * @property KEY
2470  * @static
2471  * @final
2472  */
2473 KeyListener.KEY = {
2474     ALT          : 18,
2475     BACK_SPACE   : 8,
2476     CAPS_LOCK    : 20,
2477     CONTROL      : 17,
2478     DELETE       : 46,
2479     DOWN         : 40,
2480     END          : 35,
2481     ENTER        : 13,
2482     ESCAPE       : 27,
2483     HOME         : 36,
2484     LEFT         : 37,
2485     META         : 224,
2486     NUM_LOCK     : 144,
2487     PAGE_DOWN    : 34,
2488     PAGE_UP      : 33, 
2489     PAUSE        : 19,
2490     PRINTSCREEN  : 44,
2491     RIGHT        : 39,
2492     SCROLL_LOCK  : 145,
2493     SHIFT        : 16,
2494     SPACE        : 32,
2495     TAB          : 9,
2496     UP           : 38
2497 };
2498
2499 })();
2500 YAHOO.register("event", YAHOO.util.Event, {version: "2.8.0r4", build: "2449"});