| /* |
| Copyright (c) 2008, Yahoo! Inc. All rights reserved. |
| Code licensed under the BSD License: |
| http://developer.yahoo.net/yui/license.txt |
| version: 2.6.0 |
| */ |
| |
| /** |
| * 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); |
| |
| } |
| |
| |
| /** |
| * In order to make it possible to execute the rest of the subscriber |
| * stack when one thows an exception, the subscribers exceptions are |
| * caught. The most recent exception is stored in this property |
| * @property lastError |
| * @type Error |
| */ |
| this.lastError = null; |
| }; |
| |
| /** |
| * 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() { |
| |
| this.lastError = null; |
| |
| var errors = [], |
| len=this.subscribers.length; |
| |
| if (!len && this.silent) { |
| return true; |
| } |
| |
| var args=[].slice.call(arguments, 0), ret=true, i, rebuild=false; |
| |
| if (!this.silent) { |
| } |
| |
| // make a copy of the subscribers so that there are |
| // no index problems if one subscriber removes another. |
| var subs = this.subscribers.slice(), throwErrors = YAHOO.util.Event.throwErrors; |
| |
| for (i=0; i<len; ++i) { |
| var s = subs[i]; |
| if (!s) { |
| rebuild=true; |
| } else { |
| 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]; |
| } |
| |
| try { |
| ret = s.fn.call(scope, param, s.obj); |
| } catch(e) { |
| this.lastError = e; |
| // errors.push(e); |
| if (throwErrors) { |
| throw e; |
| } |
| } |
| } else { |
| try { |
| ret = s.fn.call(scope, this.type, args, s.obj); |
| } catch(ex) { |
| this.lastError = ex; |
| if (throwErrors) { |
| throw ex; |
| } |
| } |
| } |
| |
| if (false === ret) { |
| if (!this.silent) { |
| } |
| |
| break; |
| // return false; |
| } |
| } |
| } |
| |
| return (ret !== false); |
| }, |
| |
| /** |
| * Removes all listeners |
| * @method unsubscribeAll |
| * @return {int} The number of listeners unsubscribed |
| */ |
| unsubscribeAll: function() { |
| for (var i=this.subscribers.length-1; i>-1; i--) { |
| this._delete(i); |
| } |
| |
| this.subscribers=[]; |
| |
| return i; |
| }, |
| |
| /** |
| * @method _delete |
| * @private |
| */ |
| _delete: function(index) { |
| var s = this.subscribers[index]; |
| if (s) { |
| delete s.fn; |
| delete s.obj; |
| } |
| |
| // this.subscribers[index]=null; |
| 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 = YAHOO.lang.isUndefined(obj) ? null : obj; |
| |
| /** |
| * 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; |
| |
| /** |
| * 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; |
| |
| /** |
| * Normalized keycodes for webkit/safari |
| * @property webkitKeymap |
| * @type {int: int} |
| * @private |
| * @static |
| * @final |
| */ |
| var webkitKeymap = { |
| 63232: 38, // up |
| 63233: 40, // down |
| 63234: 37, // left |
| 63235: 39, // right |
| 63276: 33, // page up |
| 63277: 34, // page down |
| 25: 9 // SHIFT-TAB (Safari provides a different key code in |
| // this case, even though the shiftKey modifier is set) |
| }; |
| |
| // String constants used by the addFocusListener and removeFocusListener methods |
| var _FOCUS = YAHOO.env.ua.ie ? "focusin" : "focus"; |
| var _BLUR = YAHOO.env.ua.ie ? "focusout" : "blur"; |
| |
| 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 2000@amp;20 ms, so it will poll |
| * for 40 seconds or until all outstanding handlers are bound |
| * (whichever comes first). |
| * @property POLL_RETRYS |
| * @type int |
| * @static |
| * @final |
| */ |
| POLL_RETRYS: 2000, |
| |
| /** |
| * The poll interval in milliseconds |
| * @property POLL_INTERVAL |
| * @type int |
| * @static |
| * @final |
| */ |
| POLL_INTERVAL: 20, |
| |
| /** |
| * 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. Specific to |
| * unload listeners |
| * @property OBJ |
| * @type int |
| * @static |
| * @final |
| */ |
| UNLOAD_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, |
| |
| /** |
| * The original obj passed into addListener |
| * @property OBJ |
| * @type int |
| * @static |
| * @final |
| */ |
| OBJ: 5, |
| |
| /** |
| * The original scope parameter passed into addListener |
| * @property OVERRIDE |
| * @type int |
| * @static |
| * @final |
| */ |
| OVERRIDE: 6, |
| |
| /** |
| * The original capture parameter passed into _addListener |
| * @property CAPTURE |
| * @type int |
| * @static |
| * @final |
| */ |
| CAPTURE: 7, |
| |
| |
| /** |
| * addListener/removeListener can throw errors in unexpected scenarios. |
| * These errors are suppressed, the method returns false, and this property |
| * is set |
| * @property lastError |
| * @static |
| * @type Error |
| */ |
| lastError: null, |
| |
| /** |
| * Safari detection |
| * @property isSafari |
| * @private |
| * @static |
| * @deprecated use YAHOO.env.ua.webkit |
| */ |
| isSafari: YAHOO.env.ua.webkit, |
| |
| /** |
| * webkit version |
| * @property webkit |
| * @type string |
| * @private |
| * @static |
| * @deprecated use YAHOO.env.ua.webkit |
| */ |
| webkit: YAHOO.env.ua.webkit, |
| |
| /** |
| * IE detection |
| * @property isIE |
| * @private |
| * @static |
| * @deprecated use YAHOO.env.ua.ie |
| */ |
| isIE: YAHOO.env.ua.ie, |
| |
| /** |
| * poll handle |
| * @property _interval |
| * @static |
| * @private |
| */ |
| _interval: null, |
| |
| /** |
| * document readystate poll handle |
| * @property _dri |
| * @static |
| * @private |
| */ |
| _dri: null, |
| |
| /** |
| * True when the document is initially usable |
| * @property DOMReady |
| * @type boolean |
| * @static |
| */ |
| DOMReady: false, |
| |
| /** |
| * Errors thrown by subscribers of custom events are caught |
| * and the error message is written to the debug console. If |
| * this property is set to true, it will also re-throw the |
| * error. |
| * @property throwErrors |
| * @type boolean |
| * @default false |
| */ |
| throwErrors: false, |
| |
| /** |
| * @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. |
| * |
| * <p>The callback is executed with a single parameter: |
| * the custom object parameter, if provided.</p> |
| * |
| * @method onAvailable |
| * |
| * @param {string||string[]} p_id the id of the element, or an array |
| * of ids 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|object} p_override 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 |
| * @param checkContent {boolean} check child node readiness (onContentReady) |
| * @static |
| */ |
| onAvailable: function(p_id, p_fn, p_obj, p_override, checkContent) { |
| |
| var a = (YAHOO.lang.isString(p_id)) ? [p_id] : p_id; |
| |
| for (var i=0; i<a.length; i=i+1) { |
| onAvailStack.push({id: a[i], |
| fn: p_fn, |
| obj: p_obj, |
| override: p_override, |
| checkReady: checkContent }); |
| } |
| |
| retryCount = this.POLL_RETRYS; |
| |
| this.startInterval(); |
| }, |
| |
| /** |
| * 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. |
| * |
| * <p>The callback is executed with a single parameter: |
| * the custom object parameter, if provided.</p> |
| * |
| * @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|object} p_override If set to true, p_fn will execute |
| * in the scope of p_obj. If an object, p_fn will |
| * exectute in the scope of that object |
| * |
| * @static |
| */ |
| onContentReady: function(p_id, p_fn, p_obj, p_override) { |
| this.onAvailable(p_id, p_fn, p_obj, p_override, true); |
| }, |
| |
| /** |
| * Executes the supplied callback when the DOM is first usable. This |
| * will execute immediately if called after the DOMReady event has |
| * fired. @todo the DOMContentReady event does not fire when the |
| * script is dynamically injected into the page. This means the |
| * DOMReady custom event will never fire in FireFox or Opera when the |
| * library is injected. It _will_ fire in Safari, and the IE |
| * implementation would allow for us to fire it if the defered script |
| * is not available. We want this to behave the same in all browsers. |
| * Is there a way to identify when the script has been injected |
| * instead of included inline? Is there a way to know whether the |
| * window onload event has fired without having had a listener attached |
| * to it when it did so? |
| * |
| * <p>The callback is a CustomEvent, so the signature is:</p> |
| * <p>type <string>, args <array>, customobject <object></p> |
| * <p>For DOMReady events, there are no fire argments, so the |
| * signature is:</p> |
| * <p>"DOMReady", [], obj</p> |
| * |
| * |
| * @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|object} 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) { |
| if (this.DOMReady) { |
| setTimeout(function() { |
| var s = window; |
| if (p_override) { |
| if (p_override === true) { |
| s = p_obj; |
| } else { |
| s = p_override; |
| } |
| } |
| p_fn.call(s, "DOMReady", [], p_obj); |
| }, 0); |
| } else { |
| this.DOMReadyEvent.subscribe(p_fn, p_obj, p_override); |
| } |
| }, |
| |
| |
| /** |
| * Appends an event handler |
| * |
| * @method _addListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to assign the |
| * listener 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|object} override If true, the obj passed in becomes |
| * the execution scope of the listener. If an |
| * object, this object becomes the execution |
| * scope. |
| * @param {boolen} capture capture or bubble phase |
| * @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. |
| * @private |
| * @static |
| */ |
| _addListener: function(el, sType, fn, obj, override, capture) { |
| |
| 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._addListener(el[i], |
| sType, |
| fn, |
| obj, |
| override, |
| capture) && ok; |
| } |
| return ok; |
| |
| } else if (YAHOO.lang.isString(el)) { |
| 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._addListener(el, sType, fn, obj, override, capture); |
| }); |
| |
| 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, capture]; |
| 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, el), |
| obj); |
| }; |
| |
| var li = [el, sType, fn, wrappedFn, scope, obj, override, capture]; |
| 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, capture); |
| } 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, capture); |
| return false; |
| } |
| } |
| |
| return true; |
| |
| }, |
| |
| |
| /** |
| * Appends an event handler |
| * |
| * @method addListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to assign the |
| * listener 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|object} override If true, the obj passed in becomes |
| * the execution scope of the listener. If an |
| * object, this object becomes the execution |
| * scope. |
| * @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) { |
| return this._addListener(el, sType, fn, obj, override, false); |
| }, |
| |
| /** |
| * Appends a focus event handler. (The focusin event is used for Internet Explorer, |
| * the focus, capture-event for Opera, WebKit, and Gecko.) |
| * |
| * @method addFocusListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to assign the |
| * listener to. |
| * @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|object} override If true, the obj passed in becomes |
| * the execution scope of the listener. If an |
| * object, this object becomes the execution |
| * scope. |
| * @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 |
| */ |
| addFocusListener: function (el, fn, obj, override) { |
| return this._addListener(el, _FOCUS, fn, obj, override, true); |
| }, |
| |
| |
| /** |
| * Removes a focus event listener |
| * |
| * @method removeFocusListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to remove |
| * the listener from. |
| * @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 |
| */ |
| removeFocusListener: function (el, fn) { |
| return this._removeListener(el, _FOCUS, fn, true); |
| }, |
| |
| /** |
| * Appends a blur event handler. (The focusout event is used for Internet Explorer, |
| * the focusout, capture-event for Opera, WebKit, and Gecko.) |
| * |
| * @method addBlurListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to assign the |
| * listener to. |
| * @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|object} override If true, the obj passed in becomes |
| * the execution scope of the listener. If an |
| * object, this object becomes the execution |
| * scope. |
| * @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 |
| */ |
| addBlurListener: function (el, fn, obj, override) { |
| return this._addListener(el, _BLUR, fn, obj, override, true); |
| }, |
| |
| /** |
| * Removes a blur event listener |
| * |
| * @method removeBlurListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to remove |
| * the listener from. |
| * @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 |
| */ |
| removeBlurListener: function (el, fn) { |
| |
| return this._removeListener(el, _BLUR, fn, 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].slice(); |
| for (var i=0, len=lh.length; i<len; ++i) { |
| // for (var i in lh.length) { |
| 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) { |
| return (this.webkit && this.webkit < 419 && ("click"==sType || "dblclick"==sType)); |
| }, |
| |
| /** |
| * Removes an event listener |
| * |
| * @method _removeListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to remove |
| * the listener from. |
| * @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. |
| * @param {boolen} capture capture or bubble phase |
| * @return {boolean} true if the unbind was successful, false |
| * otherwise. |
| * @static |
| * @private |
| */ |
| _removeListener: function(el, sType, fn, capture) { |
| var i, len, li; |
| |
| // 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=el.length-1; i>-1; i--) { |
| ok = ( this._removeListener(el[i], sType, fn, capture) && ok ); |
| } |
| return ok; |
| } |
| |
| if (!fn || !fn.call) { |
| //return false; |
| return this.purgeElement(el, false, sType); |
| } |
| |
| if ("unload" == sType) { |
| |
| for (i=unloadListeners.length-1; i>-1; i--) { |
| li = unloadListeners[i]; |
| if (li && |
| li[0] == el && |
| li[1] == sType && |
| li[2] == fn) { |
| unloadListeners.splice(i, 1); |
| // unloadListeners[i]=null; |
| 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[4]; |
| |
| 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) { |
| // for (i in llist.length) { |
| li = llist[i]; |
| if (li && |
| li[this.EL] == el && |
| li[this.TYPE] == sType && |
| li[this.FN] == fn) { |
| llist.splice(i, 1); |
| // llist[i]=null; |
| break; |
| } |
| } |
| } |
| |
| } else { |
| try { |
| this._simpleRemove(el, sType, cacheItem[this.WFN], capture); |
| } 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); |
| // listeners[index]=null; |
| |
| return true; |
| |
| }, |
| |
| |
| /** |
| * Removes an event listener |
| * |
| * @method removeListener |
| * |
| * @param {String|HTMLElement|Array|NodeList} el An id, an element |
| * reference, or a collection of ids and/or elements to remove |
| * the listener from. |
| * @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) { |
| |
| return this._removeListener(el, sType, fn, false); |
| |
| }, |
| |
| |
| /** |
| * Returns the event's target element. Safari sometimes provides |
| * a text node, and this is automatically resolved to the text |
| * node's parent so that it behaves like other browsers. |
| * @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(n) { |
| try { |
| if (n && 3 == n.nodeType) { |
| return n.parentNode; |
| } |
| } catch(e) { } |
| |
| return n; |
| }, |
| |
| /** |
| * 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 |
| * @param {HTMLElement} boundEl the element the listener is attached to |
| * @return {Event} the event |
| * @static |
| */ |
| getEvent: function(e, boundEl) { |
| 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) { |
| var code = ev.keyCode || ev.charCode || 0; |
| |
| // webkit key normalization |
| if (YAHOO.env.ua.webkit && (code in webkitKeymap)) { |
| code = webkitKeymap[code]; |
| } |
| return code; |
| }, |
| |
| /** |
| * Locating the saved event handler data by function ref |
| * |
| * @method _getCacheIndex |
| * @static |
| * @private |
| */ |
| _getCacheIndex: function(el, sType, fn) { |
| for (var i=0, l=listeners.length; i<l; i=i+1) { |
| 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) { |
| try { |
| return ( o && // o is something |
| typeof o !== "string" && // o is not a string |
| o.length && // o is indexed |
| !o.tagName && // o is not an HTML element |
| !o.alert && // o is not a window |
| typeof o[0] !== "undefined" ); |
| } catch(ex) { |
| return false; |
| } |
| |
| }, |
| |
| /** |
| * @private |
| * @property elCache |
| * DOM element cache |
| * @static |
| * @deprecated Elements are not cached due to issues that arise when |
| * elements are removed and re-added |
| */ |
| 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 (typeof id === "string") ? document.getElementById(id) : 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(); |
| |
| // Available elements may not have been detected before the |
| // window load event fires. Try to find them now so that the |
| // the user is more likely to get the onAvailable notifications |
| // before the window load notification |
| EU._tryPreloadAttach(); |
| |
| } |
| }, |
| |
| /** |
| * Fires the DOMReady event listeners the first time the document is |
| * usable. |
| * @method _ready |
| * @static |
| * @private |
| */ |
| _ready: function(e) { |
| var EU = YAHOO.util.Event; |
| if (!EU.DOMReady) { |
| EU.DOMReady=true; |
| |
| // 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 (onAvailStack.length === 0) { |
| retryCount = 0; |
| clearInterval(this._interval); |
| this._interval = null; |
| return; |
| } |
| |
| if (this.locked) { |
| return; |
| } |
| |
| if (this.isIE) { |
| // Hold off if DOMReady has not fired and check current |
| // readyState to protect against the IE operation aborted |
| // issue. |
| if (!this.DOMReady) { |
| this.startInterval(); |
| return; |
| } |
| } |
| |
| 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 && onAvailStack.length > 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, ready=[]; |
| |
| // onAvailable onContentReady |
| for (i=0, len=onAvailStack.length; i<len; i=i+1) { |
| item = onAvailStack[i]; |
| if (item) { |
| el = this.getEl(item.id); |
| if (el) { |
| if (item.checkReady) { |
| if (loadComplete || el.nextSibling || !tryAgain) { |
| ready.push(item); |
| onAvailStack[i] = null; |
| } |
| } else { |
| executeItem(el, item); |
| onAvailStack[i] = null; |
| } |
| } else { |
| notAvail.push(item); |
| } |
| } |
| } |
| |
| // make sure onContentReady fires after onAvailable |
| for (i=0, len=ready.length; i<len; i=i+1) { |
| item = ready[i]; |
| executeItem(this.getEl(item.id), item); |
| } |
| |
| |
| retryCount--; |
| |
| if (tryAgain) { |
| for (i=onAvailStack.length-1; i>-1; i--) { |
| item = onAvailStack[i]; |
| if (!item || !item.id) { |
| onAvailStack.splice(i, 1); |
| } |
| } |
| |
| this.startInterval(); |
| } else { |
| clearInterval(this._interval); |
| this._interval = null; |
| } |
| |
| this.locked = false; |
| |
| }, |
| |
| /** |
| * 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 oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el; |
| var elListeners = this.getListeners(oEl, sType), i, len; |
| if (elListeners) { |
| for (i=elListeners.length-1; i>-1; i--) { |
| var l = elListeners[i]; |
| this._removeListener(oEl, l.type, l.fn, l.capture); |
| } |
| } |
| |
| if (recurse && oEl && oEl.childNodes) { |
| for (i=0,len=oEl.childNodes.length; i<len ; ++i) { |
| this.purgeElement(oEl.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|string} the element or element id 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: |
| * type: (string) the type of event |
| * fn: (function) the callback supplied to addListener |
| * obj: (object) the custom object supplied to addListener |
| * adjust: (boolean|object) whether or not to adjust the default scope |
| * scope: (boolean) the derived scope based on the adjust parameter |
| * scope: (capture) the capture parameter supplied to addListener |
| * 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]; |
| } |
| |
| var oEl = (YAHOO.lang.isString(el)) ? this.getEl(el) : el; |
| |
| for (var j=0;j<searchLists.length; j=j+1) { |
| var searchList = searchLists[j]; |
| if (searchList) { |
| for (var i=0,len=searchList.length; i<len ; ++i) { |
| var l = searchList[i]; |
| if ( l && l[this.EL] === oEl && |
| (!sType || sType === l[this.TYPE]) ) { |
| results.push({ |
| type: l[this.TYPE], |
| fn: l[this.FN], |
| obj: l[this.OBJ], |
| adjust: l[this.OVERRIDE], |
| scope: l[this.ADJ_SCOPE], |
| capture: l[this.CAPTURE], |
| 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, |
| ul = unloadListeners.slice(); |
| |
| // execute and clear stored unload listeners |
| for (i=0,len=unloadListeners.length; i<len; ++i) { |
| l = ul[i]; |
| if (l) { |
| var scope = window; |
| if (l[EU.ADJ_SCOPE]) { |
| if (l[EU.ADJ_SCOPE] === true) { |
| scope = l[EU.UNLOAD_OBJ]; |
| } else { |
| scope = l[EU.ADJ_SCOPE]; |
| } |
| } |
| l[EU.FN].call(scope, EU.getEvent(e, l[EU.EL]), l[EU.UNLOAD_OBJ] ); |
| ul[i] = null; |
| l=null; |
| scope=null; |
| } |
| } |
| |
| unloadListeners = null; |
| |
| // Remove listeners to handle IE memory leaks |
| //if (YAHOO.env.ua.ie && listeners && listeners.length > 0) { |
| |
| // 2.5.0 listeners are removed for all browsers again. FireFox preserves |
| // at least some listeners between page refreshes, potentially causing |
| // errors during page load (mouseover listeners firing before they |
| // should if the user moves the mouse at the correct moment). |
| if (listeners) { |
| for (j=listeners.length-1; j>-1; j--) { |
| l = listeners[j]; |
| if (l) { |
| EU._removeListener(l[EU.EL], l[EU.TYPE], l[EU.FN], l[EU.CAPTURE], j); |
| } |
| } |
| l=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 |
| * @static |
| * @deprecated still here for backwards compatibility |
| */ |
| 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; |
| |
| /** |
| * YAHOO.util.Event.onFocus is an alias for addFocusListener |
| * @method on |
| * @see addFocusListener |
| * @static |
| */ |
| EU.onFocus = EU.addFocusListener; |
| |
| /** |
| * YAHOO.util.Event.onBlur is an alias for addBlurListener |
| * @method onBlur |
| * @see addBlurListener |
| * @static |
| */ |
| EU.onBlur = EU.addBlurListener; |
| |
| |
| /*! 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) { |
| |
| // Process onAvailable/onContentReady items when the |
| // DOM is ready. |
| YAHOO.util.Event.onDOMReady( |
| YAHOO.util.Event._tryPreloadAttach, |
| YAHOO.util.Event, true); |
| |
| var n = document.createElement('p'); |
| |
| EU._dri = setInterval(function() { |
| try { |
| // throws an error if doc is not ready |
| n.doScroll('left'); |
| clearInterval(EU._dri); |
| EU._dri = null; |
| EU._ready(); |
| n = null; |
| } catch (ex) { |
| } |
| }, EU.POLL_INTERVAL); |
| |
| |
| // The document's readyState in Safari currently will |
| // change to loaded/complete before images are loaded. |
| } else if (EU.webkit && EU.webkit < 525) { |
| |
| EU._dri = setInterval(function() { |
| var rs=document.readyState; |
| if ("loaded" == rs || "complete" == rs) { |
| clearInterval(EU._dri); |
| EU._dri = null; |
| EU._ready(); |
| } |
| }, EU.POLL_INTERVAL); |
| |
| // FireFox and Opera: These browsers provide a event for this |
| // moment. The latest WebKit releases now support this event. |
| } 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 {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. If the type |
| * is not specified, it will attempt to remove |
| * the listener from all hosted events. |
| * @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 evts = this.__yui_events; |
| if (p_type) { |
| var ce = evts[p_type]; |
| if (ce) { |
| return ce.unsubscribe(p_fn, p_obj); |
| } |
| } else { |
| var ret = true; |
| for (var i in evts) { |
| if (YAHOO.lang.hasOwnProperty(evts, i)) { |
| ret = ret && evts[i].unsubscribe(p_fn, p_obj); |
| } |
| } |
| return ret; |
| } |
| |
| return false; |
| }, |
| |
| /** |
| * Removes all listeners from the specified event. If the event type |
| * is not specified, all listeners from all hosted custom events will |
| * be removed. |
| * @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); |
| |
| 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 |
| * |
| */ |
| fireEvent: function(p_type, arg1, arg2, etc) { |
| |
| this.__yui_events = this.__yui_events || {}; |
| var ce = this.__yui_events[p_type]; |
| |
| if (!ce) { |
| return null; |
| } |
| |
| var args = []; |
| for (var i=1; i<arguments.length; ++i) { |
| args.push(arguments[i]); |
| } |
| return ce.fire.apply(ce, args); |
| }, |
| |
| /** |
| * 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; |
| } |
| |
| }; |
| |
| //@TODO optimize |
| //@TODO use event utility, lang abstractions |
| //@TODO replace |
| |
| /** |
| * 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. |
| * |
| * @knownissue the "keypress" event is completely broken in Safari 2.x and below. |
| * the workaround is use "keydown" for key listening. However, if |
| * it is desired to prevent the default behavior of the keystroke, |
| * that can only be done on the keypress event. This makes key |
| * handling quite ugly. |
| * @knownissue keydown is also broken in Safari 2.x and below for the ESC key. |
| * There currently is no workaround other than choosing another |
| * key to listen for. |
| */ |
| 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; |
| |
| 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"; |
| |
| /** |
| * keycode constants for a subset of the special keys |
| * @property KEY |
| * @static |
| * @final |
| */ |
| YAHOO.util.KeyListener.KEY = { |
| ALT : 18, |
| BACK_SPACE : 8, |
| CAPS_LOCK : 20, |
| CONTROL : 17, |
| DELETE : 46, |
| DOWN : 40, |
| END : 35, |
| ENTER : 13, |
| ESCAPE : 27, |
| HOME : 36, |
| LEFT : 37, |
| META : 224, |
| NUM_LOCK : 144, |
| PAGE_DOWN : 34, |
| PAGE_UP : 33, |
| PAUSE : 19, |
| PRINTSCREEN : 44, |
| RIGHT : 39, |
| SCROLL_LOCK : 145, |
| SHIFT : 16, |
| SPACE : 32, |
| TAB : 9, |
| UP : 38 |
| }; |
| YAHOO.register("event", YAHOO.util.Event, {version: "2.6.0", build: "1321"}); |