Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / KeyMap.html
index 073915d..57fc756 100644 (file)
+<!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>
+  <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();">
-    <pre class="prettyprint lang-js">/*!
- * Ext JS Library 3.0.3
- * Copyright(c) 2006-2009 Ext JS, LLC
- * licensing@extjs.com
- * http://www.extjs.com/license
+<body onload="prettyPrint(); highlight();">
+  <pre class="prettyprint lang-js"><span id='Ext-util-KeyMap'>/**
+</span> * @class Ext.util.KeyMap
+ * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
+ * The constructor accepts the same config object as defined by {@link #addBinding}.
+ * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
+ * combination it will call the function with this signature (if the match is a multi-key
+ * combination the callback will still be called only once): (String key, Ext.EventObject e)
+ * A KeyMap can also handle a string representation of keys. By default KeyMap starts enabled.&lt;br /&gt;
+ * Usage:
+ &lt;pre&gt;&lt;code&gt;
+// map one key by key code
+var map = new Ext.util.KeyMap(&quot;my-element&quot;, {
+    key: 13, // or Ext.EventObject.ENTER
+    fn: myHandler,
+    scope: myObject
+});
+
+// map multiple keys to one action by string
+var map = new Ext.util.KeyMap(&quot;my-element&quot;, {
+    key: &quot;a\r\n\t&quot;,
+    fn: myHandler,
+    scope: myObject
+});
+
+// map multiple keys to multiple actions by strings and array of codes
+var map = new Ext.util.KeyMap(&quot;my-element&quot;, [
+    {
+        key: [10,13],
+        fn: function(){ alert(&quot;Return was pressed&quot;); }
+    }, {
+        key: &quot;abc&quot;,
+        fn: function(){ alert('a, b or c was pressed'); }
+    }, {
+        key: &quot;\t&quot;,
+        ctrl:true,
+        shift:true,
+        fn: function(){ alert('Control + shift + tab was pressed.'); }
+    }
+]);
+&lt;/code&gt;&lt;/pre&gt;
  */
