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