/*
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 & lt ; string & gt ; , args & lt ; array & gt ; , customobject & lt ; object & gt ; < / 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 :
* & 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 | object ) whether or not to adjust the default scope
* & nbsp ; & nbsp ; scope : ( boolean ) the derived scope based on the adjust parameter
* & nbsp ; & nbsp ; scope : ( capture ) the capture parameter supplied to addListener
* & 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];
}
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" });
Messung V0.5 in Prozent C=70 H=93 G=82
¤ Dauer der Verarbeitung: 0.82 Sekunden
(vorverarbeitet am 2026-09-06)
¤
*© Formatika GbR, Deutschland