2 * @class Ext.EventObject
4 Just as {@link Ext.core.Element} wraps around a native DOM node, Ext.EventObject
5 wraps the browser's native event-object normalizing cross-browser differences,
6 such as which mouse button is clicked, keys pressed, mechanisms to stop
7 event-propagation along with a method to prevent default actions from taking place.
11 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
13 var target = e.getTarget(); // same as t (the target HTMLElement)
17 var myDiv = {@link Ext#get Ext.get}("myDiv"); // get reference to an {@link Ext.core.Element}
18 myDiv.on( // 'on' is shorthand for addListener
19 "click", // perform an action on click of myDiv
20 handleClick // reference to the action handler
23 // other methods to do the same:
24 Ext.EventManager.on("myDiv", 'click', handleClick);
25 Ext.EventManager.addListener("myDiv", 'click', handleClick);
30 Ext.define('Ext.EventObjectImpl', {
31 uses: ['Ext.util.Point'],
33 /** Key constant @type Number */
35 /** Key constant @type Number */
37 /** Key constant @type Number */
39 /** Key constant @type Number */
41 /** Key constant @type Number */
43 /** Key constant @type Number */
45 /** Key constant @type Number */
47 /** Key constant @type Number */
49 /** Key constant @type Number */
51 /** Key constant @type Number */
53 /** Key constant @type Number */
55 /** Key constant @type Number */
57 /** Key constant @type Number */
59 /** Key constant @type Number */
61 /** Key constant @type Number */
63 /** Key constant @type Number */
65 /** Key constant @type Number */
67 /** Key constant @type Number */
69 /** Key constant @type Number */
71 /** Key constant @type Number */
73 /** Key constant @type Number */
75 /** Key constant @type Number */
77 /** Key constant @type Number */
79 /** Key constant @type Number */
81 /** Key constant @type Number */
83 /** Key constant @type Number */
85 /** Key constant @type Number */
87 /** Key constant @type Number */
89 /** Key constant @type Number */
91 /** Key constant @type Number */
93 /** Key constant @type Number */
95 /** Key constant @type Number */
97 /** Key constant @type Number */
99 /** Key constant @type Number */
101 /** Key constant @type Number */
103 /** Key constant @type Number */
105 /** Key constant @type Number */
107 /** Key constant @type Number */
109 /** Key constant @type Number */
111 /** Key constant @type Number */
113 /** Key constant @type Number */
115 /** Key constant @type Number */
117 /** Key constant @type Number */
119 /** Key constant @type Number */
121 /** Key constant @type Number */
123 /** Key constant @type Number */
125 /** Key constant @type Number */
127 /** Key constant @type Number */
129 /** Key constant @type Number */
131 /** Key constant @type Number */
133 /** Key constant @type Number */
135 /** Key constant @type Number */
137 /** Key constant @type Number */
139 /** Key constant @type Number */
141 /** Key constant @type Number */
143 /** Key constant @type Number */
145 /** Key constant @type Number */
147 /** Key constant @type Number */
149 /** Key constant @type Number */
151 /** Key constant @type Number */
153 /** Key constant @type Number */
155 /** Key constant @type Number */
157 /** Key constant @type Number */
159 /** Key constant @type Number */
161 /** Key constant @type Number */
163 /** Key constant @type Number */
165 /** Key constant @type Number */
167 /** Key constant @type Number */
169 /** Key constant @type Number */
171 /** Key constant @type Number */
173 /** Key constant @type Number */
175 /** Key constant @type Number */
177 /** Key constant @type Number */
179 /** Key constant @type Number */
181 /** Key constant @type Number */
183 /** Key constant @type Number */
185 /** Key constant @type Number */
187 /** Key constant @type Number */
189 /** Key constant @type Number */
191 /** Key constant @type Number */
193 /** Key constant @type Number */
195 /** Key constant @type Number */
197 /** Key constant @type Number */
199 /** Key constant @type Number */
201 /** Key constant @type Number */
203 /** Key constant @type Number */
205 /** Key constant @type Number */
212 clickRe: /(dbl)?click/,
213 // safari keypress events for special keys return bad keycodes
220 63276: 33, // page up
221 63277: 34, // page down
226 // normalize button clicks, don't see any way to feature detect this.
237 constructor: function(event, freezeEvent){
239 this.setEvent(event.browserEvent || event, freezeEvent);
243 setEvent: function(event, freezeEvent){
244 var me = this, button, options;
246 if (event == me || (event && event.browserEvent)) { // already wrapped
249 me.browserEvent = event;
252 button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
253 if (me.clickRe.test(event.type) && button == -1) {
259 shiftKey: event.shiftKey,
260 // mac metaKey behaves like ctrlKey
261 ctrlKey: event.ctrlKey || event.metaKey || false,
262 altKey: event.altKey,
263 // in getKey these will be normalized for the mac
264 keyCode: event.keyCode,
265 charCode: event.charCode,
266 // cache the targets for the delayed and or buffered events
267 target: Ext.EventManager.getTarget(event),
268 relatedTarget: Ext.EventManager.getRelatedTarget(event),
269 currentTarget: event.currentTarget,
270 xy: (freezeEvent ? me.getXY() : null)
284 Ext.apply(me, options);
289 * Stop the event (preventDefault and stopPropagation)
291 stopEvent: function(){
292 this.stopPropagation();
293 this.preventDefault();
297 * Prevents the browsers default handling of the event.
299 preventDefault: function(){
300 if (this.browserEvent) {
301 Ext.EventManager.preventDefault(this.browserEvent);
306 * Cancels bubbling of the event.
308 stopPropagation: function(){
309 var browserEvent = this.browserEvent;
312 if (browserEvent.type == 'mousedown') {
313 Ext.EventManager.stoppedMouseDownEvent.fire(this);
315 Ext.EventManager.stopPropagation(browserEvent);
320 * Gets the character code for the event.
323 getCharCode: function(){
324 return this.charCode || this.keyCode;
328 * Returns a normalized keyCode for the event.
329 * @return {Number} The key code
332 return this.normalizeKey(this.keyCode || this.charCode);
336 * Normalize key codes across browsers
338 * @param {Number} key The key code
339 * @return {Number} The normalized code
341 normalizeKey: function(key){
342 // can't feature detect this
343 return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
347 * Gets the x coordinate of the event.
349 * @deprecated 4.0 Replaced by {@link #getX}
351 getPageX: function(){
356 * Gets the y coordinate of the event.
358 * @deprecated 4.0 Replaced by {@link #getY}
360 getPageY: function(){
365 * Gets the x coordinate of the event.
369 return this.getXY()[0];
373 * Gets the y coordinate of the event.
377 return this.getXY()[1];
381 * Gets the page coordinates of the event.
382 * @return {Array} The xy values like [x, y]
387 this.xy = Ext.EventManager.getPageXY(this.browserEvent);
393 * Gets the target for the event.
394 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
395 * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
396 * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
397 * @return {HTMLelement}
399 getTarget : function(selector, maxDepth, returnEl){
401 return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
403 return returnEl ? Ext.get(this.target) : this.target;
407 * Gets the related target.
408 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
409 * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
410 * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
411 * @return {HTMLElement}
413 getRelatedTarget : function(selector, maxDepth, returnEl){
415 return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
417 return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
421 * Normalizes mouse wheel delta across browsers
422 * @return {Number} The delta
424 getWheelDelta : function(){
425 var event = this.browserEvent,
428 if (event.wheelDelta) { /* IE/Opera. */
429 delta = event.wheelDelta / 120;
430 } else if (event.detail){ /* Mozilla case. */
431 delta = -event.detail / 3;
437 * 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.
438 * Example usage:<pre><code>
439 // Handle click on any child of an element
440 Ext.getBody().on('click', function(e){
441 if(e.within('some-el')){
442 alert('Clicked on a child of some-el!');
446 // Handle click directly on an element, ignoring clicks on child nodes
447 Ext.getBody().on('click', function(e,t){
448 if((t.id == 'some-el') && !e.within(t, true)){
449 alert('Clicked directly on some-el!');
453 * @param {Mixed} el The id, DOM element or Ext.core.Element to check
454 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
455 * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
458 within : function(el, related, allowEl){
460 var t = related ? this.getRelatedTarget() : this.getTarget(),
464 result = Ext.fly(el).contains(t);
465 if (!result && allowEl) {
466 result = t == Ext.getDom(el);
475 * Checks if the key pressed was a "navigation" key
476 * @return {Boolean} True if the press is a navigation keypress
478 isNavKeyPress : function(){
480 k = this.normalizeKey(me.keyCode);
482 return (k >= 33 && k <= 40) || // Page Up/Down, End, Home, Left, Up, Right, Down
489 * Checks if the key pressed was a "special" key
490 * @return {Boolean} True if the press is a special keypress
492 isSpecialKey : function(){
493 var k = this.normalizeKey(this.keyCode);
494 return (this.type == 'keypress' && this.ctrlKey) ||
495 this.isNavKeyPress() ||
496 (k == this.BACKSPACE) || // Backspace
497 (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
498 (k >= 44 && k <= 46); // Print Screen, Insert, Delete
502 * Returns a point object that consists of the object coordinates.
503 * @return {Ext.util.Point} point
505 getPoint : function(){
506 var xy = this.getXY();
507 return Ext.create('Ext.util.Point', xy[0], xy[1]);
511 * Returns true if the control, meta, shift or alt key was pressed during this event.
514 hasModifier : function(){
515 return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
519 * Injects a DOM event using the data in this object and (optionally) a new target.
520 * This is a low-level technique and not likely to be used by application code. The
521 * currently supported event types are:
522 * <p><b>HTMLEvents</b></p>
533 * <p><b>MouseEvents</b></p>
543 * <p><b>UIEvents</b></p>
551 * @param {Element/HTMLElement} target If specified, the target for the event. This
552 * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
553 * is used to determine the target.
555 injectEvent: function () {
557 dispatchers = {}; // keyed by event type (e.g., 'mousedown')
559 // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
561 // IE9 has createEvent, but this code causes major problems with htmleditor (it
562 // blocks all mouse events and maybe more). TODO
564 if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
566 createHtmlEvent: function (doc, type, bubbles, cancelable) {
567 var event = doc.createEvent('HTMLEvents');
569 event.initEvent(type, bubbles, cancelable);
573 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
574 clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
575 button, relatedTarget) {
576 var event = doc.createEvent('MouseEvents'),
577 view = doc.defaultView || window;
579 if (event.initMouseEvent) {
580 event.initMouseEvent(type, bubbles, cancelable, view, detail,
581 clientX, clientY, clientX, clientY, ctrlKey, altKey,
582 shiftKey, metaKey, button, relatedTarget);
583 } else { // old Safari
584 event = doc.createEvent('UIEvents');
585 event.initEvent(type, bubbles, cancelable);
587 event.detail = detail;
588 event.screenX = clientX;
589 event.screenY = clientY;
590 event.clientX = clientX;
591 event.clientY = clientY;
592 event.ctrlKey = ctrlKey;
593 event.altKey = altKey;
594 event.metaKey = metaKey;
595 event.shiftKey = shiftKey;
596 event.button = button;
597 event.relatedTarget = relatedTarget;
603 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
604 var event = doc.createEvent('UIEvents'),
605 view = doc.defaultView || window;
607 event.initUIEvent(type, bubbles, cancelable, view, detail);
611 fireEvent: function (target, type, event) {
612 target.dispatchEvent(event);
615 fixTarget: function (target) {
616 // Safari3 doesn't have window.dispatchEvent()
617 if (target == window && !target.dispatchEvent) {
624 } else if (document.createEventObject) { // else if (IE)
625 var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
628 createHtmlEvent: function (doc, type, bubbles, cancelable) {
629 var event = doc.createEventObject();
630 event.bubbles = bubbles;
631 event.cancelable = cancelable;
635 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
636 clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
637 button, relatedTarget) {
638 var event = doc.createEventObject();
639 event.bubbles = bubbles;
640 event.cancelable = cancelable;
641 event.detail = detail;
642 event.screenX = clientX;
643 event.screenY = clientY;
644 event.clientX = clientX;
645 event.clientY = clientY;
646 event.ctrlKey = ctrlKey;
647 event.altKey = altKey;
648 event.shiftKey = shiftKey;
649 event.metaKey = metaKey;
650 event.button = crazyIEButtons[button] || button;
651 event.relatedTarget = relatedTarget; // cannot assign to/fromElement
655 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
656 var event = doc.createEventObject();
657 event.bubbles = bubbles;
658 event.cancelable = cancelable;
662 fireEvent: function (target, type, event) {
663 target.fireEvent('on' + type, event);
666 fixTarget: function (target) {
667 if (target == document) {
668 // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
669 // IE6,IE7 cannot properly call document.fireEvent()
670 return document.documentElement;
682 load: [false, false],
683 unload: [false, false],
684 select: [true, false],
685 change: [true, false],
686 submit: [true, true],
687 reset: [true, false],
688 resize: [true, false],
689 scroll: [true, false]
691 function (name, value) {
692 var bubbles = value[0], cancelable = value[1];
693 dispatchers[name] = function (targetEl, srcEvent) {
694 var e = API.createHtmlEvent(name, bubbles, cancelable);
695 API.fireEvent(targetEl, name, e);
702 function createMouseEventDispatcher (type, detail) {
703 var cancelable = (type != 'mousemove');
704 return function (targetEl, srcEvent) {
705 var xy = srcEvent.getXY(),
706 e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
707 detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
708 srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
709 srcEvent.relatedTarget);
710 API.fireEvent(targetEl, type, e);
714 Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
715 function (eventName) {
716 dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
723 focusin: [true, false],
724 focusout: [true, false],
725 activate: [true, true],
726 focus: [false, false],
729 function (name, value) {
730 var bubbles = value[0], cancelable = value[1];
731 dispatchers[name] = function (targetEl, srcEvent) {
732 var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
733 API.fireEvent(targetEl, name, e);
739 // not even sure what ancient browsers fall into this category...
741 dispatchers = {}; // never mind all those we just built :P
744 fixTarget: function (t) {
750 function cannotInject (target, srcEvent) {
752 // TODO log something
756 return function (target) {
758 dispatcher = dispatchers[me.type] || cannotInject,
759 t = target ? (target.dom || target) : me.getTarget();
761 t = API.fixTarget(t);
764 }() // call to produce method
768 Ext.EventObject = new Ext.EventObjectImpl();