PageRenderTime 50ms CodeModel.GetById 17ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/hippo/src/main/webapp/ext/src/util/KeyMap.js

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