Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / EventManager.html
index 25a4846..5f472c2 100644 (file)
@@ -1,4 +1,21 @@
-<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-EventManager'>/**
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>The source code</title>
+  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+  <style type="text/css">
+    .highlight { display: block; background-color: #ddd; }
+  </style>
+  <script type="text/javascript">
+    function highlight() {
+      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+    }
+  </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+  <pre class="prettyprint lang-js"><span id='Ext-EventManager'>/**
 </span> * @class Ext.EventManager
  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
  * several useful events directly.
@@ -49,6 +66,7 @@ Ext.EventManager = {
 
         if(window.attachEvent){
             // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
+            // licensed courtesy of http://developer.yahoo.com/yui/license.html
             if (window != top) {
                 return false;
             }
@@ -131,7 +149,7 @@ Ext.EventManager = {
      * accessed shorthanded as Ext.onReady().
      * @param {Function} fn The method the event invokes.
      * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the handler function executes. Defaults to the browser window.
-     * @param {boolean} options (optional) Options object as passed to {@link Ext.core.Element#addListener}.
+     * @param {Boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}.
      */
     onDocumentReady: function(fn, scope, options){
         options = options || {};
@@ -169,15 +187,15 @@ Ext.EventManager = {
 
 <span id='Ext-EventManager-method-getId'>    /**
 </span>     * Get the id of the element. If one has not been assigned, automatically assign it.
-     * @param {Mixed} element The element to get the id for.
+     * @param {HTMLElement/Ext.Element} element The element to get the id for.
      * @return {String} id
      */
     getId : function(element) {
         var skipGarbageCollection = false,
             id;
-    
+
         element = Ext.getDom(element);
-    
+
         if (element === document || element === window) {
             id = element === document ? Ext.documentId : Ext.windowId;
         }
@@ -188,9 +206,9 @@ Ext.EventManager = {
         if (element &amp;&amp; (element.getElementById || element.navigator)) {
             skipGarbageCollection = true;
         }
-    
+
         if (!Ext.cache[id]){
-            Ext.core.Element.addToCache(new Ext.core.Element(element), id);
+            Ext.Element.addToCache(new Ext.Element(element), id);
             if (skipGarbageCollection) {
                 Ext.cache[id].skipGarbageCollection = true;
             }
@@ -283,13 +301,13 @@ Ext.EventManager = {
 
 <span id='Ext-EventManager-method-addListener'>    /**
 </span>    * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
-    * use {@link Ext.core.Element#addListener} directly on an Element in favor of calling this version.
+    * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
     * @param {String/HTMLElement} el The html element or id to assign the event handler to.
     * @param {String} eventName The name of the event to listen for.
     * @param {Function} handler The handler function the event invokes. This function is passed
     * the following parameters:&lt;ul&gt;
     * &lt;li&gt;evt : EventObject&lt;div class=&quot;sub-desc&quot;&gt;The {@link Ext.EventObject EventObject} describing the event.&lt;/div&gt;&lt;/li&gt;
-    * &lt;li&gt;t : Element&lt;div class=&quot;sub-desc&quot;&gt;The {@link Ext.core.Element Element} which was the target of the event.
+    * &lt;li&gt;t : Element&lt;div class=&quot;sub-desc&quot;&gt;The {@link Ext.Element Element} which was the target of the event.
     * Note that this may be filtered by using the &lt;tt&gt;delegate&lt;/tt&gt; option.&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;o : Object&lt;div class=&quot;sub-desc&quot;&gt;The options object from the addListener call.&lt;/div&gt;&lt;/li&gt;
     * &lt;/ul&gt;
@@ -309,11 +327,11 @@ Ext.EventManager = {
     * handler is &lt;em&gt;not&lt;/em&gt; invoked, but the new handler is scheduled in its place.&lt;/div&gt;&lt;/li&gt;
     * &lt;li&gt;target : Element&lt;div class=&quot;sub-desc&quot;&gt;Only call the handler if the event was fired on the target Element, &lt;i&gt;not&lt;/i&gt; if the event was bubbled up from a child node.&lt;/div&gt;&lt;/li&gt;
     * &lt;/ul&gt;&lt;br&gt;
-    * &lt;p&gt;See {@link Ext.core.Element#addListener} for examples of how to use these options.&lt;/p&gt;
+    * &lt;p&gt;See {@link Ext.Element#addListener} for examples of how to use these options.&lt;/p&gt;
     */
     addListener: function(element, eventName, fn, scope, options){
         // Check if we've been passed a &quot;config style&quot; event.
-        if (Ext.isObject(eventName)) {
+        if (typeof eventName !== 'string') {
             this.prepareListenerConfig(element, eventName);
             return;
         }
@@ -370,7 +388,7 @@ Ext.EventManager = {
 
 <span id='Ext-EventManager-method-removeListener'>    /**
 </span>    * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
-    * you will use {@link Ext.core.Element#removeListener} directly on an Element in favor of calling this version.
+    * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
     * @param {String/HTMLElement} el The id or html element from which to remove the listener.
     * @param {String} eventName The name of the event.
     * @param {Function} fn The handler function to remove. &lt;b&gt;This must be a reference to the function passed into the {@link #addListener} call.&lt;/b&gt;
@@ -379,7 +397,7 @@ Ext.EventManager = {
     */
     removeListener : function(element, eventName, fn, scope) {
         // handle our listener config object syntax
-        if (Ext.isObject(eventName)) {
+        if (typeof eventName !== 'string') {
             this.prepareListenerConfig(element, eventName, true);
             return;
         }
@@ -423,13 +441,13 @@ Ext.EventManager = {
                 }
 
                 // remove listener from cache
-                cache.splice(i, 1);
+                Ext.Array.erase(cache, i, 1);
             }
         }
     },
 
 <span id='Ext-EventManager-method-removeAll'>    /**
-</span>    * Removes all event handers from an element.  Typically you will use {@link Ext.core.Element#removeAllListeners}
+</span>    * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
     * directly on an Element in favor of calling this version.
     * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
     */
@@ -450,7 +468,7 @@ Ext.EventManager = {
     },
 
 <span id='Ext-EventManager-method-purgeElement'>    /**
-</span>     * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.core.Element#purgeAllListeners}
+</span>     * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.Element#purgeAllListeners}
      * directly on an Element in favor of calling this version.
      * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
      * @param {String} eventName (optional) The name of the event.
@@ -480,74 +498,79 @@ Ext.EventManager = {
      * @param {String} ename The event name
      * @param {Function} fn The function to execute
      * @param {Object} scope The scope to execute callback in
-     * @param {Object} o The options
+     * @param {Object} options The options
+     * @return {Function} the wrapper function
      */
     createListenerWrap : function(dom, ename, fn, scope, options) {
-        options = !Ext.isObject(options) ? {} : options;
+        options = options || {};
 
-        var f = ['if(!Ext) {return;}'],
-            gen;
+        var f, gen;
 
-        if(options.buffer || options.delay || options.freezeEvent) {
-            f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
-        } else {
-            f.push('e = Ext.EventObject.setEvent(e);');
-        }
+        return function wrap(e, args) {
+            // Compile the implementation upon first firing
+            if (!gen) {
+                f = ['if(!Ext) {return;}'];
 
-        if (options.delegate) {
-            f.push('var t = e.getTarget(&quot;' + options.delegate + '&quot;, this);');
-            f.push('if(!t) {return;}');
-        } else {
-            f.push('var t = e.target;');
-        }
+                if(options.buffer || options.delay || options.freezeEvent) {
+                    f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
+                } else {
+                    f.push('e = Ext.EventObject.setEvent(e);');
+                }
 
-        if (options.target) {
-            f.push('if(e.target !== options.target) {return;}');
-        }
+                if (options.delegate) {
+                    f.push('var t = e.getTarget(&quot;' + options.delegate + '&quot;, this);');
+                    f.push('if(!t) {return;}');
+                } else {
+                    f.push('var t = e.target;');
+                }
 
-        if(options.stopEvent) {
-            f.push('e.stopEvent();');
-        } else {
-            if(options.preventDefault) {
-                f.push('e.preventDefault();');
-            }
-            if(options.stopPropagation) {
-                f.push('e.stopPropagation();');
-            }
-        }
+                if (options.target) {
+                    f.push('if(e.target !== options.target) {return;}');
+                }
 
-        if(options.normalized === false) {
-            f.push('e = e.browserEvent;');
-        }
+                if(options.stopEvent) {
+                    f.push('e.stopEvent();');
+                } else {
+                    if(options.preventDefault) {
+                        f.push('e.preventDefault();');
+                    }
+                    if(options.stopPropagation) {
+                        f.push('e.stopPropagation();');
+                    }
+                }
 
-        if(options.buffer) {
-            f.push('(wrap.task &amp;&amp; clearTimeout(wrap.task));');
-            f.push('wrap.task = setTimeout(function(){');
-        }
+                if(options.normalized === false) {
+                    f.push('e = e.browserEvent;');
+                }
 
-        if(options.delay) {
-            f.push('wrap.tasks = wrap.tasks || [];');
-            f.push('wrap.tasks.push(setTimeout(function(){');
-        }
+                if(options.buffer) {
+                    f.push('(wrap.task &amp;&amp; clearTimeout(wrap.task));');
+                    f.push('wrap.task = setTimeout(function(){');
+                }
 
-        // finally call the actual handler fn
-        f.push('fn.call(scope || dom, e, t, options);');
+                if(options.delay) {
+                    f.push('wrap.tasks = wrap.tasks || [];');
+                    f.push('wrap.tasks.push(setTimeout(function(){');
+                }
 
-        if(options.single) {
-            f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
-        }
+                // finally call the actual handler fn
+                f.push('fn.call(scope || dom, e, t, options);');
 
-        if(options.delay) {
-            f.push('}, ' + options.delay + '));');
-        }
+                if(options.single) {
+                    f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
+                }
 
-        if(options.buffer) {
-            f.push('}, ' + options.buffer + ');');
-        }
+                if(options.delay) {
+                    f.push('}, ' + options.delay + '));');
+                }
 
-        gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
+                if(options.buffer) {
+                    f.push('}, ' + options.buffer + ');');
+                }
+
+                gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
+            }
 
-        return function wrap(e, args) {
             gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
         };
     },
@@ -560,6 +583,10 @@ Ext.EventManager = {
      * @return {Array} The events for the element
      */
     getEventListenerCache : function(element, eventName) {
+        if (!element) {
+            return [];
+        }
+
         var eventCache = this.getElementEventCache(element);
         return eventCache[eventName] || (eventCache[eventName] = []);
     },
@@ -571,6 +598,9 @@ Ext.EventManager = {
      * @return {Object} The event cache for the object
      */
     getElementEventCache : function(element) {
+        if (!element) {
+            return {};
+        }
         var elementCache = Ext.cache[this.getId(element)];
         return elementCache.events || (elementCache.events = {});
     },
@@ -660,9 +690,9 @@ Ext.EventManager = {
     },
 
 <span id='Ext-EventManager-method-getPageXY'>    /**
-</span>     * Gets the x &amp; ycoordinate from the event
+</span>     * Gets the x &amp; y coordinate from the event
      * @param {Object} event The event
-     * @return {Array} The x/y coordinate
+     * @return {Number[]} The x/y coordinate
      */
     getPageXY: function(event) {
         event = event.browserEvent || event;
@@ -722,7 +752,7 @@ Ext.EventManager = {
      * passes new viewport width and height to handlers.
      * @param {Function} fn      The handler function the window resize event invokes.
      * @param {Object}   scope   The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the handler function executes. Defaults to the browser window.
-     * @param {boolean}  options Options object as passed to {@link Ext.core.Element#addListener}
+     * @param {Boolean}  options Options object as passed to {@link Ext.Element#addListener}
      */
     onWindowResize: function(fn, scope, options){
         var resize = this.resizeEvent;
@@ -739,8 +769,8 @@ Ext.EventManager = {
      */
     fireResize: function(){
         var me = this,
-            w = Ext.core.Element.getViewWidth(),
-            h = Ext.core.Element.getViewHeight();
+            w = Ext.Element.getViewWidth(),
+            h = Ext.Element.getViewHeight();
 
          //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
          if(me.curHeight != h || me.curWidth != w){
@@ -812,7 +842,7 @@ Ext.EventManager = {
 <span id='Ext-EventManager-property-useKeyDown'>    /**
 </span>     * note 1: IE fires ONLY the keydown event on specialkey autorepeat
      * note 2: Safari &lt; 3.1, Gecko (Mac/Linux) &amp; Opera fire only the keypress event on specialkey autorepeat
-     * (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
+     * (research done by Jan Wolter at http://unixpapa.com/js/key.html)
      * @private
      */
     useKeyDown: Ext.isWebKit ?
@@ -863,7 +893,7 @@ Ext.EventManager.un = Ext.EventManager.removeListener;
         // find the body element
         var bd = document.body || document.getElementsByTagName('body')[0],
             baseCSSPrefix = Ext.baseCSSPrefix,
-            cls = [],
+            cls = [baseCSSPrefix + 'body'],
             htmlCls = [],
             html;
 
@@ -873,66 +903,107 @@ Ext.EventManager.un = Ext.EventManager.removeListener;
 
         html = bd.parentNode;
 
+        function add (c) {
+            cls.push(baseCSSPrefix + c);
+        }
+
         //Let's keep this human readable!
         if (Ext.isIE) {
-            cls.push(baseCSSPrefix + 'ie');
-        }
-        if (Ext.isIE6) {
-            cls.push(baseCSSPrefix + 'ie6');
-        }
-        if (Ext.isIE7) {
-            cls.push(baseCSSPrefix + 'ie7');
-        }
-        if (Ext.isIE8) {
-            cls.push(baseCSSPrefix + 'ie8');
-        }
-        if (Ext.isIE9) {
-            cls.push(baseCSSPrefix + 'ie9');
+            add('ie');
+
+            // very often CSS needs to do checks like &quot;IE7+&quot; or &quot;IE6 or 7&quot;. To help
+            // reduce the clutter (since CSS/SCSS cannot do these tests), we add some
+            // additional classes:
+            //
+            //      x-ie7p      : IE7+      :  7 &lt;= ieVer
+            //      x-ie7m      : IE7-      :  ieVer &lt;= 7
+            //      x-ie8p      : IE8+      :  8 &lt;= ieVer
+            //      x-ie8m      : IE8-      :  ieVer &lt;= 8
+            //      x-ie9p      : IE9+      :  9 &lt;= ieVer
+            //      x-ie78      : IE7 or 8  :  7 &lt;= ieVer &lt;= 8
+            //
+            if (Ext.isIE6) {
+                add('ie6');
+            } else { // ignore pre-IE6 :)
+                add('ie7p');
+
+                if (Ext.isIE7) {
+                    add('ie7');
+                } else {
+                    add('ie8p');
+
+                    if (Ext.isIE8) {
+                        add('ie8');
+                    } else {
+                        add('ie9p');
+
+                        if (Ext.isIE9) {
+                            add('ie9');
+                        }
+                    }
+                }
+            }
+
+            if (Ext.isIE6 || Ext.isIE7) {
+                add('ie7m');
+            }
+            if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
+                add('ie8m');
+            }
+            if (Ext.isIE7 || Ext.isIE8) {
+                add('ie78');
+            }
         }
         if (Ext.isGecko) {
-            cls.push(baseCSSPrefix + 'gecko');
-        }
-        if (Ext.isGecko3) {
-            cls.push(baseCSSPrefix + 'gecko3');
-        }
-        if (Ext.isGecko4) {
-            cls.push(baseCSSPrefix + 'gecko4');
+            add('gecko');
+            if (Ext.isGecko3) {
+                add('gecko3');
+            }
+            if (Ext.isGecko4) {
+                add('gecko4');
+            }
+            if (Ext.isGecko5) {
+                add('gecko5');
+            }
         }
         if (Ext.isOpera) {
-            cls.push(baseCSSPrefix + 'opera');
+            add('opera');
         }
         if (Ext.isWebKit) {
-            cls.push(baseCSSPrefix + 'webkit');
+            add('webkit');
         }
         if (Ext.isSafari) {
-            cls.push(baseCSSPrefix + 'safari');
-        }
-        if (Ext.isSafari2) {
-            cls.push(baseCSSPrefix + 'safari2');
-        }
-        if (Ext.isSafari3) {
-            cls.push(baseCSSPrefix + 'safari3');
-        }
-        if (Ext.isSafari4) {
-            cls.push(baseCSSPrefix + 'safari4');
+            add('safari');
+            if (Ext.isSafari2) {
+                add('safari2');
+            }
+            if (Ext.isSafari3) {
+                add('safari3');
+            }
+            if (Ext.isSafari4) {
+                add('safari4');
+            }
+            if (Ext.isSafari5) {
+                add('safari5');
+            }
         }
         if (Ext.isChrome) {
-            cls.push(baseCSSPrefix + 'chrome');
+            add('chrome');
         }
         if (Ext.isMac) {
-            cls.push(baseCSSPrefix + 'mac');
+            add('mac');
         }
         if (Ext.isLinux) {
-            cls.push(baseCSSPrefix + 'linux');
+            add('linux');
         }
         if (!Ext.supports.CSS3BorderRadius) {
-            cls.push(baseCSSPrefix + 'nbr');
+            add('nbr');
         }
         if (!Ext.supports.CSS3LinearGradient) {
-            cls.push(baseCSSPrefix + 'nlg');
+            add('nlg');
         }
         if (!Ext.scopeResetCSS) {
-            cls.push(baseCSSPrefix + 'reset');
+            add('reset');
         }
 
         // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
@@ -947,9 +1018,6 @@ Ext.EventManager.un = Ext.EventManager.removeListener;
             htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
             if (!Ext.isStrict) {
                 htmlCls.push(baseCSSPrefix + 'quirks');
-                if (Ext.isIE &amp;&amp; !Ext.isStrict) {
-                    Ext.isIEQuirks = true;
-                }
             }
             Ext.fly(html, '_internal').addCls(htmlCls);
         }
@@ -960,4 +1028,6 @@ Ext.EventManager.un = Ext.EventManager.removeListener;
 
     Ext.onReady(initExtCss);
 })();
-</pre></pre></body></html>
\ No newline at end of file
+</pre>
+</body>
+</html>