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