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