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