-<div id="cls-Ext.KeyMap"></div>/**\r
- * @class Ext.KeyMap\r
- * Handles mapping keys to actions for an element. One key map can be used for multiple actions.\r
- * The constructor accepts the same config object as defined by {@link #addBinding}.\r
- * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key\r
- * combination it will call the function with this signature (if the match is a multi-key\r
- * combination the callback will still be called only once): (String key, Ext.EventObject e)\r
- * A KeyMap can also handle a string representation of keys.<br />\r
- * Usage:\r
- <pre><code>\r
-// map one key by key code\r
-var map = new Ext.KeyMap("my-element", {\r
-    key: 13, // or Ext.EventObject.ENTER\r
-    fn: myHandler,\r
-    scope: myObject\r
-});\r
-\r
-// map multiple keys to one action by string\r
-var map = new Ext.KeyMap("my-element", {\r
-    key: "a\r\n\t",\r
-    fn: myHandler,\r
-    scope: myObject\r
-});\r
-\r
-// map multiple keys to multiple actions by strings and array of codes\r
-var map = new Ext.KeyMap("my-element", [\r
-    {\r
-        key: [10,13],\r
-        fn: function(){ alert("Return was pressed"); }\r
-    }, {\r
-        key: "abc",\r
-        fn: function(){ alert('a, b or c was pressed'); }\r
-    }, {\r
-        key: "\t",\r
-        ctrl:true,\r
-        shift:true,\r
-        fn: function(){ alert('Control + shift + tab was pressed.'); }\r
-    }\r
-]);\r
-</code></pre>\r
- * <b>Note: A KeyMap starts enabled</b>\r
- * @constructor\r
- * @param {Mixed} el The element to bind to\r
- * @param {Object} config The config (see {@link #addBinding})\r
- * @param {String} eventName (optional) The event to bind to (defaults to "keydown")\r
- */\r
-Ext.KeyMap = function(el, config, eventName){\r
-    this.el  = Ext.get(el);\r
-    this.eventName = eventName || "keydown";\r
-    this.bindings = [];\r
-    if(config){\r
-        this.addBinding(config);\r
-    }\r
-    this.enable();\r
-};\r
-\r
-Ext.KeyMap.prototype = {\r
-    <div id="prop-Ext.KeyMap-stopEvent"></div>/**\r
-     * True to stop the event from bubbling and prevent the default browser action if the\r
-     * key was handled by the KeyMap (defaults to false)\r
-     * @type Boolean\r
-     */\r
-    stopEvent : false,\r
-\r
-    <div id="method-Ext.KeyMap-addBinding"></div>/**\r
-     * Add a new binding to this KeyMap. The following config object properties are supported:\r
-     * <pre>\r
-Property    Type             Description\r
-----------  ---------------  ----------------------------------------------------------------------\r
-key         String/Array     A single keycode or an array of keycodes to handle\r
-shift       Boolean          True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)\r
-ctrl        Boolean          True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)\r
-alt         Boolean          True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)\r
-handler     Function         The function to call when KeyMap finds the expected key combination\r
-fn          Function         Alias of handler (for backwards-compatibility)\r
-scope       Object           The scope of the callback function\r
-stopEvent   Boolean          True to stop the event from bubbling and prevent the default browser action if the key was handled by the KeyMap (defaults to false)\r
-</pre>\r
-     *\r
-     * Usage:\r
-     * <pre><code>\r
-// Create a KeyMap\r
-var map = new Ext.KeyMap(document, {\r
-    key: Ext.EventObject.ENTER,\r
-    fn: handleKey,\r
-    scope: this\r
-});\r
-\r
-//Add a new binding to the existing KeyMap later\r
-map.addBinding({\r
-    key: 'abc',\r
-    shift: true,\r
-    fn: handleKey,\r
-    scope: this\r
-});\r
-</code></pre>\r
-     * @param {Object/Array} config A single KeyMap config or an array of configs\r
-     */\r
-       addBinding : function(config){\r
-        if(Ext.isArray(config)){\r
-            Ext.each(config, function(c){\r
-                this.addBinding(c);\r
-            }, this);\r
-            return;\r
-        }\r
-        var keyCode = config.key,\r
-            fn = config.fn || config.handler,\r
-            scope = config.scope;\r
-\r
-       if (config.stopEvent) {\r
-           this.stopEvent = config.stopEvent;    \r
-       }       \r
-\r
-        if(typeof keyCode == "string"){\r
-            var ks = [];\r
-            var keyString = keyCode.toUpperCase();\r
-            for(var j = 0, len = keyString.length; j < len; j++){\r
-                ks.push(keyString.charCodeAt(j));\r
-            }\r
-            keyCode = ks;\r
-        }\r
-        var keyArray = Ext.isArray(keyCode);\r
-        \r
-        var handler = function(e){\r
-            if(this.checkModifiers(config, e)){\r
-                var k = e.getKey();\r
-                if(keyArray){\r
-                    for(var i = 0, len = keyCode.length; i < len; i++){\r
-                        if(keyCode[i] == k){\r
-                          if(this.stopEvent){\r
-                              e.stopEvent();\r
-                          }\r
-                          fn.call(scope || window, k, e);\r
-                          return;\r
-                        }\r
-                    }\r
-                }else{\r
-                    if(k == keyCode){\r
-                        if(this.stopEvent){\r
-                           e.stopEvent();\r
-                        }\r
-                        fn.call(scope || window, k, e);\r
-                    }\r
-                }\r
-            }\r
-        };\r
-        this.bindings.push(handler);\r
-       },\r
-    \r
-    // private\r
-    checkModifiers: function(config, e){\r
-        var val, key, keys = ['shift', 'ctrl', 'alt'];\r
-        for (var i = 0, len = keys.length; i < len; ++i){\r
-            key = keys[i];\r
-            val = config[key];\r
-            if(!(val === undefined || (val === e[key + 'Key']))){\r
-                return false;\r
-            }\r
-        }\r
-        return true;\r
-    },\r
-\r
-    <div id="method-Ext.KeyMap-on"></div>/**\r
-     * Shorthand for adding a single key listener\r
-     * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the\r
-     * following options:\r
-     * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}\r
-     * @param {Function} fn The function to call\r
-     * @param {Object} scope (optional) The scope of the function\r
-     */\r
-    on : function(key, fn, scope){\r
-        var keyCode, shift, ctrl, alt;\r
-        if(typeof key == "object" && !Ext.isArray(key)){\r
-            keyCode = key.key;\r
-            shift = key.shift;\r
-            ctrl = key.ctrl;\r
-            alt = key.alt;\r
-        }else{\r
-            keyCode = key;\r
-        }\r
-        this.addBinding({\r
-            key: keyCode,\r
-            shift: shift,\r
-            ctrl: ctrl,\r
-            alt: alt,\r
-            fn: fn,\r
-            scope: scope\r
-        });\r
-    },\r
-\r
-    // private\r
-    handleKeyDown : function(e){\r
-           if(this.enabled){ //just in case\r
-           var b = this.bindings;\r
-           for(var i = 0, len = b.length; i < len; i++){\r
-               b[i].call(this, e);\r
-           }\r
-           }\r
-       },\r
-\r
-       <div id="method-Ext.KeyMap-isEnabled"></div>/**\r
-        * Returns true if this KeyMap is enabled\r
-        * @return {Boolean}\r
-        */\r
-       isEnabled : function(){\r
-           return this.enabled;\r
-       },\r
-\r
-       <div id="method-Ext.KeyMap-enable"></div>/**\r
-        * Enables this KeyMap\r
-        */\r
-       enable: function(){\r
-               if(!this.enabled){\r
-                   this.el.on(this.eventName, this.handleKeyDown, this);\r
-                   this.enabled = true;\r
-               }\r
-       },\r
-\r
-       <div id="method-Ext.KeyMap-disable"></div>/**\r
-        * Disable this KeyMap\r
-        */\r
-       disable: function(){\r
-               if(this.enabled){\r
-                   this.el.removeListener(this.eventName, this.handleKeyDown, this);\r
-                   this.enabled = false;\r
-               }\r
-       },\r
-    \r
-    <div id="method-Ext.KeyMap-setDisabled"></div>/**\r
-     * Convenience function for setting disabled/enabled by boolean.\r
-     * @param {Boolean} disabled\r
-     */\r
-    setDisabled : function(disabled){\r
-        this[disabled ? "disable" : "enable"]();\r
-    }\r
-};</pre>
+Ext.define('Ext.util.KeyMap', {
+    alternateClassName: 'Ext.KeyMap',
+
+<span id='Ext-util-KeyMap-method-constructor'>    /**
+</span>     * Creates new KeyMap.
+     * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
+     * @param {Object} binding The binding (see {@link #addBinding})
+     * @param {String} [eventName=&quot;keydown&quot;] The event to bind to
+     */
+    constructor: function(el, binding, eventName){
+        var me = this;
+
+        Ext.apply(me, {
+            el: Ext.get(el),
+            eventName: eventName || me.eventName,
+            bindings: []
+        });
+        if (binding) {
+            me.addBinding(binding);
+        }
+        me.enable();
+    },
+
+    eventName: 'keydown',
+
+<span id='Ext-util-KeyMap-method-addBinding'>    /**
+</span>     * Add a new binding to this KeyMap. The following config object properties are supported:
+     * &lt;pre&gt;
+Property            Type             Description
+----------          ---------------  ----------------------------------------------------------------------
+key                 String/Array     A single keycode or an array of keycodes to handle
+shift               Boolean          True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
+ctrl                Boolean          True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
+alt                 Boolean          True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
+handler             Function         The function to call when KeyMap finds the expected key combination
+fn                  Function         Alias of handler (for backwards-compatibility)
+scope               Object           The scope of the callback function
+defaultEventAction  String           A default action to apply to the event. Possible values are: stopEvent, stopPropagation, preventDefault. If no value is set no action is performed.
+&lt;/pre&gt;
+     *
+     * Usage:
+     * &lt;pre&gt;&lt;code&gt;
+// Create a KeyMap
+var map = new Ext.util.KeyMap(document, {
+    key: Ext.EventObject.ENTER,
+    fn: handleKey,
+    scope: this
+});
+
+//Add a new binding to the existing KeyMap later
+map.addBinding({
+    key: 'abc',
+    shift: true,
+    fn: handleKey,
+    scope: this
+});
+&lt;/code&gt;&lt;/pre&gt;
+     * @param {Object/Object[]} binding A single KeyMap config or an array of configs
+     */
+    addBinding : function(binding){
+        if (Ext.isArray(binding)) {
+            Ext.each(binding, this.addBinding, this);
+            return;
+        }
+
+        var keyCode = binding.key,
+            processed = false,
+            key,
+            keys,
+            keyString,
+            i,
+            len;
+
+        if (Ext.isString(keyCode)) {
+            keys = [];
+            keyString = keyCode.toUpperCase();
+
+            for (i = 0, len = keyString.length; i &lt; len; ++i){
+                keys.push(keyString.charCodeAt(i));
+            }
+            keyCode = keys;
+            processed = true;
+        }
+
+        if (!Ext.isArray(keyCode)) {
+            keyCode = [keyCode];
+        }
+
+        if (!processed) {
+            for (i = 0, len = keyCode.length; i &lt; len; ++i) {
+                key = keyCode[i];
+                if (Ext.isString(key)) {
+                    keyCode[i] = key.toUpperCase().charCodeAt(0);
+                }
+            }
+        }
+
+        this.bindings.push(Ext.apply({
+            keyCode: keyCode
+        }, binding));
+    },
+
+<span id='Ext-util-KeyMap-method-handleKeyDown'>    /**
+</span>     * Process any keydown events on the element
+     * @private
+     * @param {Ext.EventObject} event
+     */
+    handleKeyDown: function(event) {
+        if (this.enabled) { //just in case
+            var bindings = this.bindings,
+                i = 0,
+                len = bindings.length;
+
+            event = this.processEvent(event);
+            for(; i &lt; len; ++i){
+                this.processBinding(bindings[i], event);
+            }
+        }
+    },
+
+<span id='Ext-util-KeyMap-method-processEvent'>    /**
+</span>     * Ugly hack to allow this class to be tested. Currently WebKit gives
+     * no way to raise a key event properly with both
+     * a) A keycode
+     * b) The alt/ctrl/shift modifiers
+     * So we have to simulate them here. Yuk!
+     * This is a stub method intended to be overridden by tests.
+     * More info: https://bugs.webkit.org/show_bug.cgi?id=16735
+     * @private
+     */
+    processEvent: function(event){
+        return event;
+    },
+
+<span id='Ext-util-KeyMap-method-processBinding'>    /**
+</span>     * Process a particular binding and fire the handler if necessary.
+     * @private
+     * @param {Object} binding The binding information
+     * @param {Ext.EventObject} event
+     */
+    processBinding: function(binding, event){
+        if (this.checkModifiers(binding, event)) {
+            var key = event.getKey(),
+                handler = binding.fn || binding.handler,
+                scope = binding.scope || this,
+                keyCode = binding.keyCode,
+                defaultEventAction = binding.defaultEventAction,
+                i,
+                len,
+                keydownEvent = new Ext.EventObjectImpl(event);
+
+
+            for (i = 0, len = keyCode.length; i &lt; len; ++i) {
+                if (key === keyCode[i]) {
+                    if (handler.call(scope, key, event) !== true &amp;&amp; defaultEventAction) {
+                        keydownEvent[defaultEventAction]();
+                    }
+                    break;
+                }
+            }
+        }
+    },
+
+<span id='Ext-util-KeyMap-method-checkModifiers'>    /**
+</span>     * Check if the modifiers on the event match those on the binding
+     * @private
+     * @param {Object} binding
+     * @param {Ext.EventObject} event
+     * @return {Boolean} True if the event matches the binding
+     */
+    checkModifiers: function(binding, e){
+        var keys = ['shift', 'ctrl', 'alt'],
+            i = 0,
+            len = keys.length,
+            val, key;
+
+        for (; i &lt; len; ++i){
+            key = keys[i];
+            val = binding[key];
+            if (!(val === undefined || (val === e[key + 'Key']))) {
+                return false;
+            }
+        }
+        return true;
+    },
+
+<span id='Ext-util-KeyMap-method-on'>    /**
+</span>     * Shorthand for adding a single key listener
+     * @param {Number/Number[]/Object} key Either the numeric key code, array of key codes or an object with the
+     * following options:
+     * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope (&lt;code&gt;this&lt;/code&gt; reference) in which the function is executed. Defaults to the browser window.
+     */
+    on: function(key, fn, scope) {
+        var keyCode, shift, ctrl, alt;
+        if (Ext.isObject(key) &amp;&amp; !Ext.isArray(key)) {
+            keyCode = key.key;
+            shift = key.shift;
+            ctrl = key.ctrl;
+            alt = key.alt;
+        } else {
+            keyCode = key;
+        }
+        this.addBinding({
+            key: keyCode,
+            shift: shift,
+            ctrl: ctrl,
+            alt: alt,
+            fn: fn,
+            scope: scope
+        });
+    },
+
+<span id='Ext-util-KeyMap-method-isEnabled'>    /**
+</span>     * Returns true if this KeyMap is enabled
+     * @return {Boolean}
+     */
+    isEnabled : function(){
+        return this.enabled;
+    },
+
+<span id='Ext-util-KeyMap-method-enable'>    /**
+</span>     * Enables this KeyMap
+     */
+    enable: function(){
+        var me = this;
+        
+        if (!me.enabled) {
+            me.el.on(me.eventName, me.handleKeyDown, me);
+            me.enabled = true;
+        }
+    },
+
+<span id='Ext-util-KeyMap-method-disable'>    /**
+</span>     * Disable this KeyMap
+     */
+    disable: function(){
+        var me = this;
+        
+        if (me.enabled) {
+            me.el.removeListener(me.eventName, me.handleKeyDown, me);
+            me.enabled = false;
+        }
+    },
+
+<span id='Ext-util-KeyMap-method-setDisabled'>    /**
+</span>     * Convenience function for setting disabled/enabled by boolean.
+     * @param {Boolean} disabled
+     */
+    setDisabled : function(disabled){
+        if (disabled) {
+            this.disable();
+        } else {
+            this.enable();
+        }
+    },
+
+<span id='Ext-util-KeyMap-method-destroy'>    /**
+</span>     * Destroys the KeyMap instance and removes all handlers.
+     * @param {Boolean} removeEl True to also remove the attached element
+     */
+    destroy: function(removeEl){
+        var me = this;
+
+        me.bindings = [];
+        me.disable();
+        if (removeEl === true) {
+            me.el.remove();
+        }
+        delete me.el;
+    }
+});</pre>
 </body>
-</html>
\ No newline at end of file
+</html>