MDL-32843 import YUI 3.5.1
[moodle.git] / lib / yui / 3.5.1 / build / event-key / event-key-debug.js
blob5ecebf010229f3362be5bc18f4eba2885434874c
1 /*
2 YUI 3.5.1 (build 22)
3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
7 YUI.add('event-key', function(Y) {
9 /**
10  * Functionality to listen for one or more specific key combinations.
11  * @module event
12  * @submodule event-key
13  */
15 var ALT      = "+alt",
16     CTRL     = "+ctrl",
17     META     = "+meta",
18     SHIFT    = "+shift",
20     trim     = Y.Lang.trim,
22     eventDef = {
23         KEY_MAP: {
24             enter    : 13,
25             esc      : 27,
26             backspace: 8,
27             tab      : 9,
28             pageup   : 33,
29             pagedown : 34
30         },
32         _typeRE: /^(up|down|press):/,
33         _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g,
35         processArgs: function (args) {
36             var spec = args.splice(3,1)[0],
37                 mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []),
38                 config = {
39                     type: this._typeRE.test(spec) ? RegExp.$1 : null,
40                     mods: mods,
41                     keys: null
42                 },
43                 // strip type and modifiers from spec, leaving only keyCodes
44                 bits = spec.replace(this._keysRE, ''),
45                 chr, uc, lc, i;
47             if (bits) {
48                 bits = bits.split(',');
50                 config.keys = {};
52                 // FIXME: need to support '65,esc' => keypress, keydown
53                 for (i = bits.length - 1; i >= 0; --i) {
54                     chr = trim(bits[i]);
56                     // catch sloppy filters, trailing commas, etc 'a,,'
57                     if (!chr) {
58                         continue;
59                     }
61                     // non-numerics are single characters or key names
62                     if (+chr == chr) {
63                         config.keys[chr] = mods;
64                     } else {
65                         lc = chr.toLowerCase();
67                         if (this.KEY_MAP[lc]) {
68                             config.keys[this.KEY_MAP[lc]] = mods;
69                             // FIXME: '65,enter' defaults keydown for both
70                             if (!config.type) {
71                                 config.type = "down"; // safest
72                             }
73                         } else {
74                             // FIXME: Character mapping only works for keypress
75                             // events. Otherwise, it uses String.fromCharCode()
76                             // from the keyCode, which is wrong.
77                             chr = chr.charAt(0);
78                             uc  = chr.toUpperCase();
80                             if (mods["+shift"]) {
81                                 chr = uc;
82                             }
84                             // FIXME: stupid assumption that
85                             // the keycode of the lower case == the
86                             // charCode of the upper case
87                             // a (key:65,char:97), A (key:65,char:65)
88                             config.keys[chr.charCodeAt(0)] =
89                                 (chr === uc) ?
90                                     // upper case chars get +shift free
91                                     Y.merge(mods, { "+shift": true }) :
92                                     mods;
93                         }
94                     }
95                 }
96             }
98             if (!config.type) {
99                 config.type = "press";
100             }
102             return config;
103         },
105         on: function (node, sub, notifier, filter) {
106             var spec   = sub._extra,
107                 type   = "key" + spec.type,
108                 keys   = spec.keys,
109                 method = (filter) ? "delegate" : "on";
111             // Note: without specifying any keyCodes, this becomes a
112             // horribly inefficient alias for 'keydown' (et al), but I
113             // can't abort this subscription for a simple
114             // Y.on('keypress', ...);
115             // Please use keyCodes or just subscribe directly to keydown,
116             // keyup, or keypress
117             sub._detach = node[method](type, function (e) {
118                 var key = keys ? keys[e.which] : spec.mods;
120                 if (key &&
121                     (!key[ALT]   || (key[ALT]   && e.altKey)) &&
122                     (!key[CTRL]  || (key[CTRL]  && e.ctrlKey)) &&
123                     (!key[META]  || (key[META]  && e.metaKey)) &&
124                     (!key[SHIFT] || (key[SHIFT] && e.shiftKey)))
125                 {
126                     notifier.fire(e);
127                 }
128             }, filter);
129         },
131         detach: function (node, sub, notifier) {
132             sub._detach.detach();
133         }
134     };
136 eventDef.delegate = eventDef.on;
137 eventDef.detachDelegate = eventDef.detach;
140  * <p>Add a key listener.  The listener will only be notified if the
141  * keystroke detected meets the supplied specification.  The
142  * specification is a string that is defined as:</p>
143  * 
144  * <dl>
145  *   <dt>spec</dt>
146  *   <dd><code>[{type}:]{code}[,{code}]*</code></dd>
147  *   <dt>type</dt>
148  *   <dd><code>"down", "up", or "press"</code></dd>
149  *   <dt>code</dt>
150  *   <dd><code>{keyCode|character|keyName}[+{modifier}]*</code></dd>
151  *   <dt>modifier</dt>
152  *   <dd><code>"shift", "ctrl", "alt", or "meta"</code></dd>
153  *   <dt>keyName</dt>
154  *   <dd><code>"enter", "backspace", "esc", "tab", "pageup", or "pagedown"</code></dd>
155  * </dl>
157  * <p>Examples:</p>
158  * <ul>
159  *   <li><code>Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");</code></li>
160  *   <li><code>Y.delegate("key", preventSubmit, "enter", "#forms", "input[type=text]");</code></li>
161  *   <li><code>Y.one("doc").on("key", viNav, "j,k,l,;");</code></li>
162  * </ul>
163  *   
164  * @event key
165  * @for YUI
166  * @param type {string} 'key'
167  * @param fn {function} the function to execute
168  * @param id {string|HTMLElement|collection} the element(s) to bind
169  * @param spec {string} the keyCode and modifier specification
170  * @param o optional context object
171  * @param args 0..n additional arguments to provide to the listener.
172  * @return {Event.Handle} the detach handle
173  */
174 Y.Event.define('key', eventDef, true);
177 }, '3.5.1' ,{requires:['event-synthetic']});