/*Copyright (c) 2007, Yahoo! Inc. All rights reserved.Code licensed under the BSD License:http://developer.yahoo.net/yui/license.txtversion: 2.2.2*//** * The CustomEvent class lets you define events for your application * that can be subscribed to by one or more independent component. * * @param {String}  type The type of event, which is passed to the callback *                  when the event fires * @param {Object}  oScope The context the event will fire from.  "this" will *                  refer to this object in the callback.  Default value:  *                  the window object.  The listener can override this. * @param {boolean} silent pass true to prevent the event from writing to *                  the debugsystem * @param {int}     signature the signature that the custom event subscriber *                  will receive. YAHOO.util.CustomEvent.LIST or  *                  YAHOO.util.CustomEvent.FLAT.  The default is *                  YAHOO.util.CustomEvent.LIST. * @namespace YAHOO.util * @class CustomEvent * @constructor */YAHOO.util.CustomEvent = function(type, oScope, silent, signature) {    /**     * The type of event, returned to subscribers when the event fires     * @property type     * @type string     */    this.type = type;    /**     * The scope the the event will fire from by default.  Defaults to the window      * obj     * @property scope     * @type object     */    this.scope = oScope || window;    /**     * By default all custom events are logged in the debug build, set silent     * to true to disable debug outpu for this event.     * @property silent     * @type boolean     */    this.silent = silent;    /**     * Custom events support two styles of arguments provided to the event     * subscribers.       * <ul>     * <li>YAHOO.util.CustomEvent.LIST:      *   <ul>     *   <li>param1: event name</li>     *   <li>param2: array of arguments sent to fire</li>     *   <li>param3: <optional> a custom object supplied by the subscriber</li>     *   </ul>     * </li>     * <li>YAHOO.util.CustomEvent.FLAT     *   <ul>     *   <li>param1: the first argument passed to fire.  If you need to     *           pass multiple parameters, use and array or object literal</li>     *   <li>param2: <optional> a custom object supplied by the subscriber</li>     *   </ul>     * </li>     * </ul>     *   @property signature     *   @type int     */    this.signature = signature || YAHOO.util.CustomEvent.LIST;    /**     * The subscribers to this event     * @property subscribers     * @type Subscriber[]     */    this.subscribers = [];    if (!this.silent) {    }    var onsubscribeType = "_YUICEOnSubscribe";    // Only add subscribe events for events that are not generated by     // CustomEvent    if (type !== onsubscribeType) {        /**         * Custom events provide a custom event that fires whenever there is         * a new subscriber to the event.  This provides an opportunity to         * handle the case where there is a non-repeating event that has         * already fired has a new subscriber.           *         * @event subscribeEvent         * @type YAHOO.util.CustomEvent         * @param {Function} fn The function to execute         * @param {Object}   obj An object to be passed along when the event          *                       fires         * @param {boolean|Object}  override If true, the obj passed in becomes          *                                   the execution scope of the listener.         *                                   if an object, that object becomes the         *                                   the execution scope.         */        this.subscribeEvent =                 new YAHOO.util.CustomEvent(onsubscribeType, this, true);    } };/** * Subscriber listener sigature constant.  The LIST type returns three * parameters: the event type, the array of args passed to fire, and * the optional custom object * @property YAHOO.util.CustomEvent.LIST * @static * @type int */YAHOO.util.CustomEvent.LIST = 0;/** * Subscriber listener sigature constant.  The FLAT type returns two * parameters: the first argument passed to fire and the optional  * custom object * @property YAHOO.util.CustomEvent.FLAT * @static * @type int */YAHOO.util.CustomEvent.FLAT = 1;YAHOO.util.CustomEvent.prototype = {    /**     * Subscribes the caller to this event     * @method subscribe     * @param {Function} fn        The function to execute     * @param {Object}   obj       An object to be passed along when the event      *                             fires     * @param {boolean|Object}  override If true, the obj passed in becomes      *                                   the execution scope of the listener.     *                                   if an object, that object becomes the     *                                   the execution scope.     */    subscribe: function(fn, obj, override) {        if (!fn) {throw new Error("Invalid callback for subscriber to '" + this.type + "'");        }        if (this.subscribeEvent) {            this.subscribeEvent.fire(fn, obj, override);        }        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );    },    /**     * Unsubscribes subscribers.     * @method unsubscribe     * @param {Function} fn  The subscribed function to remove, if not supplied     *                       all will be removed     * @param {Object}   obj  The custom object passed to subscribe.  This is     *                        optional, but if supplied will be used to     *                        disambiguate multiple listeners that are the same     *                        (e.g., you subscribe many object using a function     *                        that lives on the prototype)     * @return {boolean} True if the subscriber was found and detached.     */    unsubscribe: function(fn, obj) {        if (!fn) {            return this.unsubscribeAll();        }        var found = false;        for (var i=0, len=this.subscribers.length; i<len; ++i) {            var s = this.subscribers[i];            if (s && s.contains(fn, obj)) {                this._delete(i);                found = true;            }        }        return found;    },    /**     * Notifies the subscribers.  The callback functions will be executed     * from the scope specified when the event was created, and with the      * following parameters:     *   <ul>     *   <li>The type of event</li>     *   <li>All of the arguments fire() was executed with as an array</li>     *   <li>The custom object (if any) that was passed into the subscribe()      *       method</li>     *   </ul>     * @method fire      * @param {Object*} arguments an arbitrary set of parameters to pass to      *                            the handler.     * @return {boolean} false if one of the subscribers returned false,      *                   true otherwise     */    fire: function() {        var len=this.subscribers.length;        if (!len && this.silent) {            return true;        }        var args=[], ret=true, i;        for (i=0; i<arguments.length; ++i) {            args.push(arguments[i]);        }        var argslength = args.length;        if (!this.silent) {        }        for (i=0; i<len; ++i) {            var s = this.subscribers[i];            if (s) {                if (!this.silent) {                }                var scope = s.getScope(this.scope);                if (this.signature == YAHOO.util.CustomEvent.FLAT) {                    var param = null;                    if (args.length > 0) {                        param = args[0];                    }                    ret = s.fn.call(scope, param, s.obj);                } else {                    ret = s.fn.call(scope, this.type, args, s.obj);                }                if (false === ret) {                    if (!this.silent) {                    }                    //break;                    return false;                }            }        }        return true;    },    /**     * Removes all listeners     * @method unsubscribeAll     * @return {int} The number of listeners unsubscribed     */    unsubscribeAll: function() {        for (var i=0, len=this.subscribers.length; i<len; ++i) {            this._delete(len - 1 - i);        }        return i;    },    /**     * @method _delete     * @private     */    _delete: function(index) {        var s = this.subscribers[index];        if (s) {            delete s.fn;            delete s.obj;        }        // delete this.subscribers[index];        this.subscribers.splice(index, 1);    },    /**     * @method toString     */    toString: function() {         return "CustomEvent: " + "'" + this.type  + "', " +              "scope: " + this.scope;    }};//////////////////////////////////////////////////////////////////////** * Stores the subscriber information to be used when the event fires. * @param {Function} fn       The function to execute * @param {Object}   obj      An object to be passed along when the event fires * @param {boolean}  override If true, the obj passed in becomes the execution *                            scope of the listener * @class Subscriber * @constructor */YAHOO.util.Subscriber = function(fn, obj, override) {    /**     * The callback that will be execute when the event fires     * @property fn     * @type function     */    this.fn = fn;    /**     * An optional custom object that will passed to the callback when     * the event fires     * @property obj     * @type object     */    this.obj = obj || null;    /**     * The default execution scope for the event listener is defined when the     * event is created (usually the object which contains the event).     * By setting override to true, the execution scope becomes the custom     * object passed in by the subscriber.  If override is an object, that      * object becomes the scope.     * @property override     * @type boolean|object     */    this.override = override;};/** * Returns the execution scope for this listener.  If override was set to true * the custom obj will be the scope.  If override is an object, that is the * scope, otherwise the default scope will be used. * @method getScope * @param {Object} defaultScope the scope to use if this listener does not *                              override it. */YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {    if (this.override) {        if (this.override === true) {            return this.obj;        } else {            return this.override;        }    }    return defaultScope;};/** * Returns true if the fn and obj match this objects properties. * Used by the unsubscribe method to match the right subscriber. * * @method contains * @param {Function} fn the function to execute * @param {Object} obj an object to be passed along when the event fires * @return {boolean} true if the supplied arguments match this  *                   subscriber's signature. */YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {    if (obj) {        return (this.fn == fn && this.obj == obj);    } else {        return (this.fn == fn);    }};/** * @method toString */YAHOO.util.Subscriber.prototype.toString = function() {    return "Subscriber { obj: " + (this.obj || "")  +            ", override: " +  (this.override || "no") + " }";};/** * The Event Utility provides utilities for managing DOM Events and tools * for building event systems * * @module event * @title Event Utility * @namespace YAHOO.util * @requires yahoo */// The first instance of Event will win if it is loaded more than once.// @TODO this needs to be changed so that only the state data that needs to// be preserved is kept, while methods are overwritten/added as needed.// This means that the module pattern can't be used.if (!YAHOO.util.Event) {/** * The event utility provides functions to add and remove event listeners, * event cleansing.  It also tries to automatically remove listeners it * registers during the unload event. * * @class Event * @static */    YAHOO.util.Event = function() {        /**         * True after the onload event has fired         * @property loadComplete         * @type boolean         * @static         * @private         */        var loadComplete =  false;        /**         * True when the document is initially usable         * @property DOMReady         * @type boolean         * @static         * @private         */        var DOMReady = false;        /**         * Cache of wrapped listeners         * @property listeners         * @type array         * @static         * @private         */        var listeners = [];        /**         * User-defined unload function that will be fired before all events         * are detached         * @property unloadListeners         * @type array         * @static         * @private         */        var unloadListeners = [];        /**         * Cache of DOM0 event handlers to work around issues with DOM2 events         * in Safari         * @property legacyEvents         * @static         * @private         */        var legacyEvents = [];        /**         * Listener stack for DOM0 events         * @property legacyHandlers         * @static         * @private         */        var legacyHandlers = [];        /**         * The number of times to poll after window.onload.  This number is         * increased if additional late-bound handlers are requested after         * the page load.         * @property retryCount         * @static         * @private         */        var retryCount = 0;        /**         * onAvailable listeners         * @property onAvailStack         * @static         * @private         */        var onAvailStack = [];        /**         * Lookup table for legacy events         * @property legacyMap         * @static         * @private         */        var legacyMap = [];        /**         * Counter for auto id generation         * @property counter         * @static         * @private         */        var counter = 0;                /**         * addListener/removeListener can throw errors in unexpected scenarios.         * These errors are suppressed, the method returns false, and this property         * is set         * @property lastError         * @type Error         */        var lastError = null;        return {            /**             * The number of times we should look for elements that are not             * in the DOM at the time the event is requested after the document             * has been loaded.  The default is 200@amp;50 ms, so it will poll             * for 10 seconds or until all outstanding handlers are bound             * (whichever comes first).             * @property POLL_RETRYS             * @type int             * @static             * @final             */            POLL_RETRYS: 200,            /**             * The poll interval in milliseconds             * @property POLL_INTERVAL             * @type int             * @static             * @final             */            POLL_INTERVAL: 10,            /**             * Element to bind, int constant             * @property EL             * @type int             * @static             * @final             */            EL: 0,            /**             * Type of event, int constant             * @property TYPE             * @type int             * @static             * @final             */            TYPE: 1,            /**             * Function to execute, int constant             * @property FN             * @type int             * @static             * @final             */            FN: 2,            /**             * Function wrapped for scope correction and cleanup, int constant             * @property WFN             * @type int             * @static             * @final             */            WFN: 3,            /**             * Object passed in by the user that will be returned as a              * parameter to the callback, int constant             * @property OBJ             * @type int             * @static             * @final             */            OBJ: 3,            /**             * Adjusted scope, either the element we are registering the event             * on or the custom object passed in by the listener, int constant             * @property ADJ_SCOPE             * @type int             * @static             * @final             */            ADJ_SCOPE: 4,            /**             * Safari detection is necessary to work around the preventDefault             * bug that makes it so you can't cancel a href click from the              * handler.  Since this function has been used outside of this             * utility, it was changed to detect all KHTML browser to be more             * friendly towards the non-Safari browsers that share the engine.             * Internally, the preventDefault bug detection now uses the             * webkit property.             * @property isSafari             * @private             * @static             * @deprecated             */            isSafari: (/KHTML/gi).test(navigator.userAgent),                        /**             * If WebKit is detected, we keep track of the version number of             * the engine.  The webkit property will contain a string with             * the webkit version number if webkit is detected, null             * otherwise.             * Safari 1.3.2 (312.6): 312.8.1 <-- currently the latest             *                       available on Mac OSX 10.3.             * Safari 2.0.2: 416 <-- hasOwnProperty introduced             * Safari 2.0.4: 418 <-- preventDefault fixed (I believe)             * Safari 2.0.4 (419.3): 418.9.1 <-- current release             *             * http://developer.apple.com/internet/safari/uamatrix.html             * @property webkit             * @type string             * @static             */            webkit: function() {                var v=navigator.userAgent.match(/AppleWebKit\/([^ ]*)/);                if (v&&v[1]) {                    return v[1];                }                return null;            }(),                        /**             * IE detection needed to properly calculate pageX and pageY.               * capabilities checking didn't seem to work because another              * browser that does not provide the properties have the values              * calculated in a different manner than IE.             * @property isIE             * @private             * @static             */            isIE: (!this.webkit && !navigator.userAgent.match(/opera/gi) &&                     navigator.userAgent.match(/msie/gi)),            /**             * poll handle             * @property _interval             * @private             */            _interval: null,            /**             * @method startInterval             * @static             * @private             */            startInterval: function() {                if (!this._interval) {                    var self = this;                    var callback = function() { self._tryPreloadAttach(); };                    this._interval = setInterval(callback, this.POLL_INTERVAL);                }            },
            /**             * Executes the supplied callback when the item with the supplied             * id is found.  This is meant to be used to execute behavior as             * soon as possible as the page loads.  If you use this after the             * initial page load it will poll for a fixed time for the element.             * The number of times it will poll and the frequency are             * configurable.  By default it will poll for 10 seconds.             *             * @method onAvailable             *             * @param {string}   p_id the id of the element to look for.             * @param {function} p_fn what to execute when the element is found.             * @param {object}   p_obj an optional object to be passed back as             *                   a parameter to p_fn.             * @param {boolean}  p_override If set to true, p_fn will execute             *                   in the scope of p_obj             *             * @static             */            onAvailable: function(p_id, p_fn, p_obj, p_override) {                onAvailStack.push( { id:         p_id,                                      fn:         p_fn,                                      obj:        p_obj,                                      override:   p_override,                                      checkReady: false    } );                retryCount = this.POLL_RETRYS;                this.startInterval();            },            /**             * Executes the supplied callback when the DOM is first usable.             *             * @method onDOMReady             *             * @param {function} p_fn what to execute when the element is found.             * @param {object}   p_obj an optional object to be passed back as             *                   a parameter to p_fn.             * @param {boolean}  p_scope If set to true, p_fn will execute             *                   in the scope of p_obj, if set to an object it             *                   will execute in the scope of that object             *             * @static             */            onDOMReady: function(p_fn, p_obj, p_override) {                this.DOMReadyEvent.subscribe(p_fn, p_obj, p_override);            },            /**             * Works the same way as onAvailable, but additionally checks the             * state of sibling elements to determine if the content of the             * available element is safe to modify.             *             * @method onContentReady             *             * @param {string}   p_id the id of the element to look for.             * @param {function} p_fn what to execute when the element is ready.             * @param {object}   p_obj an optional object to be passed back as             *                   a parameter to p_fn.             * @param {boolean}  p_override If set to true, p_fn will execute             *                   in the scope of p_obj             *             * @static             */            onContentReady: function(p_id, p_fn, p_obj, p_override) {                onAvailStack.push( { id:         p_id,                                      fn:         p_fn,                                      obj:        p_obj,                                      override:   p_override,                                     checkReady: true      } );                retryCount = this.POLL_RETRYS;                this.startInterval();            },            /**             * Appends an event handler             *             * @method addListener             *             * @param {Object}   el        The html element to assign the              *                             event to             * @param {String}   sType     The type of event to append             * @param {Function} fn        The method the event invokes             * @param {Object}   obj    An arbitrary object that will be              *                             passed as a parameter to the handler             * @param {boolean}  override  If true, the obj passed in becomes             *                             the execution scope of the listener             * @return {boolean} True if the action was successful or defered,             *                        false if one or more of the elements              *                        could not have the listener attached,             *                        or if the operation throws an exception.             * @static             */            addListener: function(el, sType, fn, obj, override) {                if (!fn || !fn.call) {                    return false;                }                // The el argument can be an array of elements or element ids.                if ( this._isValidCollection(el)) {                    var ok = true;                    for (var i=0,len=el.length; i<len; ++i) {                        ok = this.on(el[i],                                        sType,                                        fn,                                        obj,                                        override) && ok;                    }                    return ok;                } else if (typeof el == "string") {                    var oEl = this.getEl(el);                    // If the el argument is a string, we assume it is                     // actually the id of the element.  If the page is loaded                    // we convert el to the actual element, otherwise we                     // defer attaching the event until onload event fires                    // check to see if we need to delay hooking up the event                     // until after the page loads.                    if (oEl) {                        el = oEl;                    } else {                        // defer adding the event until the element is available                        this.onAvailable(el, function() {                           YAHOO.util.Event.on(el, sType, fn, obj, override);                        });                        return true;                    }                }                // Element should be an html element or an array if we get                 // here.                if (!el) {                    return false;                }                // we need to make sure we fire registered unload events                 // prior to automatically unhooking them.  So we hang on to                 // these instead of attaching them to the window and fire the                // handles explicitly during our one unload event.                if ("unload" == sType && obj !== this) {                    unloadListeners[unloadListeners.length] =                            [el, sType, fn, obj, override];                    return true;                }                // if the user chooses to override the scope, we use the custom                // object passed in, otherwise the executing scope will be the                // HTML element that the event is registered on                var scope = el;                if (override) {                    if (override === true) {                        scope = obj;                    } else {                        scope = override;                    }                }                // wrap the function so we can return the obj object when                // the event fires;                var wrappedFn = function(e) {                        return fn.call(scope, YAHOO.util.Event.getEvent(e),                                 obj);                    };                var li = [el, sType, fn, wrappedFn, scope];                var index = listeners.length;                // cache the listener so we can try to automatically unload                listeners[index] = li;                if (this.useLegacyEvent(el, sType)) {                    var legacyIndex = this.getLegacyIndex(el, sType);                    // Add a new dom0 wrapper if one is not detected for this                    // element                    if ( legacyIndex == -1 ||                                 el != legacyEvents[legacyIndex][0] ) {                        legacyIndex = legacyEvents.length;                        legacyMap[el.id + sType] = legacyIndex;                        // cache the signature for the DOM0 event, and                         // include the existing handler for the event, if any                        legacyEvents[legacyIndex] =                             [el, sType, el["on" + sType]];                        legacyHandlers[legacyIndex] = [];                        el["on" + sType] =                             function(e) {                                YAHOO.util.Event.fireLegacyEvent(                                    YAHOO.util.Event.getEvent(e), legacyIndex);                            };                    }                    // add a reference to the wrapped listener to our custom                    // stack of events                    //legacyHandlers[legacyIndex].push(index);                    legacyHandlers[legacyIndex].push(li);                } else {                    try {                        this._simpleAdd(el, sType, wrappedFn, false);                    } catch(ex) {                        // handle an error trying to attach an event.  If it fails                        // we need to clean up the cache                        this.lastError = ex;                        this.removeListener(el, sType, fn);                        return false;                    }                }                return true;                            },            /**             * When using legacy events, the handler is routed to this object             * so we can fire our custom listener stack.             * @method fireLegacyEvent             * @static             * @private             */            fireLegacyEvent: function(e, legacyIndex) {                var ok=true,le,lh,li,scope,ret;                                lh = legacyHandlers[legacyIndex];                for (var i=0,len=lh.length; i<len; ++i) {                    li = lh[i];                    if ( li && li[this.WFN] ) {                        scope = li[this.ADJ_SCOPE];                        ret = li[this.WFN].call(scope, e);                        ok = (ok && ret);                    }                }                // Fire the original handler if we replaced one.  We fire this                // after the other events to keep stopPropagation/preventDefault                // that happened in the DOM0 handler from touching our DOM2                // substitute                le = legacyEvents[legacyIndex];                if (le && le[2]) {                    le[2](e);                }                                return ok;            },            /**             * Returns the legacy event index that matches the supplied              * signature             * @method getLegacyIndex             * @static             * @private             */            getLegacyIndex: function(el, sType) {                var key = this.generateId(el) + sType;                if (typeof legacyMap[key] == "undefined") {                     return -1;                } else {                    return legacyMap[key];                }            },            /**             * Logic that determines when we should automatically use legacy             * events instead of DOM2 events.  Currently this is limited to old             * Safari browsers with a broken preventDefault             * @method useLegacyEvent             * @static             * @private             */            useLegacyEvent: function(el, sType) {                if (this.webkit && ("click"==sType || "dblclick"==sType)) {                    var v = parseInt(this.webkit, 10);                    if (!isNaN(v) && v<418) {                        return true;                    }                }                return false;            },                                /**             * Removes an event handler             *             * @method removeListener             *             * @param {Object} el the html element or the id of the element to              * assign the event to.             * @param {String} sType the type of event to remove.             * @param {Function} fn the method the event invokes.  If fn is             * undefined, then all event handlers for the type of event are              * removed.             * @return {boolean} true if the unbind was successful, false              * otherwise.             * @static             */            removeListener: function(el, sType, fn) {                var i, len;                // The el argument can be a string                if (typeof el == "string") {                    el = this.getEl(el);                // The el argument can be an array of elements or element ids.                } else if ( this._isValidCollection(el)) {                    var ok = true;                    for (i=0,len=el.length; i<len; ++i) {                        ok = ( this.removeListener(el[i], sType, fn) && ok );                    }                    return ok;                }                if (!fn || !fn.call) {                    //return false;                    return this.purgeElement(el, false, sType);                }                if ("unload" == sType) {                    for (i=0, len=unloadListeners.length; i<len; i++) {                        var li = unloadListeners[i];                        if (li &&                             li[0] == el &&                             li[1] == sType &&                             li[2] == fn) {                                unloadListeners.splice(i, 1);                                return true;                        }                    }                    return false;                }                var cacheItem = null;                // The index is a hidden parameter; needed to remove it from                // the method signature because it was tempting users to                // try and take advantage of it, which is not possible.                var index = arguments[3];                  if ("undefined" == typeof index) {                    index = this._getCacheIndex(el, sType, fn);                }                if (index >= 0) {                    cacheItem = listeners[index];                }                if (!el || !cacheItem) {                    return false;                }                if (this.useLegacyEvent(el, sType)) {                    var legacyIndex = this.getLegacyIndex(el, sType);                    var llist = legacyHandlers[legacyIndex];                    if (llist) {                        for (i=0, len=llist.length; i<len; ++i) {                            li = llist[i];                            if (li &&                                 li[this.EL] == el &&                                 li[this.TYPE] == sType &&                                 li[this.FN] == fn) {                                    llist.splice(i, 1);                                    break;                            }                        }                    }                } else {                    try {                        this._simpleRemove(el, sType, cacheItem[this.WFN], false);                    } catch(ex) {                        this.lastError = ex;                        return false;                    }                }                // removed the wrapped handler                delete listeners[index][this.WFN];                delete listeners[index][this.FN];                listeners.splice(index, 1);                return true;            },            /**             * Returns the event's target element             * @method getTarget             * @param {Event} ev the event             * @param {boolean} resolveTextNode when set to true the target's             *                  parent will be returned if the target is a              *                  text node.  @deprecated, the text node is             *                  now resolved automatically             * @return {HTMLElement} the event's target             * @static             */            getTarget: function(ev, resolveTextNode) {                var t = ev.target || ev.srcElement;                return this.resolveTextNode(t);            },            /**             * In some cases, some browsers will return a text node inside             * the actual element that was targeted.  This normalizes the             * return value for getTarget and getRelatedTarget.             * @method resolveTextNode             * @param {HTMLElement} node node to resolve             * @return {HTMLElement} the normized node             * @static             */            resolveTextNode: function(node) {                // if (node && node.nodeName &&                         // "#TEXT" == node.nodeName.toUpperCase()) {                if (node && 3 == node.nodeType) {                    return node.parentNode;                } else {                    return node;                }            },            /**             * Returns the event's pageX             * @method getPageX             * @param {Event} ev the event             * @return {int} the event's pageX             * @static             */            getPageX: function(ev) {                var x = ev.pageX;                if (!x && 0 !== x) {                    x = ev.clientX || 0;                    if ( this.isIE ) {                        x += this._getScrollLeft();                    }                }                return x;            },            /**             * Returns the event's pageY             * @method getPageY             * @param {Event} ev the event             * @return {int} the event's pageY             * @static             */            getPageY: function(ev) {                var y = ev.pageY;                if (!y && 0 !== y) {                    y = ev.clientY || 0;                    if ( this.isIE ) {                        y += this._getScrollTop();                    }                }                return y;            },            /**             * Returns the pageX and pageY properties as an indexed array.             * @method getXY             * @param {Event} ev the event             * @return {[x, y]} the pageX and pageY properties of the event             * @static             */            getXY: function(ev) {                return [this.getPageX(ev), this.getPageY(ev)];            },            /**             * Returns the event's related target              * @method getRelatedTarget             * @param {Event} ev the event             * @return {HTMLElement} the event's relatedTarget             * @static             */            getRelatedTarget: function(ev) {                var t = ev.relatedTarget;                if (!t) {                    if (ev.type == "mouseout") {                        t = ev.toElement;                    } else if (ev.type == "mouseover") {                        t = ev.fromElement;                    }                }                return this.resolveTextNode(t);            },            /**             * Returns the time of the event.  If the time is not included, the             * event is modified using the current time.             * @method getTime             * @param {Event} ev the event             * @return {Date} the time of the event             * @static             */            getTime: function(ev) {                if (!ev.time) {                    var t = new Date().getTime();                    try {                        ev.time = t;                    } catch(ex) {                         this.lastError = ex;                        return t;                    }                }                return ev.time;            },            /**             * Convenience method for stopPropagation + preventDefault             * @method stopEvent             * @param {Event} ev the event             * @static             */            stopEvent: function(ev) {                this.stopPropagation(ev);                this.preventDefault(ev);            },            /**             * Stops event propagation             * @method stopPropagation             * @param {Event} ev the event             * @static             */            stopPropagation: function(ev) {                if (ev.stopPropagation) {                    ev.stopPropagation();                } else {                    ev.cancelBubble = true;                }            },            /**             * Prevents the default behavior of the event             * @method preventDefault             * @param {Event} ev the event             * @static             */            preventDefault: function(ev) {                if (ev.preventDefault) {                    ev.preventDefault();                } else {                    ev.returnValue = false;                }            },                         /**             * Finds the event in the window object, the caller's arguments, or             * in the arguments of another method in the callstack.  This is             * executed automatically for events registered through the event             * manager, so the implementer should not normally need to execute             * this function at all.             * @method getEvent             * @param {Event} e the event parameter from the handler             * @return {Event} the event              * @static             */            getEvent: function(e) {                var ev = e || window.event;                if (!ev) {                    var c = this.getEvent.caller;                    while (c) {                        ev = c.arguments[0];                        if (ev && Event == ev.constructor) {                            break;                        }                        c = c.caller;                    }                }                return ev;            },            /**             * Returns the charcode for an event             * @method getCharCode             * @param {Event} ev the event             * @return {int} the event's charCode             * @static             */            getCharCode: function(ev) {
                return ev.charCode || ev.keyCode || 0;            },            /**             * Locating the saved event handler data by function ref             *             * @method _getCacheIndex             * @static             * @private             */            _getCacheIndex: function(el, sType, fn) {                for (var i=0,len=listeners.length; i<len; ++i) {                    var li = listeners[i];                    if ( li                 &&                          li[this.FN] == fn  &&                          li[this.EL] == el  &&                          li[this.TYPE] == sType ) {                        return i;                    }                }                return -1;            },            /**             * Generates an unique ID for the element if it does not already              * have one.             * @method generateId             * @param el the element to create the id for             * @return {string} the resulting id of the element             * @static             */            generateId: function(el) {                var id = el.id;                if (!id) {                    id = "yuievtautoid-" + counter;                    ++counter;                    el.id = id;                }                return id;            },            /**             * We want to be able to use getElementsByTagName as a collection             * to attach a group of events to.  Unfortunately, different              * browsers return different types of collections.  This function             * tests to determine if the object is array-like.  It will also              * fail if the object is an array, but is empty.             * @method _isValidCollection             * @param o the object to test             * @return {boolean} true if the object is array-like and populated             * @static             * @private             */            _isValidCollection: function(o) {                return ( o                    && // o is something                         o.length             && // o is indexed                         typeof o != "string" && // o is not a string                         !o.tagName           && // o is not an HTML element                         !o.alert             && // o is not a window                         typeof o[0] != "undefined" );            },            /**             * @private             * @property elCache             * DOM element cache             * @static             * @deprecated Elements are not cached any longer             */            elCache: {},            /**             * We cache elements bound by id because when the unload event              * fires, we can no longer use document.getElementById             * @method getEl
             * @static             * @private             * @deprecated Elements are not cached any longer             */            getEl: function(id) {                return document.getElementById(id);            },            /**             * Clears the element cache             * @deprecated Elements are not cached any longer             * @method clearCache             * @static             * @private             */            clearCache: function() { },            /**             * Custom event the fires when the dom is initially usable             * @event DOMReadyEvent             */            DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", this),            /**             * hook up any deferred listeners             * @method _load             * @static             * @private             */            _load: function(e) {                if (!loadComplete) {                    loadComplete = true;                    var EU = YAHOO.util.Event;                    // just in case DOMReady did not go off for some reason                    EU._ready();                    // Remove the listener to assist with the IE memory issue, but not                    // for other browsers because FF 1.0x does not like it.                    if (this.isIE) {                        EU._simpleRemove(window, "load", EU._load);                    }                }            },            /**             * Fires the DOMReady event listeners the first time the document is             * usable.             * @method _ready             * @static             * @private             */            _ready: function(e) {                if (!DOMReady) {                    DOMReady=true;                    var EU = YAHOO.util.Event;                    // Fire the content ready custom event                    EU.DOMReadyEvent.fire();                    // Remove the DOMContentLoaded (FF/Opera)                    EU._simpleRemove(document, "DOMContentLoaded", EU._ready);                }            },            /**             * Polling function that runs before the onload event fires,              * attempting to attach to DOM Nodes as soon as they are              * available             * @method _tryPreloadAttach             * @static             * @private             */            _tryPreloadAttach: function() {                if (this.locked) {                    return false;                }                if (this.isIE && !DOMReady) {                    return false;                }                this.locked = true;                // keep trying until after the page is loaded.  We need to                 // check the page load state prior to trying to bind the                 // elements so that we can be certain all elements have been                 // tested appropriately                var tryAgain = !loadComplete;                if (!tryAgain) {                    tryAgain = (retryCount > 0);                }                // onAvailable                var notAvail = [];                var executeItem = function (el, item) {                    var scope = el;                    if (item.override) {                        if (item.override === true) {                            scope = item.obj;                        } else {                            scope = item.override;                        }                    }                    item.fn.call(scope, item.obj);                };                var i,len,item,el;                // onAvailable                for (i=0,len=onAvailStack.length; i<len; ++i) {                    item = onAvailStack[i];                    if (item && !item.checkReady) {                        el = this.getEl(item.id);                        if (el) {                            executeItem(el, item);                            onAvailStack[i] = null;                        } else {                            notAvail.push(item);                        }                    }                }                // onContentReady                for (i=0,len=onAvailStack.length; i<len; ++i) {                    item = onAvailStack[i];                    if (item && item.checkReady) {                        el = this.getEl(item.id);                        if (el) {                            // The element is available, but not necessarily ready                            // @todo should we test parentNode.nextSibling?                            if (loadComplete || el.nextSibling) {                                executeItem(el, item);                                onAvailStack[i] = null;                            }                        } else {                            notAvail.push(item);                        }                    }                }                retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;                if (tryAgain) {                    // we may need to strip the nulled out items here                    this.startInterval();                } else {                    clearInterval(this._interval);                    this._interval = null;                }                this.locked = false;                return true;            },            /**             * Removes all listeners attached to the given element via addListener.             * Optionally, the node's children can also be purged.             * Optionally, you can specify a specific type of event to remove.             * @method purgeElement             * @param {HTMLElement} el the element to purge             * @param {boolean} recurse recursively purge this element's children             * as well.  Use with caution.             * @param {string} sType optional type of listener to purge. If             * left out, all listeners will be removed             * @static             */            purgeElement: function(el, recurse, sType) {                var elListeners = this.getListeners(el, sType);                if (elListeners) {                    for (var i=0,len=elListeners.length; i<len ; ++i) {                        var l = elListeners[i];                        // can't use the index on the changing collection                        //this.removeListener(el, l.type, l.fn, l.index);                        this.removeListener(el, l.type, l.fn);                    }                }                if (recurse && el && el.childNodes) {                    for (i=0,len=el.childNodes.length; i<len ; ++i) {                        this.purgeElement(el.childNodes[i], recurse, sType);                    }                }            },            /**             * Returns all listeners attached to the given element via addListener.             * Optionally, you can specify a specific type of event to return.             * @method getListeners             * @param el {HTMLElement} the element to inspect              * @param sType {string} optional type of listener to return. If             * left out, all listeners will be returned             * @return {Object} the listener. Contains the following fields:             * &nbsp;&nbsp;type:   (string)   the type of event             * &nbsp;&nbsp;fn:     (function) the callback supplied to addListener             * &nbsp;&nbsp;obj:    (object)   the custom object supplied to addListener             * &nbsp;&nbsp;adjust: (boolean)  whether or not to adjust the default scope             * &nbsp;&nbsp;index:  (int)      its position in the Event util listener cache             * @static             */                       getListeners: function(el, sType) {                var results=[], searchLists;                if (!sType) {                    searchLists = [listeners, unloadListeners];                } else if (sType == "unload") {                    searchLists = [unloadListeners];                } else {                    searchLists = [listeners];                }                for (var j=0;j<searchLists.length; ++j) {                    var searchList = searchLists[j];                    if (searchList && searchList.length > 0) {                        for (var i=0,len=searchList.length; i<len ; ++i) {                            var l = searchList[i];                            if ( l  && l[this.EL] === el &&                                     (!sType || sType === l[this.TYPE]) ) {                                results.push({                                    type:   l[this.TYPE],                                    fn:     l[this.FN],                                    obj:    l[this.OBJ],                                    adjust: l[this.ADJ_SCOPE],                                    index:  i                                });                            }                        }                    }                }                return (results.length) ? results : null;            },            /**             * Removes all listeners registered by pe.event.  Called              * automatically during the unload event.             * @method _unload             * @static             * @private             */            _unload: function(e) {                var EU = YAHOO.util.Event, i, j, l, len, index;                for (i=0,len=unloadListeners.length; i<len; ++i) {                    l = unloadListeners[i];                    if (l) {                        var scope = window;                        if (l[EU.ADJ_SCOPE]) {                            if (l[EU.ADJ_SCOPE] === true) {                                scope = l[EU.OBJ];                            } else {                                scope = l[EU.ADJ_SCOPE];                            }                        }                        l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ] );                        unloadListeners[i] = null;                        l=null;                        scope=null;                    }                }                unloadListeners = null;                if (listeners && listeners.length > 0) {                    j = listeners.length;                    while (j) {                        index = j-1;                        l = listeners[index];                        if (l) {                            EU.removeListener(l[EU.EL], l[EU.TYPE],                                     l[EU.FN], index);                        }                         j = j - 1;                    }                    l=null;                    EU.clearCache();                }                for (i=0,len=legacyEvents.length; i<len; ++i) {                    // dereference the element                    //delete legacyEvents[i][0];                    legacyEvents[i][0] = null;                    // delete the array item                    //delete legacyEvents[i];                    legacyEvents[i] = null;                }                legacyEvents = null;                EU._simpleRemove(window, "unload", EU._unload);            },            /**             * Returns scrollLeft             * @method _getScrollLeft             * @static             * @private             */            _getScrollLeft: function() {                return this._getScroll()[1];            },            /**             * Returns scrollTop             * @method _getScrollTop             * @static             * @private             */            _getScrollTop: function() {                return this._getScroll()[0];            },            /**             * Returns the scrollTop and scrollLeft.  Used to calculate the              * pageX and pageY in Internet Explorer             * @method _getScroll             * @static             * @private             */            _getScroll: function() {                var dd = document.documentElement, db = document.body;                if (dd && (dd.scrollTop || dd.scrollLeft)) {                    return [dd.scrollTop, dd.scrollLeft];                } else if (db) {                    return [db.scrollTop, db.scrollLeft];                } else {                    return [0, 0];                }            },                        /**             * Used by old versions of CustomEvent, restored for backwards             * compatibility             * @method regCE             * @private             */            regCE: function() {                // does nothing            },            /**             * Adds a DOM event directly without the caching, cleanup, scope adj, etc             *             * @method _simpleAdd             * @param {HTMLElement} el      the element to bind the handler to             * @param {string}      sType   the type of event handler             * @param {function}    fn      the callback to invoke             * @param {boolen}      capture capture or bubble phase             * @static             * @private             */            _simpleAdd: function () {                if (window.addEventListener) {                    return function(el, sType, fn, capture) {                        el.addEventListener(sType, fn, (capture));                    };                } else if (window.attachEvent) {                    return function(el, sType, fn, capture) {                        el.attachEvent("on" + sType, fn);                    };                } else {                    return function(){};                }            }(),            /**             * Basic remove listener             *             * @method _simpleRemove             * @param {HTMLElement} el      the element to bind the handler to             * @param {string}      sType   the type of event handler             * @param {function}    fn      the callback to invoke             * @param {boolen}      capture capture or bubble phase             * @static             * @private             */            _simpleRemove: function() {                if (window.removeEventListener) {                    return function (el, sType, fn, capture) {                        el.removeEventListener(sType, fn, (capture));                    };                } else if (window.detachEvent) {                    return function (el, sType, fn) {                        el.detachEvent("on" + sType, fn);                    };                } else {                    return function(){};                }            }()        };    }();    (function() {        var EU = YAHOO.util.Event;        /**         * YAHOO.util.Event.on is an alias for addListener         * @method on         * @see addListener         * @static         */        EU.on = EU.addListener;        /////////////////////////////////////////////////////////////        // DOMReady        // based on work by: Dean Edwards/John Resig/Matthias Miller         // Internet Explorer: use the readyState of a defered script.        // This isolates what appears to be a safe moment to manipulate        // the DOM prior to when the document's readyState suggests        // it is safe to do so.        if (EU.isIE) {	            document.write('<scr' + 'ipt id="_yui_eu_dr" defer="true" src="//:"></script>');                    var el = document.getElementById("_yui_eu_dr");            el.onreadystatechange = function() {                if ("complete" == this.readyState) {                    this.parentNode.removeChild(this);                    YAHOO.util.Event._ready();                }            };            el=null;            // Process onAvailable/onContentReady items when when the             // DOM is ready.            YAHOO.util.Event.onDOMReady(                    YAHOO.util.Event._tryPreloadAttach,                    YAHOO.util.Event, true);                // Safari: The document's readyState in Safari currently will        // change to loaded/complete before images are loaded.        } else if (EU.webkit) {            EU._drwatch = setInterval(function(){                var rs=document.readyState;                if ("loaded" == rs || "complete" == rs) {                    clearInterval(EU._drwatch);                    EU._drwatch = null;                    EU._ready();                }            }, EU.POLL_INTERVAL);         // FireFox and Opera: These browsers provide a event for this        // moment.        } else {            EU._simpleAdd(document, "DOMContentLoaded", EU._ready);        }        /////////////////////////////////////////////////////////////        EU._simpleAdd(window, "load", EU._load);        EU._simpleAdd(window, "unload", EU._unload);        EU._tryPreloadAttach();    })();}/** * EventProvider is designed to be used with YAHOO.augment to wrap  * CustomEvents in an interface that allows events to be subscribed to  * and fired by name.  This makes it possible for implementing code to * subscribe to an event that either has not been created yet, or will * not be created at all. * * @Class EventProvider */YAHOO.util.EventProvider = function() { };YAHOO.util.EventProvider.prototype = {    /**     * Private storage of custom events     * @property __yui_events     * @type Object[]     * @private     */    __yui_events: null,    /**     * Private storage of custom event subscribers     * @property __yui_subscribers     * @type Object[]     * @private     */    __yui_subscribers: null,        /**     * Subscribe to a CustomEvent by event type     *     * @method subscribe     * @param p_type     {string}   the type, or name of the event     * @param p_fn       {function} the function to exectute when the event fires     * @param p_obj     * @param p_obj      {Object}   An object to be passed along when the event      *                              fires     * @param p_override {boolean}  If true, the obj passed in becomes the      *                              execution scope of the listener     */    subscribe: function(p_type, p_fn, p_obj, p_override) {        this.__yui_events = this.__yui_events || {};        var ce = this.__yui_events[p_type];        if (ce) {            ce.subscribe(p_fn, p_obj, p_override);        } else {            this.__yui_subscribers = this.__yui_subscribers || {};            var subs = this.__yui_subscribers;            if (!subs[p_type]) {                subs[p_type] = [];            }            subs[p_type].push(                { fn: p_fn, obj: p_obj, override: p_override } );        }    },    /**     * Unsubscribes one or more listeners the from the specified event     * @method unsubscribe     * @param p_type {string}   The type, or name of the event     * @param p_fn   {Function} The subscribed function to unsubscribe, if not     *                          supplied, all subscribers will be removed.     * @param p_obj  {Object}   The custom object passed to subscribe.  This is     *                        optional, but if supplied will be used to     *                        disambiguate multiple listeners that are the same     *                        (e.g., you subscribe many object using a function     *                        that lives on the prototype)     * @return {boolean} true if the subscriber was found and detached.     */    unsubscribe: function(p_type, p_fn, p_obj) {        this.__yui_events = this.__yui_events || {};        var ce = this.__yui_events[p_type];        if (ce) {            return ce.unsubscribe(p_fn, p_obj);        } else {            return false;        }    },        /**     * Removes all listeners from the specified event     * @method unsubscribeAll     * @param p_type {string}   The type, or name of the event     */    unsubscribeAll: function(p_type) {        return this.unsubscribe(p_type);    },    /**     * Creates a new custom event of the specified type.  If a custom event     * by that name already exists, it will not be re-created.  In either     * case the custom event is returned.      *     * @method createEvent     *     * @param p_type {string} the type, or name of the event     * @param p_config {object} optional config params.  Valid properties are:     *     *  <ul>     *    <li>     *      scope: defines the default execution scope.  If not defined     *      the default scope will be this instance.     *    </li>     *    <li>     *      silent: if true, the custom event will not generate log messages.     *      This is false by default.     *    </li>     *    <li>     *      onSubscribeCallback: specifies a callback to execute when the     *      event has a new subscriber.  This will fire immediately for     *      each queued subscriber if any exist prior to the creation of     *      the event.     *    </li>     *  </ul>     *     *  @return {CustomEvent} the custom event     *     */    createEvent: function(p_type, p_config) {        this.__yui_events = this.__yui_events || {};        var opts = p_config || {};        var events = this.__yui_events;        if (events[p_type]) {        } else {            var scope  = opts.scope  || this;            var silent = opts.silent || null;            var ce = new YAHOO.util.CustomEvent(p_type, scope, silent,                    YAHOO.util.CustomEvent.FLAT);            events[p_type] = ce;            if (opts.onSubscribeCallback) {                ce.subscribeEvent.subscribe(opts.onSubscribeCallback);            }            this.__yui_subscribers = this.__yui_subscribers || {};            var qs = this.__yui_subscribers[p_type];            if (qs) {                for (var i=0; i<qs.length; ++i) {                    ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);                }            }        }        return events[p_type];    },   /**     * Fire a custom event by name.  The callback functions will be executed     * from the scope specified when the event was created, and with the      * following parameters:     *   <ul>     *   <li>The first argument fire() was executed with</li>     *   <li>The custom object (if any) that was passed into the subscribe()      *       method</li>     *   </ul>     * @method fireEvent     * @param p_type    {string}  the type, or name of the event     * @param arguments {Object*} an arbitrary set of parameters to pass to      *                            the handler.     * @return {boolean} the return value from CustomEvent.fire, or null if      *                   the custom event does not exist.     */    fireEvent: function(p_type, arg1, arg2, etc) {        this.__yui_events = this.__yui_events || {};        var ce = this.__yui_events[p_type];        if (ce) {            var args = [];            for (var i=1; i<arguments.length; ++i) {                args.push(arguments[i]);            }            return ce.fire.apply(ce, args);        } else {            return null;        }    },    /**     * Returns true if the custom event of the provided type has been created     * with createEvent.     * @method hasEvent     * @param type {string} the type, or name of the event     */    hasEvent: function(type) {        if (this.__yui_events) {            if (this.__yui_events[type]) {                return true;            }        }        return false;    }};/*** KeyListener is a utility that provides an easy interface for listening for* keydown/keyup events fired against DOM elements.* @namespace YAHOO.util* @class KeyListener* @constructor* @param {HTMLElement} attachTo The element or element ID to which the key *                               event should be attached* @param {String}      attachTo The element or element ID to which the key*                               event should be attached* @param {Object}      keyData  The object literal representing the key(s) *                               to detect. Possible attributes are *                               shift(boolean), alt(boolean), ctrl(boolean) *                               and keys(either an int or an array of ints *                               representing keycodes).* @param {Function}    handler  The CustomEvent handler to fire when the *                               key event is detected* @param {Object}      handler  An object literal representing the handler. * @param {String}      event    Optional. The event (keydown or keyup) to *                               listen for. Defaults automatically to keydown.*/YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {    if (!attachTo) {    } else if (!keyData) {    } else if (!handler) {    }         if (!event) {        event = YAHOO.util.KeyListener.KEYDOWN;    }    /**    * The CustomEvent fired internally when a key is pressed    * @event keyEvent    * @private    * @param {Object} keyData The object literal representing the key(s) to     *                         detect. Possible attributes are shift(boolean),     *                         alt(boolean), ctrl(boolean) and keys(either an     *                         int or an array of ints representing keycodes).    */    var keyEvent = new YAHOO.util.CustomEvent("keyPressed");        /**    * The CustomEvent fired when the KeyListener is enabled via the enable()     * function    * @event enabledEvent    * @param {Object} keyData The object literal representing the key(s) to     *                         detect. Possible attributes are shift(boolean),     *                         alt(boolean), ctrl(boolean) and keys(either an     *                         int or an array of ints representing keycodes).    */    this.enabledEvent = new YAHOO.util.CustomEvent("enabled");    /**    * The CustomEvent fired when the KeyListener is disabled via the     * disable() function    * @event disabledEvent    * @param {Object} keyData The object literal representing the key(s) to     *                         detect. Possible attributes are shift(boolean),     *                         alt(boolean), ctrl(boolean) and keys(either an     *                         int or an array of ints representing keycodes).    */    this.disabledEvent = new YAHOO.util.CustomEvent("disabled");    if (typeof attachTo == 'string') {        attachTo = document.getElementById(attachTo);    }    if (typeof handler == 'function') {        keyEvent.subscribe(handler);    } else {        keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);    }    /**    * Handles the key event when a key is pressed.    * @method handleKeyPress    * @param {DOMEvent} e   The keypress DOM event    * @param {Object}   obj The DOM event scope object    * @private    */    function handleKeyPress(e, obj) {        if (! keyData.shift) {              keyData.shift = false;         }        if (! keyData.alt) {                keyData.alt = false;        }        if (! keyData.ctrl) {            keyData.ctrl = false;        }        // check held down modifying keys first        if (e.shiftKey == keyData.shift &&             e.altKey   == keyData.alt &&            e.ctrlKey  == keyData.ctrl) { // if we pass this, all modifiers match                        var dataItem;            var keyPressed;            if (keyData.keys instanceof Array) {                for (var i=0;i<keyData.keys.length;i++) {                    dataItem = keyData.keys[i];                    if (dataItem == e.charCode ) {                        keyEvent.fire(e.charCode, e);                        break;                    } else if (dataItem == e.keyCode) {                        keyEvent.fire(e.keyCode, e);                        break;                    }                }            } else {                dataItem = keyData.keys;                if (dataItem == e.charCode ) {                    keyEvent.fire(e.charCode, e);                } else if (dataItem == e.keyCode) {                    keyEvent.fire(e.keyCode, e);                }            }        }    }    /**    * Enables the KeyListener by attaching the DOM event listeners to the     * target DOM element    * @method enable    */    this.enable = function() {        if (! this.enabled) {            YAHOO.util.Event.addListener(attachTo, event, handleKeyPress);            this.enabledEvent.fire(keyData);        }        /**        * Boolean indicating the enabled/disabled state of the Tooltip        * @property enabled        * @type Boolean        */        this.enabled = true;    };    /**    * Disables the KeyListener by removing the DOM event listeners from the     * target DOM element    * @method disable    */    this.disable = function() {        if (this.enabled) {            YAHOO.util.Event.removeListener(attachTo, event, handleKeyPress);            this.disabledEvent.fire(keyData);        }        this.enabled = false;    };    /**    * Returns a String representation of the object.    * @method toString    * @return {String}  The string representation of the KeyListener    */     this.toString = function() {        return "KeyListener [" + keyData.keys + "] " + attachTo.tagName +                 (attachTo.id ? "[" + attachTo.id + "]" : "");    };};/*** Constant representing the DOM "keydown" event.* @property YAHOO.util.KeyListener.KEYDOWN* @static* @final* @type String*/YAHOO.util.KeyListener.KEYDOWN = "keydown";/*** Constant representing the DOM "keyup" event.* @property YAHOO.util.KeyListener.KEYUP* @static* @final* @type String*/YAHOO.util.KeyListener.KEYUP = "keyup";YAHOO.register("event", YAHOO.util.Event, {version: "2.2.2", build: "204"});