Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / KeyMap.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-util-KeyMap-method-constructor'><span id='Ext-util-KeyMap'>/**
19 </span></span> * @class Ext.util.KeyMap
20  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
21  * The constructor accepts the same config object as defined by {@link #addBinding}.
22  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
23  * combination it will call the function with this signature (if the match is a multi-key
24  * combination the callback will still be called only once): (String key, Ext.EventObject e)
25  * A KeyMap can also handle a string representation of keys.&lt;br /&gt;
26  * Usage:
27  &lt;pre&gt;&lt;code&gt;
28 // map one key by key code
29 var map = new Ext.util.KeyMap(&quot;my-element&quot;, {
30     key: 13, // or Ext.EventObject.ENTER
31     fn: myHandler,
32     scope: myObject
33 });
34
35 // map multiple keys to one action by string
36 var map = new Ext.util.KeyMap(&quot;my-element&quot;, {
37     key: &quot;a\r\n\t&quot;,
38     fn: myHandler,
39     scope: myObject
40 });
41
42 // map multiple keys to multiple actions by strings and array of codes
43 var map = new Ext.util.KeyMap(&quot;my-element&quot;, [
44     {
45         key: [10,13],
46         fn: function(){ alert(&quot;Return was pressed&quot;); }
47     }, {
48         key: &quot;abc&quot;,
49         fn: function(){ alert('a, b or c was pressed'); }
50     }, {
51         key: &quot;\t&quot;,
52         ctrl:true,
53         shift:true,
54         fn: function(){ alert('Control + shift + tab was pressed.'); }
55     }
56 ]);
57 &lt;/code&gt;&lt;/pre&gt;
58  * &lt;b&gt;Note: A KeyMap starts enabled&lt;/b&gt;
59  * @constructor
60  * @param {Mixed} el The element to bind to
61  * @param {Object} binding The binding (see {@link #addBinding})
62  * @param {String} eventName (optional) The event to bind to (defaults to &quot;keydown&quot;)
63  */
64 Ext.define('Ext.util.KeyMap', {
65     alternateClassName: 'Ext.KeyMap',
66     
67     constructor: function(el, binding, eventName){
68         var me = this;
69         
70         Ext.apply(me, {
71             el: Ext.get(el),
72             eventName: eventName || me.eventName,
73             bindings: []
74         });
75         if (binding) {
76             me.addBinding(binding);
77         }
78         me.enable();
79     },
80     
81     eventName: 'keydown',
82
83 <span id='Ext-util-KeyMap-method-addBinding'>    /**
84 </span>     * Add a new binding to this KeyMap. The following config object properties are supported:
85      * &lt;pre&gt;
86 Property            Type             Description
87 ----------          ---------------  ----------------------------------------------------------------------
88 key                 String/Array     A single keycode or an array of keycodes to handle
89 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)
90 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)
91 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)
92 handler             Function         The function to call when KeyMap finds the expected key combination
93 fn                  Function         Alias of handler (for backwards-compatibility)
94 scope               Object           The scope of the callback function
95 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. 
96 &lt;/pre&gt;
97      *
98      * Usage:
99      * &lt;pre&gt;&lt;code&gt;
100 // Create a KeyMap
101 var map = new Ext.util.KeyMap(document, {
102     key: Ext.EventObject.ENTER,
103     fn: handleKey,
104     scope: this
105 });
106
107 //Add a new binding to the existing KeyMap later
108 map.addBinding({
109     key: 'abc',
110     shift: true,
111     fn: handleKey,
112     scope: this
113 });
114 &lt;/code&gt;&lt;/pre&gt;
115      * @param {Object/Array} binding A single KeyMap config or an array of configs
116      */
117     addBinding : function(binding){
118         if (Ext.isArray(binding)) {
119             Ext.each(binding, this.addBinding, this);
120             return;
121         }
122         
123         var keyCode = binding.key,
124             processed = false,
125             key,
126             keys,
127             keyString,
128             i,
129             len;
130
131         if (Ext.isString(keyCode)) {
132             keys = [];
133             keyString = keyCode.toLowerCase();
134             
135             for (i = 0, len = keyString.length; i &lt; len; ++i){
136                 keys.push(keyString.charCodeAt(i));
137             }
138             keyCode = keys;
139             processed = true;
140         }
141         
142         if (!Ext.isArray(keyCode)) {
143             keyCode = [keyCode];
144         }
145         
146         if (!processed) {
147             for (i = 0, len = keyCode.length; i &lt; len; ++i) {
148                 key = keyCode[i];
149                 if (Ext.isString(key)) {
150                     keyCode[i] = key.toLowerCase().charCodeAt(0);
151                 }
152             }
153         }
154         
155         this.bindings.push(Ext.apply({
156             keyCode: keyCode
157         }, binding));
158     },
159     
160 <span id='Ext-util-KeyMap-method-handleKeyDown'>    /**
161 </span>     * Process any keydown events on the element
162      * @private
163      * @param {Ext.EventObject} event
164      */
165     handleKeyDown: function(event) {
166         if (this.enabled) { //just in case
167             var bindings = this.bindings,
168                 i = 0,
169                 len = bindings.length;
170                 
171             event = this.processEvent(event);
172             for(; i &lt; len; ++i){
173                 this.processBinding(bindings[i], event);
174             }
175         }
176     },
177     
178 <span id='Ext-util-KeyMap-method-processEvent'>    /**
179 </span>     * Ugly hack to allow this class to be tested. Currently WebKit gives
180      * no way to raise a key event properly with both
181      * a) A keycode
182      * b) The alt/ctrl/shift modifiers
183      * So we have to simulate them here. Yuk! 
184      * This is a stub method intended to be overridden by tests.
185      * More info: https://bugs.webkit.org/show_bug.cgi?id=16735
186      * @private
187      */
188     processEvent: function(event){
189         return event;
190     },
191     
192 <span id='Ext-util-KeyMap-method-processBinding'>    /**
193 </span>     * Process a particular binding and fire the handler if necessary.
194      * @private
195      * @param {Object} binding The binding information
196      * @param {Ext.EventObject} event
197      */
198     processBinding: function(binding, event){
199         if (this.checkModifiers(binding, event)) {
200             var key = event.getKey(),
201                 handler = binding.fn || binding.handler,
202                 scope = binding.scope || this,
203                 keyCode = binding.keyCode,
204                 defaultEventAction = binding.defaultEventAction,
205                 i,
206                 len,
207                 keydownEvent = new Ext.EventObjectImpl(event);
208                 
209             
210             for (i = 0, len = keyCode.length; i &lt; len; ++i) {
211                 if (key === keyCode[i]) {
212                     if (handler.call(scope, key, event) !== true &amp;&amp; defaultEventAction) {
213                         keydownEvent[defaultEventAction]();
214                     }
215                     break;
216                 }
217             }
218         }
219     },
220     
221 <span id='Ext-util-KeyMap-method-checkModifiers'>    /**
222 </span>     * Check if the modifiers on the event match those on the binding
223      * @private
224      * @param {Object} binding
225      * @param {Ext.EventObject} event
226      * @return {Boolean} True if the event matches the binding
227      */
228     checkModifiers: function(binding, e){
229         var keys = ['shift', 'ctrl', 'alt'],
230             i = 0,
231             len = keys.length,
232             val, key;
233             
234         for (; i &lt; len; ++i){
235             key = keys[i];
236             val = binding[key];
237             if (!(val === undefined || (val === e[key + 'Key']))) {
238                 return false;
239             }
240         }
241         return true;
242     },
243
244 <span id='Ext-util-KeyMap-method-on'>    /**
245 </span>     * Shorthand for adding a single key listener
246      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
247      * following options:
248      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
249      * @param {Function} fn The function to call
250      * @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.
251      */
252     on: function(key, fn, scope) {
253         var keyCode, shift, ctrl, alt;
254         if (Ext.isObject(key) &amp;&amp; !Ext.isArray(key)) {
255             keyCode = key.key;
256             shift = key.shift;
257             ctrl = key.ctrl;
258             alt = key.alt;
259         } else {
260             keyCode = key;
261         }
262         this.addBinding({
263             key: keyCode,
264             shift: shift,
265             ctrl: ctrl,
266             alt: alt,
267             fn: fn,
268             scope: scope
269         });
270     },
271
272 <span id='Ext-util-KeyMap-method-isEnabled'>    /**
273 </span>     * Returns true if this KeyMap is enabled
274      * @return {Boolean}
275      */
276     isEnabled : function(){
277         return this.enabled;
278     },
279
280 <span id='Ext-util-KeyMap-method-enable'>    /**
281 </span>     * Enables this KeyMap
282      */
283     enable: function(){
284         if(!this.enabled){
285             this.el.on(this.eventName, this.handleKeyDown, this);
286             this.enabled = true;
287         }
288     },
289
290 <span id='Ext-util-KeyMap-method-disable'>    /**
291 </span>     * Disable this KeyMap
292      */
293     disable: function(){
294         if(this.enabled){
295             this.el.removeListener(this.eventName, this.handleKeyDown, this);
296             this.enabled = false;
297         }
298     },
299
300 <span id='Ext-util-KeyMap-method-setDisabled'>    /**
301 </span>     * Convenience function for setting disabled/enabled by boolean.
302      * @param {Boolean} disabled
303      */
304     setDisabled : function(disabled){
305         if (disabled) {
306             this.disable();
307         } else {
308             this.enable();
309         }
310     },
311     
312 <span id='Ext-util-KeyMap-method-destroy'>    /**
313 </span>     * Destroys the KeyMap instance and removes all handlers.
314      * @param {Boolean} removeEl True to also remove the attached element
315      */
316     destroy: function(removeEl){
317         var me = this;
318         
319         me.bindings = [];
320         me.disable();
321         if (removeEl === true) {
322             me.el.remove();
323         }
324         delete me.el;
325     }
326 });</pre>
327 </body>
328 </html>