Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / src / util / KeyNav.js
1 /*!
2  * Ext JS Library 3.3.1
3  * Copyright(c) 2006-2010 Sencha Inc.
4  * licensing@sencha.com
5  * http://www.sencha.com/license
6  */
7 /**
8  * @class Ext.KeyNav
9  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
10  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
11  * way to implement custom navigation schemes for any UI component.</p>
12  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13  * pageUp, pageDown, del, home, end.  Usage:</p>
14  <pre><code>
15 var nav = new Ext.KeyNav("my-element", {
16     "left" : function(e){
17         this.moveLeft(e.ctrlKey);
18     },
19     "right" : function(e){
20         this.moveRight(e.ctrlKey);
21     },
22     "enter" : function(e){
23         this.save();
24     },
25     scope : this
26 });
27 </code></pre>
28  * @constructor
29  * @param {Mixed} el The element to bind to
30  * @param {Object} config The config
31  */
32 Ext.KeyNav = function(el, config){
33     this.el = Ext.get(el);
34     Ext.apply(this, config);
35     if(!this.disabled){
36         this.disabled = true;
37         this.enable();
38     }
39 };
40
41 Ext.KeyNav.prototype = {
42     /**
43      * @cfg {Boolean} disabled
44      * True to disable this KeyNav instance (defaults to false)
45      */
46     disabled : false,
47     /**
48      * @cfg {String} defaultEventAction
49      * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are
50      * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
51      * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')
52      */
53     defaultEventAction: "stopEvent",
54     /**
55      * @cfg {Boolean} forceKeyDown
56      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
57      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
58      * handle keydown instead of keypress.
59      */
60     forceKeyDown : false,
61
62     // private
63     relay : function(e){
64         var k = e.getKey(),
65             h = this.keyToHandler[k];
66         if(h && this[h]){
67             if(this.doRelay(e, this[h], h) !== true){
68                 e[this.defaultEventAction]();
69             }
70         }
71     },
72
73     // private
74     doRelay : function(e, h, hname){
75         return h.call(this.scope || this, e, hname);
76     },
77
78     // possible handlers
79     enter : false,
80     left : false,
81     right : false,
82     up : false,
83     down : false,
84     tab : false,
85     esc : false,
86     pageUp : false,
87     pageDown : false,
88     del : false,
89     home : false,
90     end : false,
91
92     // quick lookup hash
93     keyToHandler : {
94         37 : "left",
95         39 : "right",
96         38 : "up",
97         40 : "down",
98         33 : "pageUp",
99         34 : "pageDown",
100         46 : "del",
101         36 : "home",
102         35 : "end",
103         13 : "enter",
104         27 : "esc",
105         9  : "tab"
106     },
107     
108     stopKeyUp: function(e) {
109         var k = e.getKey();
110
111         if (k >= 37 && k <= 40) {
112             // *** bugfix - safari 2.x fires 2 keyup events on cursor keys
113             // *** (note: this bugfix sacrifices the "keyup" event originating from keyNav elements in Safari 2)
114             e.stopEvent();
115         }
116     },
117     
118     /**
119      * Destroy this KeyNav (this is the same as calling disable).
120      */
121     destroy: function(){
122         this.disable();    
123     },
124
125         /**
126          * Enable this KeyNav
127          */
128         enable: function() {
129         if (this.disabled) {
130             if (Ext.isSafari2) {
131                 // call stopKeyUp() on "keyup" event
132                 this.el.on('keyup', this.stopKeyUp, this);
133             }
134
135             this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
136             this.disabled = false;
137         }
138     },
139
140         /**
141          * Disable this KeyNav
142          */
143         disable: function() {
144         if (!this.disabled) {
145             if (Ext.isSafari2) {
146                 // remove "keyup" event handler
147                 this.el.un('keyup', this.stopKeyUp, this);
148             }
149
150             this.el.un(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
151             this.disabled = true;
152         }
153     },
154     
155     /**
156      * Convenience function for setting disabled/enabled by boolean.
157      * @param {Boolean} disabled
158      */
159     setDisabled : function(disabled){
160         this[disabled ? "disable" : "enable"]();
161     },
162     
163     // private
164     isKeydown: function(){
165         return this.forceKeyDown || Ext.EventManager.useKeydown;
166     }
167 };