annotate onlypaths/js/ext/keymap.js @ 60:b92b3b099c02 laserkard

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