OLD | NEW |
1 <!-- | 1 <!-- |
2 @license | 2 @license |
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | 3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | 4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt |
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | 5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | 6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt |
7 Code distributed by Google as part of the polymer project is also | 7 Code distributed by Google as part of the polymer project is also |
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | 8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt |
9 --> | 9 --> |
10 | 10 |
11 <link rel="import" href="../polymer/polymer.html"> | 11 <link rel="import" href="../polymer/polymer.html"> |
12 | 12 |
13 <script> | 13 <script> |
14 (function() { | 14 (function() { |
15 'use strict'; | 15 'use strict'; |
16 | 16 |
17 /** | 17 /** |
18 * Chrome uses an older version of DOM Level 3 Keyboard Events | 18 * Chrome uses an older version of DOM Level 3 Keyboard Events |
19 * | 19 * |
20 * Most keys are labeled as text, but some are Unicode codepoints. | 20 * Most keys are labeled as text, but some are Unicode codepoints. |
21 * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-200712
21/keyset.html#KeySet-Set | 21 * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-200712
21/keyset.html#KeySet-Set |
22 */ | 22 */ |
23 var KEY_IDENTIFIER = { | 23 var KEY_IDENTIFIER = { |
| 24 'U+0008': 'backspace', |
24 'U+0009': 'tab', | 25 'U+0009': 'tab', |
25 'U+001B': 'esc', | 26 'U+001B': 'esc', |
26 'U+0020': 'space', | 27 'U+0020': 'space', |
27 'U+002A': '*', | |
28 'U+0030': '0', | |
29 'U+0031': '1', | |
30 'U+0032': '2', | |
31 'U+0033': '3', | |
32 'U+0034': '4', | |
33 'U+0035': '5', | |
34 'U+0036': '6', | |
35 'U+0037': '7', | |
36 'U+0038': '8', | |
37 'U+0039': '9', | |
38 'U+0041': 'a', | |
39 'U+0042': 'b', | |
40 'U+0043': 'c', | |
41 'U+0044': 'd', | |
42 'U+0045': 'e', | |
43 'U+0046': 'f', | |
44 'U+0047': 'g', | |
45 'U+0048': 'h', | |
46 'U+0049': 'i', | |
47 'U+004A': 'j', | |
48 'U+004B': 'k', | |
49 'U+004C': 'l', | |
50 'U+004D': 'm', | |
51 'U+004E': 'n', | |
52 'U+004F': 'o', | |
53 'U+0050': 'p', | |
54 'U+0051': 'q', | |
55 'U+0052': 'r', | |
56 'U+0053': 's', | |
57 'U+0054': 't', | |
58 'U+0055': 'u', | |
59 'U+0056': 'v', | |
60 'U+0057': 'w', | |
61 'U+0058': 'x', | |
62 'U+0059': 'y', | |
63 'U+005A': 'z', | |
64 'U+007F': 'del' | 28 'U+007F': 'del' |
65 }; | 29 }; |
66 | 30 |
67 /** | 31 /** |
68 * Special table for KeyboardEvent.keyCode. | 32 * Special table for KeyboardEvent.keyCode. |
69 * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even bett
er | 33 * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even bett
er |
70 * than that. | 34 * than that. |
71 * | 35 * |
72 * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEve
nt.keyCode#Value_of_keyCode | 36 * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEve
nt.keyCode#Value_of_keyCode |
73 */ | 37 */ |
74 var KEY_CODE = { | 38 var KEY_CODE = { |
| 39 8: 'backspace', |
75 9: 'tab', | 40 9: 'tab', |
76 13: 'enter', | 41 13: 'enter', |
77 27: 'esc', | 42 27: 'esc', |
78 33: 'pageup', | 43 33: 'pageup', |
79 34: 'pagedown', | 44 34: 'pagedown', |
80 35: 'end', | 45 35: 'end', |
81 36: 'home', | 46 36: 'home', |
82 32: 'space', | 47 32: 'space', |
83 37: 'left', | 48 37: 'left', |
84 38: 'up', | 49 38: 'up', |
85 39: 'right', | 50 39: 'right', |
86 40: 'down', | 51 40: 'down', |
87 46: 'del', | 52 46: 'del', |
88 106: '*' | 53 106: '*' |
89 }; | 54 }; |
90 | 55 |
91 /** | 56 /** |
92 * MODIFIER_KEYS maps the short name for modifier keys used in a key | 57 * MODIFIER_KEYS maps the short name for modifier keys used in a key |
93 * combo string to the property name that references those same keys | 58 * combo string to the property name that references those same keys |
94 * in a KeyboardEvent instance. | 59 * in a KeyboardEvent instance. |
95 */ | 60 */ |
96 var MODIFIER_KEYS = { | 61 var MODIFIER_KEYS = { |
97 shift: 'shiftKey', | 62 'shift': 'shiftKey', |
98 ctrl: 'ctrlKey', | 63 'ctrl': 'ctrlKey', |
99 alt: 'altKey', | 64 'alt': 'altKey', |
100 meta: 'metaKey' | 65 'meta': 'metaKey' |
101 }; | 66 }; |
102 | 67 |
103 /** | 68 /** |
104 * KeyboardEvent.key is mostly represented by printable character made by | 69 * KeyboardEvent.key is mostly represented by printable character made by |
105 * the keyboard, with unprintable keys labeled nicely. | 70 * the keyboard, with unprintable keys labeled nicely. |
106 * | 71 * |
107 * However, on OS X, Alt+char can make a Unicode character that follows an | 72 * However, on OS X, Alt+char can make a Unicode character that follows an |
108 * Apple-specific mapping. In this case, we | 73 * Apple-specific mapping. In this case, we fall back to .keyCode. |
109 * fall back to .keyCode. | |
110 */ | 74 */ |
111 var KEY_CHAR = /[a-z0-9*]/; | 75 var KEY_CHAR = /[a-z0-9*]/; |
112 | 76 |
113 /** | 77 /** |
114 * Matches a keyIdentifier string. | 78 * Matches a keyIdentifier string. |
115 */ | 79 */ |
116 var IDENT_CHAR = /U\+/; | 80 var IDENT_CHAR = /U\+/; |
117 | 81 |
118 /** | 82 /** |
119 * Matches arrow keys in Gecko 27.0+ | 83 * Matches arrow keys in Gecko 27.0+ |
120 */ | 84 */ |
121 var ARROW_KEY = /^arrow/; | 85 var ARROW_KEY = /^arrow/; |
122 | 86 |
123 /** | 87 /** |
124 * Matches space keys everywhere (notably including IE10's exceptional name | 88 * Matches space keys everywhere (notably including IE10's exceptional name |
125 * `spacebar`). | 89 * `spacebar`). |
126 */ | 90 */ |
127 var SPACE_KEY = /^space(bar)?/; | 91 var SPACE_KEY = /^space(bar)?/; |
128 | 92 |
129 function transformKey(key) { | 93 /** |
| 94 * Transforms the key. |
| 95 * @param {string} key The KeyBoardEvent.key |
| 96 * @param {Boolean} [noSpecialChars] Limits the transformation to |
| 97 * alpha-numeric characters. |
| 98 */ |
| 99 function transformKey(key, noSpecialChars) { |
130 var validKey = ''; | 100 var validKey = ''; |
131 if (key) { | 101 if (key) { |
132 var lKey = key.toLowerCase(); | 102 var lKey = key.toLowerCase(); |
133 if (lKey.length == 1) { | 103 if (lKey === ' ' || SPACE_KEY.test(lKey)) { |
134 if (KEY_CHAR.test(lKey)) { | 104 validKey = 'space'; |
| 105 } else if (lKey.length == 1) { |
| 106 if (!noSpecialChars || KEY_CHAR.test(lKey)) { |
135 validKey = lKey; | 107 validKey = lKey; |
136 } | 108 } |
137 } else if (ARROW_KEY.test(lKey)) { | 109 } else if (ARROW_KEY.test(lKey)) { |
138 validKey = lKey.replace('arrow', ''); | 110 validKey = lKey.replace('arrow', ''); |
139 } else if (SPACE_KEY.test(lKey)) { | |
140 validKey = 'space'; | |
141 } else if (lKey == 'multiply') { | 111 } else if (lKey == 'multiply') { |
142 // numpad '*' can map to Multiply on IE/Windows | 112 // numpad '*' can map to Multiply on IE/Windows |
143 validKey = '*'; | 113 validKey = '*'; |
144 } else { | 114 } else { |
145 validKey = lKey; | 115 validKey = lKey; |
146 } | 116 } |
147 } | 117 } |
148 return validKey; | 118 return validKey; |
149 } | 119 } |
150 | 120 |
151 function transformKeyIdentifier(keyIdent) { | 121 function transformKeyIdentifier(keyIdent) { |
152 var validKey = ''; | 122 var validKey = ''; |
153 if (keyIdent) { | 123 if (keyIdent) { |
154 if (IDENT_CHAR.test(keyIdent)) { | 124 if (keyIdent in KEY_IDENTIFIER) { |
155 validKey = KEY_IDENTIFIER[keyIdent]; | 125 validKey = KEY_IDENTIFIER[keyIdent]; |
| 126 } else if (IDENT_CHAR.test(keyIdent)) { |
| 127 keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16); |
| 128 validKey = String.fromCharCode(keyIdent).toLowerCase(); |
156 } else { | 129 } else { |
157 validKey = keyIdent.toLowerCase(); | 130 validKey = keyIdent.toLowerCase(); |
158 } | 131 } |
159 } | 132 } |
160 return validKey; | 133 return validKey; |
161 } | 134 } |
162 | 135 |
163 function transformKeyCode(keyCode) { | 136 function transformKeyCode(keyCode) { |
164 var validKey = ''; | 137 var validKey = ''; |
165 if (Number(keyCode)) { | 138 if (Number(keyCode)) { |
(...skipping 10 matching lines...) Expand all Loading... |
176 } else if (keyCode >= 96 && keyCode <= 105) { | 149 } else if (keyCode >= 96 && keyCode <= 105) { |
177 // num pad 0-9 | 150 // num pad 0-9 |
178 validKey = String(96 - keyCode); | 151 validKey = String(96 - keyCode); |
179 } else { | 152 } else { |
180 validKey = KEY_CODE[keyCode]; | 153 validKey = KEY_CODE[keyCode]; |
181 } | 154 } |
182 } | 155 } |
183 return validKey; | 156 return validKey; |
184 } | 157 } |
185 | 158 |
186 function normalizedKeyForEvent(keyEvent) { | 159 /** |
187 // fall back from .key, to .keyIdentifier, to .keyCode, and then to | 160 * Calculates the normalized key for a KeyboardEvent. |
188 // .detail.key to support artificial keyboard events | 161 * @param {KeyboardEvent} keyEvent |
189 return transformKey(keyEvent.key) || | 162 * @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key |
| 163 * transformation to alpha-numeric chars. This is useful with key |
| 164 * combinations like shift + 2, which on FF for MacOS produces |
| 165 * keyEvent.key = @ |
| 166 * To get 2 returned, set noSpecialChars = true |
| 167 * To get @ returned, set noSpecialChars = false |
| 168 */ |
| 169 function normalizedKeyForEvent(keyEvent, noSpecialChars) { |
| 170 // Fall back from .key, to .keyIdentifier, to .keyCode, and then to |
| 171 // .detail.key to support artificial keyboard events. |
| 172 return transformKey(keyEvent.key, noSpecialChars) || |
190 transformKeyIdentifier(keyEvent.keyIdentifier) || | 173 transformKeyIdentifier(keyEvent.keyIdentifier) || |
191 transformKeyCode(keyEvent.keyCode) || | 174 transformKeyCode(keyEvent.keyCode) || |
192 transformKey(keyEvent.detail.key) || ''; | 175 transformKey(keyEvent.detail.key, noSpecialChars) || ''; |
193 } | 176 } |
194 | 177 |
195 function keyComboMatchesEvent(keyCombo, keyEvent) { | 178 function keyComboMatchesEvent(keyCombo, event) { |
196 return normalizedKeyForEvent(keyEvent) === keyCombo.key && | 179 // For combos with modifiers we support only alpha-numeric keys |
197 !!keyEvent.shiftKey === !!keyCombo.shiftKey && | 180 var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers); |
198 !!keyEvent.ctrlKey === !!keyCombo.ctrlKey && | 181 return keyEvent === keyCombo.key && |
199 !!keyEvent.altKey === !!keyCombo.altKey && | 182 (!keyCombo.hasModifiers || ( |
200 !!keyEvent.metaKey === !!keyCombo.metaKey; | 183 !!event.shiftKey === !!keyCombo.shiftKey && |
| 184 !!event.ctrlKey === !!keyCombo.ctrlKey && |
| 185 !!event.altKey === !!keyCombo.altKey && |
| 186 !!event.metaKey === !!keyCombo.metaKey) |
| 187 ); |
201 } | 188 } |
202 | 189 |
203 function parseKeyComboString(keyComboString) { | 190 function parseKeyComboString(keyComboString) { |
| 191 if (keyComboString.length === 1) { |
| 192 return { |
| 193 combo: keyComboString, |
| 194 key: keyComboString, |
| 195 event: 'keydown' |
| 196 }; |
| 197 } |
204 return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboP
art) { | 198 return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboP
art) { |
205 var eventParts = keyComboPart.split(':'); | 199 var eventParts = keyComboPart.split(':'); |
206 var keyName = eventParts[0]; | 200 var keyName = eventParts[0]; |
207 var event = eventParts[1]; | 201 var event = eventParts[1]; |
208 | 202 |
209 if (keyName in MODIFIER_KEYS) { | 203 if (keyName in MODIFIER_KEYS) { |
210 parsedKeyCombo[MODIFIER_KEYS[keyName]] = true; | 204 parsedKeyCombo[MODIFIER_KEYS[keyName]] = true; |
| 205 parsedKeyCombo.hasModifiers = true; |
211 } else { | 206 } else { |
212 parsedKeyCombo.key = keyName; | 207 parsedKeyCombo.key = keyName; |
213 parsedKeyCombo.event = event || 'keydown'; | 208 parsedKeyCombo.event = event || 'keydown'; |
214 } | 209 } |
215 | 210 |
216 return parsedKeyCombo; | 211 return parsedKeyCombo; |
217 }, { | 212 }, { |
218 combo: keyComboString.split(':').shift() | 213 combo: keyComboString.split(':').shift() |
219 }); | 214 }); |
220 } | 215 } |
221 | 216 |
222 function parseEventString(eventString) { | 217 function parseEventString(eventString) { |
223 return eventString.split(' ').map(function(keyComboString) { | 218 return eventString.trim().split(' ').map(function(keyComboString) { |
224 return parseKeyComboString(keyComboString); | 219 return parseKeyComboString(keyComboString); |
225 }); | 220 }); |
226 } | 221 } |
227 | 222 |
228 | |
229 /** | 223 /** |
230 * `Polymer.IronA11yKeysBehavior` provides a normalized interface for proces
sing | 224 * `Polymer.IronA11yKeysBehavior` provides a normalized interface for proces
sing |
231 * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3
.org/TR/wai-aria-practices/#kbd_general_binding). | 225 * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3
.org/TR/wai-aria-practices/#kbd_general_binding). |
232 * The element takes care of browser differences with respect to Keyboard ev
ents | 226 * The element takes care of browser differences with respect to Keyboard ev
ents |
233 * and uses an expressive syntax to filter key presses. | 227 * and uses an expressive syntax to filter key presses. |
234 * | 228 * |
235 * Use the `keyBindings` prototype property to express what combination of k
eys | 229 * Use the `keyBindings` prototype property to express what combination of k
eys |
236 * will trigger the event to fire. | 230 * will trigger the event to fire. |
237 * | 231 * |
238 * Use the `key-event-target` attribute to set up event handlers on a specif
ic | 232 * Use the `key-event-target` attribute to set up event handlers on a specif
ic |
239 * node. | 233 * node. |
240 * The `keys-pressed` event will fire when one of the key combinations set w
ith the | 234 * The `keys-pressed` event will fire when one of the key combinations set w
ith the |
241 * `keys` property is pressed. | 235 * `keys` property is pressed. |
242 * | 236 * |
243 * @demo demo/index.html | 237 * @demo demo/index.html |
244 * @polymerBehavior IronA11yKeysBehavior | 238 * @polymerBehavior |
245 */ | 239 */ |
246 Polymer.IronA11yKeysBehavior = { | 240 Polymer.IronA11yKeysBehavior = { |
247 properties: { | 241 properties: { |
248 /** | 242 /** |
249 * The HTMLElement that will be firing relevant KeyboardEvents. | 243 * The HTMLElement that will be firing relevant KeyboardEvents. |
250 */ | 244 */ |
251 keyEventTarget: { | 245 keyEventTarget: { |
252 type: Object, | 246 type: Object, |
253 value: function() { | 247 value: function() { |
254 return this; | 248 return this; |
255 } | 249 } |
256 }, | 250 }, |
257 | 251 |
| 252 /** |
| 253 * If true, this property will cause the implementing element to |
| 254 * automatically stop propagation on any handled KeyboardEvents. |
| 255 */ |
| 256 stopKeyboardEventPropagation: { |
| 257 type: Boolean, |
| 258 value: false |
| 259 }, |
| 260 |
258 _boundKeyHandlers: { | 261 _boundKeyHandlers: { |
259 type: Array, | 262 type: Array, |
260 value: function() { | 263 value: function() { |
261 return []; | 264 return []; |
262 } | 265 } |
263 }, | 266 }, |
264 | 267 |
265 // We use this due to a limitation in IE10 where instances will have | 268 // We use this due to a limitation in IE10 where instances will have |
266 // own properties of everything on the "prototype". | 269 // own properties of everything on the "prototype". |
267 _imperativeKeyBindings: { | 270 _imperativeKeyBindings: { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 * When called, will remove all imperatively-added key bindings. | 308 * When called, will remove all imperatively-added key bindings. |
306 */ | 309 */ |
307 removeOwnKeyBindings: function() { | 310 removeOwnKeyBindings: function() { |
308 this._imperativeKeyBindings = {}; | 311 this._imperativeKeyBindings = {}; |
309 this._prepKeyBindings(); | 312 this._prepKeyBindings(); |
310 this._resetKeyEventListeners(); | 313 this._resetKeyEventListeners(); |
311 }, | 314 }, |
312 | 315 |
313 keyboardEventMatchesKeys: function(event, eventString) { | 316 keyboardEventMatchesKeys: function(event, eventString) { |
314 var keyCombos = parseEventString(eventString); | 317 var keyCombos = parseEventString(eventString); |
315 var index; | 318 for (var i = 0; i < keyCombos.length; ++i) { |
316 | 319 if (keyComboMatchesEvent(keyCombos[i], event)) { |
317 for (index = 0; index < keyCombos.length; ++index) { | |
318 if (keyComboMatchesEvent(keyCombos[index], event)) { | |
319 return true; | 320 return true; |
320 } | 321 } |
321 } | 322 } |
322 | |
323 return false; | 323 return false; |
324 }, | 324 }, |
325 | 325 |
326 _collectKeyBindings: function() { | 326 _collectKeyBindings: function() { |
327 var keyBindings = this.behaviors.map(function(behavior) { | 327 var keyBindings = this.behaviors.map(function(behavior) { |
328 return behavior.keyBindings; | 328 return behavior.keyBindings; |
329 }); | 329 }); |
330 | 330 |
331 if (keyBindings.indexOf(this.keyBindings) === -1) { | 331 if (keyBindings.indexOf(this.keyBindings) === -1) { |
332 keyBindings.push(this.keyBindings); | 332 keyBindings.push(this.keyBindings); |
333 } | 333 } |
334 | 334 |
335 return keyBindings; | 335 return keyBindings; |
336 }, | 336 }, |
337 | 337 |
338 _prepKeyBindings: function() { | 338 _prepKeyBindings: function() { |
339 this._keyBindings = {}; | 339 this._keyBindings = {}; |
340 | 340 |
341 this._collectKeyBindings().forEach(function(keyBindings) { | 341 this._collectKeyBindings().forEach(function(keyBindings) { |
342 for (var eventString in keyBindings) { | 342 for (var eventString in keyBindings) { |
343 this._addKeyBinding(eventString, keyBindings[eventString]); | 343 this._addKeyBinding(eventString, keyBindings[eventString]); |
344 } | 344 } |
345 }, this); | 345 }, this); |
346 | 346 |
347 for (var eventString in this._imperativeKeyBindings) { | 347 for (var eventString in this._imperativeKeyBindings) { |
348 this._addKeyBinding(eventString, this._imperativeKeyBindings[eventStri
ng]); | 348 this._addKeyBinding(eventString, this._imperativeKeyBindings[eventStri
ng]); |
349 } | 349 } |
| 350 |
| 351 // Give precedence to combos with modifiers to be checked first. |
| 352 for (var eventName in this._keyBindings) { |
| 353 this._keyBindings[eventName].sort(function (kb1, kb2) { |
| 354 var b1 = kb1[0].hasModifiers; |
| 355 var b2 = kb2[0].hasModifiers; |
| 356 return (b1 === b2) ? 0 : b1 ? -1 : 1; |
| 357 }) |
| 358 } |
350 }, | 359 }, |
351 | 360 |
352 _addKeyBinding: function(eventString, handlerName) { | 361 _addKeyBinding: function(eventString, handlerName) { |
353 parseEventString(eventString).forEach(function(keyCombo) { | 362 parseEventString(eventString).forEach(function(keyCombo) { |
354 this._keyBindings[keyCombo.event] = | 363 this._keyBindings[keyCombo.event] = |
355 this._keyBindings[keyCombo.event] || []; | 364 this._keyBindings[keyCombo.event] || []; |
356 | 365 |
357 this._keyBindings[keyCombo.event].push([ | 366 this._keyBindings[keyCombo.event].push([ |
358 keyCombo, | 367 keyCombo, |
359 handlerName | 368 handlerName |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 keyHandlerTuple = this._boundKeyHandlers.pop(); | 400 keyHandlerTuple = this._boundKeyHandlers.pop(); |
392 keyEventTarget = keyHandlerTuple[0]; | 401 keyEventTarget = keyHandlerTuple[0]; |
393 eventName = keyHandlerTuple[1]; | 402 eventName = keyHandlerTuple[1]; |
394 boundKeyHandler = keyHandlerTuple[2]; | 403 boundKeyHandler = keyHandlerTuple[2]; |
395 | 404 |
396 keyEventTarget.removeEventListener(eventName, boundKeyHandler); | 405 keyEventTarget.removeEventListener(eventName, boundKeyHandler); |
397 } | 406 } |
398 }, | 407 }, |
399 | 408 |
400 _onKeyBindingEvent: function(keyBindings, event) { | 409 _onKeyBindingEvent: function(keyBindings, event) { |
401 keyBindings.forEach(function(keyBinding) { | 410 if (this.stopKeyboardEventPropagation) { |
402 var keyCombo = keyBinding[0]; | 411 event.stopPropagation(); |
403 var handlerName = keyBinding[1]; | 412 } |
404 | 413 |
405 if (!event.defaultPrevented && keyComboMatchesEvent(keyCombo, event))
{ | 414 // if event has been already prevented, don't do anything |
| 415 if (event.defaultPrevented) { |
| 416 return; |
| 417 } |
| 418 |
| 419 for (var i = 0; i < keyBindings.length; i++) { |
| 420 var keyCombo = keyBindings[i][0]; |
| 421 var handlerName = keyBindings[i][1]; |
| 422 if (keyComboMatchesEvent(keyCombo, event)) { |
406 this._triggerKeyHandler(keyCombo, handlerName, event); | 423 this._triggerKeyHandler(keyCombo, handlerName, event); |
| 424 // exit the loop if eventDefault was prevented |
| 425 if (event.defaultPrevented) { |
| 426 return; |
| 427 } |
407 } | 428 } |
408 }, this); | 429 } |
409 }, | 430 }, |
410 | 431 |
411 _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) { | 432 _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) { |
412 var detail = Object.create(keyCombo); | 433 var detail = Object.create(keyCombo); |
413 detail.keyboardEvent = keyboardEvent; | 434 detail.keyboardEvent = keyboardEvent; |
414 | 435 var event = new CustomEvent(keyCombo.event, { |
415 this[handlerName].call(this, new CustomEvent(keyCombo.event, { | 436 detail: detail, |
416 detail: detail | 437 cancelable: true |
417 })); | 438 }); |
| 439 this[handlerName].call(this, event); |
| 440 if (event.defaultPrevented) { |
| 441 keyboardEvent.preventDefault(); |
| 442 } |
418 } | 443 } |
419 }; | 444 }; |
420 })(); | 445 })(); |
421 </script> | 446 </script> |
OLD | NEW |