2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
9 * The CustomEvent class lets you define events for your application
10 * that can be subscribed to by one or more independent component.
12 * @param {String} type The type of event, which is passed to the callback
13 * when the event fires
14 * @param {Object} oScope The context the event will fire from. "this" will
15 * refer to this object in the callback. Default value:
16 * the window object. The listener can override this.
17 * @param {boolean} silent pass true to prevent the event from writing to
19 * @param {int} signature the signature that the custom event subscriber
20 * will receive. YAHOO.util.CustomEvent.LIST or
21 * YAHOO.util.CustomEvent.FLAT. The default is
22 * YAHOO.util.CustomEvent.LIST.
23 * @namespace YAHOO.util
27 YAHOO
.util
.CustomEvent = function(type
, oScope
, silent
, signature
) {
30 * The type of event, returned to subscribers when the event fires
37 * The scope the the event will fire from by default. Defaults to the window
42 this.scope
= oScope
|| window
;
45 * By default all custom events are logged in the debug build, set silent
46 * to true to disable debug outpu for this event.
53 * Custom events support two styles of arguments provided to the event
56 * <li>YAHOO.util.CustomEvent.LIST:
58 * <li>param1: event name</li>
59 * <li>param2: array of arguments sent to fire</li>
60 * <li>param3: <optional> a custom object supplied by the subscriber</li>
63 * <li>YAHOO.util.CustomEvent.FLAT
65 * <li>param1: the first argument passed to fire. If you need to
66 * pass multiple parameters, use and array or object literal</li>
67 * <li>param2: <optional> a custom object supplied by the subscriber</li>
74 this.signature
= signature
|| YAHOO
.util
.CustomEvent
.LIST
;
77 * The subscribers to this event
78 * @property subscribers
81 this.subscribers
= [];
86 var onsubscribeType
= "_YUICEOnSubscribe";
88 // Only add subscribe events for events that are not generated by
90 if (type
!== onsubscribeType
) {
93 * Custom events provide a custom event that fires whenever there is
94 * a new subscriber to the event. This provides an opportunity to
95 * handle the case where there is a non-repeating event that has
96 * already fired has a new subscriber.
98 * @event subscribeEvent
99 * @type YAHOO.util.CustomEvent
100 * @param {Function} fn The function to execute
101 * @param {Object} obj An object to be passed along when the event
103 * @param {boolean|Object} override If true, the obj passed in becomes
104 * the execution scope of the listener.
105 * if an object, that object becomes the
106 * the execution scope.
108 this.subscribeEvent
=
109 new YAHOO
.util
.CustomEvent(onsubscribeType
, this, true);
115 * Subscriber listener sigature constant. The LIST type returns three
116 * parameters: the event type, the array of args passed to fire, and
117 * the optional custom object
118 * @property YAHOO.util.CustomEvent.LIST
122 YAHOO
.util
.CustomEvent
.LIST
= 0;
125 * Subscriber listener sigature constant. The FLAT type returns two
126 * parameters: the first argument passed to fire and the optional
128 * @property YAHOO.util.CustomEvent.FLAT
132 YAHOO
.util
.CustomEvent
.FLAT
= 1;
134 YAHOO
.util
.CustomEvent
.prototype = {
137 * Subscribes the caller to this event
139 * @param {Function} fn The function to execute
140 * @param {Object} obj An object to be passed along when the event
142 * @param {boolean|Object} override If true, the obj passed in becomes
143 * the execution scope of the listener.
144 * if an object, that object becomes the
145 * the execution scope.
147 subscribe: function(fn
, obj
, override
) {
150 throw new Error("Invalid callback for subscriber to '" + this.type
+ "'");
153 if (this.subscribeEvent
) {
154 this.subscribeEvent
.fire(fn
, obj
, override
);
157 this.subscribers
.push( new YAHOO
.util
.Subscriber(fn
, obj
, override
) );
161 * Unsubscribes subscribers.
162 * @method unsubscribe
163 * @param {Function} fn The subscribed function to remove, if not supplied
164 * all will be removed
165 * @param {Object} obj The custom object passed to subscribe. This is
166 * optional, but if supplied will be used to
167 * disambiguate multiple listeners that are the same
168 * (e.g., you subscribe many object using a function
169 * that lives on the prototype)
170 * @return {boolean} True if the subscriber was found and detached.
172 unsubscribe: function(fn
, obj
) {
175 return this.unsubscribeAll();
179 for (var i
=0, len
=this.subscribers
.length
; i
<len
; ++i
) {
180 var s
= this.subscribers
[i
];
181 if (s
&& s
.contains(fn
, obj
)) {
191 * Notifies the subscribers. The callback functions will be executed
192 * from the scope specified when the event was created, and with the
193 * following parameters:
195 * <li>The type of event</li>
196 * <li>All of the arguments fire() was executed with as an array</li>
197 * <li>The custom object (if any) that was passed into the subscribe()
201 * @param {Object*} arguments an arbitrary set of parameters to pass to
203 * @return {boolean} false if one of the subscribers returned false,
207 var len
=this.subscribers
.length
;
208 if (!len
&& this.silent
) {
212 var args
=[], ret
=true, i
, rebuild
=false;
214 for (i
=0; i
<arguments
.length
; ++i
) {
215 args
.push(arguments
[i
]);
218 var argslength
= args
.length
;
223 for (i
=0; i
<len
; ++i
) {
224 var s
= this.subscribers
[i
];
231 var scope
= s
.getScope(this.scope
);
233 if (this.signature
== YAHOO
.util
.CustomEvent
.FLAT
) {
235 if (args
.length
> 0) {
238 ret
= s
.fn
.call(scope
, param
, s
.obj
);
240 ret
= s
.fn
.call(scope
, this.type
, args
, s
.obj
);
253 var newlist
=[],subs
=this.subscribers
;
254 for (i
=0,len
=subs
.length
; i
<len
; ++i
) {
256 newlist
.push(subs
[i
]);
259 this.subscribers
=newlist
;
266 * Removes all listeners
267 * @method unsubscribeAll
268 * @return {int} The number of listeners unsubscribed
270 unsubscribeAll: function() {
271 for (var i
=0, len
=this.subscribers
.length
; i
<len
; ++i
) {
272 this._delete(len
- 1 - i
);
284 _delete: function(index
) {
285 var s
= this.subscribers
[index
];
291 this.subscribers
[index
]=null;
297 toString: function() {
298 return "CustomEvent: " + "'" + this.type
+ "', " +
299 "scope: " + this.scope
;
304 /////////////////////////////////////////////////////////////////////
307 * Stores the subscriber information to be used when the event fires.
308 * @param {Function} fn The function to execute
309 * @param {Object} obj An object to be passed along when the event fires
310 * @param {boolean} override If true, the obj passed in becomes the execution
311 * scope of the listener
315 YAHOO
.util
.Subscriber = function(fn
, obj
, override
) {
318 * The callback that will be execute when the event fires
325 * An optional custom object that will passed to the callback when
330 this.obj
= YAHOO
.lang
.isUndefined(obj
) ? null : obj
;
333 * The default execution scope for the event listener is defined when the
334 * event is created (usually the object which contains the event).
335 * By setting override to true, the execution scope becomes the custom
336 * object passed in by the subscriber. If override is an object, that
337 * object becomes the scope.
339 * @type boolean|object
341 this.override
= override
;
346 * Returns the execution scope for this listener. If override was set to true
347 * the custom obj will be the scope. If override is an object, that is the
348 * scope, otherwise the default scope will be used.
350 * @param {Object} defaultScope the scope to use if this listener does not
353 YAHOO
.util
.Subscriber
.prototype.getScope = function(defaultScope
) {
355 if (this.override
=== true) {
358 return this.override
;
365 * Returns true if the fn and obj match this objects properties.
366 * Used by the unsubscribe method to match the right subscriber.
369 * @param {Function} fn the function to execute
370 * @param {Object} obj an object to be passed along when the event fires
371 * @return {boolean} true if the supplied arguments match this
372 * subscriber's signature.
374 YAHOO
.util
.Subscriber
.prototype.contains = function(fn
, obj
) {
376 return (this.fn
== fn
&& this.obj
== obj
);
378 return (this.fn
== fn
);
385 YAHOO
.util
.Subscriber
.prototype.toString = function() {
386 return "Subscriber { obj: " + this.obj
+
387 ", override: " + (this.override
|| "no") + " }";
391 * The Event Utility provides utilities for managing DOM Events and tools
392 * for building event systems
395 * @title Event Utility
396 * @namespace YAHOO.util
400 // The first instance of Event will win if it is loaded more than once.
401 // @TODO this needs to be changed so that only the state data that needs to
402 // be preserved is kept, while methods are overwritten/added as needed.
403 // This means that the module pattern can't be used.
404 if (!YAHOO
.util
.Event
) {
407 * The event utility provides functions to add and remove event listeners,
408 * event cleansing. It also tries to automatically remove listeners it
409 * registers during the unload event.
414 YAHOO
.util
.Event = function() {
417 * True after the onload event has fired
418 * @property loadComplete
423 var loadComplete
= false;
426 * True when the document is initially usable
432 var DOMReady
= false;
435 * Cache of wrapped listeners
436 * @property listeners
444 * User-defined unload function that will be fired before all events
446 * @property unloadListeners
451 var unloadListeners
= [];
454 * Cache of DOM0 event handlers to work around issues with DOM2 events
456 * @property legacyEvents
460 var legacyEvents
= [];
463 * Listener stack for DOM0 events
464 * @property legacyHandlers
468 var legacyHandlers
= [];
471 * The number of times to poll after window.onload. This number is
472 * increased if additional late-bound handlers are requested after
474 * @property retryCount
481 * onAvailable listeners
482 * @property onAvailStack
486 var onAvailStack
= [];
489 * Lookup table for legacy events
490 * @property legacyMap
497 * Counter for auto id generation
505 * Normalized keycodes for webkit/safari
506 * @property webkitKeymap
522 * The number of times we should look for elements that are not
523 * in the DOM at the time the event is requested after the document
524 * has been loaded. The default is 4000@amp;10 ms, so it will poll
525 * for 40 seconds or until all outstanding handlers are bound
526 * (whichever comes first).
527 * @property POLL_RETRYS
535 * The poll interval in milliseconds
536 * @property POLL_INTERVAL
544 * Element to bind, int constant
553 * Type of event, int constant
562 * Function to execute, int constant
571 * Function wrapped for scope correction and cleanup, int constant
580 * Object passed in by the user that will be returned as a
581 * parameter to the callback, int constant
590 * Adjusted scope, either the element we are registering the event
591 * on or the custom object passed in by the listener, int constant
592 * @property ADJ_SCOPE
600 * addListener/removeListener can throw errors in unexpected scenarios.
601 * These errors are suppressed, the method returns false, and this property
603 * @property lastError
614 * @deprecated use YAHOO.env.ua.webkit
616 isSafari
: YAHOO
.env
.ua
.webkit
,
624 * @deprecated use YAHOO.env.ua.webkit
626 webkit
: YAHOO
.env
.ua
.webkit
,
633 * @deprecated use YAHOO.env.ua.ie
635 isIE
: YAHOO
.env
.ua
.ie
,
639 * @property _interval
646 * @method startInterval
650 startInterval: function() {
651 if (!this._interval
) {
653 var callback = function() { self
._tryPreloadAttach(); };
654 this._interval
= setInterval(callback
, this.POLL_INTERVAL
);
659 * Executes the supplied callback when the item with the supplied
660 * id is found. This is meant to be used to execute behavior as
661 * soon as possible as the page loads. If you use this after the
662 * initial page load it will poll for a fixed time for the element.
663 * The number of times it will poll and the frequency are
664 * configurable. By default it will poll for 10 seconds.
666 * <p>The callback is executed with a single parameter:
667 * the custom object parameter, if provided.</p>
669 * @method onAvailable
671 * @param {string} p_id the id of the element to look for.
672 * @param {function} p_fn what to execute when the element is found.
673 * @param {object} p_obj an optional object to be passed back as
674 * a parameter to p_fn.
675 * @param {boolean|object} p_override If set to true, p_fn will execute
676 * in the scope of p_obj, if set to an object it
677 * will execute in the scope of that object
681 onAvailable: function(p_id
, p_fn
, p_obj
, p_override
) {
682 onAvailStack
.push( { id
: p_id
,
685 override
: p_override
,
686 checkReady
: false } );
687 retryCount
= this.POLL_RETRYS
;
688 this.startInterval();
692 * Executes the supplied callback when the DOM is first usable. This
693 * will execute immediately if called after the DOMReady event has
694 * fired. @todo the DOMContentReady event does not fire when the
695 * script is dynamically injected into the page. This means the
696 * DOMReady custom event will never fire in FireFox or Opera when the
697 * library is injected. It _will_ fire in Safari, and the IE
698 * implementation would allow for us to fire it if the defered script
699 * is not available. We want this to behave the same in all browsers.
700 * Is there a way to identify when the script has been injected
701 * instead of included inline? Is there a way to know whether the
702 * window onload event has fired without having had a listener attached
703 * to it when it did so?
705 * <p>The callback is a CustomEvent, so the signature is:</p>
706 * <p>type <string>, args <array>, customobject <object></p>
707 * <p>For DOMReady events, there are no fire argments, so the
709 * <p>"DOMReady", [], obj</p>
714 * @param {function} p_fn what to execute when the element is found.
715 * @param {object} p_obj an optional object to be passed back as
716 * a parameter to p_fn.
717 * @param {boolean|object} p_scope If set to true, p_fn will execute
718 * in the scope of p_obj, if set to an object it
719 * will execute in the scope of that object
723 onDOMReady: function(p_fn
, p_obj
, p_override
) {
725 setTimeout(function() {
728 if (p_override
=== true) {
734 p_fn
.call(s
, "DOMReady", [], p_obj
);
737 this.DOMReadyEvent
.subscribe(p_fn
, p_obj
, p_override
);
742 * Works the same way as onAvailable, but additionally checks the
743 * state of sibling elements to determine if the content of the
744 * available element is safe to modify.
746 * <p>The callback is executed with a single parameter:
747 * the custom object parameter, if provided.</p>
749 * @method onContentReady
751 * @param {string} p_id the id of the element to look for.
752 * @param {function} p_fn what to execute when the element is ready.
753 * @param {object} p_obj an optional object to be passed back as
754 * a parameter to p_fn.
755 * @param {boolean|object} p_override If set to true, p_fn will execute
756 * in the scope of p_obj. If an object, p_fn will
757 * exectute in the scope of that object
761 onContentReady: function(p_id
, p_fn
, p_obj
, p_override
) {
762 onAvailStack
.push( { id
: p_id
,
765 override
: p_override
,
766 checkReady
: true } );
768 retryCount
= this.POLL_RETRYS
;
769 this.startInterval();
773 * Appends an event handler
775 * @method addListener
777 * @param {String|HTMLElement|Array|NodeList} el An id, an element
778 * reference, or a collection of ids and/or elements to assign the
780 * @param {String} sType The type of event to append
781 * @param {Function} fn The method the event invokes
782 * @param {Object} obj An arbitrary object that will be
783 * passed as a parameter to the handler
784 * @param {Boolean|object} override If true, the obj passed in becomes
785 * the execution scope of the listener. If an
786 * object, this object becomes the execution
788 * @return {Boolean} True if the action was successful or defered,
789 * false if one or more of the elements
790 * could not have the listener attached,
791 * or if the operation throws an exception.
794 addListener: function(el
, sType
, fn
, obj
, override
) {
796 if (!fn
|| !fn
.call
) {
797 // throw new TypeError(sType + " addListener call failed, callback undefined");
801 // The el argument can be an array of elements or element ids.
802 if ( this._isValidCollection(el
)) {
804 for (var i
=0,len
=el
.length
; i
<len
; ++i
) {
813 } else if (YAHOO
.lang
.isString(el
)) {
814 var oEl
= this.getEl(el
);
815 // If the el argument is a string, we assume it is
816 // actually the id of the element. If the page is loaded
817 // we convert el to the actual element, otherwise we
818 // defer attaching the event until onload event fires
820 // check to see if we need to delay hooking up the event
821 // until after the page loads.
825 // defer adding the event until the element is available
826 this.onAvailable(el
, function() {
827 YAHOO
.util
.Event
.on(el
, sType
, fn
, obj
, override
);
834 // Element should be an html element or an array if we get
840 // we need to make sure we fire registered unload events
841 // prior to automatically unhooking them. So we hang on to
842 // these instead of attaching them to the window and fire the
843 // handles explicitly during our one unload event.
844 if ("unload" == sType
&& obj
!== this) {
845 unloadListeners
[unloadListeners
.length
] =
846 [el
, sType
, fn
, obj
, override
];
851 // if the user chooses to override the scope, we use the custom
852 // object passed in, otherwise the executing scope will be the
853 // HTML element that the event is registered on
856 if (override
=== true) {
863 // wrap the function so we can return the obj object when
865 var wrappedFn = function(e
) {
866 return fn
.call(scope
, YAHOO
.util
.Event
.getEvent(e
),
870 var li
= [el
, sType
, fn
, wrappedFn
, scope
];
871 var index
= listeners
.length
;
872 // cache the listener so we can try to automatically unload
873 listeners
[index
] = li
;
875 if (this.useLegacyEvent(el
, sType
)) {
876 var legacyIndex
= this.getLegacyIndex(el
, sType
);
878 // Add a new dom0 wrapper if one is not detected for this
880 if ( legacyIndex
== -1 ||
881 el
!= legacyEvents
[legacyIndex
][0] ) {
883 legacyIndex
= legacyEvents
.length
;
884 legacyMap
[el
.id
+ sType
] = legacyIndex
;
886 // cache the signature for the DOM0 event, and
887 // include the existing handler for the event, if any
888 legacyEvents
[legacyIndex
] =
889 [el
, sType
, el
["on" + sType
]];
890 legacyHandlers
[legacyIndex
] = [];
894 YAHOO
.util
.Event
.fireLegacyEvent(
895 YAHOO
.util
.Event
.getEvent(e
), legacyIndex
);
899 // add a reference to the wrapped listener to our custom
901 //legacyHandlers[legacyIndex].push(index);
902 legacyHandlers
[legacyIndex
].push(li
);
906 this._simpleAdd(el
, sType
, wrappedFn
, false);
908 // handle an error trying to attach an event. If it fails
909 // we need to clean up the cache
911 this.removeListener(el
, sType
, fn
);
921 * When using legacy events, the handler is routed to this object
922 * so we can fire our custom listener stack.
923 * @method fireLegacyEvent
927 fireLegacyEvent: function(e
, legacyIndex
) {
928 var ok
=true,le
,lh
,li
,scope
,ret
;
930 lh
= legacyHandlers
[legacyIndex
];
931 for (var i
=0,len
=lh
.length
; i
<len
; ++i
) {
933 if ( li
&& li
[this.WFN
] ) {
934 scope
= li
[this.ADJ_SCOPE
];
935 ret
= li
[this.WFN
].call(scope
, e
);
940 // Fire the original handler if we replaced one. We fire this
941 // after the other events to keep stopPropagation/preventDefault
942 // that happened in the DOM0 handler from touching our DOM2
944 le
= legacyEvents
[legacyIndex
];
953 * Returns the legacy event index that matches the supplied
955 * @method getLegacyIndex
959 getLegacyIndex: function(el
, sType
) {
960 var key
= this.generateId(el
) + sType
;
961 if (typeof legacyMap
[key
] == "undefined") {
964 return legacyMap
[key
];
969 * Logic that determines when we should automatically use legacy
970 * events instead of DOM2 events. Currently this is limited to old
971 * Safari browsers with a broken preventDefault
972 * @method useLegacyEvent
976 useLegacyEvent: function(el
, sType
) {
977 if (this.webkit
&& ("click"==sType
|| "dblclick"==sType
)) {
978 var v
= parseInt(this.webkit
, 10);
979 if (!isNaN(v
) && v
<418) {
987 * Removes an event listener
989 * @method removeListener
991 * @param {String|HTMLElement|Array|NodeList} el An id, an element
992 * reference, or a collection of ids and/or elements to remove
994 * @param {String} sType the type of event to remove.
995 * @param {Function} fn the method the event invokes. If fn is
996 * undefined, then all event handlers for the type of event are
998 * @return {boolean} true if the unbind was successful, false
1002 removeListener: function(el
, sType
, fn
) {
1005 // The el argument can be a string
1006 if (typeof el
== "string") {
1007 el
= this.getEl(el
);
1008 // The el argument can be an array of elements or element ids.
1009 } else if ( this._isValidCollection(el
)) {
1011 for (i
=0,len
=el
.length
; i
<len
; ++i
) {
1012 ok
= ( this.removeListener(el
[i
], sType
, fn
) && ok
);
1017 if (!fn
|| !fn
.call
) {
1019 return this.purgeElement(el
, false, sType
);
1022 if ("unload" == sType
) {
1024 for (i
=0, len
=unloadListeners
.length
; i
<len
; i
++) {
1025 var li
= unloadListeners
[i
];
1030 //unloadListeners.splice(i, 1);
1031 unloadListeners
[i
]=null;
1039 var cacheItem
= null;
1041 // The index is a hidden parameter; needed to remove it from
1042 // the method signature because it was tempting users to
1043 // try and take advantage of it, which is not possible.
1044 var index
= arguments
[3];
1046 if ("undefined" == typeof index
) {
1047 index
= this._getCacheIndex(el
, sType
, fn
);
1051 cacheItem
= listeners
[index
];
1054 if (!el
|| !cacheItem
) {
1059 if (this.useLegacyEvent(el
, sType
)) {
1060 var legacyIndex
= this.getLegacyIndex(el
, sType
);
1061 var llist
= legacyHandlers
[legacyIndex
];
1063 for (i
=0, len
=llist
.length
; i
<len
; ++i
) {
1066 li
[this.EL
] == el
&&
1067 li
[this.TYPE
] == sType
&&
1068 li
[this.FN
] == fn
) {
1069 //llist.splice(i, 1);
1078 this._simpleRemove(el
, sType
, cacheItem
[this.WFN
], false);
1080 this.lastError
= ex
;
1085 // removed the wrapped handler
1086 delete listeners
[index
][this.WFN
];
1087 delete listeners
[index
][this.FN
];
1088 //listeners.splice(index, 1);
1089 listeners
[index
]=null;
1096 * Returns the event's target element. Safari sometimes provides
1097 * a text node, and this is automatically resolved to the text
1098 * node's parent so that it behaves like other browsers.
1100 * @param {Event} ev the event
1101 * @param {boolean} resolveTextNode when set to true the target's
1102 * parent will be returned if the target is a
1103 * text node. @deprecated, the text node is
1104 * now resolved automatically
1105 * @return {HTMLElement} the event's target
1108 getTarget: function(ev
, resolveTextNode
) {
1109 var t
= ev
.target
|| ev
.srcElement
;
1110 return this.resolveTextNode(t
);
1114 * In some cases, some browsers will return a text node inside
1115 * the actual element that was targeted. This normalizes the
1116 * return value for getTarget and getRelatedTarget.
1117 * @method resolveTextNode
1118 * @param {HTMLElement} node node to resolve
1119 * @return {HTMLElement} the normized node
1122 resolveTextNode: function(node
) {
1123 if (node
&& 3 == node
.nodeType
) {
1124 return node
.parentNode
;
1131 * Returns the event's pageX
1133 * @param {Event} ev the event
1134 * @return {int} the event's pageX
1137 getPageX: function(ev
) {
1139 if (!x
&& 0 !== x
) {
1140 x
= ev
.clientX
|| 0;
1143 x
+= this._getScrollLeft();
1151 * Returns the event's pageY
1153 * @param {Event} ev the event
1154 * @return {int} the event's pageY
1157 getPageY: function(ev
) {
1159 if (!y
&& 0 !== y
) {
1160 y
= ev
.clientY
|| 0;
1163 y
+= this._getScrollTop();
1172 * Returns the pageX and pageY properties as an indexed array.
1174 * @param {Event} ev the event
1175 * @return {[x, y]} the pageX and pageY properties of the event
1178 getXY: function(ev
) {
1179 return [this.getPageX(ev
), this.getPageY(ev
)];
1183 * Returns the event's related target
1184 * @method getRelatedTarget
1185 * @param {Event} ev the event
1186 * @return {HTMLElement} the event's relatedTarget
1189 getRelatedTarget: function(ev
) {
1190 var t
= ev
.relatedTarget
;
1192 if (ev
.type
== "mouseout") {
1194 } else if (ev
.type
== "mouseover") {
1199 return this.resolveTextNode(t
);
1203 * Returns the time of the event. If the time is not included, the
1204 * event is modified using the current time.
1206 * @param {Event} ev the event
1207 * @return {Date} the time of the event
1210 getTime: function(ev
) {
1212 var t
= new Date().getTime();
1216 this.lastError
= ex
;
1225 * Convenience method for stopPropagation + preventDefault
1227 * @param {Event} ev the event
1230 stopEvent: function(ev
) {
1231 this.stopPropagation(ev
);
1232 this.preventDefault(ev
);
1236 * Stops event propagation
1237 * @method stopPropagation
1238 * @param {Event} ev the event
1241 stopPropagation: function(ev
) {
1242 if (ev
.stopPropagation
) {
1243 ev
.stopPropagation();
1245 ev
.cancelBubble
= true;
1250 * Prevents the default behavior of the event
1251 * @method preventDefault
1252 * @param {Event} ev the event
1255 preventDefault: function(ev
) {
1256 if (ev
.preventDefault
) {
1257 ev
.preventDefault();
1259 ev
.returnValue
= false;
1264 * Finds the event in the window object, the caller's arguments, or
1265 * in the arguments of another method in the callstack. This is
1266 * executed automatically for events registered through the event
1267 * manager, so the implementer should not normally need to execute
1268 * this function at all.
1270 * @param {Event} e the event parameter from the handler
1271 * @return {Event} the event
1274 getEvent: function(e
) {
1275 var ev
= e
|| window
.event
;
1278 var c
= this.getEvent
.caller
;
1280 ev
= c
.arguments
[0];
1281 if (ev
&& Event
== ev
.constructor) {
1292 * Returns the charcode for an event
1293 * @method getCharCode
1294 * @param {Event} ev the event
1295 * @return {int} the event's charCode
1298 getCharCode: function(ev
) {
1299 var code
= ev
.keyCode
|| ev
.charCode
|| 0;
1301 // webkit normalization
1302 if (YAHOO
.env
.ua
.webkit
&& (code
in webkitKeymap
)) {
1303 code
= webkitKeymap
[code
];
1309 * Locating the saved event handler data by function ref
1311 * @method _getCacheIndex
1315 _getCacheIndex: function(el
, sType
, fn
) {
1316 for (var i
=0,len
=listeners
.length
; i
<len
; ++i
) {
1317 var li
= listeners
[i
];
1319 li
[this.FN
] == fn
&&
1320 li
[this.EL
] == el
&&
1321 li
[this.TYPE
] == sType
) {
1330 * Generates an unique ID for the element if it does not already
1332 * @method generateId
1333 * @param el the element to create the id for
1334 * @return {string} the resulting id of the element
1337 generateId: function(el
) {
1341 id
= "yuievtautoid-" + counter
;
1351 * We want to be able to use getElementsByTagName as a collection
1352 * to attach a group of events to. Unfortunately, different
1353 * browsers return different types of collections. This function
1354 * tests to determine if the object is array-like. It will also
1355 * fail if the object is an array, but is empty.
1356 * @method _isValidCollection
1357 * @param o the object to test
1358 * @return {boolean} true if the object is array-like and populated
1362 _isValidCollection: function(o
) {
1364 return ( o
&& // o is something
1365 o
.length
&& // o is indexed
1366 typeof o
!= "string" && // o is not a string
1367 !o
.tagName
&& // o is not an HTML element
1368 !o
.alert
&& // o is not a window
1369 typeof o
[0] != "undefined" );
1381 * @deprecated Elements are not cached due to issues that arise when
1382 * elements are removed and re-added
1387 * We cache elements bound by id because when the unload event
1388 * fires, we can no longer use document.getElementById
1392 * @deprecated Elements are not cached any longer
1394 getEl: function(id
) {
1395 return document
.getElementById(id
);
1399 * Clears the element cache
1400 * @deprecated Elements are not cached any longer
1401 * @method clearCache
1405 clearCache: function() { },
1408 * Custom event the fires when the dom is initially usable
1409 * @event DOMReadyEvent
1411 DOMReadyEvent
: new YAHOO
.util
.CustomEvent("DOMReady", this),
1414 * hook up any deferred listeners
1419 _load: function(e
) {
1421 if (!loadComplete
) {
1422 loadComplete
= true;
1423 var EU
= YAHOO
.util
.Event
;
1425 // Just in case DOMReady did not go off for some reason
1428 // Available elements may not have been detected before the
1429 // window load event fires. Try to find them now so that the
1430 // the user is more likely to get the onAvailable notifications
1431 // before the window load notification
1432 EU
._tryPreloadAttach();
1434 // Remove the listener to assist with the IE memory issue, but not
1435 // for other browsers because FF 1.0x does not like it.
1437 //EU._simpleRemove(window, "load", EU._load);
1443 * Fires the DOMReady event listeners the first time the document is
1449 _ready: function(e
) {
1452 var EU
= YAHOO
.util
.Event
;
1454 // Fire the content ready custom event
1455 EU
.DOMReadyEvent
.fire();
1457 // Remove the DOMContentLoaded (FF/Opera)
1458 EU
._simpleRemove(document
, "DOMContentLoaded", EU
._ready
);
1463 * Polling function that runs before the onload event fires,
1464 * attempting to attach to DOM Nodes as soon as they are
1466 * @method _tryPreloadAttach
1470 _tryPreloadAttach: function() {
1477 // Hold off if DOMReady has not fired and check current
1478 // readyState to protect against the IE operation aborted
1480 //if (!DOMReady || "complete" !== document.readyState) {
1482 this.startInterval();
1490 // keep trying until after the page is loaded. We need to
1491 // check the page load state prior to trying to bind the
1492 // elements so that we can be certain all elements have been
1493 // tested appropriately
1494 var tryAgain
= !loadComplete
;
1496 tryAgain
= (retryCount
> 0);
1502 var executeItem = function (el
, item
) {
1504 if (item
.override
) {
1505 if (item
.override
=== true) {
1508 scope
= item
.override
;
1511 item
.fn
.call(scope
, item
.obj
);
1517 for (i
=0,len
=onAvailStack
.length
; i
<len
; ++i
) {
1518 item
= onAvailStack
[i
];
1519 if (item
&& !item
.checkReady
) {
1520 el
= this.getEl(item
.id
);
1522 executeItem(el
, item
);
1523 onAvailStack
[i
] = null;
1525 notAvail
.push(item
);
1531 for (i
=0,len
=onAvailStack
.length
; i
<len
; ++i
) {
1532 item
= onAvailStack
[i
];
1533 if (item
&& item
.checkReady
) {
1534 el
= this.getEl(item
.id
);
1537 // The element is available, but not necessarily ready
1538 // @todo should we test parentNode.nextSibling?
1539 if (loadComplete
|| el
.nextSibling
) {
1540 executeItem(el
, item
);
1541 onAvailStack
[i
] = null;
1544 notAvail
.push(item
);
1549 retryCount
= (notAvail
.length
=== 0) ? 0 : retryCount
- 1;
1552 // we may need to strip the nulled out items here
1553 this.startInterval();
1555 clearInterval(this._interval
);
1556 this._interval
= null;
1559 this.locked
= false;
1566 * Removes all listeners attached to the given element via addListener.
1567 * Optionally, the node's children can also be purged.
1568 * Optionally, you can specify a specific type of event to remove.
1569 * @method purgeElement
1570 * @param {HTMLElement} el the element to purge
1571 * @param {boolean} recurse recursively purge this element's children
1572 * as well. Use with caution.
1573 * @param {string} sType optional type of listener to purge. If
1574 * left out, all listeners will be removed
1577 purgeElement: function(el
, recurse
, sType
) {
1578 var elListeners
= this.getListeners(el
, sType
);
1580 for (var i
=0,len
=elListeners
.length
; i
<len
; ++i
) {
1581 var l
= elListeners
[i
];
1582 // can't use the index on the changing collection
1583 this.removeListener(el
, l
.type
, l
.fn
, l
.index
);
1584 //this.removeListener(el, l.type, l.fn);
1588 if (recurse
&& el
&& el
.childNodes
) {
1589 for (i
=0,len
=el
.childNodes
.length
; i
<len
; ++i
) {
1590 this.purgeElement(el
.childNodes
[i
], recurse
, sType
);
1596 * Returns all listeners attached to the given element via addListener.
1597 * Optionally, you can specify a specific type of event to return.
1598 * @method getListeners
1599 * @param el {HTMLElement} the element to inspect
1600 * @param sType {string} optional type of listener to return. If
1601 * left out, all listeners will be returned
1602 * @return {Object} the listener. Contains the following fields:
1603 * type: (string) the type of event
1604 * fn: (function) the callback supplied to addListener
1605 * obj: (object) the custom object supplied to addListener
1606 * adjust: (boolean) whether or not to adjust the default scope
1607 * index: (int) its position in the Event util listener cache
1610 getListeners: function(el
, sType
) {
1611 var results
=[], searchLists
;
1613 searchLists
= [listeners
, unloadListeners
];
1614 } else if (sType
== "unload") {
1615 searchLists
= [unloadListeners
];
1617 searchLists
= [listeners
];
1620 for (var j
=0;j
<searchLists
.length
; ++j
) {
1621 var searchList
= searchLists
[j
];
1622 if (searchList
&& searchList
.length
> 0) {
1623 for (var i
=0,len
=searchList
.length
; i
<len
; ++i
) {
1624 var l
= searchList
[i
];
1625 if ( l
&& l
[this.EL
] === el
&&
1626 (!sType
|| sType
=== l
[this.TYPE
]) ) {
1631 adjust
: l
[this.ADJ_SCOPE
],
1639 return (results
.length
) ? results
: null;
1643 * Removes all listeners registered by pe.event. Called
1644 * automatically during the unload event.
1649 _unload: function(e
) {
1651 var EU
= YAHOO
.util
.Event
, i
, j
, l
, len
, index
;
1653 for (i
=0,len
=unloadListeners
.length
; i
<len
; ++i
) {
1654 l
= unloadListeners
[i
];
1657 if (l
[EU
.ADJ_SCOPE
]) {
1658 if (l
[EU
.ADJ_SCOPE
] === true) {
1661 scope
= l
[EU
.ADJ_SCOPE
];
1664 l
[EU
.FN
].call(scope
, EU
.getEvent(e
), l
[EU
.OBJ
] );
1665 unloadListeners
[i
] = null;
1671 unloadListeners
= null;
1673 if (listeners
&& listeners
.length
> 0) {
1674 j
= listeners
.length
;
1677 l
= listeners
[index
];
1679 EU
.removeListener(l
[EU
.EL
], l
[EU
.TYPE
], l
[EU
.FN
], index
);
1688 for (i
=0,len
=legacyEvents
.length
; i
<len
; ++i
) {
1689 // dereference the element
1690 //delete legacyEvents[i][0];
1691 legacyEvents
[i
][0] = null;
1693 // delete the array item
1694 //delete legacyEvents[i];
1695 legacyEvents
[i
] = null;
1698 legacyEvents
= null;
1700 EU
._simpleRemove(window
, "unload", EU
._unload
);
1705 * Returns scrollLeft
1706 * @method _getScrollLeft
1710 _getScrollLeft: function() {
1711 return this._getScroll()[1];
1716 * @method _getScrollTop
1720 _getScrollTop: function() {
1721 return this._getScroll()[0];
1725 * Returns the scrollTop and scrollLeft. Used to calculate the
1726 * pageX and pageY in Internet Explorer
1727 * @method _getScroll
1731 _getScroll: function() {
1732 var dd
= document
.documentElement
, db
= document
.body
;
1733 if (dd
&& (dd
.scrollTop
|| dd
.scrollLeft
)) {
1734 return [dd
.scrollTop
, dd
.scrollLeft
];
1736 return [db
.scrollTop
, db
.scrollLeft
];
1743 * Used by old versions of CustomEvent, restored for backwards
1748 * @deprecated still here for backwards compatibility
1755 * Adds a DOM event directly without the caching, cleanup, scope adj, etc
1757 * @method _simpleAdd
1758 * @param {HTMLElement} el the element to bind the handler to
1759 * @param {string} sType the type of event handler
1760 * @param {function} fn the callback to invoke
1761 * @param {boolen} capture capture or bubble phase
1765 _simpleAdd: function () {
1766 if (window
.addEventListener
) {
1767 return function(el
, sType
, fn
, capture
) {
1768 el
.addEventListener(sType
, fn
, (capture
));
1770 } else if (window
.attachEvent
) {
1771 return function(el
, sType
, fn
, capture
) {
1772 el
.attachEvent("on" + sType
, fn
);
1775 return function(){};
1780 * Basic remove listener
1782 * @method _simpleRemove
1783 * @param {HTMLElement} el the element to bind the handler to
1784 * @param {string} sType the type of event handler
1785 * @param {function} fn the callback to invoke
1786 * @param {boolen} capture capture or bubble phase
1790 _simpleRemove: function() {
1791 if (window
.removeEventListener
) {
1792 return function (el
, sType
, fn
, capture
) {
1793 el
.removeEventListener(sType
, fn
, (capture
));
1795 } else if (window
.detachEvent
) {
1796 return function (el
, sType
, fn
) {
1797 el
.detachEvent("on" + sType
, fn
);
1800 return function(){};
1808 var EU
= YAHOO
.util
.Event
;
1811 * YAHOO.util.Event.on is an alias for addListener
1816 EU
.on
= EU
.addListener
;
1818 /////////////////////////////////////////////////////////////
1820 // based on work by: Dean Edwards/John Resig/Matthias Miller
1822 // Internet Explorer: use the readyState of a defered script.
1823 // This isolates what appears to be a safe moment to manipulate
1824 // the DOM prior to when the document's readyState suggests
1825 // it is safe to do so.
1828 // Process onAvailable/onContentReady items when when the
1830 YAHOO
.util
.Event
.onDOMReady(
1831 YAHOO
.util
.Event
._tryPreloadAttach
,
1832 YAHOO
.util
.Event
, true);
1835 var el
, d
=document
, b
=d
.body
;
1837 // If the library is being injected after window.onload, it
1838 // is not safe to document.write the script tag. Detecting
1839 // this state doesn't appear possible, so we expect a flag
1840 // in YAHOO_config to be set if the library is being injected.
1841 if (("undefined" !== typeof YAHOO_config
) && YAHOO_config
.injecting
) {
1844 //var dr = d.readyState;
1845 //if ("complete" === dr || "interactive" === dr) {
1846 //YAHOO.util.Event._ready();
1847 //YAHOO.util.Event._tryPreloadAttach();
1850 el
= document
.createElement("script");
1851 var p
=d
.getElementsByTagName("head")[0] || b
;
1852 p
.insertBefore(el
, p
.firstChild
);
1857 d
.write('<scr'+'ipt id="_yui_eu_dr" defer="true" src="//:"><'+'/script>');
1858 el
=document
.getElementById("_yui_eu_dr");
1863 el
.onreadystatechange = function() {
1864 if ("complete" === this.readyState
) {
1865 this.parentNode
.removeChild(this);
1866 YAHOO
.util
.Event
._ready();
1870 // The library was likely injected into the page
1871 // rendering onDOMReady unreliable
1872 // YAHOO.util.Event._ready();
1878 // Safari: The document's readyState in Safari currently will
1879 // change to loaded/complete before images are loaded.
1880 //} else if (EU.webkit) {
1881 } else if (EU
.webkit
) {
1883 EU
._drwatch
= setInterval(function(){
1884 var rs
=document
.readyState
;
1885 if ("loaded" == rs
|| "complete" == rs
) {
1886 clearInterval(EU
._drwatch
);
1890 }, EU
.POLL_INTERVAL
);
1892 // FireFox and Opera: These browsers provide a event for this
1896 // @todo will this fire when the library is injected?
1898 EU
._simpleAdd(document
, "DOMContentLoaded", EU
._ready
);
1901 /////////////////////////////////////////////////////////////
1904 EU
._simpleAdd(window
, "load", EU
._load
);
1905 EU
._simpleAdd(window
, "unload", EU
._unload
);
1906 EU
._tryPreloadAttach();
1911 * EventProvider is designed to be used with YAHOO.augment to wrap
1912 * CustomEvents in an interface that allows events to be subscribed to
1913 * and fired by name. This makes it possible for implementing code to
1914 * subscribe to an event that either has not been created yet, or will
1915 * not be created at all.
1917 * @Class EventProvider
1919 YAHOO
.util
.EventProvider = function() { };
1921 YAHOO
.util
.EventProvider
.prototype = {
1924 * Private storage of custom events
1925 * @property __yui_events
1932 * Private storage of custom event subscribers
1933 * @property __yui_subscribers
1937 __yui_subscribers
: null,
1940 * Subscribe to a CustomEvent by event type
1943 * @param p_type {string} the type, or name of the event
1944 * @param p_fn {function} the function to exectute when the event fires
1945 * @param p_obj {Object} An object to be passed along when the event
1947 * @param p_override {boolean} If true, the obj passed in becomes the
1948 * execution scope of the listener
1950 subscribe: function(p_type
, p_fn
, p_obj
, p_override
) {
1952 this.__yui_events
= this.__yui_events
|| {};
1953 var ce
= this.__yui_events
[p_type
];
1956 ce
.subscribe(p_fn
, p_obj
, p_override
);
1958 this.__yui_subscribers
= this.__yui_subscribers
|| {};
1959 var subs
= this.__yui_subscribers
;
1960 if (!subs
[p_type
]) {
1964 { fn
: p_fn
, obj
: p_obj
, override
: p_override
} );
1969 * Unsubscribes one or more listeners the from the specified event
1970 * @method unsubscribe
1971 * @param p_type {string} The type, or name of the event. If the type
1972 * is not specified, it will attempt to remove
1973 * the listener from all hosted events.
1974 * @param p_fn {Function} The subscribed function to unsubscribe, if not
1975 * supplied, all subscribers will be removed.
1976 * @param p_obj {Object} The custom object passed to subscribe. This is
1977 * optional, but if supplied will be used to
1978 * disambiguate multiple listeners that are the same
1979 * (e.g., you subscribe many object using a function
1980 * that lives on the prototype)
1981 * @return {boolean} true if the subscriber was found and detached.
1983 unsubscribe: function(p_type
, p_fn
, p_obj
) {
1984 this.__yui_events
= this.__yui_events
|| {};
1985 var evts
= this.__yui_events
;
1987 var ce
= evts
[p_type
];
1989 return ce
.unsubscribe(p_fn
, p_obj
);
1992 for (var i
in evts
) {
1994 if (YAHOO
.lang
.hasOwnProperty(evts
, i
)) {
1995 ret
= ret
&& evts
[i
].unsubscribe(p_fn
, p_obj
);
2005 * Removes all listeners from the specified event. If the event type
2006 * is not specified, all listeners from all hosted custom events will
2008 * @method unsubscribeAll
2009 * @param p_type {string} The type, or name of the event
2011 unsubscribeAll: function(p_type
) {
2012 return this.unsubscribe(p_type
);
2016 * Creates a new custom event of the specified type. If a custom event
2017 * by that name already exists, it will not be re-created. In either
2018 * case the custom event is returned.
2020 * @method createEvent
2022 * @param p_type {string} the type, or name of the event
2023 * @param p_config {object} optional config params. Valid properties are:
2027 * scope: defines the default execution scope. If not defined
2028 * the default scope will be this instance.
2031 * silent: if true, the custom event will not generate log messages.
2032 * This is false by default.
2035 * onSubscribeCallback: specifies a callback to execute when the
2036 * event has a new subscriber. This will fire immediately for
2037 * each queued subscriber if any exist prior to the creation of
2042 * @return {CustomEvent} the custom event
2045 createEvent: function(p_type
, p_config
) {
2047 this.__yui_events
= this.__yui_events
|| {};
2048 var opts
= p_config
|| {};
2049 var events
= this.__yui_events
;
2051 if (events
[p_type
]) {
2054 var scope
= opts
.scope
|| this;
2055 var silent
= (opts
.silent
);
2057 var ce
= new YAHOO
.util
.CustomEvent(p_type
, scope
, silent
,
2058 YAHOO
.util
.CustomEvent
.FLAT
);
2059 events
[p_type
] = ce
;
2061 if (opts
.onSubscribeCallback
) {
2062 ce
.subscribeEvent
.subscribe(opts
.onSubscribeCallback
);
2065 this.__yui_subscribers
= this.__yui_subscribers
|| {};
2066 var qs
= this.__yui_subscribers
[p_type
];
2069 for (var i
=0; i
<qs
.length
; ++i
) {
2070 ce
.subscribe(qs
[i
].fn
, qs
[i
].obj
, qs
[i
].override
);
2075 return events
[p_type
];
2080 * Fire a custom event by name. The callback functions will be executed
2081 * from the scope specified when the event was created, and with the
2082 * following parameters:
2084 * <li>The first argument fire() was executed with</li>
2085 * <li>The custom object (if any) that was passed into the subscribe()
2088 * If the custom event has not been explicitly created, it will be
2089 * created now with the default config, scoped to the host object
2091 * @param p_type {string} the type, or name of the event
2092 * @param arguments {Object*} an arbitrary set of parameters to pass to
2094 * @return {boolean} the return value from CustomEvent.fire
2097 fireEvent: function(p_type
, arg1
, arg2
, etc
) {
2099 this.__yui_events
= this.__yui_events
|| {};
2100 var ce
= this.__yui_events
[p_type
];
2107 for (var i
=1; i
<arguments
.length
; ++i
) {
2108 args
.push(arguments
[i
]);
2110 return ce
.fire
.apply(ce
, args
);
2114 * Returns true if the custom event of the provided type has been created
2117 * @param type {string} the type, or name of the event
2119 hasEvent: function(type
) {
2120 if (this.__yui_events
) {
2121 if (this.__yui_events
[type
]) {
2131 * KeyListener is a utility that provides an easy interface for listening for
2132 * keydown/keyup events fired against DOM elements.
2133 * @namespace YAHOO.util
2134 * @class KeyListener
2136 * @param {HTMLElement} attachTo The element or element ID to which the key
2137 * event should be attached
2138 * @param {String} attachTo The element or element ID to which the key
2139 * event should be attached
2140 * @param {Object} keyData The object literal representing the key(s)
2141 * to detect. Possible attributes are
2142 * shift(boolean), alt(boolean), ctrl(boolean)
2143 * and keys(either an int or an array of ints
2144 * representing keycodes).
2145 * @param {Function} handler The CustomEvent handler to fire when the
2146 * key event is detected
2147 * @param {Object} handler An object literal representing the handler.
2148 * @param {String} event Optional. The event (keydown or keyup) to
2149 * listen for. Defaults automatically to keydown.
2151 * @knownissue the "keypress" event is completely broken in Safari 2.x and below.
2152 * the workaround is use "keydown" for key listening. However, if
2153 * it is desired to prevent the default behavior of the keystroke,
2154 * that can only be done on the keypress event. This makes key
2155 * handling quite ugly.
2156 * @knownissue keydown is also broken in Safari 2.x and below for the ESC key.
2157 * There currently is no workaround other than choosing another
2158 * key to listen for.
2160 YAHOO
.util
.KeyListener = function(attachTo
, keyData
, handler
, event
) {
2162 } else if (!keyData
) {
2163 } else if (!handler
) {
2167 event
= YAHOO
.util
.KeyListener
.KEYDOWN
;
2171 * The CustomEvent fired internally when a key is pressed
2174 * @param {Object} keyData The object literal representing the key(s) to
2175 * detect. Possible attributes are shift(boolean),
2176 * alt(boolean), ctrl(boolean) and keys(either an
2177 * int or an array of ints representing keycodes).
2179 var keyEvent
= new YAHOO
.util
.CustomEvent("keyPressed");
2182 * The CustomEvent fired when the KeyListener is enabled via the enable()
2184 * @event enabledEvent
2185 * @param {Object} keyData The object literal representing the key(s) to
2186 * detect. Possible attributes are shift(boolean),
2187 * alt(boolean), ctrl(boolean) and keys(either an
2188 * int or an array of ints representing keycodes).
2190 this.enabledEvent
= new YAHOO
.util
.CustomEvent("enabled");
2193 * The CustomEvent fired when the KeyListener is disabled via the
2194 * disable() function
2195 * @event disabledEvent
2196 * @param {Object} keyData The object literal representing the key(s) to
2197 * detect. Possible attributes are shift(boolean),
2198 * alt(boolean), ctrl(boolean) and keys(either an
2199 * int or an array of ints representing keycodes).
2201 this.disabledEvent
= new YAHOO
.util
.CustomEvent("disabled");
2203 if (typeof attachTo
== 'string') {
2204 attachTo
= document
.getElementById(attachTo
);
2207 if (typeof handler
== 'function') {
2208 keyEvent
.subscribe(handler
);
2210 keyEvent
.subscribe(handler
.fn
, handler
.scope
, handler
.correctScope
);
2214 * Handles the key event when a key is pressed.
2215 * @method handleKeyPress
2216 * @param {DOMEvent} e The keypress DOM event
2217 * @param {Object} obj The DOM event scope object
2220 function handleKeyPress(e
, obj
) {
2221 if (! keyData
.shift
) {
2222 keyData
.shift
= false;
2224 if (! keyData
.alt
) {
2225 keyData
.alt
= false;
2227 if (! keyData
.ctrl
) {
2228 keyData
.ctrl
= false;
2231 // check held down modifying keys first
2232 if (e
.shiftKey
== keyData
.shift
&&
2233 e
.altKey
== keyData
.alt
&&
2234 e
.ctrlKey
== keyData
.ctrl
) { // if we pass this, all modifiers match
2239 if (keyData
.keys
instanceof Array
) {
2240 for (var i
=0;i
<keyData
.keys
.length
;i
++) {
2241 dataItem
= keyData
.keys
[i
];
2243 if (dataItem
== e
.charCode
) {
2244 keyEvent
.fire(e
.charCode
, e
);
2246 } else if (dataItem
== e
.keyCode
) {
2247 keyEvent
.fire(e
.keyCode
, e
);
2252 dataItem
= keyData
.keys
;
2253 if (dataItem
== e
.charCode
) {
2254 keyEvent
.fire(e
.charCode
, e
);
2255 } else if (dataItem
== e
.keyCode
) {
2256 keyEvent
.fire(e
.keyCode
, e
);
2263 * Enables the KeyListener by attaching the DOM event listeners to the
2264 * target DOM element
2267 this.enable = function() {
2268 if (! this.enabled
) {
2269 YAHOO
.util
.Event
.addListener(attachTo
, event
, handleKeyPress
);
2270 this.enabledEvent
.fire(keyData
);
2273 * Boolean indicating the enabled/disabled state of the Tooltip
2277 this.enabled
= true;
2281 * Disables the KeyListener by removing the DOM event listeners from the
2282 * target DOM element
2285 this.disable = function() {
2287 YAHOO
.util
.Event
.removeListener(attachTo
, event
, handleKeyPress
);
2288 this.disabledEvent
.fire(keyData
);
2290 this.enabled
= false;
2294 * Returns a String representation of the object.
2296 * @return {String} The string representation of the KeyListener
2298 this.toString = function() {
2299 return "KeyListener [" + keyData
.keys
+ "] " + attachTo
.tagName
+
2300 (attachTo
.id
? "[" + attachTo
.id
+ "]" : "");
2306 * Constant representing the DOM "keydown" event.
2307 * @property YAHOO.util.KeyListener.KEYDOWN
2312 YAHOO
.util
.KeyListener
.KEYDOWN
= "keydown";
2315 * Constant representing the DOM "keyup" event.
2316 * @property YAHOO.util.KeyListener.KEYUP
2321 YAHOO
.util
.KeyListener
.KEYUP
= "keyup";
2322 YAHOO
.register("event", YAHOO
.util
.Event
, {version
: "2.3.0", build
: "442"});