Ext.lib.Event = function() { var loadComplete = false, listeners = [], unloadListeners = [], retryCount = 0, onAvailStack = [], _interval, locked = false, win = window, doc = document, // constants POLL_RETRYS = 200, POLL_INTERVAL = 20, EL = 0, TYPE = 1, FN = 2, WFN = 3, OBJ = 3, ADJ_SCOPE = 4, SCROLLLEFT = 'scrollLeft', SCROLLTOP = 'scrollTop', UNLOAD = 'unload', MOUSEOVER = 'mouseover', MOUSEOUT = 'mouseout', // private doAdd = function() { var ret; if (win.addEventListener) { ret = function(el, eventName, fn, capture) { if (eventName == 'mouseenter') { fn = fn.createInterceptor(checkRelatedTarget); el.addEventListener(MOUSEOVER, fn, (capture)); } else if (eventName == 'mouseleave') { fn = fn.createInterceptor(checkRelatedTarget); el.addEventListener(MOUSEOUT, fn, (capture)); } else { el.addEventListener(eventName, fn, (capture)); } return fn; }; } else if (win.attachEvent) { ret = function(el, eventName, fn, capture) { el.attachEvent("on" + eventName, fn); return fn; }; } else { ret = function(){}; } return ret; }(), // private doRemove = function(){ var ret; if (win.removeEventListener) { ret = function (el, eventName, fn, capture) { if (eventName == 'mouseenter') { eventName = MOUSEOVER; } else if (eventName == 'mouseleave') { eventName = MOUSEOUT; } el.removeEventListener(eventName, fn, (capture)); }; } else if (win.detachEvent) { ret = function (el, eventName, fn) { el.detachEvent("on" + eventName, fn); }; } else { ret = function(){}; } return ret; }(); var isXUL = Ext.isGecko ? function(node){ return Object.prototype.toString.call(node) == '[object XULElement]'; } : function(){}; var isTextNode = Ext.isGecko ? function(node){ try{ return node.nodeType == 3; }catch(e) { return false; } } : function(node){ return node.nodeType == 3; }; function checkRelatedTarget(e) { var related = pub.getRelatedTarget(e); return !(isXUL(related) || elContains(e.currentTarget,related)); } function elContains(parent, child) { if(parent && parent.firstChild){ while(child) { if(child === parent) { return true; } try { child = child.parentNode; } catch(e) { // In FF if you mouseout an text input element // thats inside a div sometimes it randomly throws // Permission denied to get property HTMLDivElement.parentNode // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427 return false; } if(child && (child.nodeType != 1)) { child = null; } } } return false; } // private function _getCacheIndex(el, eventName, fn) { var index = -1; Ext.each(listeners, function (v,i) { if(v && v[FN] == fn && v[EL] == el && v[TYPE] == eventName) { index = i; } }); return index; } // private function _tryPreloadAttach() { var ret = false, notAvail = [], element, tryAgain = !loadComplete || (retryCount > 0); if (!locked) { locked = true; Ext.each(onAvailStack, function (v,i,a){ if(v && (element = doc.getElementById(v.id))){ if(!v.checkReady || loadComplete || element.nextSibling || (doc && doc.body)) { element = v.override ? (v.override === true ? v.obj : v.override) : element; v.fn.call(element, v.obj); onAvailStack[i] = null; } else { notAvail.push(v); } } }); retryCount = (notAvail.length === 0) ? 0 : retryCount - 1; if (tryAgain) { startInterval(); } else { clearInterval(_interval); _interval = null; } ret = !(locked = false); } return ret; } // private function startInterval() { if(!_interval){ var callback = function() { _tryPreloadAttach(); }; _interval = setInterval(callback, POLL_INTERVAL); } } // private function getScroll() { var dd = doc.documentElement, db = doc.body; if(dd && (dd[SCROLLTOP] || dd[SCROLLLEFT])){ return [dd[SCROLLLEFT], dd[SCROLLTOP]]; }else if(db){ return [db[SCROLLLEFT], db[SCROLLTOP]]; }else{ return [0, 0]; } } // private function getPageCoord (ev, xy) { ev = ev.browserEvent || ev; var coord = ev['page' + xy]; if (!coord && coord !== 0) { coord = ev['client' + xy] || 0; if (Ext.isIE) { coord += getScroll()[xy == "X" ? 0 : 1]; } } return coord; } var pub = { onAvailable : function(p_id, p_fn, p_obj, p_override) { onAvailStack.push({ id: p_id, fn: p_fn, obj: p_obj, override: p_override, checkReady: false }); retryCount = POLL_RETRYS; startInterval(); }, addListener: function(el, eventName, fn) { var ret; el = Ext.getDom(el); if (el && fn) { if (UNLOAD == eventName) { ret = !!(unloadListeners[unloadListeners.length] = [el, eventName, fn]); } else { listeners.push([el, eventName, fn, ret = doAdd(el, eventName, fn, false)]); } } return !!ret; }, removeListener: function(el, eventName, fn) { var ret = false, index, cacheItem; el = Ext.getDom(el); if(!fn) { ret = this.purgeElement(el, false, eventName); } else if (UNLOAD == eventName) { Ext.each(unloadListeners, function(v, i, a) { if( v && v[0] == el && v[1] == eventName && v[2] == fn) { unloadListeners.splice(i, 1); ret = true; } }); } else { index = arguments[3] || _getCacheIndex(el, eventName, fn); cacheItem = listeners[index]; if (el && cacheItem) { doRemove(el, eventName, cacheItem[WFN], false); cacheItem[WFN] = cacheItem[FN] = null; listeners.splice(index, 1); ret = true; } } return ret; }, getTarget : function(ev) { ev = ev.browserEvent || ev; return this.resolveTextNode(ev.target || ev.srcElement); }, resolveTextNode : function(node) { return node && !isXUL(node) && isTextNode(node) ? node.parentNode : node; }, getRelatedTarget : function(ev) { ev = ev.browserEvent || ev; return this.resolveTextNode(ev.relatedTarget || (ev.type == MOUSEOUT ? ev.toElement : ev.type == MOUSEOVER ? ev.fromElement : null)); }, getPageX : function(ev) { return getPageCoord(ev, "X"); }, getPageY : function(ev) { return getPageCoord(ev, "Y"); }, getXY : function(ev) { return [this.getPageX(ev), this.getPageY(ev)]; }, // Is this useful? Removing to save space unless use case exists. // getTime: function(ev) { // ev = ev.browserEvent || ev; // if (!ev.time) { // var t = new Date().getTime(); // try { // ev.time = t; // } catch(ex) { // return t; // } // } // return ev.time; // }, stopEvent : function(ev) { this.stopPropagation(ev); this.preventDefault(ev); }, stopPropagation : function(ev) { ev = ev.browserEvent || ev; if (ev.stopPropagation) { ev.stopPropagation(); } else { ev.cancelBubble = true; } }, preventDefault : function(ev) { ev = ev.browserEvent || ev; if (ev.preventDefault) { ev.preventDefault(); } else { ev.returnValue = false; } }, getEvent : function(e) { e = e || win.event; if (!e) { var c = this.getEvent.caller; while (c) { e = c.arguments[0]; if (e && Event == e.constructor) { break; } c = c.caller; } } return e; }, getCharCode : function(ev) { ev = ev.browserEvent || ev; return ev.charCode || ev.keyCode || 0; }, //clearCache: function() {}, _load : function(e) { loadComplete = true; var EU = Ext.lib.Event; if (Ext.isIE && e !== true) { // IE8 complains that _load is null or not an object // so lets remove self via arguments.callee doRemove(win, "load", arguments.callee); } }, purgeElement : function(el, recurse, eventName) { var me = this; Ext.each( me.getListeners(el, eventName), function(v){ if(v){ me.removeListener(el, v.type, v.fn); } }); if (recurse && el && el.childNodes) { Ext.each(el.childNodes, function(v){ me.purgeElement(v, recurse, eventName); }); } }, getListeners : function(el, eventName) { var me = this, results = [], searchLists; if (eventName){ searchLists = eventName == UNLOAD ? unloadListeners : listeners; }else{ searchLists = listeners.concat(unloadListeners); } Ext.each(searchLists, function(v, i){ if (v && v[EL] == el && (!eventName || eventName == v[TYPE])) { results.push({ type: v[TYPE], fn: v[FN], obj: v[OBJ], adjust: v[ADJ_SCOPE], index: i }); } }); return results.length ? results : null; }, _unload : function(e) { var EU = Ext.lib.Event, i, j, l, len, index, scope; Ext.each(unloadListeners, function(v) { if (v) { try{ scope = v[ADJ_SCOPE] ? (v[ADJ_SCOPE] === true ? v[OBJ] : v[ADJ_SCOPE]) : win; v[FN].call(scope, EU.getEvent(e), v[OBJ]); }catch(ex){} } }); unloadListeners = null; if(listeners && (j = listeners.length)){ while(j){ if((l = listeners[index = --j])){ EU.removeListener(l[EL], l[TYPE], l[FN], index); } } //EU.clearCache(); } doRemove(win, UNLOAD, EU._unload); } }; // Initialize stuff. pub.on = pub.addListener; pub.un = pub.removeListener; if (doc && doc.body) { pub._load(true); } else { doAdd(win, "load", pub._load); } doAdd(win, UNLOAD, pub._unload); _tryPreloadAttach(); return pub; }();