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