initial import
[roojs1] / Roo / EventManager.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11
12 /**
13  * @class Roo.EventManager
14  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
15  * several useful events directly.
16  * See {@link Roo.EventObject} for more details on normalized event objects.
17  * @singleton
18  */
19 Roo.EventManager = function(){
20     var docReadyEvent, docReadyProcId, docReadyState = false;
21     var resizeEvent, resizeTask, textEvent, textSize;
22     var E = Roo.lib.Event;
23     var D = Roo.lib.Dom;
24
25
26     var fireDocReady = function(){
27         if(!docReadyState){
28             docReadyState = true;
29             Roo.isReady = true;
30             if(docReadyProcId){
31                 clearInterval(docReadyProcId);
32             }
33             if(Roo.isGecko || Roo.isOpera) {
34                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
35             }
36             if(Roo.isIE){
37                 var defer = document.getElementById("ie-deferred-loader");
38                 if(defer){
39                     defer.onreadystatechange = null;
40                     defer.parentNode.removeChild(defer);
41                 }
42             }
43             if(docReadyEvent){
44                 docReadyEvent.fire();
45                 docReadyEvent.clearListeners();
46             }
47         }
48     };
49     
50     var initDocReady = function(){
51         docReadyEvent = new Roo.util.Event();
52         if(Roo.isGecko || Roo.isOpera) {
53             document.addEventListener("DOMContentLoaded", fireDocReady, false);
54         }else if(Roo.isIE){
55             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
56             var defer = document.getElementById("ie-deferred-loader");
57             defer.onreadystatechange = function(){
58                 if(this.readyState == "complete"){
59                     fireDocReady();
60                 }
61             };
62         }else if(Roo.isSafari){ 
63             docReadyProcId = setInterval(function(){
64                 var rs = document.readyState;
65                 if(rs == "complete") {
66                     fireDocReady();     
67                  }
68             }, 10);
69         }
70         // no matter what, make sure it fires on load
71         E.on(window, "load", fireDocReady);
72     };
73
74     var createBuffered = function(h, o){
75         var task = new Roo.util.DelayedTask(h);
76         return function(e){
77             // create new event object impl so new events don't wipe out properties
78             e = new Roo.EventObjectImpl(e);
79             task.delay(o.buffer, h, null, [e]);
80         };
81     };
82
83     var createSingle = function(h, el, ename, fn){
84         return function(e){
85             Roo.EventManager.removeListener(el, ename, fn);
86             h(e);
87         };
88     };
89
90     var createDelayed = function(h, o){
91         return function(e){
92             // create new event object impl so new events don't wipe out properties
93             e = new Roo.EventObjectImpl(e);
94             setTimeout(function(){
95                 h(e);
96             }, o.delay || 10);
97         };
98     };
99
100     var listen = function(element, ename, opt, fn, scope){
101         var o = (!opt || typeof opt == "boolean") ? {} : opt;
102         fn = fn || o.fn; scope = scope || o.scope;
103         var el = Roo.getDom(element);
104         if(!el){
105             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
106         }
107         var h = function(e){
108             e = Roo.EventObject.setEvent(e);
109             var t;
110             if(o.delegate){
111                 t = e.getTarget(o.delegate, el);
112                 if(!t){
113                     return;
114                 }
115             }else{
116                 t = e.target;
117             }
118             if(o.stopEvent === true){
119                 e.stopEvent();
120             }
121             if(o.preventDefault === true){
122                e.preventDefault();
123             }
124             if(o.stopPropagation === true){
125                 e.stopPropagation();
126             }
127
128             if(o.normalized === false){
129                 e = e.browserEvent;
130             }
131
132             fn.call(scope || el, e, t, o);
133         };
134         if(o.delay){
135             h = createDelayed(h, o);
136         }
137         if(o.single){
138             h = createSingle(h, el, ename, fn);
139         }
140         if(o.buffer){
141             h = createBuffered(h, o);
142         }
143         fn._handlers = fn._handlers || [];
144         fn._handlers.push([Roo.id(el), ename, h]);
145
146         E.on(el, ename, h);
147         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
148             el.addEventListener("DOMMouseScroll", h, false);
149             E.on(window, 'unload', function(){
150                 el.removeEventListener("DOMMouseScroll", h, false);
151             });
152         }
153         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
154             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
155         }
156         return h;
157     };
158
159     var stopListening = function(el, ename, fn){
160         var id = Roo.id(el), hds = fn._handlers, hd = fn;
161         if(hds){
162             for(var i = 0, len = hds.length; i < len; i++){
163                 var h = hds[i];
164                 if(h[0] == id && h[1] == ename){
165                     hd = h[2];
166                     hds.splice(i, 1);
167                     break;
168                 }
169             }
170         }
171         E.un(el, ename, hd);
172         el = Roo.getDom(el);
173         if(ename == "mousewheel" && el.addEventListener){
174             el.removeEventListener("DOMMouseScroll", hd, false);
175         }
176         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
177             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
178         }
179     };
180
181     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
182     
183     var pub = {
184         
185         
186         /** 
187          * Fix for doc tools
188          * @scope Roo.EventManager
189          */
190         
191         
192         /** 
193          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
194          * object with a Roo.EventObject
195          * @param {Function} fn        The method the event invokes
196          * @param {Object}   scope    An object that becomes the scope of the handler
197          * @param {boolean}  override If true, the obj passed in becomes
198          *                             the execution scope of the listener
199          * @return {Function} The wrapped function
200          * @deprecated
201          */
202         wrap : function(fn, scope, override){
203             return function(e){
204                 Roo.EventObject.setEvent(e);
205                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
206             };
207         },
208         
209         /**
210      * Appends an event handler to an element (shorthand for addListener)
211      * @param {String/HTMLElement}   element        The html element or id to assign the
212      * @param {String}   eventName The type of event to listen for
213      * @param {Function} handler The method the event invokes
214      * @param {Object}   scope (optional) The scope in which to execute the handler
215      * function. The handler function's "this" context.
216      * @param {Object}   options (optional) An object containing handler configuration
217      * properties. This may contain any of the following properties:<ul>
218      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
219      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
220      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
221      * <li>preventDefault {Boolean} True to prevent the default action</li>
222      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
223      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
224      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
225      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
226      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
227      * by the specified number of milliseconds. If the event fires again within that time, the original
228      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
229      * </ul><br>
230      * <p>
231      * <b>Combining Options</b><br>
232      * Using the options argument, it is possible to combine different types of listeners:<br>
233      * <br>
234      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
235      * Code:<pre><code>
236 el.on('click', this.onClick, this, {
237     single: true,
238     delay: 100,
239     stopEvent : true,
240     forumId: 4
241 });</code></pre>
242      * <p>
243      * <b>Attaching multiple handlers in 1 call</b><br>
244       * The method also allows for a single argument to be passed which is a config object containing properties
245      * which specify multiple handlers.
246      * <p>
247      * Code:<pre><code>
248 el.on({
249     'click' : {
250         fn: this.onClick
251         scope: this,
252         delay: 100
253     },
254     'mouseover' : {
255         fn: this.onMouseOver
256         scope: this
257     },
258     'mouseout' : {
259         fn: this.onMouseOut
260         scope: this
261     }
262 });</code></pre>
263      * <p>
264      * Or a shorthand syntax:<br>
265      * Code:<pre><code>
266 el.on({
267     'click' : this.onClick,
268     'mouseover' : this.onMouseOver,
269     'mouseout' : this.onMouseOut
270     scope: this
271 });</code></pre>
272      */
273         addListener : function(element, eventName, fn, scope, options){
274             if(typeof eventName == "object"){
275                 var o = eventName;
276                 for(var e in o){
277                     if(propRe.test(e)){
278                         continue;
279                     }
280                     if(typeof o[e] == "function"){
281                         // shared options
282                         listen(element, e, o, o[e], o.scope);
283                     }else{
284                         // individual options
285                         listen(element, e, o[e]);
286                     }
287                 }
288                 return;
289             }
290             return listen(element, eventName, options, fn, scope);
291         },
292         
293         /**
294          * Removes an event handler
295          *
296          * @param {String/HTMLElement}   element        The id or html element to remove the 
297          *                             event from
298          * @param {String}   eventName     The type of event
299          * @param {Function} fn
300          * @return {Boolean} True if a listener was actually removed
301          */
302         removeListener : function(element, eventName, fn){
303             return stopListening(element, eventName, fn);
304         },
305         
306         /**
307          * Fires when the document is ready (before onload and before images are loaded). Can be 
308          * accessed shorthanded Roo.onReady().
309          * @param {Function} fn        The method the event invokes
310          * @param {Object}   scope    An  object that becomes the scope of the handler
311          * @param {boolean}  options
312          */
313         onDocumentReady : function(fn, scope, options){
314             if(docReadyState){ // if it already fired
315                 docReadyEvent.addListener(fn, scope, options);
316                 docReadyEvent.fire();
317                 docReadyEvent.clearListeners();
318                 return;
319             }
320             if(!docReadyEvent){
321                 initDocReady();
322             }
323             docReadyEvent.addListener(fn, scope, options);
324         },
325         
326         /**
327          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
328          * @param {Function} fn        The method the event invokes
329          * @param {Object}   scope    An object that becomes the scope of the handler
330          * @param {boolean}  options
331          */
332         onWindowResize : function(fn, scope, options){
333             if(!resizeEvent){
334                 resizeEvent = new Roo.util.Event();
335                 resizeTask = new Roo.util.DelayedTask(function(){
336                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
337                 });
338                 E.on(window, "resize", function(){
339                     if(Roo.isIE){
340                         resizeTask.delay(50);
341                     }else{
342                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
343                     }
344                 });
345             }
346             resizeEvent.addListener(fn, scope, options);
347         },
348
349         /**
350          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
351          * @param {Function} fn        The method the event invokes
352          * @param {Object}   scope    An object that becomes the scope of the handler
353          * @param {boolean}  options
354          */
355         onTextResize : function(fn, scope, options){
356             if(!textEvent){
357                 textEvent = new Roo.util.Event();
358                 var textEl = new Roo.Element(document.createElement('div'));
359                 textEl.dom.className = 'x-text-resize';
360                 textEl.dom.innerHTML = 'X';
361                 textEl.appendTo(document.body);
362                 textSize = textEl.dom.offsetHeight;
363                 setInterval(function(){
364                     if(textEl.dom.offsetHeight != textSize){
365                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
366                     }
367                 }, this.textResizeInterval);
368             }
369             textEvent.addListener(fn, scope, options);
370         },
371
372         /**
373          * Removes the passed window resize listener.
374          * @param {Function} fn        The method the event invokes
375          * @param {Object}   scope    The scope of handler
376          */
377         removeResizeListener : function(fn, scope){
378             if(resizeEvent){
379                 resizeEvent.removeListener(fn, scope);
380             }
381         },
382
383         // private
384         fireResize : function(){
385             if(resizeEvent){
386                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
387             }   
388         },
389         /**
390          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
391          */
392         ieDeferSrc : false,
393         /**
394          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
395          */
396         textResizeInterval : 50
397     };
398     
399     /**
400      * Fix for doc tools
401      * @scopeAlias pub=Roo.EventManager
402      */
403     
404      /**
405      * Appends an event handler to an element (shorthand for addListener)
406      * @param {String/HTMLElement}   element        The html element or id to assign the
407      * @param {String}   eventName The type of event to listen for
408      * @param {Function} handler The method the event invokes
409      * @param {Object}   scope (optional) The scope in which to execute the handler
410      * function. The handler function's "this" context.
411      * @param {Object}   options (optional) An object containing handler configuration
412      * properties. This may contain any of the following properties:<ul>
413      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
414      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
415      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
416      * <li>preventDefault {Boolean} True to prevent the default action</li>
417      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
418      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
419      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
420      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
421      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
422      * by the specified number of milliseconds. If the event fires again within that time, the original
423      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
424      * </ul><br>
425      * <p>
426      * <b>Combining Options</b><br>
427      * Using the options argument, it is possible to combine different types of listeners:<br>
428      * <br>
429      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
430      * Code:<pre><code>
431 el.on('click', this.onClick, this, {
432     single: true,
433     delay: 100,
434     stopEvent : true,
435     forumId: 4
436 });</code></pre>
437      * <p>
438      * <b>Attaching multiple handlers in 1 call</b><br>
439       * The method also allows for a single argument to be passed which is a config object containing properties
440      * which specify multiple handlers.
441      * <p>
442      * Code:<pre><code>
443 el.on({
444     'click' : {
445         fn: this.onClick
446         scope: this,
447         delay: 100
448     },
449     'mouseover' : {
450         fn: this.onMouseOver
451         scope: this
452     },
453     'mouseout' : {
454         fn: this.onMouseOut
455         scope: this
456     }
457 });</code></pre>
458      * <p>
459      * Or a shorthand syntax:<br>
460      * Code:<pre><code>
461 el.on({
462     'click' : this.onClick,
463     'mouseover' : this.onMouseOver,
464     'mouseout' : this.onMouseOut
465     scope: this
466 });</code></pre>
467      */
468     pub.on = pub.addListener;
469     pub.un = pub.removeListener;
470
471     pub.stoppedMouseDownEvent = new Roo.util.Event();
472     return pub;
473 }();
474 /**
475   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
476   * @param {Function} fn        The method the event invokes
477   * @param {Object}   scope    An  object that becomes the scope of the handler
478   * @param {boolean}  override If true, the obj passed in becomes
479   *                             the execution scope of the listener
480   * @member Roo
481   * @method onReady
482  */
483 Roo.onReady = Roo.EventManager.onDocumentReady;
484
485 Roo.onReady(function(){
486     var bd = Roo.get(document.body);
487     if(!bd){ return; }
488
489     var cls = [
490             Roo.isIE ? "roo-ie"
491             : Roo.isGecko ? "roo-gecko"
492             : Roo.isOpera ? "roo-opera"
493             : Roo.isSafari ? "roo-safari" : ""];
494
495     if(Roo.isMac){
496         cls.push("roo-mac");
497     }
498     if(Roo.isLinux){
499         cls.push("roo-linux");
500     }
501     if(Roo.isBorderBox){
502         cls.push('roo-border-box');
503     }
504     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
505         var p = bd.dom.parentNode;
506         if(p){
507             p.className += ' roo-strict';
508         }
509     }
510     bd.addClass(cls.join(' '));
511 });
512
513 /**
514  * @class Roo.EventObject
515  * EventObject exposes the Yahoo! UI Event functionality directly on the object
516  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
517  * Example:
518  * <pre><code>
519  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
520     e.preventDefault();
521     var target = e.getTarget();
522     ...
523  }
524  var myDiv = Roo.get("myDiv");
525  myDiv.on("click", handleClick);
526  //or
527  Roo.EventManager.on("myDiv", 'click', handleClick);
528  Roo.EventManager.addListener("myDiv", 'click', handleClick);
529  </code></pre>
530  * @singleton
531  */
532 Roo.EventObject = function(){
533     
534     var E = Roo.lib.Event;
535     
536     // safari keypress events for special keys return bad keycodes
537     var safariKeys = {
538         63234 : 37, // left
539         63235 : 39, // right
540         63232 : 38, // up
541         63233 : 40, // down
542         63276 : 33, // page up
543         63277 : 34, // page down
544         63272 : 46, // delete
545         63273 : 36, // home
546         63275 : 35  // end
547     };
548
549     // normalize button clicks
550     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
551                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
552
553     Roo.EventObjectImpl = function(e){
554         if(e){
555             this.setEvent(e.browserEvent || e);
556         }
557     };
558     Roo.EventObjectImpl.prototype = {
559         /**
560          * Used to fix doc tools.
561          * @scope Roo.EventObject.prototype
562          */
563             
564
565         
566         
567         /** The normal browser event */
568         browserEvent : null,
569         /** The button pressed in a mouse event */
570         button : -1,
571         /** True if the shift key was down during the event */
572         shiftKey : false,
573         /** True if the control key was down during the event */
574         ctrlKey : false,
575         /** True if the alt key was down during the event */
576         altKey : false,
577
578         /** Key constant 
579         * @type Number */
580         BACKSPACE : 8,
581         /** Key constant 
582         * @type Number */
583         TAB : 9,
584         /** Key constant 
585         * @type Number */
586         RETURN : 13,
587         /** Key constant 
588         * @type Number */
589         ENTER : 13,
590         /** Key constant 
591         * @type Number */
592         SHIFT : 16,
593         /** Key constant 
594         * @type Number */
595         CONTROL : 17,
596         /** Key constant 
597         * @type Number */
598         ESC : 27,
599         /** Key constant 
600         * @type Number */
601         SPACE : 32,
602         /** Key constant 
603         * @type Number */
604         PAGEUP : 33,
605         /** Key constant 
606         * @type Number */
607         PAGEDOWN : 34,
608         /** Key constant 
609         * @type Number */
610         END : 35,
611         /** Key constant 
612         * @type Number */
613         HOME : 36,
614         /** Key constant 
615         * @type Number */
616         LEFT : 37,
617         /** Key constant 
618         * @type Number */
619         UP : 38,
620         /** Key constant 
621         * @type Number */
622         RIGHT : 39,
623         /** Key constant 
624         * @type Number */
625         DOWN : 40,
626         /** Key constant 
627         * @type Number */
628         DELETE : 46,
629         /** Key constant 
630         * @type Number */
631         F5 : 116,
632
633            /** @private */
634         setEvent : function(e){
635             if(e == this || (e && e.browserEvent)){ // already wrapped
636                 return e;
637             }
638             this.browserEvent = e;
639             if(e){
640                 // normalize buttons
641                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
642                 if(e.type == 'click' && this.button == -1){
643                     this.button = 0;
644                 }
645                 this.type = e.type;
646                 this.shiftKey = e.shiftKey;
647                 // mac metaKey behaves like ctrlKey
648                 this.ctrlKey = e.ctrlKey || e.metaKey;
649                 this.altKey = e.altKey;
650                 // in getKey these will be normalized for the mac
651                 this.keyCode = e.keyCode;
652                 // keyup warnings on firefox.
653                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
654                 // cache the target for the delayed and or buffered events
655                 this.target = E.getTarget(e);
656                 // same for XY
657                 this.xy = E.getXY(e);
658             }else{
659                 this.button = -1;
660                 this.shiftKey = false;
661                 this.ctrlKey = false;
662                 this.altKey = false;
663                 this.keyCode = 0;
664                 this.charCode =0;
665                 this.target = null;
666                 this.xy = [0, 0];
667             }
668             return this;
669         },
670
671         /**
672          * Stop the event (preventDefault and stopPropagation)
673          */
674         stopEvent : function(){
675             if(this.browserEvent){
676                 if(this.browserEvent.type == 'mousedown'){
677                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
678                 }
679                 E.stopEvent(this.browserEvent);
680             }
681         },
682
683         /**
684          * Prevents the browsers default handling of the event.
685          */
686         preventDefault : function(){
687             if(this.browserEvent){
688                 E.preventDefault(this.browserEvent);
689             }
690         },
691
692         /** @private */
693         isNavKeyPress : function(){
694             var k = this.keyCode;
695             k = Roo.isSafari ? (safariKeys[k] || k) : k;
696             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
697         },
698
699         isSpecialKey : function(){
700             var k = this.keyCode;
701             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
702             (k == 16) || (k == 17) ||
703             (k >= 18 && k <= 20) ||
704             (k >= 33 && k <= 35) ||
705             (k >= 36 && k <= 39) ||
706             (k >= 44 && k <= 45);
707         },
708         /**
709          * Cancels bubbling of the event.
710          */
711         stopPropagation : function(){
712             if(this.browserEvent){
713                 if(this.type == 'mousedown'){
714                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
715                 }
716                 E.stopPropagation(this.browserEvent);
717             }
718         },
719
720         /**
721          * Gets the key code for the event.
722          * @return {Number}
723          */
724         getCharCode : function(){
725             return this.charCode || this.keyCode;
726         },
727
728         /**
729          * Returns a normalized keyCode for the event.
730          * @return {Number} The key code
731          */
732         getKey : function(){
733             var k = this.keyCode || this.charCode;
734             return Roo.isSafari ? (safariKeys[k] || k) : k;
735         },
736
737         /**
738          * Gets the x coordinate of the event.
739          * @return {Number}
740          */
741         getPageX : function(){
742             return this.xy[0];
743         },
744
745         /**
746          * Gets the y coordinate of the event.
747          * @return {Number}
748          */
749         getPageY : function(){
750             return this.xy[1];
751         },
752
753         /**
754          * Gets the time of the event.
755          * @return {Number}
756          */
757         getTime : function(){
758             if(this.browserEvent){
759                 return E.getTime(this.browserEvent);
760             }
761             return null;
762         },
763
764         /**
765          * Gets the page coordinates of the event.
766          * @return {Array} The xy values like [x, y]
767          */
768         getXY : function(){
769             return this.xy;
770         },
771
772         /**
773          * Gets the target for the event.
774          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
775          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
776                 search as a number or element (defaults to 10 || document.body)
777          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
778          * @return {HTMLelement}
779          */
780         getTarget : function(selector, maxDepth, returnEl){
781             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
782         },
783         /**
784          * Gets the related target.
785          * @return {HTMLElement}
786          */
787         getRelatedTarget : function(){
788             if(this.browserEvent){
789                 return E.getRelatedTarget(this.browserEvent);
790             }
791             return null;
792         },
793
794         /**
795          * Normalizes mouse wheel delta across browsers
796          * @return {Number} The delta
797          */
798         getWheelDelta : function(){
799             var e = this.browserEvent;
800             var delta = 0;
801             if(e.wheelDelta){ /* IE/Opera. */
802                 delta = e.wheelDelta/120;
803             }else if(e.detail){ /* Mozilla case. */
804                 delta = -e.detail/3;
805             }
806             return delta;
807         },
808
809         /**
810          * Returns true if the control, meta, shift or alt key was pressed during this event.
811          * @return {Boolean}
812          */
813         hasModifier : function(){
814             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
815         },
816
817         /**
818          * Returns true if the target of this event equals el or is a child of el
819          * @param {String/HTMLElement/Element} el
820          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
821          * @return {Boolean}
822          */
823         within : function(el, related){
824             var t = this[related ? "getRelatedTarget" : "getTarget"]();
825             return t && Roo.fly(el).contains(t);
826         },
827
828         getPoint : function(){
829             return new Roo.lib.Point(this.xy[0], this.xy[1]);
830         }
831     };
832
833     return new Roo.EventObjectImpl();
834 }();
835             
836