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