Upgrade to ExtJS 3.3.0 - Released 10/06/2010
[extjs.git] / docs / source / ext-base-event.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.0
11  * Copyright(c) 2006-2010 Ext JS, Inc.
12  * licensing@extjs.com
13  * http://www.extjs.com/license
14  */
15 Ext.lib.Event = function() {
16     var loadComplete = false,
17         unloadListeners = {},
18         retryCount = 0,
19         onAvailStack = [],
20         _interval,
21         locked = false,
22         win = window,
23         doc = document,
24
25         // constants
26         POLL_RETRYS = 200,
27         POLL_INTERVAL = 20,
28         TYPE = 0,
29         FN = 1,
30         OBJ = 2,
31         ADJ_SCOPE = 3,
32         SCROLLLEFT = 'scrollLeft',
33         SCROLLTOP = 'scrollTop',
34         UNLOAD = 'unload',
35         MOUSEOVER = 'mouseover',
36         MOUSEOUT = 'mouseout',
37         // private
38         doAdd = function() {
39             var ret;
40             if (win.addEventListener) {
41                 ret = function(el, eventName, fn, capture) {
42                     if (eventName == 'mouseenter') {
43                         fn = fn.createInterceptor(checkRelatedTarget);
44                         el.addEventListener(MOUSEOVER, fn, (capture));
45                     } else if (eventName == 'mouseleave') {
46                         fn = fn.createInterceptor(checkRelatedTarget);
47                         el.addEventListener(MOUSEOUT, fn, (capture));
48                     } else {
49                         el.addEventListener(eventName, fn, (capture));
50                     }
51                     return fn;
52                 };
53             } else if (win.attachEvent) {
54                 ret = function(el, eventName, fn, capture) {
55                     el.attachEvent("on" + eventName, fn);
56                     return fn;
57                 };
58             } else {
59                 ret = function(){};
60             }
61             return ret;
62         }(),
63         // private
64         doRemove = function(){
65             var ret;
66             if (win.removeEventListener) {
67                 ret = function (el, eventName, fn, capture) {
68                     if (eventName == 'mouseenter') {
69                         eventName = MOUSEOVER;
70                     } else if (eventName == 'mouseleave') {
71                         eventName = MOUSEOUT;
72                     }
73                     el.removeEventListener(eventName, fn, (capture));
74                 };
75             } else if (win.detachEvent) {
76                 ret = function (el, eventName, fn) {
77                     el.detachEvent("on" + eventName, fn);
78                 };
79             } else {
80                 ret = function(){};
81             }
82             return ret;
83         }();
84
85     function checkRelatedTarget(e) {
86         return !elContains(e.currentTarget, pub.getRelatedTarget(e));
87     }
88
89     function elContains(parent, child) {
90        if(parent && parent.firstChild){
91          while(child) {
92             if(child === parent) {
93                 return true;
94             }
95             child = child.parentNode;
96             if(child && (child.nodeType != 1)) {
97                 child = null;
98             }
99           }
100         }
101         return false;
102     }
103
104     // private
105     function _tryPreloadAttach() {
106         var ret = false,
107             notAvail = [],
108             element, i, v, override,
109             tryAgain = !loadComplete || (retryCount > 0);
110
111         if(!locked){
112             locked = true;
113             
114             for(i = 0; i < onAvailStack.length; ++i){
115                 v = onAvailStack[i];
116                 if(v && (element = doc.getElementById(v.id))){
117                     if(!v.checkReady || loadComplete || element.nextSibling || (doc && doc.body)) {
118                         override = v.override;
119                         element = override ? (override === true ? v.obj : override) : element;
120                         v.fn.call(element, v.obj);
121                         onAvailStack.remove(v);
122                         --i;
123                     }else{
124                         notAvail.push(v);
125                     }
126                 }
127             }
128
129             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
130
131             if (tryAgain) {
132                 startInterval();
133             } else {
134                 clearInterval(_interval);
135                 _interval = null;
136             }
137             ret = !(locked = false);
138         }
139         return ret;
140     }
141
142     // private
143     function startInterval() {
144         if(!_interval){
145             var callback = function() {
146                 _tryPreloadAttach();
147             };
148             _interval = setInterval(callback, POLL_INTERVAL);
149         }
150     }
151
152     // private
153     function getScroll() {
154         var dd = doc.documentElement,
155             db = doc.body;
156         if(dd && (dd[SCROLLTOP] || dd[SCROLLLEFT])){
157             return [dd[SCROLLLEFT], dd[SCROLLTOP]];
158         }else if(db){
159             return [db[SCROLLLEFT], db[SCROLLTOP]];
160         }else{
161             return [0, 0];
162         }
163     }
164
165     // private
166     function getPageCoord (ev, xy) {
167         ev = ev.browserEvent || ev;
168         var coord  = ev['page' + xy];
169         if (!coord && coord !== 0) {
170             coord = ev['client' + xy] || 0;
171
172             if (Ext.isIE) {
173                 coord += getScroll()[xy == "X" ? 0 : 1];
174             }
175         }
176
177         return coord;
178     }
179
180     var pub =  {
181         extAdapter: true,
182         onAvailable : function(p_id, p_fn, p_obj, p_override) {
183             onAvailStack.push({
184                 id:         p_id,
185                 fn:         p_fn,
186                 obj:        p_obj,
187                 override:   p_override,
188                 checkReady: false });
189
190             retryCount = POLL_RETRYS;
191             startInterval();
192         },
193
194         // This function should ALWAYS be called from Ext.EventManager
195         addListener: function(el, eventName, fn) {
196             el = Ext.getDom(el);
197             if (el && fn) {
198                 if (eventName == UNLOAD) {
199                     if (unloadListeners[el.id] === undefined) {
200                         unloadListeners[el.id] = [];
201                     }
202                     unloadListeners[el.id].push([eventName, fn]);
203                     return fn;
204                 }
205                 return doAdd(el, eventName, fn, false);
206             }
207             return false;
208         },
209
210         // This function should ALWAYS be called from Ext.EventManager
211         removeListener: function(el, eventName, fn) {
212             el = Ext.getDom(el);
213             var i, len, li, lis;
214             if (el && fn) {
215                 if(eventName == UNLOAD){
216                     if((lis = unloadListeners[el.id]) !== undefined){
217                         for(i = 0, len = lis.length; i < len; i++){
218                             if((li = lis[i]) && li[TYPE] == eventName && li[FN] == fn){
219                                 unloadListeners[el.id].splice(i, 1);
220                             }
221                         }
222                     }
223                     return;
224                 }
225                 doRemove(el, eventName, fn, false);
226             }
227         },
228
229         getTarget : function(ev) {
230             ev = ev.browserEvent || ev;
231             return this.resolveTextNode(ev.target || ev.srcElement);
232         },
233
234         resolveTextNode : Ext.isGecko ? function(node){
235             if(!node){
236                 return;
237             }
238             // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
239             var s = HTMLElement.prototype.toString.call(node);
240             if(s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]'){
241                 return;
242             }
243             return node.nodeType == 3 ? node.parentNode : node;
244         } : function(node){
245             return node && node.nodeType == 3 ? node.parentNode : node;
246         },
247
248         getRelatedTarget : function(ev) {
249             ev = ev.browserEvent || ev;
250             return this.resolveTextNode(ev.relatedTarget ||
251                 (/(mouseout|mouseleave)/.test(ev.type) ? ev.toElement :
252                  /(mouseover|mouseenter)/.test(ev.type) ? ev.fromElement : null));
253         },
254
255         getPageX : function(ev) {
256             return getPageCoord(ev, "X");
257         },
258
259         getPageY : function(ev) {
260             return getPageCoord(ev, "Y");
261         },
262
263
264         getXY : function(ev) {
265             return [this.getPageX(ev), this.getPageY(ev)];
266         },
267
268         stopEvent : function(ev) {
269             this.stopPropagation(ev);
270             this.preventDefault(ev);
271         },
272
273         stopPropagation : function(ev) {
274             ev = ev.browserEvent || ev;
275             if (ev.stopPropagation) {
276                 ev.stopPropagation();
277             } else {
278                 ev.cancelBubble = true;
279             }
280         },
281
282         preventDefault : function(ev) {
283             ev = ev.browserEvent || ev;
284             if (ev.preventDefault) {
285                 ev.preventDefault();
286             } else {
287                 ev.returnValue = false;
288             }
289         },
290
291         getEvent : function(e) {
292             e = e || win.event;
293             if (!e) {
294                 var c = this.getEvent.caller;
295                 while (c) {
296                     e = c.arguments[0];
297                     if (e && Event == e.constructor) {
298                         break;
299                     }
300                     c = c.caller;
301                 }
302             }
303             return e;
304         },
305
306         getCharCode : function(ev) {
307             ev = ev.browserEvent || ev;
308             return ev.charCode || ev.keyCode || 0;
309         },
310
311         //clearCache: function() {},
312         // deprecated, call from EventManager
313         getListeners : function(el, eventName) {
314             Ext.EventManager.getListeners(el, eventName);
315         },
316
317         // deprecated, call from EventManager
318         purgeElement : function(el, recurse, eventName) {
319             Ext.EventManager.purgeElement(el, recurse, eventName);
320         },
321
322         _load : function(e) {
323             loadComplete = true;
324             
325             if (Ext.isIE && e !== true) {
326                 // IE8 complains that _load is null or not an object
327                 // so lets remove self via arguments.callee
328                 doRemove(win, "load", arguments.callee);
329             }
330         },
331
332         _unload : function(e) {
333              var EU = Ext.lib.Event,
334                 i, v, ul, id, len, scope;
335
336             for (id in unloadListeners) {
337                 ul = unloadListeners[id];
338                 for (i = 0, len = ul.length; i < len; i++) {
339                     v = ul[i];
340                     if (v) {
341                         try{
342                             scope = v[ADJ_SCOPE] ? (v[ADJ_SCOPE] === true ? v[OBJ] : v[ADJ_SCOPE]) :  win;
343                             v[FN].call(scope, EU.getEvent(e), v[OBJ]);
344                         }catch(ex){}
345                     }
346                 }
347             };
348
349             Ext.EventManager._unload();
350
351             doRemove(win, UNLOAD, EU._unload);
352         }
353     };
354
355     // Initialize stuff.
356     pub.on = pub.addListener;
357     pub.un = pub.removeListener;
358     if (doc && doc.body) {
359         pub._load(true);
360     } else {
361         doAdd(win, "load", pub._load);
362     }
363     doAdd(win, UNLOAD, pub._unload);
364     _tryPreloadAttach();
365
366     return pub;
367 }();
368 </pre>    
369 </body>
370 </html>