Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / EventManager.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-EventManager'>/**
2 </span> * @class Ext.EventManager
3  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
4  * several useful events directly.
5  * See {@link Ext.EventObject} for more details on normalized event objects.
6  * @singleton
7  */
8 Ext.EventManager = {
9
10     // --------------------- onReady ---------------------
11
12 <span id='Ext-EventManager-property-hasBoundOnReady'>    /**
13 </span>     * Check if we have bound our global onReady listener
14      * @private
15      */
16     hasBoundOnReady: false,
17
18 <span id='Ext-EventManager-property-hasFiredReady'>    /**
19 </span>     * Check if fireDocReady has been called
20      * @private
21      */
22     hasFiredReady: false,
23
24 <span id='Ext-EventManager-property-readyTimeout'>    /**
25 </span>     * Timer for the document ready event in old IE versions
26      * @private
27      */
28     readyTimeout: null,
29
30 <span id='Ext-EventManager-property-hasOnReadyStateChange'>    /**
31 </span>     * Checks if we have bound an onreadystatechange event
32      * @private
33      */
34     hasOnReadyStateChange: false,
35
36 <span id='Ext-EventManager-property-readyEvent'>    /**
37 </span>     * Holds references to any onReady functions
38      * @private
39      */
40     readyEvent: new Ext.util.Event(),
41
42 <span id='Ext-EventManager-method-checkReadyState'>    /**
43 </span>     * Check the ready state for old IE versions
44      * @private
45      * @return {Boolean} True if the document is ready
46      */
47     checkReadyState: function(){
48         var me = Ext.EventManager;
49
50         if(window.attachEvent){
51             // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
52             if (window != top) {
53                 return false;
54             }
55             try{
56                 document.documentElement.doScroll('left');
57             }catch(e){
58                 return false;
59             }
60             me.fireDocReady();
61             return true;
62         }
63         if (document.readyState == 'complete') {
64             me.fireDocReady();
65             return true;
66         }
67         me.readyTimeout = setTimeout(arguments.callee, 2);
68         return false;
69     },
70
71 <span id='Ext-EventManager-method-bindReadyEvent'>    /**
72 </span>     * Binds the appropriate browser event for checking if the DOM has loaded.
73      * @private
74      */
75     bindReadyEvent: function(){
76         var me = Ext.EventManager;
77         if (me.hasBoundOnReady) {
78             return;
79         }
80
81         if (document.addEventListener) {
82             document.addEventListener('DOMContentLoaded', me.fireDocReady, false);
83             // fallback, load will ~always~ fire
84             window.addEventListener('load', me.fireDocReady, false);
85         } else {
86             // check if the document is ready, this will also kick off the scroll checking timer
87             if (!me.checkReadyState()) {
88                 document.attachEvent('onreadystatechange', me.checkReadyState);
89                 me.hasOnReadyStateChange = true;
90             }
91             // fallback, onload will ~always~ fire
92             window.attachEvent('onload', me.fireDocReady, false);
93         }
94         me.hasBoundOnReady = true;
95     },
96
97 <span id='Ext-EventManager-method-fireDocReady'>    /**
98 </span>     * We know the document is loaded, so trigger any onReady events.
99      * @private
100      */
101     fireDocReady: function(){
102         var me = Ext.EventManager;
103
104         // only unbind these events once
105         if (!me.hasFiredReady) {
106             me.hasFiredReady = true;
107
108             if (document.addEventListener) {
109                 document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);
110                 window.removeEventListener('load', me.fireDocReady, false);
111             } else {
112                 if (me.readyTimeout !== null) {
113                     clearTimeout(me.readyTimeout);
114                 }
115                 if (me.hasOnReadyStateChange) {
116                     document.detachEvent('onreadystatechange', me.checkReadyState);
117                 }
118                 window.detachEvent('onload', me.fireDocReady);
119             }
120             Ext.supports.init();
121         }
122         if (!Ext.isReady) {
123             Ext.isReady = true;
124             me.onWindowUnload();
125             me.readyEvent.fire();
126         }
127     },
128
129 <span id='Ext-EventManager-method-onDocumentReady'>    /**
130 </span>     * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
131      * accessed shorthanded as Ext.onReady().
132      * @param {Function} fn The method the event invokes.
133      * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the handler function executes. Defaults to the browser window.
134      * @param {boolean} options (optional) Options object as passed to {@link Ext.core.Element#addListener}.
135      */
136     onDocumentReady: function(fn, scope, options){
137         options = options || {};
138         var me = Ext.EventManager,
139             readyEvent = me.readyEvent;
140
141         // force single to be true so our event is only ever fired once.
142         options.single = true;
143
144         // Document already loaded, let's just fire it
145         if (Ext.isReady) {
146             readyEvent.addListener(fn, scope, options);
147             readyEvent.fire();
148         } else {
149             options.delay = options.delay || 1;
150             readyEvent.addListener(fn, scope, options);
151             me.bindReadyEvent();
152         }
153     },
154
155
156     // --------------------- event binding ---------------------
157
158 <span id='Ext-EventManager-property-stoppedMouseDownEvent'>    /**
159 </span>     * Contains a list of all document mouse downs, so we can ensure they fire even when stopEvent is called.
160      * @private
161      */
162     stoppedMouseDownEvent: new Ext.util.Event(),
163
164 <span id='Ext-EventManager-property-propRe'>    /**
165 </span>     * Options to parse for the 4th argument to addListener.
166      * @private
167      */
168     propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,
169
170 <span id='Ext-EventManager-method-getId'>    /**
171 </span>     * Get the id of the element. If one has not been assigned, automatically assign it.
172      * @param {Mixed} element The element to get the id for.
173      * @return {String} id
174      */
175     getId : function(element) {
176         var skipGarbageCollection = false,
177             id;
178     
179         element = Ext.getDom(element);
180     
181         if (element === document || element === window) {
182             id = element === document ? Ext.documentId : Ext.windowId;
183         }
184         else {
185             id = Ext.id(element);
186         }
187         // skip garbage collection for special elements (window, document, iframes)
188         if (element &amp;&amp; (element.getElementById || element.navigator)) {
189             skipGarbageCollection = true;
190         }
191     
192         if (!Ext.cache[id]){
193             Ext.core.Element.addToCache(new Ext.core.Element(element), id);
194             if (skipGarbageCollection) {
195                 Ext.cache[id].skipGarbageCollection = true;
196             }
197         }
198         return id;
199     },
200
201 <span id='Ext-EventManager-method-prepareListenerConfig'>    /**
202 </span>     * Convert a &quot;config style&quot; listener into a set of flat arguments so they can be passed to addListener
203      * @private
204      * @param {Object} element The element the event is for
205      * @param {Object} event The event configuration
206      * @param {Object} isRemove True if a removal should be performed, otherwise an add will be done.
207      */
208     prepareListenerConfig: function(element, config, isRemove){
209         var me = this,
210             propRe = me.propRe,
211             key, value, args;
212
213         // loop over all the keys in the object
214         for (key in config) {
215             if (config.hasOwnProperty(key)) {
216                 // if the key is something else then an event option
217                 if (!propRe.test(key)) {
218                     value = config[key];
219                     // if the value is a function it must be something like click: function(){}, scope: this
220                     // which means that there might be multiple event listeners with shared options
221                     if (Ext.isFunction(value)) {
222                         // shared options
223                         args = [element, key, value, config.scope, config];
224                     } else {
225                         // if its not a function, it must be an object like click: {fn: function(){}, scope: this}
226                         args = [element, key, value.fn, value.scope, value];
227                     }
228
229                     if (isRemove === true) {
230                         me.removeListener.apply(this, args);
231                     } else {
232                         me.addListener.apply(me, args);
233                     }
234                 }
235             }
236         }
237     },
238
239 <span id='Ext-EventManager-method-normalizeEvent'>    /**
240 </span>     * Normalize cross browser event differences
241      * @private
242      * @param {Object} eventName The event name
243      * @param {Object} fn The function to execute
244      * @return {Object} The new event name/function
245      */
246     normalizeEvent: function(eventName, fn){
247         if (/mouseenter|mouseleave/.test(eventName) &amp;&amp; !Ext.supports.MouseEnterLeave) {
248             if (fn) {
249                 fn = Ext.Function.createInterceptor(fn, this.contains, this);
250             }
251             eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
252         } else if (eventName == 'mousewheel' &amp;&amp; !Ext.supports.MouseWheel &amp;&amp; !Ext.isOpera){
253             eventName = 'DOMMouseScroll';
254         }
255         return {
256             eventName: eventName,
257             fn: fn
258         };
259     },
260
261 <span id='Ext-EventManager-method-contains'>    /**
262 </span>     * Checks whether the event's relatedTarget is contained inside (or &lt;b&gt;is&lt;/b&gt;) the element.
263      * @private
264      * @param {Object} event
265      */
266     contains: function(event){
267         var parent = event.browserEvent.currentTarget,
268             child = this.getRelatedTarget(event);
269
270         if (parent &amp;&amp; parent.firstChild) {
271             while (child) {
272                 if (child === parent) {
273                     return false;
274                 }
275                 child = child.parentNode;
276                 if (child &amp;&amp; (child.nodeType != 1)) {
277                     child = null;
278                 }
279             }
280         }
281         return true;
282     },
283
284 <span id='Ext-EventManager-method-addListener'>    /**
285 </span>    * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
286     * use {@link Ext.core.Element#addListener} directly on an Element in favor of calling this version.
287     * @param {String/HTMLElement} el The html element or id to assign the event handler to.
288     * @param {String} eventName The name of the event to listen for.
289     * @param {Function} handler The handler function the event invokes. This function is passed
290     * the following parameters:&lt;ul&gt;
291     * &lt;li&gt;evt : EventObject&lt;div class=&quot;sub-desc&quot;&gt;The {@link Ext.EventObject EventObject} describing the event.&lt;/div&gt;&lt;/li&gt;
292     * &lt;li&gt;t : Element&lt;div class=&quot;sub-desc&quot;&gt;The {@link Ext.core.Element Element} which was the target of the event.
293     * Note that this may be filtered by using the &lt;tt&gt;delegate&lt;/tt&gt; option.&lt;/div&gt;&lt;/li&gt;
294     * &lt;li&gt;o : Object&lt;div class=&quot;sub-desc&quot;&gt;The options object from the addListener call.&lt;/div&gt;&lt;/li&gt;
295     * &lt;/ul&gt;
296     * @param {Object} scope (optional) The scope (&lt;b&gt;&lt;code&gt;this&lt;/code&gt;&lt;/b&gt; reference) in which the handler function is executed. &lt;b&gt;Defaults to the Element&lt;/b&gt;.
297     * @param {Object} options (optional) An object containing handler configuration properties.
298     * This may contain any of the following properties:&lt;ul&gt;
299     * &lt;li&gt;scope : Object&lt;div class=&quot;sub-desc&quot;&gt;The scope (&lt;b&gt;&lt;code&gt;this&lt;/code&gt;&lt;/b&gt; reference) in which the handler function is executed. &lt;b&gt;Defaults to the Element&lt;/b&gt;.&lt;/div&gt;&lt;/li&gt;
300     * &lt;li&gt;delegate : String&lt;div class=&quot;sub-desc&quot;&gt;A simple selector to filter the target or look for a descendant of the target&lt;/div&gt;&lt;/li&gt;
301     * &lt;li&gt;stopEvent : Boolean&lt;div class=&quot;sub-desc&quot;&gt;True to stop the event. That is stop propagation, and prevent the default action.&lt;/div&gt;&lt;/li&gt;
302     * &lt;li&gt;preventDefault : Boolean&lt;div class=&quot;sub-desc&quot;&gt;True to prevent the default action&lt;/div&gt;&lt;/li&gt;
303     * &lt;li&gt;stopPropagation : Boolean&lt;div class=&quot;sub-desc&quot;&gt;True to prevent event propagation&lt;/div&gt;&lt;/li&gt;
304     * &lt;li&gt;normalized : Boolean&lt;div class=&quot;sub-desc&quot;&gt;False to pass a browser event to the handler function instead of an Ext.EventObject&lt;/div&gt;&lt;/li&gt;
305     * &lt;li&gt;delay : Number&lt;div class=&quot;sub-desc&quot;&gt;The number of milliseconds to delay the invocation of the handler after te event fires.&lt;/div&gt;&lt;/li&gt;
306     * &lt;li&gt;single : Boolean&lt;div class=&quot;sub-desc&quot;&gt;True to add a handler to handle just the next firing of the event, and then remove itself.&lt;/div&gt;&lt;/li&gt;
307     * &lt;li&gt;buffer : Number&lt;div class=&quot;sub-desc&quot;&gt;Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
308     * by the specified number of milliseconds. If the event fires again within that time, the original
309     * handler is &lt;em&gt;not&lt;/em&gt; invoked, but the new handler is scheduled in its place.&lt;/div&gt;&lt;/li&gt;
310     * &lt;li&gt;target : Element&lt;div class=&quot;sub-desc&quot;&gt;Only call the handler if the event was fired on the target Element, &lt;i&gt;not&lt;/i&gt; if the event was bubbled up from a child node.&lt;/div&gt;&lt;/li&gt;
311     * &lt;/ul&gt;&lt;br&gt;
312     * &lt;p&gt;See {@link Ext.core.Element#addListener} for examples of how to use these options.&lt;/p&gt;
313     */
314     addListener: function(element, eventName, fn, scope, options){
315         // Check if we've been passed a &quot;config style&quot; event.
316         if (Ext.isObject(eventName)) {
317             this.prepareListenerConfig(element, eventName);
318             return;
319         }
320
321         var dom = Ext.getDom(element),
322             bind,
323             wrap;
324
325         //&lt;debug&gt;
326         if (!dom){
327             Ext.Error.raise({
328                 sourceClass: 'Ext.EventManager',
329                 sourceMethod: 'addListener',
330                 targetElement: element,
331                 eventName: eventName,
332                 msg: 'Error adding &quot;' + eventName + '\&quot; listener for nonexistent element &quot;' + element + '&quot;'
333             });
334         }
335         if (!fn) {
336             Ext.Error.raise({
337                 sourceClass: 'Ext.EventManager',
338                 sourceMethod: 'addListener',
339                 targetElement: element,
340                 eventName: eventName,
341                 msg: 'Error adding &quot;' + eventName + '\&quot; listener. The handler function is undefined.'
342             });
343         }
344         //&lt;/debug&gt;
345
346         // create the wrapper function
347         options = options || {};
348
349         bind = this.normalizeEvent(eventName, fn);
350         wrap = this.createListenerWrap(dom, eventName, bind.fn, scope, options);
351
352
353         if (dom.attachEvent) {
354             dom.attachEvent('on' + bind.eventName, wrap);
355         } else {
356             dom.addEventListener(bind.eventName, wrap, options.capture || false);
357         }
358
359         if (dom == document &amp;&amp; eventName == 'mousedown') {
360             this.stoppedMouseDownEvent.addListener(wrap);
361         }
362
363         // add all required data into the event cache
364         this.getEventListenerCache(dom, eventName).push({
365             fn: fn,
366             wrap: wrap,
367             scope: scope
368         });
369     },
370
371 <span id='Ext-EventManager-method-removeListener'>    /**
372 </span>    * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
373     * you will use {@link Ext.core.Element#removeListener} directly on an Element in favor of calling this version.
374     * @param {String/HTMLElement} el The id or html element from which to remove the listener.
375     * @param {String} eventName The name of the event.
376     * @param {Function} fn The handler function to remove. &lt;b&gt;This must be a reference to the function passed into the {@link #addListener} call.&lt;/b&gt;
377     * @param {Object} scope If a scope (&lt;b&gt;&lt;code&gt;this&lt;/code&gt;&lt;/b&gt; reference) was specified when the listener was added,
378     * then this must refer to the same object.
379     */
380     removeListener : function(element, eventName, fn, scope) {
381         // handle our listener config object syntax
382         if (Ext.isObject(eventName)) {
383             this.prepareListenerConfig(element, eventName, true);
384             return;
385         }
386
387         var dom = Ext.getDom(element),
388             cache = this.getEventListenerCache(dom, eventName),
389             bindName = this.normalizeEvent(eventName).eventName,
390             i = cache.length, j,
391             listener, wrap, tasks;
392
393
394         while (i--) {
395             listener = cache[i];
396
397             if (listener &amp;&amp; (!fn || listener.fn == fn) &amp;&amp; (!scope || listener.scope === scope)) {
398                 wrap = listener.wrap;
399
400                 // clear buffered calls
401                 if (wrap.task) {
402                     clearTimeout(wrap.task);
403                     delete wrap.task;
404                 }
405
406                 // clear delayed calls
407                 j = wrap.tasks &amp;&amp; wrap.tasks.length;
408                 if (j) {
409                     while (j--) {
410                         clearTimeout(wrap.tasks[j]);
411                     }
412                     delete wrap.tasks;
413                 }
414
415                 if (dom.detachEvent) {
416                     dom.detachEvent('on' + bindName, wrap);
417                 } else {
418                     dom.removeEventListener(bindName, wrap, false);
419                 }
420
421                 if (wrap &amp;&amp; dom == document &amp;&amp; eventName == 'mousedown') {
422                     this.stoppedMouseDownEvent.removeListener(wrap);
423                 }
424
425                 // remove listener from cache
426                 cache.splice(i, 1);
427             }
428         }
429     },
430
431 <span id='Ext-EventManager-method-removeAll'>    /**
432 </span>    * Removes all event handers from an element.  Typically you will use {@link Ext.core.Element#removeAllListeners}
433     * directly on an Element in favor of calling this version.
434     * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
435     */
436     removeAll : function(element){
437         var dom = Ext.getDom(element),
438             cache, ev;
439         if (!dom) {
440             return;
441         }
442         cache = this.getElementEventCache(dom);
443
444         for (ev in cache) {
445             if (cache.hasOwnProperty(ev)) {
446                 this.removeListener(dom, ev);
447             }
448         }
449         Ext.cache[dom.id].events = {};
450     },
451
452 <span id='Ext-EventManager-method-purgeElement'>    /**
453 </span>     * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.core.Element#purgeAllListeners}
454      * directly on an Element in favor of calling this version.
455      * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
456      * @param {String} eventName (optional) The name of the event.
457      */
458     purgeElement : function(element, eventName) {
459         var dom = Ext.getDom(element),
460             i = 0, len;
461
462         if(eventName) {
463             this.removeListener(dom, eventName);
464         }
465         else {
466             this.removeAll(dom);
467         }
468
469         if(dom &amp;&amp; dom.childNodes) {
470             for(len = element.childNodes.length; i &lt; len; i++) {
471                 this.purgeElement(element.childNodes[i], eventName);
472             }
473         }
474     },
475
476 <span id='Ext-EventManager-method-createListenerWrap'>    /**
477 </span>     * Create the wrapper function for the event
478      * @private
479      * @param {HTMLElement} dom The dom element
480      * @param {String} ename The event name
481      * @param {Function} fn The function to execute
482      * @param {Object} scope The scope to execute callback in
483      * @param {Object} o The options
484      */
485     createListenerWrap : function(dom, ename, fn, scope, options) {
486         options = !Ext.isObject(options) ? {} : options;
487
488         var f = ['if(!Ext) {return;}'],
489             gen;
490
491         if(options.buffer || options.delay || options.freezeEvent) {
492             f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
493         } else {
494             f.push('e = Ext.EventObject.setEvent(e);');
495         }
496
497         if (options.delegate) {
498             f.push('var t = e.getTarget(&quot;' + options.delegate + '&quot;, this);');
499             f.push('if(!t) {return;}');
500         } else {
501             f.push('var t = e.target;');
502         }
503
504         if (options.target) {
505             f.push('if(e.target !== options.target) {return;}');
506         }
507
508         if(options.stopEvent) {
509             f.push('e.stopEvent();');
510         } else {
511             if(options.preventDefault) {
512                 f.push('e.preventDefault();');
513             }
514             if(options.stopPropagation) {
515                 f.push('e.stopPropagation();');
516             }
517         }
518
519         if(options.normalized === false) {
520             f.push('e = e.browserEvent;');
521         }
522
523         if(options.buffer) {
524             f.push('(wrap.task &amp;&amp; clearTimeout(wrap.task));');
525             f.push('wrap.task = setTimeout(function(){');
526         }
527
528         if(options.delay) {
529             f.push('wrap.tasks = wrap.tasks || [];');
530             f.push('wrap.tasks.push(setTimeout(function(){');
531         }
532
533         // finally call the actual handler fn
534         f.push('fn.call(scope || dom, e, t, options);');
535
536         if(options.single) {
537             f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
538         }
539
540         if(options.delay) {
541             f.push('}, ' + options.delay + '));');
542         }
543
544         if(options.buffer) {
545             f.push('}, ' + options.buffer + ');');
546         }
547
548         gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
549
550         return function wrap(e, args) {
551             gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
552         };
553     },
554
555 <span id='Ext-EventManager-method-getEventListenerCache'>    /**
556 </span>     * Get the event cache for a particular element for a particular event
557      * @private
558      * @param {HTMLElement} element The element
559      * @param {Object} eventName The event name
560      * @return {Array} The events for the element
561      */
562     getEventListenerCache : function(element, eventName) {
563         var eventCache = this.getElementEventCache(element);
564         return eventCache[eventName] || (eventCache[eventName] = []);
565     },
566
567 <span id='Ext-EventManager-method-getElementEventCache'>    /**
568 </span>     * Gets the event cache for the object
569      * @private
570      * @param {HTMLElement} element The element
571      * @return {Object} The event cache for the object
572      */
573     getElementEventCache : function(element) {
574         var elementCache = Ext.cache[this.getId(element)];
575         return elementCache.events || (elementCache.events = {});
576     },
577
578     // --------------------- utility methods ---------------------
579     mouseLeaveRe: /(mouseout|mouseleave)/,
580     mouseEnterRe: /(mouseover|mouseenter)/,
581
582 <span id='Ext-EventManager-method-stopEvent'>    /**
583 </span>     * Stop the event (preventDefault and stopPropagation)
584      * @param {Event} The event to stop
585      */
586     stopEvent: function(event) {
587         this.stopPropagation(event);
588         this.preventDefault(event);
589     },
590
591 <span id='Ext-EventManager-method-stopPropagation'>    /**
592 </span>     * Cancels bubbling of the event.
593      * @param {Event} The event to stop bubbling.
594      */
595     stopPropagation: function(event) {
596         event = event.browserEvent || event;
597         if (event.stopPropagation) {
598             event.stopPropagation();
599         } else {
600             event.cancelBubble = true;
601         }
602     },
603
604 <span id='Ext-EventManager-method-preventDefault'>    /**
605 </span>     * Prevents the browsers default handling of the event.
606      * @param {Event} The event to prevent the default
607      */
608     preventDefault: function(event) {
609         event = event.browserEvent || event;
610         if (event.preventDefault) {
611             event.preventDefault();
612         } else {
613             event.returnValue = false;
614             // Some keys events require setting the keyCode to -1 to be prevented
615             try {
616               // all ctrl + X and F1 -&gt; F12
617               if (event.ctrlKey || event.keyCode &gt; 111 &amp;&amp; event.keyCode &lt; 124) {
618                   event.keyCode = -1;
619               }
620             } catch (e) {
621                 // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
622             }
623         }
624     },
625
626 <span id='Ext-EventManager-method-getRelatedTarget'>    /**
627 </span>     * Gets the related target from the event.
628      * @param {Object} event The event
629      * @return {HTMLElement} The related target.
630      */
631     getRelatedTarget: function(event) {
632         event = event.browserEvent || event;
633         var target = event.relatedTarget;
634         if (!target) {
635             if (this.mouseLeaveRe.test(event.type)) {
636                 target = event.toElement;
637             } else if (this.mouseEnterRe.test(event.type)) {
638                 target = event.fromElement;
639             }
640         }
641         return this.resolveTextNode(target);
642     },
643
644 <span id='Ext-EventManager-method-getPageX'>    /**
645 </span>     * Gets the x coordinate from the event
646      * @param {Object} event The event
647      * @return {Number} The x coordinate
648      */
649     getPageX: function(event) {
650         return this.getXY(event)[0];
651     },
652
653 <span id='Ext-EventManager-method-getPageY'>    /**
654 </span>     * Gets the y coordinate from the event
655      * @param {Object} event The event
656      * @return {Number} The y coordinate
657      */
658     getPageY: function(event) {
659         return this.getXY(event)[1];
660     },
661
662 <span id='Ext-EventManager-method-getPageXY'>    /**
663 </span>     * Gets the x &amp; ycoordinate from the event
664      * @param {Object} event The event
665      * @return {Array} The x/y coordinate
666      */
667     getPageXY: function(event) {
668         event = event.browserEvent || event;
669         var x = event.pageX,
670             y = event.pageY,
671             doc = document.documentElement,
672             body = document.body;
673
674         // pageX/pageY not available (undefined, not null), use clientX/clientY instead
675         if (!x &amp;&amp; x !== 0) {
676             x = event.clientX + (doc &amp;&amp; doc.scrollLeft || body &amp;&amp; body.scrollLeft || 0) - (doc &amp;&amp; doc.clientLeft || body &amp;&amp; body.clientLeft || 0);
677             y = event.clientY + (doc &amp;&amp; doc.scrollTop  || body &amp;&amp; body.scrollTop  || 0) - (doc &amp;&amp; doc.clientTop  || body &amp;&amp; body.clientTop  || 0);
678         }
679         return [x, y];
680     },
681
682 <span id='Ext-EventManager-method-getTarget'>    /**
683 </span>     * Gets the target of the event.
684      * @param {Object} event The event
685      * @return {HTMLElement} target
686      */
687     getTarget: function(event) {
688         event = event.browserEvent || event;
689         return this.resolveTextNode(event.target || event.srcElement);
690     },
691
692 <span id='Ext-EventManager-property-resolveTextNode'>    /**
693 </span>     * Resolve any text nodes accounting for browser differences.
694      * @private
695      * @param {HTMLElement} node The node
696      * @return {HTMLElement} The resolved node
697      */
698     // technically no need to browser sniff this, however it makes no sense to check this every time, for every event, whether the string is equal.
699     resolveTextNode: Ext.isGecko ?
700         function(node) {
701             if (!node) {
702                 return;
703             }
704             // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
705             var s = HTMLElement.prototype.toString.call(node);
706             if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
707                 return;
708             }
709                 return node.nodeType == 3 ? node.parentNode: node;
710             }: function(node) {
711                 return node &amp;&amp; node.nodeType == 3 ? node.parentNode: node;
712             },
713
714     // --------------------- custom event binding ---------------------
715
716     // Keep track of the current width/height
717     curWidth: 0,
718     curHeight: 0,
719
720 <span id='Ext-EventManager-method-onWindowResize'>    /**
721 </span>     * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
722      * passes new viewport width and height to handlers.
723      * @param {Function} fn      The handler function the window resize event invokes.
724      * @param {Object}   scope   The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the handler function executes. Defaults to the browser window.
725      * @param {boolean}  options Options object as passed to {@link Ext.core.Element#addListener}
726      */
727     onWindowResize: function(fn, scope, options){
728         var resize = this.resizeEvent;
729         if(!resize){
730             this.resizeEvent = resize = new Ext.util.Event();
731             this.on(window, 'resize', this.fireResize, this, {buffer: 100});
732         }
733         resize.addListener(fn, scope, options);
734     },
735
736 <span id='Ext-EventManager-method-fireResize'>    /**
737 </span>     * Fire the resize event.
738      * @private
739      */
740     fireResize: function(){
741         var me = this,
742             w = Ext.core.Element.getViewWidth(),
743             h = Ext.core.Element.getViewHeight();
744
745          //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
746          if(me.curHeight != h || me.curWidth != w){
747              me.curHeight = h;
748              me.curWidth = w;
749              me.resizeEvent.fire(w, h);
750          }
751     },
752
753 <span id='Ext-EventManager-method-removeResizeListener'>    /**
754 </span>     * Removes the passed window resize listener.
755      * @param {Function} fn        The method the event invokes
756      * @param {Object}   scope    The scope of handler
757      */
758     removeResizeListener: function(fn, scope){
759         if (this.resizeEvent) {
760             this.resizeEvent.removeListener(fn, scope);
761         }
762     },
763
764     onWindowUnload: function() {
765         var unload = this.unloadEvent;
766         if (!unload) {
767             this.unloadEvent = unload = new Ext.util.Event();
768             this.addListener(window, 'unload', this.fireUnload, this);
769         }
770     },
771
772 <span id='Ext-EventManager-method-fireUnload'>    /**
773 </span>     * Fires the unload event for items bound with onWindowUnload
774      * @private
775      */
776     fireUnload: function() {
777         // wrap in a try catch, could have some problems during unload
778         try {
779             this.removeUnloadListener();
780             // Work around FF3 remembering the last scroll position when refreshing the grid and then losing grid view
781             if (Ext.isGecko3) {
782                 var gridviews = Ext.ComponentQuery.query('gridview'),
783                     i = 0,
784                     ln = gridviews.length;
785                 for (; i &lt; ln; i++) {
786                     gridviews[i].scrollToTop();
787                 }
788             }
789             // Purge all elements in the cache
790             var el,
791                 cache = Ext.cache;
792             for (el in cache) {
793                 if (cache.hasOwnProperty(el)) {
794                     Ext.EventManager.removeAll(el);
795                 }
796             }
797         } catch(e) {
798         }
799     },
800
801 <span id='Ext-EventManager-method-removeUnloadListener'>    /**
802 </span>     * Removes the passed window unload listener.
803      * @param {Function} fn        The method the event invokes
804      * @param {Object}   scope    The scope of handler
805      */
806     removeUnloadListener: function(){
807         if (this.unloadEvent) {
808             this.removeListener(window, 'unload', this.fireUnload);
809         }
810     },
811
812 <span id='Ext-EventManager-property-useKeyDown'>    /**
813 </span>     * note 1: IE fires ONLY the keydown event on specialkey autorepeat
814      * note 2: Safari &lt; 3.1, Gecko (Mac/Linux) &amp; Opera fire only the keypress event on specialkey autorepeat
815      * (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
816      * @private
817      */
818     useKeyDown: Ext.isWebKit ?
819                    parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) &gt;= 525 :
820                    !((Ext.isGecko &amp;&amp; !Ext.isWindows) || Ext.isOpera),
821
822 <span id='Ext-EventManager-method-getKeyEvent'>    /**
823 </span>     * Indicates which event to use for getting key presses.
824      * @return {String} The appropriate event name.
825      */
826     getKeyEvent: function(){
827         return this.useKeyDown ? 'keydown' : 'keypress';
828     }
829 };
830
831 <span id='Ext-method-onReady'>/**
832 </span> * Alias for {@link Ext.Loader#onReady Ext.Loader.onReady} with withDomReady set to true
833  * @member Ext
834  * @method onReady
835  */
836 Ext.onReady = function(fn, scope, options) {
837     Ext.Loader.onReady(fn, scope, true, options);
838 };
839
840 <span id='Ext-method-onDocumentReady'>/**
841 </span> * Alias for {@link Ext.EventManager#onDocumentReady Ext.EventManager.onDocumentReady}
842  * @member Ext
843  * @method onDocumentReady
844  */
845 Ext.onDocumentReady = Ext.EventManager.onDocumentReady;
846
847 <span id='Ext-EventManager-method-on'>/**
848 </span> * Alias for {@link Ext.EventManager#addListener Ext.EventManager.addListener}
849  * @member Ext.EventManager
850  * @method on
851  */
852 Ext.EventManager.on = Ext.EventManager.addListener;
853
854 <span id='Ext-EventManager-method-un'>/**
855 </span> * Alias for {@link Ext.EventManager#removeListener Ext.EventManager.removeListener}
856  * @member Ext.EventManager
857  * @method un
858  */
859 Ext.EventManager.un = Ext.EventManager.removeListener;
860
861 (function(){
862     var initExtCss = function() {
863         // find the body element
864         var bd = document.body || document.getElementsByTagName('body')[0],
865             baseCSSPrefix = Ext.baseCSSPrefix,
866             cls = [],
867             htmlCls = [],
868             html;
869
870         if (!bd) {
871             return false;
872         }
873
874         html = bd.parentNode;
875
876         //Let's keep this human readable!
877         if (Ext.isIE) {
878             cls.push(baseCSSPrefix + 'ie');
879         }
880         if (Ext.isIE6) {
881             cls.push(baseCSSPrefix + 'ie6');
882         }
883         if (Ext.isIE7) {
884             cls.push(baseCSSPrefix + 'ie7');
885         }
886         if (Ext.isIE8) {
887             cls.push(baseCSSPrefix + 'ie8');
888         }
889         if (Ext.isIE9) {
890             cls.push(baseCSSPrefix + 'ie9');
891         }
892         if (Ext.isGecko) {
893             cls.push(baseCSSPrefix + 'gecko');
894         }
895         if (Ext.isGecko3) {
896             cls.push(baseCSSPrefix + 'gecko3');
897         }
898         if (Ext.isGecko4) {
899             cls.push(baseCSSPrefix + 'gecko4');
900         }
901         if (Ext.isOpera) {
902             cls.push(baseCSSPrefix + 'opera');
903         }
904         if (Ext.isWebKit) {
905             cls.push(baseCSSPrefix + 'webkit');
906         }
907         if (Ext.isSafari) {
908             cls.push(baseCSSPrefix + 'safari');
909         }
910         if (Ext.isSafari2) {
911             cls.push(baseCSSPrefix + 'safari2');
912         }
913         if (Ext.isSafari3) {
914             cls.push(baseCSSPrefix + 'safari3');
915         }
916         if (Ext.isSafari4) {
917             cls.push(baseCSSPrefix + 'safari4');
918         }
919         if (Ext.isChrome) {
920             cls.push(baseCSSPrefix + 'chrome');
921         }
922         if (Ext.isMac) {
923             cls.push(baseCSSPrefix + 'mac');
924         }
925         if (Ext.isLinux) {
926             cls.push(baseCSSPrefix + 'linux');
927         }
928         if (!Ext.supports.CSS3BorderRadius) {
929             cls.push(baseCSSPrefix + 'nbr');
930         }
931         if (!Ext.supports.CSS3LinearGradient) {
932             cls.push(baseCSSPrefix + 'nlg');
933         }
934         if (!Ext.scopeResetCSS) {
935             cls.push(baseCSSPrefix + 'reset');
936         }
937
938         // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
939         if (html) {
940             if (Ext.isStrict &amp;&amp; (Ext.isIE6 || Ext.isIE7)) {
941                 Ext.isBorderBox = false;
942             }
943             else {
944                 Ext.isBorderBox = true;
945             }
946
947             htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
948             if (!Ext.isStrict) {
949                 htmlCls.push(baseCSSPrefix + 'quirks');
950                 if (Ext.isIE &amp;&amp; !Ext.isStrict) {
951                     Ext.isIEQuirks = true;
952                 }
953             }
954             Ext.fly(html, '_internal').addCls(htmlCls);
955         }
956
957         Ext.fly(bd, '_internal').addCls(cls);
958         return true;
959     };
960
961     Ext.onReady(initExtCss);
962 })();
963 </pre></pre></body></html>