3
* Copyright(c) 2006-2008, Ext JS, LLC.
6
* http://extjs.com/license
10
* @class Ext.EventManager
11
* Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
12
* several useful events directly.
13
* See {@link Ext.EventObject} for more details on normalized event objects.
16
Ext.EventManager = function(){
17
var docReadyEvent, docReadyProcId, docReadyState = false;
18
var resizeEvent, resizeTask, textEvent, textSize;
19
var E = Ext.lib.Event;
21
// fix parser confusion
22
var xname = 'Ex' + 't';
26
var addListener = function(el, ename, fn, wrap, scope){
44
E.on(el, ename, wrap);
46
if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
47
el.addEventListener("DOMMouseScroll", wrap, false);
48
E.on(window, 'unload', function(){
49
el.removeEventListener("DOMMouseScroll", wrap, false);
52
if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
53
Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
57
var removeListener = function(el, ename, fn, scope){
59
var id = Ext.id(el), es = elHash[id], wrap;
61
var ls = es[ename], l;
63
for(var i = 0, len = ls.length; i < len; i++){
65
if(l.fn == fn && (!scope || l.scope == scope)){
67
E.un(el, ename, wrap);
74
if(ename == "mousewheel" && el.addEventListener && wrap){
75
el.removeEventListener("DOMMouseScroll", wrap, false);
77
if(ename == "mousedown" && el == document && wrap){ // fix stopped mousedowns on the document
78
Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
82
var removeAll = function(el){
84
var id = Ext.id(el), es = elHash[id], ls;
87
if(es.hasOwnProperty(ename)){
89
for(var i = 0, len = ls.length; i < len; i++){
90
E.un(el, ename, ls[i].wrap);
100
var fireDocReady = function(){
102
docReadyState = Ext.isReady = true;
103
if(Ext.isGecko || Ext.isOpera) {
104
document.removeEventListener("DOMContentLoaded", fireDocReady, false);
108
clearInterval(docReadyProcId);
109
docReadyProcId = null;
112
docReadyEvent.fire();
113
docReadyEvent.clearListeners();
117
var initDocReady = function(){
118
docReadyEvent = new Ext.util.Event();
124
// no matter what, make sure it fires on load
125
E.on(window, 'load', fireDocReady);
127
if(Ext.isGecko || Ext.isOpera) {
128
document.addEventListener('DOMContentLoaded', fireDocReady, false);
131
docReadyProcId = setInterval(function(){
133
// throws errors until DOM is ready
134
Ext.isReady || (document.documentElement.doScroll('left'));
138
fireDocReady(); // no errors, fire
141
document.onreadystatechange = function(){
142
if(document.readyState == 'complete'){
143
document.onreadystatechange = null;
148
else if(Ext.isSafari){
149
docReadyProcId = setInterval(function(){
150
var rs = document.readyState;
151
if(rs == 'complete') {
158
var createBuffered = function(h, o){
159
var task = new Ext.util.DelayedTask(h);
161
// create new event object impl so new events don't wipe out properties
162
e = new Ext.EventObjectImpl(e);
163
task.delay(o.buffer, h, null, [e]);
167
var createSingle = function(h, el, ename, fn, scope){
169
Ext.EventManager.removeListener(el, ename, fn, scope);
174
var createDelayed = function(h, o){
176
// create new event object impl so new events don't wipe out properties
177
e = new Ext.EventObjectImpl(e);
178
setTimeout(function(){
184
var listen = function(element, ename, opt, fn, scope){
185
var o = (!opt || typeof opt == "boolean") ? {} : opt;
186
fn = fn || o.fn; scope = scope || o.scope;
187
var el = Ext.getDom(element);
189
throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
192
// prevent errors while unload occurring
196
e = Ext.EventObject.setEvent(e);
199
t = e.getTarget(o.delegate, el);
206
if(o.stopEvent === true){
209
if(o.preventDefault === true){
212
if(o.stopPropagation === true){
216
if(o.normalized === false){
220
fn.call(scope || el, e, t, o);
223
h = createDelayed(h, o);
226
h = createSingle(h, el, ename, fn, scope);
229
h = createBuffered(h, o);
232
addListener(el, ename, fn, h, scope);
236
var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
240
* Appends an event handler to an element. The shorthand version {@link #on} is equivalent. Typically you will
241
* use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
242
* @param {String/HTMLElement} el The html element or id to assign the event handler to
243
* @param {String} eventName The type of event to listen for
244
* @param {Function} handler The handler function the event invokes This function is passed
245
* the following parameters:<ul>
246
* <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
247
* <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
248
* Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
249
* <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
251
* @param {Object} scope (optional) The scope in which to execute the handler
252
* function (the handler function's "this" context)
253
* @param {Object} options (optional) An object containing handler configuration properties.
254
* This may contain any of the following properties:<ul>
255
* <li>scope {Object} : The scope in which to execute the handler function. The handler function's "this" context.</li>
256
* <li>delegate {String} : A simple selector to filter the target or look for a descendant of the target</li>
257
* <li>stopEvent {Boolean} : True to stop the event. That is stop propagation, and prevent the default action.</li>
258
* <li>preventDefault {Boolean} : True to prevent the default action</li>
259
* <li>stopPropagation {Boolean} : True to prevent event propagation</li>
260
* <li>normalized {Boolean} : False to pass a browser event to the handler function instead of an Ext.EventObject</li>
261
* <li>delay {Number} : The number of milliseconds to delay the invocation of the handler after te event fires.</li>
262
* <li>single {Boolean} : True to add a handler to handle just the next firing of the event, and then remove itself.</li>
263
* <li>buffer {Number} : Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
264
* by the specified number of milliseconds. If the event fires again within that time, the original
265
* handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
267
* <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
269
addListener : function(element, eventName, fn, scope, options){
270
if(typeof eventName == "object"){
276
if(typeof o[e] == "function"){
278
listen(element, e, o, o[e], o.scope);
280
// individual options
281
listen(element, e, o[e]);
286
return listen(element, eventName, options, fn, scope);
290
* Removes an event handler from an element. The shorthand version {@link #un} is equivalent. Typically
291
* you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
292
* @param {String/HTMLElement} el The id or html element from which to remove the event
293
* @param {String} eventName The type of event
294
* @param {Function} fn The handler function to remove
296
removeListener : function(element, eventName, fn, scope){
297
return removeListener(element, eventName, fn, scope);
301
* Removes all event handers from an element. Typically you will use {@link Ext.Element#removeAllListeners}
302
* directly on an Element in favor of calling this version.
303
* @param {String/HTMLElement} el The id or html element from which to remove the event
305
removeAll : function(element){
306
return removeAll(element);
310
* Fires when the document is ready (before onload and before images are loaded). Can be
311
* accessed shorthanded as Ext.onReady().
312
* @param {Function} fn The method the event invokes
313
* @param {Object} scope (optional) An object that becomes the scope of the handler
314
* @param {boolean} options (optional) An object containing standard {@link #addListener} options
316
onDocumentReady : function(fn, scope, options){
320
if(docReadyState || Ext.isReady){ // if it already fired
321
options || (options = {});
322
fn.defer(options.delay||0, scope);
324
docReadyEvent.addListener(fn, scope, options);
329
* Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
330
* @param {Function} fn The method the event invokes
331
* @param {Object} scope An object that becomes the scope of the handler
332
* @param {boolean} options
334
onWindowResize : function(fn, scope, options){
336
resizeEvent = new Ext.util.Event();
337
resizeTask = new Ext.util.DelayedTask(function(){
338
resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
340
E.on(window, "resize", this.fireWindowResize, this);
342
resizeEvent.addListener(fn, scope, options);
345
// exposed only to allow manual firing
346
fireWindowResize : function(){
348
if((Ext.isIE||Ext.isAir) && resizeTask){
349
resizeTask.delay(50);
351
resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
357
* Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
358
* @param {Function} fn The method the event invokes
359
* @param {Object} scope An object that becomes the scope of the handler
360
* @param {boolean} options
362
onTextResize : function(fn, scope, options){
364
textEvent = new Ext.util.Event();
365
var textEl = new Ext.Element(document.createElement('div'));
366
textEl.dom.className = 'x-text-resize';
367
textEl.dom.innerHTML = 'X';
368
textEl.appendTo(document.body);
369
textSize = textEl.dom.offsetHeight;
370
setInterval(function(){
371
if(textEl.dom.offsetHeight != textSize){
372
textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
374
}, this.textResizeInterval);
376
textEvent.addListener(fn, scope, options);
380
* Removes the passed window resize listener.
381
* @param {Function} fn The method the event invokes
382
* @param {Object} scope The scope of handler
384
removeResizeListener : function(fn, scope){
386
resizeEvent.removeListener(fn, scope);
391
fireResize : function(){
393
resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
397
* Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)
401
* The frequency, in milliseconds, to check for text resize events (defaults to 50)
403
textResizeInterval : 50
406
* Appends an event handler to an element. Shorthand for {@link #addListener}.
407
* @param {String/HTMLElement} el The html element or id to assign the event handler to
408
* @param {String} eventName The type of event to listen for
409
* @param {Function} handler The handler function the event invokes
410
* @param {Object} scope (optional) The scope in which to execute the handler
411
* function (the handler function's "this" context)
412
* @param {Object} options (optional) An object containing standard {@link #addListener} options
413
* @member Ext.EventManager
416
pub.on = pub.addListener;
418
* Removes an event handler from an element. Shorthand for {@link #removeListener}.
419
* @param {String/HTMLElement} el The id or html element from which to remove the event
420
* @param {String} eventName The type of event
421
* @param {Function} fn The handler function to remove
422
* @return {Boolean} True if a listener was actually removed, else false
423
* @member Ext.EventManager
426
pub.un = pub.removeListener;
428
pub.stoppedMouseDownEvent = new Ext.util.Event();
432
* Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
433
* @param {Function} fn The method the event invokes
434
* @param {Object} scope An object that becomes the scope of the handler
435
* @param {boolean} override If true, the obj passed in becomes
436
* the execution scope of the listener
440
Ext.onReady = Ext.EventManager.onDocumentReady;
443
// Initialize doc classes
445
var initExtCss = function(){
446
// find the body element
447
var bd = document.body || document.getElementsByTagName('body')[0];
448
if(!bd){ return false; }
450
Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : 'ext-ie7')
451
: Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
452
: Ext.isOpera ? "ext-opera"
453
: Ext.isSafari ? "ext-safari" : ""];
459
cls.push("ext-linux");
462
cls.push('ext-border-box');
464
if(Ext.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
465
var p = bd.parentNode;
467
p.className += ' ext-strict';
470
bd.className += cls.join(' ');
475
Ext.onReady(initExtCss);
480
* @class Ext.EventObject
481
* EventObject exposes the Yahoo! UI Event functionality directly on the object
482
* passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
485
function handleClick(e){ // e is not a standard event object, it is a Ext.EventObject
487
var target = e.getTarget();
490
var myDiv = Ext.get("myDiv");
491
myDiv.on("click", handleClick);
493
Ext.EventManager.on("myDiv", 'click', handleClick);
494
Ext.EventManager.addListener("myDiv", 'click', handleClick);
498
Ext.EventObject = function(){
500
var E = Ext.lib.Event;
502
// safari keypress events for special keys return bad keycodes
509
63276 : 33, // page up
510
63277 : 34, // page down
511
63272 : 46, // delete
516
// normalize button clicks
517
var btnMap = Ext.isIE ? {1:0,4:1,2:2} :
518
(Ext.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
520
Ext.EventObjectImpl = function(e){
522
this.setEvent(e.browserEvent || e);
526
Ext.EventObjectImpl.prototype = {
527
/** The normal browser event */
529
/** The button pressed in a mouse event */
531
/** True if the shift key was down during the event */
533
/** True if the control key was down during the event */
535
/** True if the alt key was down during the event */
538
/** Key constant @type Number */
540
/** Key constant @type Number */
542
/** Key constant @type Number */
544
/** Key constant @type Number */
546
/** Key constant @type Number */
548
/** Key constant @type Number */
550
/** Key constant @type Number */
552
CONTROL : 17, // legacy
553
/** Key constant @type Number */
555
/** Key constant @type Number */
557
/** Key constant @type Number */
559
/** Key constant @type Number */
561
/** Key constant @type Number */
563
/** Key constant @type Number */
565
PAGEUP : 33, // legacy
566
/** Key constant @type Number */
568
PAGEDOWN : 34, // legacy
569
/** Key constant @type Number */
571
/** Key constant @type Number */
573
/** Key constant @type Number */
575
/** Key constant @type Number */
577
/** Key constant @type Number */
579
/** Key constant @type Number */
581
/** Key constant @type Number */
583
/** Key constant @type Number */
585
/** Key constant @type Number */
587
/** Key constant @type Number */
589
/** Key constant @type Number */
591
/** Key constant @type Number */
593
/** Key constant @type Number */
595
/** Key constant @type Number */
597
/** Key constant @type Number */
599
/** Key constant @type Number */
601
/** Key constant @type Number */
603
/** Key constant @type Number */
605
/** Key constant @type Number */
607
/** Key constant @type Number */
609
/** Key constant @type Number */
611
/** Key constant @type Number */
613
/** Key constant @type Number */
615
/** Key constant @type Number */
617
/** Key constant @type Number */
619
/** Key constant @type Number */
621
/** Key constant @type Number */
623
/** Key constant @type Number */
625
/** Key constant @type Number */
627
/** Key constant @type Number */
629
/** Key constant @type Number */
631
/** Key constant @type Number */
633
/** Key constant @type Number */
635
/** Key constant @type Number */
637
/** Key constant @type Number */
639
/** Key constant @type Number */
641
/** Key constant @type Number */
643
/** Key constant @type Number */
645
/** Key constant @type Number */
647
/** Key constant @type Number */
649
/** Key constant @type Number */
651
/** Key constant @type Number */
653
/** Key constant @type Number */
655
/** Key constant @type Number */
657
/** Key constant @type Number */
659
/** Key constant @type Number */
661
/** Key constant @type Number */
663
/** Key constant @type Number */
665
/** Key constant @type Number */
667
/** Key constant @type Number */
669
/** Key constant @type Number */
671
/** Key constant @type Number */
673
/** Key constant @type Number */
675
/** Key constant @type Number */
677
/** Key constant @type Number */
679
/** Key constant @type Number */
681
/** Key constant @type Number */
683
/** Key constant @type Number */
685
/** Key constant @type Number */
687
/** Key constant @type Number */
689
/** Key constant @type Number */
691
/** Key constant @type Number */
693
/** Key constant @type Number */
695
/** Key constant @type Number */
697
/** Key constant @type Number */
699
/** Key constant @type Number */
701
/** Key constant @type Number */
703
/** Key constant @type Number */
705
/** Key constant @type Number */
707
/** Key constant @type Number */
709
/** Key constant @type Number */
711
/** Key constant @type Number */
713
/** Key constant @type Number */
717
setEvent : function(e){
718
if(e == this || (e && e.browserEvent)){ // already wrapped
721
this.browserEvent = e;
724
this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
725
if(e.type == 'click' && this.button == -1){
729
this.shiftKey = e.shiftKey;
730
// mac metaKey behaves like ctrlKey
731
this.ctrlKey = e.ctrlKey || e.metaKey;
732
this.altKey = e.altKey;
733
// in getKey these will be normalized for the mac
734
this.keyCode = e.keyCode;
735
this.charCode = e.charCode;
736
// cache the target for the delayed and or buffered events
737
this.target = E.getTarget(e);
739
this.xy = E.getXY(e);
742
this.shiftKey = false;
743
this.ctrlKey = false;
754
* Stop the event (preventDefault and stopPropagation)
756
stopEvent : function(){
757
if(this.browserEvent){
758
if(this.browserEvent.type == 'mousedown'){
759
Ext.EventManager.stoppedMouseDownEvent.fire(this);
761
E.stopEvent(this.browserEvent);
766
* Prevents the browsers default handling of the event.
768
preventDefault : function(){
769
if(this.browserEvent){
770
E.preventDefault(this.browserEvent);
775
isNavKeyPress : function(){
776
var k = this.keyCode;
777
k = Ext.isSafari ? (safariKeys[k] || k) : k;
778
return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
781
isSpecialKey : function(){
782
var k = this.keyCode;
783
return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
784
(k == 16) || (k == 17) ||
785
(k >= 18 && k <= 20) ||
786
(k >= 33 && k <= 35) ||
787
(k >= 36 && k <= 39) ||
788
(k >= 44 && k <= 45);
792
* Cancels bubbling of the event.
794
stopPropagation : function(){
795
if(this.browserEvent){
796
if(this.browserEvent.type == 'mousedown'){
797
Ext.EventManager.stoppedMouseDownEvent.fire(this);
799
E.stopPropagation(this.browserEvent);
804
* Gets the character code for the event.
807
getCharCode : function(){
808
return this.charCode || this.keyCode;
812
* Returns a normalized keyCode for the event.
813
* @return {Number} The key code
816
var k = this.keyCode || this.charCode;
817
return Ext.isSafari ? (safariKeys[k] || k) : k;
821
* Gets the x coordinate of the event.
824
getPageX : function(){
829
* Gets the y coordinate of the event.
832
getPageY : function(){
837
* Gets the time of the event.
840
getTime : function(){
841
if(this.browserEvent){
842
return E.getTime(this.browserEvent);
848
* Gets the page coordinates of the event.
849
* @return {Array} The xy values like [x, y]
856
* Gets the target for the event.
857
* @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
858
* @param {Number/Mixed} maxDepth (optional) The max depth to
859
search as a number or element (defaults to 10 || document.body)
860
* @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
861
* @return {HTMLelement}
863
getTarget : function(selector, maxDepth, returnEl){
864
return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
868
* Gets the related target.
869
* @return {HTMLElement}
871
getRelatedTarget : function(){
872
if(this.browserEvent){
873
return E.getRelatedTarget(this.browserEvent);
879
* Normalizes mouse wheel delta across browsers
880
* @return {Number} The delta
882
getWheelDelta : function(){
883
var e = this.browserEvent;
885
if(e.wheelDelta){ /* IE/Opera. */
886
delta = e.wheelDelta/120;
887
}else if(e.detail){ /* Mozilla case. */
894
* Returns true if the control, meta, shift or alt key was pressed during this event.
897
hasModifier : function(){
898
return ((this.ctrlKey || this.altKey) || this.shiftKey) ? true : false;
902
* Returns true if the target of this event is a child of el. If the target is el, it returns false.
903
* Example usage:<pre><code>
904
// Handle click on any child of an element
905
Ext.getBody().on('click', function(e){
906
if(e.within('some-el')){
907
alert('Clicked on a child of some-el!');
911
// Handle click directly on an element, ignoring clicks on child nodes
912
Ext.getBody().on('click', function(e,t){
913
if((t.id == 'some-el') && !e.within(t, true)){
914
alert('Clicked directly on some-el!');
918
* @param {Mixed} el The id, DOM element or Ext.Element to check
919
* @param {Boolean} related (optional) true to test if the related target is within el instead of the target
922
within : function(el, related){
923
var t = this[related ? "getRelatedTarget" : "getTarget"]();
924
return t && Ext.fly(el).contains(t);
927
getPoint : function(){
928
return new Ext.lib.Point(this.xy[0], this.xy[1]);
932
return new Ext.EventObjectImpl();
b'\\ No newline at end of file'