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