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