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 function checkRelatedTarget(e) {
\r
81 return !elContains(e.currentTarget, pub.getRelatedTarget(e));
\r
84 function elContains(parent, child) {
\r
85 if(parent && parent.firstChild){
\r
87 if(child === parent) {
\r
90 child = child.parentNode;
\r
91 if(child && (child.nodeType != 1)) {
\r
101 function _getCacheIndex(el, eventName, fn) {
\r
102 for(var v, index = -1, len = listeners.length, i = len - 1; i >= 0; --i){
\r
104 if (v && v[FN] == fn && v[EL] == el && v[TYPE] == eventName) {
\r
113 function _tryPreloadAttach() {
\r
117 tryAgain = !loadComplete || (retryCount > 0);
\r
122 Ext.each(onAvailStack, function (v,i,a){
\r
123 if(v && (element = doc.getElementById(v.id))){
\r
124 if(!v.checkReady || loadComplete || element.nextSibling || (doc && doc.body)) {
\r
125 element = v.override ? (v.override === true ? v.obj : v.override) : element;
\r
126 v.fn.call(element, v.obj);
\r
127 onAvailStack[i] = null;
\r
134 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
\r
139 clearInterval(_interval);
\r
143 ret = !(locked = false);
\r
149 function startInterval() {
\r
151 var callback = function() {
\r
152 _tryPreloadAttach();
\r
154 _interval = setInterval(callback, POLL_INTERVAL);
\r
159 function getScroll() {
\r
160 var dd = doc.documentElement,
\r
162 if(dd && (dd[SCROLLTOP] || dd[SCROLLLEFT])){
\r
163 return [dd[SCROLLLEFT], dd[SCROLLTOP]];
\r
165 return [db[SCROLLLEFT], db[SCROLLTOP]];
\r
172 function getPageCoord (ev, xy) {
\r
173 ev = ev.browserEvent || ev;
\r
174 var coord = ev['page' + xy];
\r
175 if (!coord && coord !== 0) {
\r
176 coord = ev['client' + xy] || 0;
\r
179 coord += getScroll()[xy == "X" ? 0 : 1];
\r
187 onAvailable : function(p_id, p_fn, p_obj, p_override) {
\r
188 onAvailStack.push({
\r
192 override: p_override,
\r
193 checkReady: false });
\r
195 retryCount = POLL_RETRYS;
\r
200 addListener: function(el, eventName, fn) {
\r
202 el = Ext.getDom(el);
\r
204 if (UNLOAD == eventName) {
\r
205 ret = !!(unloadListeners[unloadListeners.length] = [el, eventName, fn]);
\r
207 listeners.push([el, eventName, fn, ret = doAdd(el, eventName, fn, false)]);
\r
213 removeListener: function(el, eventName, fn) {
\r
218 el = Ext.getDom(el);
\r
221 ret = this.purgeElement(el, false, eventName);
\r
222 } else if (UNLOAD == eventName) {
\r
223 Ext.each(unloadListeners, function(v, i, a) {
\r
224 if( v && v[0] == el && v[1] == eventName && v[2] == fn) {
\r
225 unloadListeners.splice(i, 1);
\r
230 index = arguments[3] || _getCacheIndex(el, eventName, fn);
\r
231 cacheItem = listeners[index];
\r
233 if (el && cacheItem) {
\r
234 doRemove(el, eventName, cacheItem[WFN], false);
\r
235 cacheItem[WFN] = cacheItem[FN] = null;
\r
236 listeners.splice(index, 1);
\r
243 getTarget : function(ev) {
\r
244 ev = ev.browserEvent || ev;
\r
245 return this.resolveTextNode(ev.target || ev.srcElement);
\r
248 resolveTextNode : Ext.isGecko ? function(node){
\r
252 // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
\r
253 var s = HTMLElement.prototype.toString.call(node);
\r
254 if(s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]'){
\r
257 return node.nodeType == 3 ? node.parentNode : node;
\r
258 } : function(node){
\r
259 return node && node.nodeType == 3 ? node.parentNode : node;
\r
262 getRelatedTarget : function(ev) {
\r
263 ev = ev.browserEvent || ev;
\r
264 return this.resolveTextNode(ev.relatedTarget ||
\r
265 (ev.type == MOUSEOUT ? ev.toElement :
\r
266 ev.type == MOUSEOVER ? ev.fromElement : null));
\r
269 getPageX : function(ev) {
\r
270 return getPageCoord(ev, "X");
\r
273 getPageY : function(ev) {
\r
274 return getPageCoord(ev, "Y");
\r
278 getXY : function(ev) {
\r
279 return [this.getPageX(ev), this.getPageY(ev)];
\r
282 // Is this useful? Removing to save space unless use case exists.
\r
283 // getTime: function(ev) {
\r
284 // ev = ev.browserEvent || ev;
\r
286 // var t = new Date().getTime();
\r
297 stopEvent : function(ev) {
\r
298 this.stopPropagation(ev);
\r
299 this.preventDefault(ev);
\r
302 stopPropagation : function(ev) {
\r
303 ev = ev.browserEvent || ev;
\r
304 if (ev.stopPropagation) {
\r
305 ev.stopPropagation();
\r
307 ev.cancelBubble = true;
\r
311 preventDefault : function(ev) {
\r
312 ev = ev.browserEvent || ev;
\r
313 if (ev.preventDefault) {
\r
314 ev.preventDefault();
\r
316 ev.returnValue = false;
\r
320 getEvent : function(e) {
\r
321 e = e || win.event;
\r
323 var c = this.getEvent.caller;
\r
325 e = c.arguments[0];
\r
326 if (e && Event == e.constructor) {
\r
335 getCharCode : function(ev) {
\r
336 ev = ev.browserEvent || ev;
\r
337 return ev.charCode || ev.keyCode || 0;
\r
340 //clearCache: function() {},
\r
342 _load : function(e) {
\r
343 loadComplete = true;
\r
344 var EU = Ext.lib.Event;
\r
345 if (Ext.isIE && e !== true) {
\r
346 // IE8 complains that _load is null or not an object
\r
347 // so lets remove self via arguments.callee
\r
348 doRemove(win, "load", arguments.callee);
\r
352 purgeElement : function(el, recurse, eventName) {
\r
354 Ext.each( me.getListeners(el, eventName), function(v){
\r
356 me.removeListener(el, v.type, v.fn, v.index);
\r
360 if (recurse && el && el.childNodes) {
\r
361 Ext.each(el.childNodes, function(v){
\r
362 me.purgeElement(v, recurse, eventName);
\r
367 getListeners : function(el, eventName) {
\r
373 searchLists = eventName == UNLOAD ? unloadListeners : listeners;
\r
375 searchLists = listeners.concat(unloadListeners);
\r
378 Ext.each(searchLists, function(v, i){
\r
379 if (v && v[EL] == el && (!eventName || eventName == v[TYPE])) {
\r
384 adjust: v[ADJ_SCOPE],
\r
390 return results.length ? results : null;
\r
393 _unload : function(e) {
\r
394 var EU = Ext.lib.Event,
\r
403 Ext.each(unloadListeners, function(v) {
\r
406 scope = v[ADJ_SCOPE] ? (v[ADJ_SCOPE] === true ? v[OBJ] : v[ADJ_SCOPE]) : win;
\r
407 v[FN].call(scope, EU.getEvent(e), v[OBJ]);
\r
412 unloadListeners = null;
\r
414 if(listeners && (j = listeners.length)){
\r
416 if((l = listeners[index = --j])){
\r
417 EU.removeListener(l[EL], l[TYPE], l[FN], index);
\r
423 doRemove(win, UNLOAD, EU._unload);
\r
427 // Initialize stuff.
\r
428 pub.on = pub.addListener;
\r
429 pub.un = pub.removeListener;
\r
430 if (doc && doc.body) {
\r
433 doAdd(win, "load", pub._load);
\r
435 doAdd(win, UNLOAD, pub._unload);
\r
436 _tryPreloadAttach();
\r