3 * Copyright(c) 2006-2009 Ext JS, LLC
5 * http://www.extjs.com/license
7 Ext.lib.Event = function() {
\r
8 var loadComplete = false,
\r
10 unloadListeners = [],
\r
27 SCROLLLEFT = 'scrollLeft',
\r
28 SCROLLTOP = 'scrollTop',
\r
30 MOUSEOVER = 'mouseover',
\r
31 MOUSEOUT = 'mouseout',
\r
33 doAdd = function() {
\r
35 if (win.addEventListener) {
\r
36 ret = function(el, eventName, fn, capture) {
\r
37 if (eventName == 'mouseenter') {
\r
38 fn = fn.createInterceptor(checkRelatedTarget);
\r
39 el.addEventListener(MOUSEOVER, fn, (capture));
\r
40 } else if (eventName == 'mouseleave') {
\r
41 fn = fn.createInterceptor(checkRelatedTarget);
\r
42 el.addEventListener(MOUSEOUT, fn, (capture));
\r
44 el.addEventListener(eventName, fn, (capture));
\r
48 } else if (win.attachEvent) {
\r
49 ret = function(el, eventName, fn, capture) {
\r
50 el.attachEvent("on" + eventName, fn);
\r
59 doRemove = function(){
\r
61 if (win.removeEventListener) {
\r
62 ret = function (el, eventName, fn, capture) {
\r
63 if (eventName == 'mouseenter') {
\r
64 eventName = MOUSEOVER;
\r
65 } else if (eventName == 'mouseleave') {
\r
66 eventName = MOUSEOUT;
\r
68 el.removeEventListener(eventName, fn, (capture));
\r
70 } else if (win.detachEvent) {
\r
71 ret = function (el, eventName, fn) {
\r
72 el.detachEvent("on" + eventName, fn);
\r
80 var isXUL = Ext.isGecko ? function(node){
\r
81 return Object.prototype.toString.call(node) == '[object XULElement]';
\r
84 var isTextNode = Ext.isGecko ? function(node){
\r
86 return node.nodeType == 3;
\r
92 return node.nodeType == 3;
\r
95 function checkRelatedTarget(e) {
\r
96 var related = pub.getRelatedTarget(e);
\r
97 return !(isXUL(related) || elContains(e.currentTarget,related));
\r
100 function elContains(parent, child) {
\r
101 if(parent && parent.firstChild){
\r
103 if(child === parent) {
\r
107 child = child.parentNode;
\r
109 // In FF if you mouseout an text input element
\r
110 // thats inside a div sometimes it randomly throws
\r
111 // Permission denied to get property HTMLDivElement.parentNode
\r
112 // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427
\r
116 if(child && (child.nodeType != 1)) {
\r
126 function _getCacheIndex(el, eventName, fn) {
\r
128 Ext.each(listeners, function (v,i) {
\r
129 if(v && v[FN] == fn && v[EL] == el && v[TYPE] == eventName) {
\r
137 function _tryPreloadAttach() {
\r
141 tryAgain = !loadComplete || (retryCount > 0);
\r
146 Ext.each(onAvailStack, function (v,i,a){
\r
147 if(v && (element = doc.getElementById(v.id))){
\r
148 if(!v.checkReady || loadComplete || element.nextSibling || (doc && doc.body)) {
\r
149 element = v.override ? (v.override === true ? v.obj : v.override) : element;
\r
150 v.fn.call(element, v.obj);
\r
151 onAvailStack[i] = null;
\r
158 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
\r
163 clearInterval(_interval);
\r
167 ret = !(locked = false);
\r
173 function startInterval() {
\r
175 var callback = function() {
\r
176 _tryPreloadAttach();
\r
178 _interval = setInterval(callback, POLL_INTERVAL);
\r
183 function getScroll() {
\r
184 var dd = doc.documentElement,
\r
186 if(dd && (dd[SCROLLTOP] || dd[SCROLLLEFT])){
\r
187 return [dd[SCROLLLEFT], dd[SCROLLTOP]];
\r
189 return [db[SCROLLLEFT], db[SCROLLTOP]];
\r
196 function getPageCoord (ev, xy) {
\r
197 ev = ev.browserEvent || ev;
\r
198 var coord = ev['page' + xy];
\r
199 if (!coord && coord !== 0) {
\r
200 coord = ev['client' + xy] || 0;
\r
203 coord += getScroll()[xy == "X" ? 0 : 1];
\r
211 onAvailable : function(p_id, p_fn, p_obj, p_override) {
\r
212 onAvailStack.push({
\r
216 override: p_override,
\r
217 checkReady: false });
\r
219 retryCount = POLL_RETRYS;
\r
224 addListener: function(el, eventName, fn) {
\r
226 el = Ext.getDom(el);
\r
228 if (UNLOAD == eventName) {
\r
229 ret = !!(unloadListeners[unloadListeners.length] = [el, eventName, fn]);
\r
231 listeners.push([el, eventName, fn, ret = doAdd(el, eventName, fn, false)]);
\r
237 removeListener: function(el, eventName, fn) {
\r
242 el = Ext.getDom(el);
\r
245 ret = this.purgeElement(el, false, eventName);
\r
246 } else if (UNLOAD == eventName) {
\r
247 Ext.each(unloadListeners, function(v, i, a) {
\r
248 if( v && v[0] == el && v[1] == eventName && v[2] == fn) {
\r
249 unloadListeners.splice(i, 1);
\r
254 index = arguments[3] || _getCacheIndex(el, eventName, fn);
\r
255 cacheItem = listeners[index];
\r
257 if (el && cacheItem) {
\r
258 doRemove(el, eventName, cacheItem[WFN], false);
\r
259 cacheItem[WFN] = cacheItem[FN] = null;
\r
260 listeners.splice(index, 1);
\r
267 getTarget : function(ev) {
\r
268 ev = ev.browserEvent || ev;
\r
269 return this.resolveTextNode(ev.target || ev.srcElement);
\r
272 resolveTextNode : function(node) {
\r
273 return node && !isXUL(node) && isTextNode(node) ? node.parentNode : node;
\r
276 getRelatedTarget : function(ev) {
\r
277 ev = ev.browserEvent || ev;
\r
278 return this.resolveTextNode(ev.relatedTarget ||
\r
279 (ev.type == MOUSEOUT ? ev.toElement :
\r
280 ev.type == MOUSEOVER ? ev.fromElement : null));
\r
283 getPageX : function(ev) {
\r
284 return getPageCoord(ev, "X");
\r
287 getPageY : function(ev) {
\r
288 return getPageCoord(ev, "Y");
\r
292 getXY : function(ev) {
\r
293 return [this.getPageX(ev), this.getPageY(ev)];
\r
296 // Is this useful? Removing to save space unless use case exists.
\r
297 // getTime: function(ev) {
\r
298 // ev = ev.browserEvent || ev;
\r
300 // var t = new Date().getTime();
\r
311 stopEvent : function(ev) {
\r
312 this.stopPropagation(ev);
\r
313 this.preventDefault(ev);
\r
316 stopPropagation : function(ev) {
\r
317 ev = ev.browserEvent || ev;
\r
318 if (ev.stopPropagation) {
\r
319 ev.stopPropagation();
\r
321 ev.cancelBubble = true;
\r
325 preventDefault : function(ev) {
\r
326 ev = ev.browserEvent || ev;
\r
327 if (ev.preventDefault) {
\r
328 ev.preventDefault();
\r
330 ev.returnValue = false;
\r
334 getEvent : function(e) {
\r
335 e = e || win.event;
\r
337 var c = this.getEvent.caller;
\r
339 e = c.arguments[0];
\r
340 if (e && Event == e.constructor) {
\r
349 getCharCode : function(ev) {
\r
350 ev = ev.browserEvent || ev;
\r
351 return ev.charCode || ev.keyCode || 0;
\r
354 //clearCache: function() {},
\r
356 _load : function(e) {
\r
357 loadComplete = true;
\r
358 var EU = Ext.lib.Event;
\r
359 if (Ext.isIE && e !== true) {
\r
360 // IE8 complains that _load is null or not an object
\r
361 // so lets remove self via arguments.callee
\r
362 doRemove(win, "load", arguments.callee);
\r
366 purgeElement : function(el, recurse, eventName) {
\r
368 Ext.each( me.getListeners(el, eventName), function(v){
\r
370 me.removeListener(el, v.type, v.fn);
\r
374 if (recurse && el && el.childNodes) {
\r
375 Ext.each(el.childNodes, function(v){
\r
376 me.purgeElement(v, recurse, eventName);
\r
381 getListeners : function(el, eventName) {
\r
387 searchLists = eventName == UNLOAD ? unloadListeners : listeners;
\r
389 searchLists = listeners.concat(unloadListeners);
\r
392 Ext.each(searchLists, function(v, i){
\r
393 if (v && v[EL] == el && (!eventName || eventName == v[TYPE])) {
\r
398 adjust: v[ADJ_SCOPE],
\r
404 return results.length ? results : null;
\r
407 _unload : function(e) {
\r
408 var EU = Ext.lib.Event,
\r
417 Ext.each(unloadListeners, function(v) {
\r
420 scope = v[ADJ_SCOPE] ? (v[ADJ_SCOPE] === true ? v[OBJ] : v[ADJ_SCOPE]) : win;
\r
421 v[FN].call(scope, EU.getEvent(e), v[OBJ]);
\r
426 unloadListeners = null;
\r
428 if(listeners && (j = listeners.length)){
\r
430 if((l = listeners[index = --j])){
\r
431 EU.removeListener(l[EL], l[TYPE], l[FN], index);
\r
437 doRemove(win, UNLOAD, EU._unload);
\r
441 // Initialize stuff.
\r
442 pub.on = pub.addListener;
\r
443 pub.un = pub.removeListener;
\r
444 if (doc && doc.body) {
\r
447 doAdd(win, "load", pub._load);
\r
449 doAdd(win, UNLOAD, pub._unload);
\r
450 _tryPreloadAttach();
\r