Upgrade to ExtJS 3.2.0 - Released 03/30/2010
[extjs.git] / docs / source / EventManager.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.2.0
11  * Copyright(c) 2006-2010 Ext JS, Inc.
12  * licensing@extjs.com
13  * http://www.extjs.com/license
14  */
15 <div id="cls-Ext.EventManager"></div>/**
16  * @class Ext.EventManager
17  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
18  * several useful events directly.
19  * See {@link Ext.EventObject} for more details on normalized event objects.
20  * @singleton
21  */
22
23 Ext.EventManager = function(){
24     var docReadyEvent,
25         docReadyProcId,
26         docReadyState = false,
27         DETECT_NATIVE = Ext.isGecko || Ext.isWebKit || Ext.isSafari,
28         E = Ext.lib.Event,
29         D = Ext.lib.Dom,
30         DOC = document,
31         WINDOW = window,
32         DOMCONTENTLOADED = "DOMContentLoaded",
33         COMPLETE = 'complete',
34         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
35         /*
36          * This cache is used to hold special js objects, the document and window, that don't have an id. We need to keep
37          * a reference to them so we can look them up at a later point.
38          */
39         specialElCache = [];
40
41      function getId(el){
42         var id = false,
43             i = 0,
44             len = specialElCache.length,
45             id = false,
46             skip = false,
47             o;
48         if(el){
49             if(el.getElementById || el.navigator){
50                 // look up the id
51                 for(; i < len; ++i){
52                     o = specialElCache[i];
53                     if(o.el === el){
54                         id = o.id;
55                         break;
56                     }
57                 }
58                 if(!id){
59                     // for browsers that support it, ensure that give the el the same id
60                     id = Ext.id(el);
61                     specialElCache.push({
62                         id: id,
63                         el: el
64                     });
65                     skip = true;
66                 }
67             }else{
68                 id = Ext.id(el);
69             }
70             if(!Ext.elCache[id]){
71                 Ext.Element.addToCache(new Ext.Element(el), id);
72                 if(skip){
73                     Ext.elCache[id].skipGC = true;
74                 }
75             }
76         }
77         return id;
78      };
79
80     /// There is some jquery work around stuff here that isn't needed in Ext Core.
81     function addListener(el, ename, fn, task, wrap, scope){
82         el = Ext.getDom(el);
83         var id = getId(el),
84             es = Ext.elCache[id].events,
85             wfn;
86
87         wfn = E.on(el, ename, wrap);
88         es[ename] = es[ename] || [];
89
90         /* 0 = Original Function,
91            1 = Event Manager Wrapped Function,
92            2 = Scope,
93            3 = Adapter Wrapped Function,
94            4 = Buffered Task
95         */
96         es[ename].push([fn, wrap, scope, wfn, task]);
97
98         // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
99         // without breaking ExtJS.
100
101         // workaround for jQuery
102         if(el.addEventListener && ename == "mousewheel"){
103             var args = ["DOMMouseScroll", wrap, false];
104             el.addEventListener.apply(el, args);
105             Ext.EventManager.addListener(WINDOW, 'unload', function(){
106                 el.removeEventListener.apply(el, args);
107             });
108         }
109
110         // fix stopped mousedowns on the document
111         if(el == DOC && ename == "mousedown"){
112             Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
113         }
114     };
115
116     function doScrollChk(){
117         /* Notes:
118              'doScroll' will NOT work in a IFRAME/FRAMESET.
119              The method succeeds but, a DOM query done immediately after -- FAILS.
120           */
121         if(window != top){
122             return false;
123         }
124
125         try{
126             DOC.documentElement.doScroll('left');
127         }catch(e){
128              return false;
129         }
130
131         fireDocReady();
132         return true;
133     }
134     <div id="method-Ext.EventManager-function"></div>/**
135      * @return {Boolean} True if the document is in a 'complete' state (or was determined to
136      * be true by other means). If false, the state is evaluated again until canceled.
137      */
138     function checkReadyState(e){
139
140         if(Ext.isIE && doScrollChk()){
141             return true;
142         }
143         if(DOC.readyState == COMPLETE){
144             fireDocReady();
145             return true;
146         }
147         docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
148         return false;
149     }
150
151     var styles;
152     function checkStyleSheets(e){
153         styles || (styles = Ext.query('style, link[rel=stylesheet]'));
154         if(styles.length == DOC.styleSheets.length){
155             fireDocReady();
156             return true;
157         }
158         docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
159         return false;
160     }
161
162     function OperaDOMContentLoaded(e){
163         DOC.removeEventListener(DOMCONTENTLOADED, arguments.callee, false);
164         checkStyleSheets();
165     }
166
167     function fireDocReady(e){
168         if(!docReadyState){
169             docReadyState = true; //only attempt listener removal once
170
171             if(docReadyProcId){
172                 clearTimeout(docReadyProcId);
173             }
174             if(DETECT_NATIVE) {
175                 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
176             }
177             if(Ext.isIE && checkReadyState.bindIE){  //was this was actually set ??
178                 DOC.detachEvent('onreadystatechange', checkReadyState);
179             }
180             E.un(WINDOW, "load", arguments.callee);
181         }
182         if(docReadyEvent && !Ext.isReady){
183             Ext.isReady = true;
184             docReadyEvent.fire();
185             docReadyEvent.listeners = [];
186         }
187
188     };
189
190     function initDocReady(){
191         docReadyEvent || (docReadyEvent = new Ext.util.Event());
192         if (DETECT_NATIVE) {
193             DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
194         }
195         /*
196          * Handle additional (exceptional) detection strategies here
197          */
198         if (Ext.isIE){
199             //Use readystatechange as a backup AND primary detection mechanism for a FRAME/IFRAME
200             //See if page is already loaded
201             if(!checkReadyState()){
202                 checkReadyState.bindIE = true;
203                 DOC.attachEvent('onreadystatechange', checkReadyState);
204             }
205
206         }else if(Ext.isOpera ){
207             /* Notes:
208                Opera needs special treatment needed here because CSS rules are NOT QUITE
209                available after DOMContentLoaded is raised.
210             */
211
212             //See if page is already loaded and all styleSheets are in place
213             (DOC.readyState == COMPLETE && checkStyleSheets()) ||
214                 DOC.addEventListener(DOMCONTENTLOADED, OperaDOMContentLoaded, false);
215
216         }else if (Ext.isWebKit){
217             //Fallback for older Webkits without DOMCONTENTLOADED support
218             checkReadyState();
219         }
220         // no matter what, make sure it fires on load
221         E.on(WINDOW, "load", fireDocReady);
222     };
223
224     function createTargeted(h, o){
225         return function(){
226             var args = Ext.toArray(arguments);
227             if(o.target == Ext.EventObject.setEvent(args[0]).target){
228                 h.apply(this, args);
229             }
230         };
231     };
232
233     function createBuffered(h, o, task){
234         return function(e){
235             // create new event object impl so new events don't wipe out properties
236             task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
237         };
238     };
239
240     function createSingle(h, el, ename, fn, scope){
241         return function(e){
242             Ext.EventManager.removeListener(el, ename, fn, scope);
243             h(e);
244         };
245     };
246
247     function createDelayed(h, o, fn){
248         return function(e){
249             var task = new Ext.util.DelayedTask(h);
250             if(!fn.tasks) {
251                 fn.tasks = [];
252             }
253             fn.tasks.push(task);
254             task.delay(o.delay || 10, h, null, [new Ext.EventObjectImpl(e)]);
255         };
256     };
257
258     function listen(element, ename, opt, fn, scope){
259         var o = !Ext.isObject(opt) ? {} : opt,
260             el = Ext.getDom(element), task;
261
262         fn = fn || o.fn;
263         scope = scope || o.scope;
264
265         if(!el){
266             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
267         }
268         function h(e){
269             // prevent errors while unload occurring
270             if(!Ext){// !window[xname]){  ==> can't we do this?
271                 return;
272             }
273             e = Ext.EventObject.setEvent(e);
274             var t;
275             if (o.delegate) {
276                 if(!(t = e.getTarget(o.delegate, el))){
277                     return;
278                 }
279             } else {
280                 t = e.target;
281             }
282             if (o.stopEvent) {
283                 e.stopEvent();
284             }
285             if (o.preventDefault) {
286                e.preventDefault();
287             }
288             if (o.stopPropagation) {
289                 e.stopPropagation();
290             }
291             if (o.normalized) {
292                 e = e.browserEvent;
293             }
294
295             fn.call(scope || el, e, t, o);
296         };
297         if(o.target){
298             h = createTargeted(h, o);
299         }
300         if(o.delay){
301             h = createDelayed(h, o, fn);
302         }
303         if(o.single){
304             h = createSingle(h, el, ename, fn, scope);
305         }
306         if(o.buffer){
307             task = new Ext.util.DelayedTask(h);
308             h = createBuffered(h, o, task);
309         }
310
311         addListener(el, ename, fn, task, h, scope);
312         return h;
313     };
314
315     var pub = {
316         <div id="method-Ext.EventManager-addListener"></div>/**
317          * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
318          * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
319          * @param {String/HTMLElement} el The html element or id to assign the event handler to.
320          * @param {String} eventName The name of the event to listen for.
321          * @param {Function} handler The handler function the event invokes. This function is passed
322          * the following parameters:<ul>
323          * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
324          * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
325          * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
326          * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
327          * </ul>
328          * @param {Object} scope (optional) The scope (<b><code>this</code></b> reference) in which the handler function is executed. <b>Defaults to the Element</b>.
329          * @param {Object} options (optional) An object containing handler configuration properties.
330          * This may contain any of the following properties:<ul>
331          * <li>scope : Object<div class="sub-desc">The scope (<b><code>this</code></b> reference) in which the handler function is executed. <b>Defaults to the Element</b>.</div></li>
332          * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
333          * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
334          * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
335          * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
336          * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
337          * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
338          * <li>single : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
339          * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
340          * by the specified number of milliseconds. If the event fires again within that time, the original
341          * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
342          * <li>target : Element<div class="sub-desc">Only call the handler if the event was fired on the target Element, <i>not</i> if the event was bubbled up from a child node.</div></li>
343          * </ul><br>
344          * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
345          */
346         addListener : function(element, eventName, fn, scope, options){
347             if(Ext.isObject(eventName)){
348                 var o = eventName, e, val;
349                 for(e in o){
350                     val = o[e];
351                     if(!propRe.test(e)){
352                         if(Ext.isFunction(val)){
353                             // shared options
354                             listen(element, e, o, val, o.scope);
355                         }else{
356                             // individual options
357                             listen(element, e, val);
358                         }
359                     }
360                 }
361             } else {
362                 listen(element, eventName, options, fn, scope);
363             }
364         },
365
366         <div id="method-Ext.EventManager-removeListener"></div>/**
367          * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
368          * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
369          * @param {String/HTMLElement} el The id or html element from which to remove the listener.
370          * @param {String} eventName The name of the event.
371          * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
372          * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
373          * then this must refer to the same object.
374          */
375         removeListener : function(el, eventName, fn, scope){
376             el = Ext.getDom(el);
377             var id = getId(el),
378                 f = el && (Ext.elCache[id].events)[eventName] || [],
379                 wrap, i, l, k, len, fnc;
380
381             for (i = 0, len = f.length; i < len; i++) {
382
383                 /* 0 = Original Function,
384                    1 = Event Manager Wrapped Function,
385                    2 = Scope,
386                    3 = Adapter Wrapped Function,
387                    4 = Buffered Task
388                 */
389                 if (Ext.isArray(fnc = f[i]) && fnc[0] == fn && (!scope || fnc[2] == scope)) {
390                     if(fnc[4]) {
391                         fnc[4].cancel();
392                     }
393                     k = fn.tasks && fn.tasks.length;
394                     if(k) {
395                         while(k--) {
396                             fn.tasks[k].cancel();
397                         }
398                         delete fn.tasks;
399                     }
400                     wrap = fnc[1];
401                     E.un(el, eventName, E.extAdapter ? fnc[3] : wrap);
402
403                     // jQuery workaround that should be removed from Ext Core
404                     if(wrap && el.addEventListener && eventName == "mousewheel"){
405                         el.removeEventListener("DOMMouseScroll", wrap, false);
406                     }
407
408                     // fix stopped mousedowns on the document
409                     if(wrap && el == DOC && eventName == "mousedown"){
410                         Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
411                     }
412
413                     f.splice(i, 1);
414                     if (f.length === 0) {
415                         delete Ext.elCache[id].events[eventName];
416                     }
417                     for (k in Ext.elCache[id].events) {
418                         return false;
419                     }
420                     Ext.elCache[id].events = {};
421                     return false;
422                 }
423             }
424         },
425
426         <div id="method-Ext.EventManager-removeAll"></div>/**
427          * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
428          * directly on an Element in favor of calling this version.
429          * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
430          */
431         removeAll : function(el){
432             el = Ext.getDom(el);
433             var id = getId(el),
434                 ec = Ext.elCache[id] || {},
435                 es = ec.events || {},
436                 f, i, len, ename, fn, k, wrap;
437
438             for(ename in es){
439                 if(es.hasOwnProperty(ename)){
440                     f = es[ename];
441                     /* 0 = Original Function,
442                        1 = Event Manager Wrapped Function,
443                        2 = Scope,
444                        3 = Adapter Wrapped Function,
445                        4 = Buffered Task
446                     */
447                     for (i = 0, len = f.length; i < len; i++) {
448                         fn = f[i];
449                         if(fn[4]) {
450                             fn[4].cancel();
451                         }
452                         if(fn[0].tasks && (k = fn[0].tasks.length)) {
453                             while(k--) {
454                                 fn[0].tasks[k].cancel();
455                             }
456                             delete fn.tasks;
457                         }
458                         wrap =  fn[1];
459                         E.un(el, ename, E.extAdapter ? fn[3] : wrap);
460
461                         // jQuery workaround that should be removed from Ext Core
462                         if(el.addEventListener && wrap && ename == "mousewheel"){
463                             el.removeEventListener("DOMMouseScroll", wrap, false);
464                         }
465
466                         // fix stopped mousedowns on the document
467                         if(wrap && el == DOC &&  ename == "mousedown"){
468                             Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
469                         }
470                     }
471                 }
472             }
473             if (Ext.elCache[id]) {
474                 Ext.elCache[id].events = {};
475             }
476         },
477
478         getListeners : function(el, eventName) {
479             el = Ext.getDom(el);
480             var id = getId(el),
481                 ec = Ext.elCache[id] || {},
482                 es = ec.events || {},
483                 results = [];
484             if (es && es[eventName]) {
485                 return es[eventName];
486             } else {
487                 return null;
488             }
489         },
490
491         purgeElement : function(el, recurse, eventName) {
492             el = Ext.getDom(el);
493             var id = getId(el),
494                 ec = Ext.elCache[id] || {},
495                 es = ec.events || {},
496                 i, f, len;
497             if (eventName) {
498                 if (es && es.hasOwnProperty(eventName)) {
499                     f = es[eventName];
500                     for (i = 0, len = f.length; i < len; i++) {
501                         Ext.EventManager.removeListener(el, eventName, f[i][0]);
502                     }
503                 }
504             } else {
505                 Ext.EventManager.removeAll(el);
506             }
507             if (recurse && el && el.childNodes) {
508                 for (i = 0, len = el.childNodes.length; i < len; i++) {
509                     Ext.EventManager.purgeElement(el.childNodes[i], recurse, eventName);
510                 }
511             }
512         },
513
514         _unload : function() {
515             var el;
516             for (el in Ext.elCache) {
517                 Ext.EventManager.removeAll(el);
518             }
519             delete Ext.elCache;
520             delete Ext.Element._flyweights;
521
522             // Abort any outstanding Ajax requests
523             var c,
524                 conn,
525                 tid,
526                 ajax = Ext.lib.Ajax;
527             (Ext.isObject(ajax.conn)) ? conn = ajax.conn : conn = {};
528             for (tid in conn) {
529                 c = conn[tid];
530                 if (c) {
531                     ajax.abort({conn: c, tId: tid});
532                 }
533             }
534         },
535         <div id="method-Ext.EventManager-onDocumentReady"></div>/**
536          * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
537          * accessed shorthanded as Ext.onReady().
538          * @param {Function} fn The method the event invokes.
539          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
540          * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
541          * <code>{single: true}</code> be used so that the handler is removed on first invocation.
542          */
543         onDocumentReady : function(fn, scope, options){
544             if(Ext.isReady){ // if it already fired or document.body is present
545                 docReadyEvent || (docReadyEvent = new Ext.util.Event());
546                 docReadyEvent.addListener(fn, scope, options);
547                 docReadyEvent.fire();
548                 docReadyEvent.listeners = [];
549             }else{
550                 if(!docReadyEvent){
551                     initDocReady();
552                 }
553                 options = options || {};
554                 options.delay = options.delay || 1;
555                 docReadyEvent.addListener(fn, scope, options);
556             }
557         },
558
559         <div id="prop-Ext.EventManager-fireDocReady"></div>/**
560          * Forces a document ready state transition for the framework.  Used when Ext is loaded
561          * into a DOM structure AFTER initial page load (Google API or other dynamic load scenario.
562          * Any pending 'onDocumentReady' handlers will be fired (if not already handled).
563          */
564         fireDocReady  : fireDocReady
565     };
566      <div id="method-Ext.EventManager-on"></div>/**
567      * Appends an event handler to an element.  Shorthand for {@link #addListener}.
568      * @param {String/HTMLElement} el The html element or id to assign the event handler to
569      * @param {String} eventName The name of the event to listen for.
570      * @param {Function} handler The handler function the event invokes.
571      * @param {Object} scope (optional) (<code>this</code> reference) in which the handler function executes. <b>Defaults to the Element</b>.
572      * @param {Object} options (optional) An object containing standard {@link #addListener} options
573      * @member Ext.EventManager
574      * @method on
575      */
576     pub.on = pub.addListener;
577     <div id="method-Ext.EventManager-un"></div>/**
578      * Removes an event handler from an element.  Shorthand for {@link #removeListener}.
579      * @param {String/HTMLElement} el The id or html element from which to remove the listener.
580      * @param {String} eventName The name of the event.
581      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #on} call.</b>
582      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
583      * then this must refer to the same object.
584      * @member Ext.EventManager
585      * @method un
586      */
587     pub.un = pub.removeListener;
588
589     pub.stoppedMouseDownEvent = new Ext.util.Event();
590     return pub;
591 }();
592 <div id="method-Ext-onReady"></div>/**
593   * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
594   * @param {Function} fn The method the event invokes.
595   * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
596   * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
597   * <code>{single: true}</code> be used so that the handler is removed on first invocation.
598   * @member Ext
599   * @method onReady
600  */
601 Ext.onReady = Ext.EventManager.onDocumentReady;
602
603
604 //Initialize doc classes
605 (function(){
606
607     var initExtCss = function(){
608         // find the body element
609         var bd = document.body || document.getElementsByTagName('body')[0];
610         if(!bd){ return false; }
611         var cls = [' ',
612                 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
613                 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
614                 : Ext.isOpera ? "ext-opera"
615                 : Ext.isWebKit ? "ext-webkit" : ""];
616
617         if(Ext.isSafari){
618             cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
619         }else if(Ext.isChrome){
620             cls.push("ext-chrome");
621         }
622
623         if(Ext.isMac){
624             cls.push("ext-mac");
625         }
626         if(Ext.isLinux){
627             cls.push("ext-linux");
628         }
629
630         if(Ext.isStrict || Ext.isBorderBox){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
631             var p = bd.parentNode;
632             if(p){
633                 p.className += Ext.isStrict ? ' ext-strict' : ' ext-border-box';
634             }
635         }
636         bd.className += cls.join(' ');
637         return true;
638     }
639
640     if(!initExtCss()){
641         Ext.onReady(initExtCss);
642     }
643 })();
644
645
646 <div id="cls-Ext.EventObject"></div>/**
647  * @class Ext.EventObject
648  * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
649  * wraps the browser's native event-object normalizing cross-browser differences,
650  * such as which mouse button is clicked, keys pressed, mechanisms to stop
651  * event-propagation along with a method to prevent default actions from taking place.
652  * <p>For example:</p>
653  * <pre><code>
654 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
655     e.preventDefault();
656     var target = e.getTarget(); // same as t (the target HTMLElement)
657     ...
658 }
659 var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
660 myDiv.on(         // 'on' is shorthand for addListener
661     "click",      // perform an action on click of myDiv
662     handleClick   // reference to the action handler
663 );
664 // other methods to do the same:
665 Ext.EventManager.on("myDiv", 'click', handleClick);
666 Ext.EventManager.addListener("myDiv", 'click', handleClick);
667  </code></pre>
668  * @singleton
669  */
670 Ext.EventObject = function(){
671     var E = Ext.lib.Event,
672         // safari keypress events for special keys return bad keycodes
673         safariKeys = {
674             3 : 13, // enter
675             63234 : 37, // left
676             63235 : 39, // right
677             63232 : 38, // up
678             63233 : 40, // down
679             63276 : 33, // page up
680             63277 : 34, // page down
681             63272 : 46, // delete
682             63273 : 36, // home
683             63275 : 35  // end
684         },
685         // normalize button clicks
686         btnMap = Ext.isIE ? {1:0,4:1,2:2} :
687                 (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
688
689     Ext.EventObjectImpl = function(e){
690         if(e){
691             this.setEvent(e.browserEvent || e);
692         }
693     };
694
695     Ext.EventObjectImpl.prototype = {
696            /** @private */
697         setEvent : function(e){
698             var me = this;
699             if(e == me || (e && e.browserEvent)){ // already wrapped
700                 return e;
701             }
702             me.browserEvent = e;
703             if(e){
704                 // normalize buttons
705                 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
706                 if(e.type == 'click' && me.button == -1){
707                     me.button = 0;
708                 }
709                 me.type = e.type;
710                 me.shiftKey = e.shiftKey;
711                 // mac metaKey behaves like ctrlKey
712                 me.ctrlKey = e.ctrlKey || e.metaKey || false;
713                 me.altKey = e.altKey;
714                 // in getKey these will be normalized for the mac
715                 me.keyCode = e.keyCode;
716                 me.charCode = e.charCode;
717                 // cache the target for the delayed and or buffered events
718                 me.target = E.getTarget(e);
719                 // same for XY
720                 me.xy = E.getXY(e);
721             }else{
722                 me.button = -1;
723                 me.shiftKey = false;
724                 me.ctrlKey = false;
725                 me.altKey = false;
726                 me.keyCode = 0;
727                 me.charCode = 0;
728                 me.target = null;
729                 me.xy = [0, 0];
730             }
731             return me;
732         },
733
734         <div id="method-Ext.EventObject-stopEvent"></div>/**
735          * Stop the event (preventDefault and stopPropagation)
736          */
737         stopEvent : function(){
738             var me = this;
739             if(me.browserEvent){
740                 if(me.browserEvent.type == 'mousedown'){
741                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
742                 }
743                 E.stopEvent(me.browserEvent);
744             }
745         },
746
747         <div id="method-Ext.EventObject-preventDefault"></div>/**
748          * Prevents the browsers default handling of the event.
749          */
750         preventDefault : function(){
751             if(this.browserEvent){
752                 E.preventDefault(this.browserEvent);
753             }
754         },
755
756         <div id="method-Ext.EventObject-stopPropagation"></div>/**
757          * Cancels bubbling of the event.
758          */
759         stopPropagation : function(){
760             var me = this;
761             if(me.browserEvent){
762                 if(me.browserEvent.type == 'mousedown'){
763                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
764                 }
765                 E.stopPropagation(me.browserEvent);
766             }
767         },
768
769         <div id="method-Ext.EventObject-getCharCode"></div>/**
770          * Gets the character code for the event.
771          * @return {Number}
772          */
773         getCharCode : function(){
774             return this.charCode || this.keyCode;
775         },
776
777         <div id="method-Ext.EventObject-getKey"></div>/**
778          * Returns a normalized keyCode for the event.
779          * @return {Number} The key code
780          */
781         getKey : function(){
782             return this.normalizeKey(this.keyCode || this.charCode)
783         },
784
785         // private
786         normalizeKey: function(k){
787             return Ext.isSafari ? (safariKeys[k] || k) : k;
788         },
789
790         <div id="method-Ext.EventObject-getPageX"></div>/**
791          * Gets the x coordinate of the event.
792          * @return {Number}
793          */
794         getPageX : function(){
795             return this.xy[0];
796         },
797
798         <div id="method-Ext.EventObject-getPageY"></div>/**
799          * Gets the y coordinate of the event.
800          * @return {Number}
801          */
802         getPageY : function(){
803             return this.xy[1];
804         },
805
806         <div id="method-Ext.EventObject-getXY"></div>/**
807          * Gets the page coordinates of the event.
808          * @return {Array} The xy values like [x, y]
809          */
810         getXY : function(){
811             return this.xy;
812         },
813
814         <div id="method-Ext.EventObject-getTarget"></div>/**
815          * Gets the target for the event.
816          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
817          * @param {Number/Mixed} maxDepth (optional) The max depth to
818                 search as a number or element (defaults to 10 || document.body)
819          * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
820          * @return {HTMLelement}
821          */
822         getTarget : function(selector, maxDepth, returnEl){
823             return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
824         },
825
826         <div id="method-Ext.EventObject-getRelatedTarget"></div>/**
827          * Gets the related target.
828          * @return {HTMLElement}
829          */
830         getRelatedTarget : function(){
831             return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
832         },
833
834         <div id="method-Ext.EventObject-getWheelDelta"></div>/**
835          * Normalizes mouse wheel delta across browsers
836          * @return {Number} The delta
837          */
838         getWheelDelta : function(){
839             var e = this.browserEvent;
840             var delta = 0;
841             if(e.wheelDelta){ /* IE/Opera. */
842                 delta = e.wheelDelta/120;
843             }else if(e.detail){ /* Mozilla case. */
844                 delta = -e.detail/3;
845             }
846             return delta;
847         },
848
849         <div id="method-Ext.EventObject-within"></div>/**
850         * Returns true if the target of this event is a child of el.  Unless the allowEl parameter is set, it will return false if if the target is el.
851         * Example usage:<pre><code>
852         // Handle click on any child of an element
853         Ext.getBody().on('click', function(e){
854             if(e.within('some-el')){
855                 alert('Clicked on a child of some-el!');
856             }
857         });
858
859         // Handle click directly on an element, ignoring clicks on child nodes
860         Ext.getBody().on('click', function(e,t){
861             if((t.id == 'some-el') && !e.within(t, true)){
862                 alert('Clicked directly on some-el!');
863             }
864         });
865         </code></pre>
866          * @param {Mixed} el The id, DOM element or Ext.Element to check
867          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
868          * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
869          * @return {Boolean}
870          */
871         within : function(el, related, allowEl){
872             if(el){
873                 var t = this[related ? "getRelatedTarget" : "getTarget"]();
874                 return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
875             }
876             return false;
877         }
878      };
879
880     return new Ext.EventObjectImpl();
881 }();
882 </pre>    
883 </body>
884 </html>