1 | /* |
---|
2 | * Ext JS Library 2.2.1 |
---|
3 | * Copyright(c) 2006-2009, Ext JS, LLC. |
---|
4 | * licensing@extjs.com |
---|
5 | * |
---|
6 | * http://extjs.com/license |
---|
7 | */ |
---|
8 | |
---|
9 | /** |
---|
10 | * @class Ext.KeyMap |
---|
11 | * Handles mapping keys to actions for an element. One key map can be used for multiple actions. |
---|
12 | * The constructor accepts the same config object as defined by {@link #addBinding}. |
---|
13 | * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key |
---|
14 | * combination it will call the function with this signature (if the match is a multi-key |
---|
15 | * combination the callback will still be called only once): (String key, Ext.EventObject e) |
---|
16 | * A KeyMap can also handle a string representation of keys.<br /> |
---|
17 | * Usage: |
---|
18 | <pre><code> |
---|
19 | // map one key by key code |
---|
20 | var map = new Ext.KeyMap("my-element", { |
---|
21 | key: 13, // or Ext.EventObject.ENTER |
---|
22 | fn: myHandler, |
---|
23 | scope: myObject |
---|
24 | }); |
---|
25 | |
---|
26 | // map multiple keys to one action by string |
---|
27 | var map = new Ext.KeyMap("my-element", { |
---|
28 | key: "a\r\n\t", |
---|
29 | fn: myHandler, |
---|
30 | scope: myObject |
---|
31 | }); |
---|
32 | |
---|
33 | // map multiple keys to multiple actions by strings and array of codes |
---|
34 | var map = new Ext.KeyMap("my-element", [ |
---|
35 | { |
---|
36 | key: [10,13], |
---|
37 | fn: function(){ alert("Return was pressed"); } |
---|
38 | }, { |
---|
39 | key: "abc", |
---|
40 | fn: function(){ alert('a, b or c was pressed'); } |
---|
41 | }, { |
---|
42 | key: "\t", |
---|
43 | ctrl:true, |
---|
44 | shift:true, |
---|
45 | fn: function(){ alert('Control + shift + tab was pressed.'); } |
---|
46 | } |
---|
47 | ]); |
---|
48 | </code></pre> |
---|
49 | * <b>Note: A KeyMap starts enabled</b> |
---|
50 | * @constructor |
---|
51 | * @param {Mixed} el The element to bind to |
---|
52 | * @param {Object} config The config (see {@link #addBinding}) |
---|
53 | * @param {String} eventName (optional) The event to bind to (defaults to "keydown") |
---|
54 | */ |
---|
55 | Ext.KeyMap = function(el, config, eventName){ |
---|
56 | this.el = Ext.get(el); |
---|
57 | this.eventName = eventName || "keydown"; |
---|
58 | this.bindings = []; |
---|
59 | if(config){ |
---|
60 | this.addBinding(config); |
---|
61 | } |
---|
62 | this.enable(); |
---|
63 | }; |
---|
64 | |
---|
65 | Ext.KeyMap.prototype = { |
---|
66 | /** |
---|
67 | * True to stop the event from bubbling and prevent the default browser action if the |
---|
68 | * key was handled by the KeyMap (defaults to false) |
---|
69 | * @type Boolean |
---|
70 | */ |
---|
71 | stopEvent : false, |
---|
72 | |
---|
73 | /** |
---|
74 | * Add a new binding to this KeyMap. The following config object properties are supported: |
---|
75 | * <pre> |
---|
76 | Property Type Description |
---|
77 | ---------- --------------- ---------------------------------------------------------------------- |
---|
78 | key String/Array A single keycode or an array of keycodes to handle |
---|
79 | shift Boolean True to handle key only when shift is pressed (defaults to false) |
---|
80 | ctrl Boolean True to handle key only when ctrl is pressed (defaults to false) |
---|
81 | alt Boolean True to handle key only when alt is pressed (defaults to false) |
---|
82 | handler Function The function to call when KeyMap finds the expected key combination |
---|
83 | fn Function Alias of handler (for backwards-compatibility) |
---|
84 | scope Object The scope of the callback function |
---|
85 | stopEvent Boolean True to stop the event |
---|
86 | </pre> |
---|
87 | * |
---|
88 | * Usage: |
---|
89 | * <pre><code> |
---|
90 | // Create a KeyMap |
---|
91 | var map = new Ext.KeyMap(document, { |
---|
92 | key: Ext.EventObject.ENTER, |
---|
93 | fn: handleKey, |
---|
94 | scope: this |
---|
95 | }); |
---|
96 | |
---|
97 | //Add a new binding to the existing KeyMap later |
---|
98 | map.addBinding({ |
---|
99 | key: 'abc', |
---|
100 | shift: true, |
---|
101 | fn: handleKey, |
---|
102 | scope: this |
---|
103 | }); |
---|
104 | </code></pre> |
---|
105 | * @param {Object/Array} config A single KeyMap config or an array of configs |
---|
106 | */ |
---|
107 | addBinding : function(config){ |
---|
108 | if(Ext.isArray(config)){ |
---|
109 | for(var i = 0, len = config.length; i < len; i++){ |
---|
110 | this.addBinding(config[i]); |
---|
111 | } |
---|
112 | return; |
---|
113 | } |
---|
114 | var keyCode = config.key, |
---|
115 | shift = config.shift, |
---|
116 | ctrl = config.ctrl, |
---|
117 | alt = config.alt, |
---|
118 | fn = config.fn || config.handler, |
---|
119 | scope = config.scope; |
---|
120 | |
---|
121 | if (config.stopEvent) { |
---|
122 | this.stopEvent = config.stopEvent; |
---|
123 | } |
---|
124 | |
---|
125 | if(typeof keyCode == "string"){ |
---|
126 | var ks = []; |
---|
127 | var keyString = keyCode.toUpperCase(); |
---|
128 | for(var j = 0, len = keyString.length; j < len; j++){ |
---|
129 | ks.push(keyString.charCodeAt(j)); |
---|
130 | } |
---|
131 | keyCode = ks; |
---|
132 | } |
---|
133 | var keyArray = Ext.isArray(keyCode); |
---|
134 | |
---|
135 | var handler = function(e){ |
---|
136 | if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){ |
---|
137 | var k = e.getKey(); |
---|
138 | if(keyArray){ |
---|
139 | for(var i = 0, len = keyCode.length; i < len; i++){ |
---|
140 | if(keyCode[i] == k){ |
---|
141 | if(this.stopEvent){ |
---|
142 | e.stopEvent(); |
---|
143 | } |
---|
144 | fn.call(scope || window, k, e); |
---|
145 | return; |
---|
146 | } |
---|
147 | } |
---|
148 | }else{ |
---|
149 | if(k == keyCode){ |
---|
150 | if(this.stopEvent){ |
---|
151 | e.stopEvent(); |
---|
152 | } |
---|
153 | fn.call(scope || window, k, e); |
---|
154 | } |
---|
155 | } |
---|
156 | } |
---|
157 | }; |
---|
158 | this.bindings.push(handler); |
---|
159 | }, |
---|
160 | |
---|
161 | /** |
---|
162 | * Shorthand for adding a single key listener |
---|
163 | * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the |
---|
164 | * following options: |
---|
165 | * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)} |
---|
166 | * @param {Function} fn The function to call |
---|
167 | * @param {Object} scope (optional) The scope of the function |
---|
168 | */ |
---|
169 | on : function(key, fn, scope){ |
---|
170 | var keyCode, shift, ctrl, alt; |
---|
171 | if(typeof key == "object" && !Ext.isArray(key)){ |
---|
172 | keyCode = key.key; |
---|
173 | shift = key.shift; |
---|
174 | ctrl = key.ctrl; |
---|
175 | alt = key.alt; |
---|
176 | }else{ |
---|
177 | keyCode = key; |
---|
178 | } |
---|
179 | this.addBinding({ |
---|
180 | key: keyCode, |
---|
181 | shift: shift, |
---|
182 | ctrl: ctrl, |
---|
183 | alt: alt, |
---|
184 | fn: fn, |
---|
185 | scope: scope |
---|
186 | }) |
---|
187 | }, |
---|
188 | |
---|
189 | // private |
---|
190 | handleKeyDown : function(e){ |
---|
191 | if(this.enabled){ //just in case |
---|
192 | var b = this.bindings; |
---|
193 | for(var i = 0, len = b.length; i < len; i++){ |
---|
194 | b[i].call(this, e); |
---|
195 | } |
---|
196 | } |
---|
197 | }, |
---|
198 | |
---|
199 | /** |
---|
200 | * Returns true if this KeyMap is enabled |
---|
201 | * @return {Boolean} |
---|
202 | */ |
---|
203 | isEnabled : function(){ |
---|
204 | return this.enabled; |
---|
205 | }, |
---|
206 | |
---|
207 | /** |
---|
208 | * Enables this KeyMap |
---|
209 | */ |
---|
210 | enable: function(){ |
---|
211 | if(!this.enabled){ |
---|
212 | this.el.on(this.eventName, this.handleKeyDown, this); |
---|
213 | this.enabled = true; |
---|
214 | } |
---|
215 | }, |
---|
216 | |
---|
217 | /** |
---|
218 | * Disable this KeyMap |
---|
219 | */ |
---|
220 | disable: function(){ |
---|
221 | if(this.enabled){ |
---|
222 | this.el.removeListener(this.eventName, this.handleKeyDown, this); |
---|
223 | this.enabled = false; |
---|
224 | } |
---|
225 | } |
---|
226 | }; |
---|