PageRenderTime 72ms CodeModel.GetById 21ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/ext-4.0.7/src/core/src/EventObject.js

https://bitbucket.org/srogerf/javascript
JavaScript | 883 lines | 468 code | 77 blank | 338 comment | 80 complexity | a30f801da6b45b07c95e9ca2f16e4709 MD5 | raw file
  1/*
  2
  3This file is part of Ext JS 4
  4
  5Copyright (c) 2011 Sencha Inc
  6
  7Contact:  http://www.sencha.com/contact
  8
  9GNU General Public License Usage
 10This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
 11
 12If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
 13
 14*/
 15/**
 16 * @class Ext.EventObject
 17
 18Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
 19wraps the browser's native event-object normalizing cross-browser differences,
 20such as which mouse button is clicked, keys pressed, mechanisms to stop
 21event-propagation along with a method to prevent default actions from taking place.
 22
 23For example:
 24
 25    function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
 26        e.preventDefault();
 27        var target = e.getTarget(); // same as t (the target HTMLElement)
 28        ...
 29    }
 30
 31    var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
 32    myDiv.on(         // 'on' is shorthand for addListener
 33        "click",      // perform an action on click of myDiv
 34        handleClick   // reference to the action handler
 35    );
 36
 37    // other methods to do the same:
 38    Ext.EventManager.on("myDiv", 'click', handleClick);
 39    Ext.EventManager.addListener("myDiv", 'click', handleClick);
 40
 41 * @singleton
 42 * @markdown
 43 */
 44Ext.define('Ext.EventObjectImpl', {
 45    uses: ['Ext.util.Point'],
 46
 47    /** Key constant @type Number */
 48    BACKSPACE: 8,
 49    /** Key constant @type Number */
 50    TAB: 9,
 51    /** Key constant @type Number */
 52    NUM_CENTER: 12,
 53    /** Key constant @type Number */
 54    ENTER: 13,
 55    /** Key constant @type Number */
 56    RETURN: 13,
 57    /** Key constant @type Number */
 58    SHIFT: 16,
 59    /** Key constant @type Number */
 60    CTRL: 17,
 61    /** Key constant @type Number */
 62    ALT: 18,
 63    /** Key constant @type Number */
 64    PAUSE: 19,
 65    /** Key constant @type Number */
 66    CAPS_LOCK: 20,
 67    /** Key constant @type Number */
 68    ESC: 27,
 69    /** Key constant @type Number */
 70    SPACE: 32,
 71    /** Key constant @type Number */
 72    PAGE_UP: 33,
 73    /** Key constant @type Number */
 74    PAGE_DOWN: 34,
 75    /** Key constant @type Number */
 76    END: 35,
 77    /** Key constant @type Number */
 78    HOME: 36,
 79    /** Key constant @type Number */
 80    LEFT: 37,
 81    /** Key constant @type Number */
 82    UP: 38,
 83    /** Key constant @type Number */
 84    RIGHT: 39,
 85    /** Key constant @type Number */
 86    DOWN: 40,
 87    /** Key constant @type Number */
 88    PRINT_SCREEN: 44,
 89    /** Key constant @type Number */
 90    INSERT: 45,
 91    /** Key constant @type Number */
 92    DELETE: 46,
 93    /** Key constant @type Number */
 94    ZERO: 48,
 95    /** Key constant @type Number */
 96    ONE: 49,
 97    /** Key constant @type Number */
 98    TWO: 50,
 99    /** Key constant @type Number */
100    THREE: 51,
101    /** Key constant @type Number */
102    FOUR: 52,
103    /** Key constant @type Number */
104    FIVE: 53,
105    /** Key constant @type Number */
106    SIX: 54,
107    /** Key constant @type Number */
108    SEVEN: 55,
109    /** Key constant @type Number */
110    EIGHT: 56,
111    /** Key constant @type Number */
112    NINE: 57,
113    /** Key constant @type Number */
114    A: 65,
115    /** Key constant @type Number */
116    B: 66,
117    /** Key constant @type Number */
118    C: 67,
119    /** Key constant @type Number */
120    D: 68,
121    /** Key constant @type Number */
122    E: 69,
123    /** Key constant @type Number */
124    F: 70,
125    /** Key constant @type Number */
126    G: 71,
127    /** Key constant @type Number */
128    H: 72,
129    /** Key constant @type Number */
130    I: 73,
131    /** Key constant @type Number */
132    J: 74,
133    /** Key constant @type Number */
134    K: 75,
135    /** Key constant @type Number */
136    L: 76,
137    /** Key constant @type Number */
138    M: 77,
139    /** Key constant @type Number */
140    N: 78,
141    /** Key constant @type Number */
142    O: 79,
143    /** Key constant @type Number */
144    P: 80,
145    /** Key constant @type Number */
146    Q: 81,
147    /** Key constant @type Number */
148    R: 82,
149    /** Key constant @type Number */
150    S: 83,
151    /** Key constant @type Number */
152    T: 84,
153    /** Key constant @type Number */
154    U: 85,
155    /** Key constant @type Number */
156    V: 86,
157    /** Key constant @type Number */
158    W: 87,
159    /** Key constant @type Number */
160    X: 88,
161    /** Key constant @type Number */
162    Y: 89,
163    /** Key constant @type Number */
164    Z: 90,
165    /** Key constant @type Number */
166    CONTEXT_MENU: 93,
167    /** Key constant @type Number */
168    NUM_ZERO: 96,
169    /** Key constant @type Number */
170    NUM_ONE: 97,
171    /** Key constant @type Number */
172    NUM_TWO: 98,
173    /** Key constant @type Number */
174    NUM_THREE: 99,
175    /** Key constant @type Number */
176    NUM_FOUR: 100,
177    /** Key constant @type Number */
178    NUM_FIVE: 101,
179    /** Key constant @type Number */
180    NUM_SIX: 102,
181    /** Key constant @type Number */
182    NUM_SEVEN: 103,
183    /** Key constant @type Number */
184    NUM_EIGHT: 104,
185    /** Key constant @type Number */
186    NUM_NINE: 105,
187    /** Key constant @type Number */
188    NUM_MULTIPLY: 106,
189    /** Key constant @type Number */
190    NUM_PLUS: 107,
191    /** Key constant @type Number */
192    NUM_MINUS: 109,
193    /** Key constant @type Number */
194    NUM_PERIOD: 110,
195    /** Key constant @type Number */
196    NUM_DIVISION: 111,
197    /** Key constant @type Number */
198    F1: 112,
199    /** Key constant @type Number */
200    F2: 113,
201    /** Key constant @type Number */
202    F3: 114,
203    /** Key constant @type Number */
204    F4: 115,
205    /** Key constant @type Number */
206    F5: 116,
207    /** Key constant @type Number */
208    F6: 117,
209    /** Key constant @type Number */
210    F7: 118,
211    /** Key constant @type Number */
212    F8: 119,
213    /** Key constant @type Number */
214    F9: 120,
215    /** Key constant @type Number */
216    F10: 121,
217    /** Key constant @type Number */
218    F11: 122,
219    /** Key constant @type Number */
220    F12: 123,
221    /**
222     * The mouse wheel delta scaling factor. This value depends on browser version and OS and
223     * attempts to produce a similar scrolling experience across all platforms and browsers.
224     *
225     * To change this value:
226     *
227     *      Ext.EventObjectImpl.prototype.WHEEL_SCALE = 72;
228     *
229     * @type Number
230     * @markdown
231     */
232    WHEEL_SCALE: (function () {
233        var scale;
234
235        if (Ext.isGecko) {
236            // Firefox uses 3 on all platforms
237            scale = 3;
238        } else if (Ext.isMac) {
239            // Continuous scrolling devices have momentum and produce much more scroll than
240            // discrete devices on the same OS and browser. To make things exciting, Safari
241            // (and not Chrome) changed from small values to 120 (like IE).
242
243            if (Ext.isSafari && Ext.webKitVersion >= 532.0) {
244                // Safari changed the scrolling factor to match IE (for details see
245                // https://bugs.webkit.org/show_bug.cgi?id=24368). The WebKit version where this
246                // change was introduced was 532.0
247                //      Detailed discussion:
248                //      https://bugs.webkit.org/show_bug.cgi?id=29601
249                //      http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
250                scale = 120;
251            } else {
252                // MS optical wheel mouse produces multiples of 12 which is close enough
253                // to help tame the speed of the continuous mice...
254                scale = 12;
255            }
256
257            // Momentum scrolling produces very fast scrolling, so increase the scale factor
258            // to help produce similar results cross platform. This could be even larger and
259            // it would help those mice, but other mice would become almost unusable as a
260            // result (since we cannot tell which device type is in use).
261            scale *= 3;
262        } else {
263            // IE, Opera and other Windows browsers use 120.
264            scale = 120;
265        }
266
267        return scale;
268    })(),
269
270    /**
271     * Simple click regex
272     * @private
273     */
274    clickRe: /(dbl)?click/,
275    // safari keypress events for special keys return bad keycodes
276    safariKeys: {
277        3: 13, // enter
278        63234: 37, // left
279        63235: 39, // right
280        63232: 38, // up
281        63233: 40, // down
282        63276: 33, // page up
283        63277: 34, // page down
284        63272: 46, // delete
285        63273: 36, // home
286        63275: 35 // end
287    },
288    // normalize button clicks, don't see any way to feature detect this.
289    btnMap: Ext.isIE ? {
290        1: 0,
291        4: 1,
292        2: 2
293    } : {
294        0: 0,
295        1: 1,
296        2: 2
297    },
298
299    constructor: function(event, freezeEvent){
300        if (event) {
301            this.setEvent(event.browserEvent || event, freezeEvent);
302        }
303    },
304
305    setEvent: function(event, freezeEvent){
306        var me = this, button, options;
307
308        if (event == me || (event && event.browserEvent)) { // already wrapped
309            return event;
310        }
311        me.browserEvent = event;
312        if (event) {
313            // normalize buttons
314            button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
315            if (me.clickRe.test(event.type) && button == -1) {
316                button = 0;
317            }
318            options = {
319                type: event.type,
320                button: button,
321                shiftKey: event.shiftKey,
322                // mac metaKey behaves like ctrlKey
323                ctrlKey: event.ctrlKey || event.metaKey || false,
324                altKey: event.altKey,
325                // in getKey these will be normalized for the mac
326                keyCode: event.keyCode,
327                charCode: event.charCode,
328                // cache the targets for the delayed and or buffered events
329                target: Ext.EventManager.getTarget(event),
330                relatedTarget: Ext.EventManager.getRelatedTarget(event),
331                currentTarget: event.currentTarget,
332                xy: (freezeEvent ? me.getXY() : null)
333            };
334        } else {
335            options = {
336                button: -1,
337                shiftKey: false,
338                ctrlKey: false,
339                altKey: false,
340                keyCode: 0,
341                charCode: 0,
342                target: null,
343                xy: [0, 0]
344            };
345        }
346        Ext.apply(me, options);
347        return me;
348    },
349
350    /**
351     * Stop the event (preventDefault and stopPropagation)
352     */
353    stopEvent: function(){
354        this.stopPropagation();
355        this.preventDefault();
356    },
357
358    /**
359     * Prevents the browsers default handling of the event.
360     */
361    preventDefault: function(){
362        if (this.browserEvent) {
363            Ext.EventManager.preventDefault(this.browserEvent);
364        }
365    },
366
367    /**
368     * Cancels bubbling of the event.
369     */
370    stopPropagation: function(){
371        var browserEvent = this.browserEvent;
372
373        if (browserEvent) {
374            if (browserEvent.type == 'mousedown') {
375                Ext.EventManager.stoppedMouseDownEvent.fire(this);
376            }
377            Ext.EventManager.stopPropagation(browserEvent);
378        }
379    },
380
381    /**
382     * Gets the character code for the event.
383     * @return {Number}
384     */
385    getCharCode: function(){
386        return this.charCode || this.keyCode;
387    },
388
389    /**
390     * Returns a normalized keyCode for the event.
391     * @return {Number} The key code
392     */
393    getKey: function(){
394        return this.normalizeKey(this.keyCode || this.charCode);
395    },
396
397    /**
398     * Normalize key codes across browsers
399     * @private
400     * @param {Number} key The key code
401     * @return {Number} The normalized code
402     */
403    normalizeKey: function(key){
404        // can't feature detect this
405        return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
406    },
407
408    /**
409     * Gets the x coordinate of the event.
410     * @return {Number}
411     * @deprecated 4.0 Replaced by {@link #getX}
412     */
413    getPageX: function(){
414        return this.getX();
415    },
416
417    /**
418     * Gets the y coordinate of the event.
419     * @return {Number}
420     * @deprecated 4.0 Replaced by {@link #getY}
421     */
422    getPageY: function(){
423        return this.getY();
424    },
425
426    /**
427     * Gets the x coordinate of the event.
428     * @return {Number}
429     */
430    getX: function() {
431        return this.getXY()[0];
432    },
433
434    /**
435     * Gets the y coordinate of the event.
436     * @return {Number}
437     */
438    getY: function() {
439        return this.getXY()[1];
440    },
441
442    /**
443     * Gets the page coordinates of the event.
444     * @return {Number[]} The xy values like [x, y]
445     */
446    getXY: function() {
447        if (!this.xy) {
448            // same for XY
449            this.xy = Ext.EventManager.getPageXY(this.browserEvent);
450        }
451        return this.xy;
452    },
453
454    /**
455     * Gets the target for the event.
456     * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
457     * @param {Number/HTMLElement} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
458     * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
459     * @return {HTMLElement}
460     */
461    getTarget : function(selector, maxDepth, returnEl){
462        if (selector) {
463            return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
464        }
465        return returnEl ? Ext.get(this.target) : this.target;
466    },
467
468    /**
469     * Gets the related target.
470     * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
471     * @param {Number/HTMLElement} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
472     * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
473     * @return {HTMLElement}
474     */
475    getRelatedTarget : function(selector, maxDepth, returnEl){
476        if (selector) {
477            return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
478        }
479        return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
480    },
481
482    /**
483     * Correctly scales a given wheel delta.
484     * @param {Number} delta The delta value.
485     */
486    correctWheelDelta : function (delta) {
487        var scale = this.WHEEL_SCALE,
488            ret = Math.round(delta / scale);
489
490        if (!ret && delta) {
491            ret = (delta < 0) ? -1 : 1; // don't allow non-zero deltas to go to zero!
492        }
493
494        return ret;
495    },
496
497    /**
498     * Returns the mouse wheel deltas for this event.
499     * @return {Object} An object with "x" and "y" properties holding the mouse wheel deltas.
500     */
501    getWheelDeltas : function () {
502        var me = this,
503            event = me.browserEvent,
504            dx = 0, dy = 0; // the deltas
505
506        if (Ext.isDefined(event.wheelDeltaX)) { // WebKit has both dimensions
507            dx = event.wheelDeltaX;
508            dy = event.wheelDeltaY;
509        } else if (event.wheelDelta) { // old WebKit and IE
510            dy = event.wheelDelta;
511        } else if (event.detail) { // Gecko
512            dy = -event.detail; // gecko is backwards
513
514            // Gecko sometimes returns really big values if the user changes settings to
515            // scroll a whole page per scroll
516            if (dy > 100) {
517                dy = 3;
518            } else if (dy < -100) {
519                dy = -3;
520            }
521
522            // Firefox 3.1 adds an axis field to the event to indicate direction of
523            // scroll.  See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
524            if (Ext.isDefined(event.axis) && event.axis === event.HORIZONTAL_AXIS) {
525                dx = dy;
526                dy = 0;
527            }
528        }
529
530        return {
531            x: me.correctWheelDelta(dx),
532            y: me.correctWheelDelta(dy)
533        };
534    },
535
536    /**
537     * Normalizes mouse wheel y-delta across browsers. To get x-delta information, use
538     * {@link #getWheelDeltas} instead.
539     * @return {Number} The mouse wheel y-delta
540     */
541    getWheelDelta : function(){
542        var deltas = this.getWheelDeltas();
543
544        return deltas.y;
545    },
546
547    /**
548     * Returns true if the target of this event is a child of el.  Unless the allowEl parameter is set, it will return false if if the target is el.
549     * Example usage:<pre><code>
550// Handle click on any child of an element
551Ext.getBody().on('click', function(e){
552    if(e.within('some-el')){
553        alert('Clicked on a child of some-el!');
554    }
555});
556
557// Handle click directly on an element, ignoring clicks on child nodes
558Ext.getBody().on('click', function(e,t){
559    if((t.id == 'some-el') && !e.within(t, true)){
560        alert('Clicked directly on some-el!');
561    }
562});
563</code></pre>
564     * @param {String/HTMLElement/Ext.Element} el The id, DOM element or Ext.Element to check
565     * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
566     * @param {Boolean} allowEl (optional) true to also check if the passed element is the target or related target
567     * @return {Boolean}
568     */
569    within : function(el, related, allowEl){
570        if(el){
571            var t = related ? this.getRelatedTarget() : this.getTarget(),
572                result;
573
574            if (t) {
575                result = Ext.fly(el).contains(t);
576                if (!result && allowEl) {
577                    result = t == Ext.getDom(el);
578                }
579                return result;
580            }
581        }
582        return false;
583    },
584
585    /**
586     * Checks if the key pressed was a "navigation" key
587     * @return {Boolean} True if the press is a navigation keypress
588     */
589    isNavKeyPress : function(){
590        var me = this,
591            k = this.normalizeKey(me.keyCode);
592
593       return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
594       k == me.RETURN ||
595       k == me.TAB ||
596       k == me.ESC;
597    },
598
599    /**
600     * Checks if the key pressed was a "special" key
601     * @return {Boolean} True if the press is a special keypress
602     */
603    isSpecialKey : function(){
604        var k = this.normalizeKey(this.keyCode);
605        return (this.type == 'keypress' && this.ctrlKey) ||
606        this.isNavKeyPress() ||
607        (k == this.BACKSPACE) || // Backspace
608        (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
609        (k >= 44 && k <= 46);   // Print Screen, Insert, Delete
610    },
611
612    /**
613     * Returns a point object that consists of the object coordinates.
614     * @return {Ext.util.Point} point
615     */
616    getPoint : function(){
617        var xy = this.getXY();
618        return Ext.create('Ext.util.Point', xy[0], xy[1]);
619    },
620
621   /**
622    * Returns true if the control, meta, shift or alt key was pressed during this event.
623    * @return {Boolean}
624    */
625    hasModifier : function(){
626        return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
627    },
628
629    /**
630     * Injects a DOM event using the data in this object and (optionally) a new target.
631     * This is a low-level technique and not likely to be used by application code. The
632     * currently supported event types are:
633     * <p><b>HTMLEvents</b></p>
634     * <ul>
635     * <li>load</li>
636     * <li>unload</li>
637     * <li>select</li>
638     * <li>change</li>
639     * <li>submit</li>
640     * <li>reset</li>
641     * <li>resize</li>
642     * <li>scroll</li>
643     * </ul>
644     * <p><b>MouseEvents</b></p>
645     * <ul>
646     * <li>click</li>
647     * <li>dblclick</li>
648     * <li>mousedown</li>
649     * <li>mouseup</li>
650     * <li>mouseover</li>
651     * <li>mousemove</li>
652     * <li>mouseout</li>
653     * </ul>
654     * <p><b>UIEvents</b></p>
655     * <ul>
656     * <li>focusin</li>
657     * <li>focusout</li>
658     * <li>activate</li>
659     * <li>focus</li>
660     * <li>blur</li>
661     * </ul>
662     * @param {Ext.Element/HTMLElement} target (optional) If specified, the target for the event. This
663     * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
664     * is used to determine the target.
665     */
666    injectEvent: function () {
667        var API,
668            dispatchers = {}; // keyed by event type (e.g., 'mousedown')
669
670        // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
671
672        // IE9 has createEvent, but this code causes major problems with htmleditor (it
673        // blocks all mouse events and maybe more). TODO
674
675        if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
676            API = {
677                createHtmlEvent: function (doc, type, bubbles, cancelable) {
678                    var event = doc.createEvent('HTMLEvents');
679
680                    event.initEvent(type, bubbles, cancelable);
681                    return event;
682                },
683
684                createMouseEvent: function (doc, type, bubbles, cancelable, detail,
685                                            clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
686                                            button, relatedTarget) {
687                    var event = doc.createEvent('MouseEvents'),
688                        view = doc.defaultView || window;
689
690                    if (event.initMouseEvent) {
691                        event.initMouseEvent(type, bubbles, cancelable, view, detail,
692                                    clientX, clientY, clientX, clientY, ctrlKey, altKey,
693                                    shiftKey, metaKey, button, relatedTarget);
694                    } else { // old Safari
695                        event = doc.createEvent('UIEvents');
696                        event.initEvent(type, bubbles, cancelable);
697                        event.view = view;
698                        event.detail = detail;
699                        event.screenX = clientX;
700                        event.screenY = clientY;
701                        event.clientX = clientX;
702                        event.clientY = clientY;
703                        event.ctrlKey = ctrlKey;
704                        event.altKey = altKey;
705                        event.metaKey = metaKey;
706                        event.shiftKey = shiftKey;
707                        event.button = button;
708                        event.relatedTarget = relatedTarget;
709                    }
710
711                    return event;
712                },
713
714                createUIEvent: function (doc, type, bubbles, cancelable, detail) {
715                    var event = doc.createEvent('UIEvents'),
716                        view = doc.defaultView || window;
717
718                    event.initUIEvent(type, bubbles, cancelable, view, detail);
719                    return event;
720                },
721
722                fireEvent: function (target, type, event) {
723                    target.dispatchEvent(event);
724                },
725
726                fixTarget: function (target) {
727                    // Safari3 doesn't have window.dispatchEvent()
728                    if (target == window && !target.dispatchEvent) {
729                        return document;
730                    }
731
732                    return target;
733                }
734            };
735        } else if (document.createEventObject) { // else if (IE)
736            var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
737
738            API = {
739                createHtmlEvent: function (doc, type, bubbles, cancelable) {
740                    var event = doc.createEventObject();
741                    event.bubbles = bubbles;
742                    event.cancelable = cancelable;
743                    return event;
744                },
745
746                createMouseEvent: function (doc, type, bubbles, cancelable, detail,
747                                            clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
748                                            button, relatedTarget) {
749                    var event = doc.createEventObject();
750                    event.bubbles = bubbles;
751                    event.cancelable = cancelable;
752                    event.detail = detail;
753                    event.screenX = clientX;
754                    event.screenY = clientY;
755                    event.clientX = clientX;
756                    event.clientY = clientY;
757                    event.ctrlKey = ctrlKey;
758                    event.altKey = altKey;
759                    event.shiftKey = shiftKey;
760                    event.metaKey = metaKey;
761                    event.button = crazyIEButtons[button] || button;
762                    event.relatedTarget = relatedTarget; // cannot assign to/fromElement
763                    return event;
764                },
765
766                createUIEvent: function (doc, type, bubbles, cancelable, detail) {
767                    var event = doc.createEventObject();
768                    event.bubbles = bubbles;
769                    event.cancelable = cancelable;
770                    return event;
771                },
772
773                fireEvent: function (target, type, event) {
774                    target.fireEvent('on' + type, event);
775                },
776
777                fixTarget: function (target) {
778                    if (target == document) {
779                        // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
780                        // IE6,IE7 cannot properly call document.fireEvent()
781                        return document.documentElement;
782                    }
783
784                    return target;
785                }
786            };
787        }
788
789        //----------------
790        // HTMLEvents
791
792        Ext.Object.each({
793                load:   [false, false],
794                unload: [false, false],
795                select: [true, false],
796                change: [true, false],
797                submit: [true, true],
798                reset:  [true, false],
799                resize: [true, false],
800                scroll: [true, false]
801            },
802            function (name, value) {
803                var bubbles = value[0], cancelable = value[1];
804                dispatchers[name] = function (targetEl, srcEvent) {
805                    var e = API.createHtmlEvent(name, bubbles, cancelable);
806                    API.fireEvent(targetEl, name, e);
807                };
808            });
809
810        //----------------
811        // MouseEvents
812
813        function createMouseEventDispatcher (type, detail) {
814            var cancelable = (type != 'mousemove');
815            return function (targetEl, srcEvent) {
816                var xy = srcEvent.getXY(),
817                    e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
818                                detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
819                                srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
820                                srcEvent.relatedTarget);
821                API.fireEvent(targetEl, type, e);
822            };
823        }
824
825        Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
826            function (eventName) {
827                dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
828            });
829
830        //----------------
831        // UIEvents
832
833        Ext.Object.each({
834                focusin:  [true, false],
835                focusout: [true, false],
836                activate: [true, true],
837                focus:    [false, false],
838                blur:     [false, false]
839            },
840            function (name, value) {
841                var bubbles = value[0], cancelable = value[1];
842                dispatchers[name] = function (targetEl, srcEvent) {
843                    var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
844                    API.fireEvent(targetEl, name, e);
845                };
846            });
847
848        //---------
849        if (!API) {
850            // not even sure what ancient browsers fall into this category...
851
852            dispatchers = {}; // never mind all those we just built :P
853
854            API = {
855                fixTarget: function (t) {
856                    return t;
857                }
858            };
859        }
860
861        function cannotInject (target, srcEvent) {
862            //<debug>
863            // TODO log something
864            //</debug>
865        }
866
867        return function (target) {
868            var me = this,
869                dispatcher = dispatchers[me.type] || cannotInject,
870                t = target ? (target.dom || target) : me.getTarget();
871
872            t = API.fixTarget(t);
873            dispatcher(t, me);
874        };
875    }() // call to produce method
876
877}, function() {
878
879Ext.EventObject = new Ext.EventObjectImpl();
880
881});
882
883