d23defd6b476ea394fadd4591d27b52a7948be2c
[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
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             if(!resizeEvent){
375                 resizeEvent = new Roo.util.Event();
376                 resizeTask = new Roo.util.DelayedTask(function(){
377                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
378                 });
379                 E.on(window, "resize", function(){
380                     if(Roo.isIE){
381                         resizeTask.delay(50);
382                     }else{
383                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
384                     }
385                 });
386             }
387             resizeEvent.addListener(fn, scope, options);
388         },
389
390         /**
391          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
392          * @param {Function} fn        The method the event invokes
393          * @param {Object}   scope    An object that becomes the scope of the handler
394          * @param {boolean}  options
395          */
396         onTextResize : function(fn, scope, options){
397             if(!textEvent){
398                 textEvent = new Roo.util.Event();
399                 var textEl = new Roo.Element(document.createElement('div'));
400                 textEl.dom.className = 'x-text-resize';
401                 textEl.dom.innerHTML = 'X';
402                 textEl.appendTo(document.body);
403                 textSize = textEl.dom.offsetHeight;
404                 setInterval(function(){
405                     if(textEl.dom.offsetHeight != textSize){
406                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
407                     }
408                 }, this.textResizeInterval);
409             }
410             textEvent.addListener(fn, scope, options);
411         },
412
413         /**
414          * Removes the passed window resize listener.
415          * @param {Function} fn        The method the event invokes
416          * @param {Object}   scope    The scope of handler
417          */
418         removeResizeListener : function(fn, scope){
419             if(resizeEvent){
420                 resizeEvent.removeListener(fn, scope);
421             }
422         },
423
424         // private
425         fireResize : function(){
426             if(resizeEvent){
427                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
428             }   
429         },
430         /**
431          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
432          */
433         ieDeferSrc : false,
434         /**
435          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
436          */
437         textResizeInterval : 50
438     };
439     
440     /**
441      * Fix for doc tools
442      * @scopeAlias pub=Roo.EventManager
443      */
444     
445      /**
446      * Appends an event handler to an element (shorthand for addListener)
447      * @param {String/HTMLElement}   element        The html element or id to assign the
448      * @param {String}   eventName The type of event to listen for
449      * @param {Function} handler The method the event invokes
450      * @param {Object}   scope (optional) The scope in which to execute the handler
451      * function. The handler function's "this" context.
452      * @param {Object}   options (optional) An object containing handler configuration
453      * properties. This may contain any of the following properties:<ul>
454      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
455      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
456      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
457      * <li>preventDefault {Boolean} True to prevent the default action</li>
458      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
459      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
460      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
461      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
462      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
463      * by the specified number of milliseconds. If the event fires again within that time, the original
464      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
465      * </ul><br>
466      * <p>
467      * <b>Combining Options</b><br>
468      * Using the options argument, it is possible to combine different types of listeners:<br>
469      * <br>
470      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
471      * Code:<pre><code>
472 el.on('click', this.onClick, this, {
473     single: true,
474     delay: 100,
475     stopEvent : true,
476     forumId: 4
477 });</code></pre>
478      * <p>
479      * <b>Attaching multiple handlers in 1 call</b><br>
480       * The method also allows for a single argument to be passed which is a config object containing properties
481      * which specify multiple handlers.
482      * <p>
483      * Code:<pre><code>
484 el.on({
485     'click' : {
486         fn: this.onClick
487         scope: this,
488         delay: 100
489     },
490     'mouseover' : {
491         fn: this.onMouseOver
492         scope: this
493     },
494     'mouseout' : {
495         fn: this.onMouseOut
496         scope: this
497     }
498 });</code></pre>
499      * <p>
500      * Or a shorthand syntax:<br>
501      * Code:<pre><code>
502 el.on({
503     'click' : this.onClick,
504     'mouseover' : this.onMouseOver,
505     'mouseout' : this.onMouseOut
506     scope: this
507 });</code></pre>
508      */
509     pub.on = pub.addListener;
510     pub.un = pub.removeListener;
511
512     pub.stoppedMouseDownEvent = new Roo.util.Event();
513     return pub;
514 }();
515 /**
516   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
517   * @param {Function} fn        The method the event invokes
518   * @param {Object}   scope    An  object that becomes the scope of the handler
519   * @param {boolean}  override If true, the obj passed in becomes
520   *                             the execution scope of the listener
521   * @member Roo
522   * @method onReady
523  */
524 Roo.onReady = Roo.EventManager.onDocumentReady;
525
526 Roo.onReady(function(){
527     var bd = Roo.get(document.body);
528     if(!bd){ return; }
529
530     var cls = [
531             Roo.isIE ? "roo-ie"
532             : Roo.isIE11 ? "roo-ie11"
533             : Roo.isEdge ? "roo-edge"
534             : Roo.isGecko ? "roo-gecko"
535             : Roo.isOpera ? "roo-opera"
536             : Roo.isSafari ? "roo-safari" : ""];
537
538     if(Roo.isMac){
539         cls.push("roo-mac");
540     }
541     if(Roo.isLinux){
542         cls.push("roo-linux");
543     }
544     if(Roo.isIOS){
545         cls.push("roo-ios");
546     }
547     if(Roo.isTouch){
548         cls.push("roo-touch");
549     }
550     if(Roo.isBorderBox){
551         cls.push('roo-border-box');
552     }
553     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
554         var p = bd.dom.parentNode;
555         if(p){
556             p.className += ' roo-strict';
557         }
558     }
559     bd.addClass(cls.join(' '));
560 });
561
562 /**
563  * @class Roo.EventObject
564  * EventObject exposes the Yahoo! UI Event functionality directly on the object
565  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
566  * Example:
567  * <pre><code>
568  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
569     e.preventDefault();
570     var target = e.getTarget();
571     ...
572  }
573  var myDiv = Roo.get("myDiv");
574  myDiv.on("click", handleClick);
575  //or
576  Roo.EventManager.on("myDiv", 'click', handleClick);
577  Roo.EventManager.addListener("myDiv", 'click', handleClick);
578  </code></pre>
579  * @singleton
580  */
581 Roo.EventObject = function(){
582     
583     var E = Roo.lib.Event;
584     
585     // safari keypress events for special keys return bad keycodes
586     var safariKeys = {
587         63234 : 37, // left
588         63235 : 39, // right
589         63232 : 38, // up
590         63233 : 40, // down
591         63276 : 33, // page up
592         63277 : 34, // page down
593         63272 : 46, // delete
594         63273 : 36, // home
595         63275 : 35  // end
596     };
597
598     // normalize button clicks
599     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
600                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
601
602     Roo.EventObjectImpl = function(e){
603         if(e){
604             this.setEvent(e.browserEvent || e);
605         }
606     };
607     Roo.EventObjectImpl.prototype = {
608         /**
609          * Used to fix doc tools.
610          * @scope Roo.EventObject.prototype
611          */
612             
613
614         
615         
616         /** The normal browser event */
617         browserEvent : null,
618         /** The button pressed in a mouse event */
619         button : -1,
620         /** True if the shift key was down during the event */
621         shiftKey : false,
622         /** True if the control key was down during the event */
623         ctrlKey : false,
624         /** True if the alt key was down during the event */
625         altKey : false,
626
627         /** Key constant 
628         * @type Number */
629         BACKSPACE : 8,
630         /** Key constant 
631         * @type Number */
632         TAB : 9,
633         /** Key constant 
634         * @type Number */
635         RETURN : 13,
636         /** Key constant 
637         * @type Number */
638         ENTER : 13,
639         /** Key constant 
640         * @type Number */
641         SHIFT : 16,
642         /** Key constant 
643         * @type Number */
644         CONTROL : 17,
645         /** Key constant 
646         * @type Number */
647         ESC : 27,
648         /** Key constant 
649         * @type Number */
650         SPACE : 32,
651         /** Key constant 
652         * @type Number */
653         PAGEUP : 33,
654         /** Key constant 
655         * @type Number */
656         PAGEDOWN : 34,
657         /** Key constant 
658         * @type Number */
659         END : 35,
660         /** Key constant 
661         * @type Number */
662         HOME : 36,
663         /** Key constant 
664         * @type Number */
665         LEFT : 37,
666         /** Key constant 
667         * @type Number */
668         UP : 38,
669         /** Key constant 
670         * @type Number */
671         RIGHT : 39,
672         /** Key constant 
673         * @type Number */
674         DOWN : 40,
675         /** Key constant 
676         * @type Number */
677         DELETE : 46,
678         /** Key constant 
679         * @type Number */
680         F5 : 116,
681
682            /** @private */
683         setEvent : function(e){
684             if(e == this || (e && e.browserEvent)){ // already wrapped
685                 return e;
686             }
687             this.browserEvent = e;
688             if(e){
689                 // normalize buttons
690                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
691                 if(e.type == 'click' && this.button == -1){
692                     this.button = 0;
693                 }
694                 this.type = e.type;
695                 this.shiftKey = e.shiftKey;
696                 // mac metaKey behaves like ctrlKey
697                 this.ctrlKey = e.ctrlKey || e.metaKey;
698                 this.altKey = e.altKey;
699                 // in getKey these will be normalized for the mac
700                 this.keyCode = e.keyCode;
701                 // keyup warnings on firefox.
702                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
703                 // cache the target for the delayed and or buffered events
704                 this.target = E.getTarget(e);
705                 // same for XY
706                 this.xy = E.getXY(e);
707             }else{
708                 this.button = -1;
709                 this.shiftKey = false;
710                 this.ctrlKey = false;
711                 this.altKey = false;
712                 this.keyCode = 0;
713                 this.charCode =0;
714                 this.target = null;
715                 this.xy = [0, 0];
716             }
717             return this;
718         },
719
720         /**
721          * Stop the event (preventDefault and stopPropagation)
722          */
723         stopEvent : function(){
724             if(this.browserEvent){
725                 if(this.browserEvent.type == 'mousedown'){
726                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
727                 }
728                 E.stopEvent(this.browserEvent);
729             }
730         },
731
732         /**
733          * Prevents the browsers default handling of the event.
734          */
735         preventDefault : function(){
736             if(this.browserEvent){
737                 E.preventDefault(this.browserEvent);
738             }
739         },
740
741         /** @private */
742         isNavKeyPress : function(){
743             var k = this.keyCode;
744             k = Roo.isSafari ? (safariKeys[k] || k) : k;
745             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
746         },
747
748         isSpecialKey : function(){
749             var k = this.keyCode;
750             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
751             (k == 16) || (k == 17) ||
752             (k >= 18 && k <= 20) ||
753             (k >= 33 && k <= 35) ||
754             (k >= 36 && k <= 39) ||
755             (k >= 44 && k <= 45);
756         },
757         /**
758          * Cancels bubbling of the event.
759          */
760         stopPropagation : function(){
761             if(this.browserEvent){
762                 if(this.type == 'mousedown'){
763                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
764                 }
765                 E.stopPropagation(this.browserEvent);
766             }
767         },
768
769         /**
770          * Gets the key code for the event.
771          * @return {Number}
772          */
773         getCharCode : function(){
774             return this.charCode || this.keyCode;
775         },
776
777         /**
778          * Returns a normalized keyCode for the event.
779          * @return {Number} The key code
780          */
781         getKey : function(){
782             var k = this.keyCode || this.charCode;
783             return Roo.isSafari ? (safariKeys[k] || k) : k;
784         },
785
786         /**
787          * Gets the x coordinate of the event.
788          * @return {Number}
789          */
790         getPageX : function(){
791             return this.xy[0];
792         },
793
794         /**
795          * Gets the y coordinate of the event.
796          * @return {Number}
797          */
798         getPageY : function(){
799             return this.xy[1];
800         },
801
802         /**
803          * Gets the time of the event.
804          * @return {Number}
805          */
806         getTime : function(){
807             if(this.browserEvent){
808                 return E.getTime(this.browserEvent);
809             }
810             return null;
811         },
812
813         /**
814          * Gets the page coordinates of the event.
815          * @return {Array} The xy values like [x, y]
816          */
817         getXY : function(){
818             return this.xy;
819         },
820
821         /**
822          * Gets the target for the event.
823          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
824          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
825                 search as a number or element (defaults to 10 || document.body)
826          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
827          * @return {HTMLelement}
828          */
829         getTarget : function(selector, maxDepth, returnEl){
830             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
831         },
832         /**
833          * Gets the related target.
834          * @return {HTMLElement}
835          */
836         getRelatedTarget : function(){
837             if(this.browserEvent){
838                 return E.getRelatedTarget(this.browserEvent);
839             }
840             return null;
841         },
842
843         /**
844          * Normalizes mouse wheel delta across browsers
845          * @return {Number} The delta
846          */
847         getWheelDelta : function(){
848             var e = this.browserEvent;
849             var delta = 0;
850             if(e.wheelDelta){ /* IE/Opera. */
851                 delta = e.wheelDelta/120;
852             }else if(e.detail){ /* Mozilla case. */
853                 delta = -e.detail/3;
854             }
855             return delta;
856         },
857
858         /**
859          * Returns true if the control, meta, shift or alt key was pressed during this event.
860          * @return {Boolean}
861          */
862         hasModifier : function(){
863             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
864         },
865
866         /**
867          * Returns true if the target of this event equals el or is a child of el
868          * @param {String/HTMLElement/Element} el
869          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
870          * @return {Boolean}
871          */
872         within : function(el, related){
873             var t = this[related ? "getRelatedTarget" : "getTarget"]();
874             return t && Roo.fly(el).contains(t);
875         },
876
877         getPoint : function(){
878             return new Roo.lib.Point(this.xy[0], this.xy[1]);
879         }
880     };
881
882     return new Roo.EventObjectImpl();
883 }();
884             
885