ext-base-event.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:14k
源码类别:

中间件编程

开发平台:

JavaScript

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