OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** @typedef {{active: boolean, | |
6 * command_name: string, | |
7 * description: string, | |
8 * extension_action: boolean, | |
9 * extension_id: string, | |
10 * global: boolean, | |
11 * keybinding: string}} | |
12 */ | |
13 var ExtensionCommand; | |
14 | |
15 cr.define('options', function() { | 5 cr.define('options', function() { |
16 'use strict'; | 6 'use strict'; |
17 | 7 |
18 /** | 8 /** |
19 * Creates a new list of extension commands. | 9 * Creates a new list of extension commands. |
20 * @param {Object=} opt_propertyBag Optional properties. | 10 * @param {Object=} opt_propertyBag Optional properties. |
21 * @constructor | 11 * @constructor |
22 * @extends {HTMLDivElement} | 12 * @extends {cr.ui.div} |
23 */ | 13 */ |
24 var ExtensionCommandList = cr.ui.define('div'); | 14 var ExtensionCommandList = cr.ui.define('div'); |
25 | 15 |
26 /** @const */ var keyComma = 188; | 16 /** @const */ var keyComma = 188; |
27 /** @const */ var keyDel = 46; | 17 /** @const */ var keyDel = 46; |
28 /** @const */ var keyDown = 40; | 18 /** @const */ var keyDown = 40; |
29 /** @const */ var keyEnd = 35; | 19 /** @const */ var keyEnd = 35; |
30 /** @const */ var keyEscape = 27; | 20 /** @const */ var keyEscape = 27; |
31 /** @const */ var keyHome = 36; | 21 /** @const */ var keyHome = 36; |
32 /** @const */ var keyIns = 45; | 22 /** @const */ var keyIns = 45; |
(...skipping 15 matching lines...) Expand all Loading... |
48 */ | 38 */ |
49 var Modifiers = { | 39 var Modifiers = { |
50 ARE_NOT_ALLOWED: 0, | 40 ARE_NOT_ALLOWED: 0, |
51 ARE_REQUIRED: 1 | 41 ARE_REQUIRED: 1 |
52 }; | 42 }; |
53 | 43 |
54 /** | 44 /** |
55 * Returns whether the passed in |keyCode| is a valid extension command | 45 * Returns whether the passed in |keyCode| is a valid extension command |
56 * char or not. This is restricted to A-Z and 0-9 (ignoring modifiers) at | 46 * char or not. This is restricted to A-Z and 0-9 (ignoring modifiers) at |
57 * the moment. | 47 * the moment. |
58 * @param {number} keyCode The keycode to consider. | 48 * @param {int} keyCode The keycode to consider. |
59 * @return {boolean} Returns whether the char is valid. | 49 * @return {boolean} Returns whether the char is valid. |
60 */ | 50 */ |
61 function validChar(keyCode) { | 51 function validChar(keyCode) { |
62 return keyCode == keyComma || | 52 return keyCode == keyComma || |
63 keyCode == keyDel || | 53 keyCode == keyDel || |
64 keyCode == keyDown || | 54 keyCode == keyDown || |
65 keyCode == keyEnd || | 55 keyCode == keyEnd || |
66 keyCode == keyHome || | 56 keyCode == keyHome || |
67 keyCode == keyIns || | 57 keyCode == keyIns || |
68 keyCode == keyLeft || | 58 keyCode == keyLeft || |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } | 132 } |
143 } | 133 } |
144 | 134 |
145 return output; | 135 return output; |
146 } | 136 } |
147 | 137 |
148 /** | 138 /** |
149 * Returns whether the passed in |keyCode| require modifiers. Currently only | 139 * Returns whether the passed in |keyCode| require modifiers. Currently only |
150 * "MediaNextTrack", "MediaPrevTrack", "MediaStop", "MediaPlayPause" are | 140 * "MediaNextTrack", "MediaPrevTrack", "MediaStop", "MediaPlayPause" are |
151 * required to be used without any modifier. | 141 * required to be used without any modifier. |
152 * @param {number} keyCode The keycode to consider. | 142 * @param {int} keyCode The keycode to consider. |
153 * @return {Modifiers} Returns whether the keycode require modifiers. | 143 * @return {Modifiers} Returns whether the keycode require modifiers. |
154 */ | 144 */ |
155 function modifiers(keyCode) { | 145 function modifiers(keyCode) { |
156 switch (keyCode) { | 146 switch (keyCode) { |
157 case keyMediaNextTrack: | 147 case keyMediaNextTrack: |
158 case keyMediaPlayPause: | 148 case keyMediaPlayPause: |
159 case keyMediaPrevTrack: | 149 case keyMediaPrevTrack: |
160 case keyMediaStop: | 150 case keyMediaStop: |
161 return Modifiers.ARE_NOT_ALLOWED; | 151 return Modifiers.ARE_NOT_ALLOWED; |
162 default: | 152 default: |
(...skipping 14 matching lines...) Expand all Loading... |
177 (countShiftAsModifier && event.shiftKey); | 167 (countShiftAsModifier && event.shiftKey); |
178 } | 168 } |
179 | 169 |
180 ExtensionCommandList.prototype = { | 170 ExtensionCommandList.prototype = { |
181 __proto__: HTMLDivElement.prototype, | 171 __proto__: HTMLDivElement.prototype, |
182 | 172 |
183 /** | 173 /** |
184 * While capturing, this records the current (last) keyboard event generated | 174 * While capturing, this records the current (last) keyboard event generated |
185 * by the user. Will be |null| after capture and during capture when no | 175 * by the user. Will be |null| after capture and during capture when no |
186 * keyboard event has been generated. | 176 * keyboard event has been generated. |
187 * @type {KeyboardEvent}. | 177 * @type: {keyboard event}. |
188 * @private | 178 * @private |
189 */ | 179 */ |
190 currentKeyEvent_: null, | 180 currentKeyEvent_: null, |
191 | 181 |
192 /** | 182 /** |
193 * While capturing, this keeps track of the previous selection so we can | 183 * While capturing, this keeps track of the previous selection so we can |
194 * revert back to if no valid assignment is made during capture. | 184 * revert back to if no valid assignment is made during capture. |
195 * @type {string}. | 185 * @type: {string}. |
196 * @private | 186 * @private |
197 */ | 187 */ |
198 oldValue_: '', | 188 oldValue_: '', |
199 | 189 |
200 /** | 190 /** |
201 * While capturing, this keeps track of which element the user asked to | 191 * While capturing, this keeps track of which element the user asked to |
202 * change. | 192 * change. |
203 * @type {HTMLElement}. | 193 * @type: {HTMLElement}. |
204 * @private | 194 * @private |
205 */ | 195 */ |
206 capturingElement_: null, | 196 capturingElement_: null, |
207 | 197 |
208 /** @override */ | 198 /** @override */ |
209 decorate: function() { | 199 decorate: function() { |
210 this.textContent = ''; | 200 this.textContent = ''; |
211 | 201 |
212 // Iterate over the extension data and add each item to the list. | 202 // Iterate over the extension data and add each item to the list. |
213 this.data_.commands.forEach(this.createNodeForExtension_.bind(this)); | 203 this.data_.commands.forEach(this.createNodeForExtension_.bind(this)); |
(...skipping 16 matching lines...) Expand all Loading... |
230 this.appendChild(node); | 220 this.appendChild(node); |
231 | 221 |
232 // Iterate over the commands data within the extension and add each item | 222 // Iterate over the commands data within the extension and add each item |
233 // to the list. | 223 // to the list. |
234 extension.commands.forEach(this.createNodeForCommand_.bind(this)); | 224 extension.commands.forEach(this.createNodeForCommand_.bind(this)); |
235 }, | 225 }, |
236 | 226 |
237 /** | 227 /** |
238 * Synthesizes and initializes an HTML element for the extension command | 228 * Synthesizes and initializes an HTML element for the extension command |
239 * metadata given in |command|. | 229 * metadata given in |command|. |
240 * @param {ExtensionCommand} command A dictionary of extension command | 230 * @param {Object} command A dictionary of extension command metadata. |
241 * metadata. | |
242 * @private | 231 * @private |
243 */ | 232 */ |
244 createNodeForCommand_: function(command) { | 233 createNodeForCommand_: function(command) { |
245 var template = $('template-collection-extension-commands').querySelector( | 234 var template = $('template-collection-extension-commands').querySelector( |
246 '.extension-command-list-command-item-wrapper'); | 235 '.extension-command-list-command-item-wrapper'); |
247 var node = template.cloneNode(true); | 236 var node = template.cloneNode(true); |
248 node.id = this.createElementId_( | 237 node.id = this.createElementId_( |
249 'command', command.extension_id, command.command_name); | 238 'command', command.extension_id, command.command_name); |
250 | 239 |
251 var description = node.querySelector('.command-description'); | 240 var description = node.querySelector('.command-description'); |
252 description.textContent = command.description; | 241 description.textContent = command.description; |
253 | 242 |
254 var shortcutNode = node.querySelector('.command-shortcut-text'); | 243 var shortcutNode = node.querySelector('.command-shortcut-text'); |
255 shortcutNode.addEventListener('mouseup', | 244 shortcutNode.addEventListener('mouseup', |
256 this.startCapture_.bind(this)); | 245 this.startCapture_.bind(this)); |
257 shortcutNode.addEventListener('focus', this.handleFocus_.bind(this)); | 246 shortcutNode.addEventListener('focus', this.handleFocus_.bind(this)); |
258 shortcutNode.addEventListener('blur', this.handleBlur_.bind(this)); | 247 shortcutNode.addEventListener('blur', this.handleBlur_.bind(this)); |
259 shortcutNode.addEventListener('keydown', this.handleKeyDown_.bind(this)); | 248 shortcutNode.addEventListener('keydown', |
| 249 this.handleKeyDown_.bind(this)); |
260 shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this)); | 250 shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this)); |
261 if (!command.active) { | 251 if (!command.active) { |
262 shortcutNode.textContent = | 252 shortcutNode.textContent = |
263 loadTimeData.getString('extensionCommandsInactive'); | 253 loadTimeData.getString('extensionCommandsInactive'); |
264 | 254 |
265 var commandShortcut = node.querySelector('.command-shortcut'); | 255 var commandShortcut = node.querySelector('.command-shortcut'); |
266 commandShortcut.classList.add('inactive-keybinding'); | 256 commandShortcut.classList.add('inactive-keybinding'); |
267 } else { | 257 } else { |
268 shortcutNode.textContent = command.keybinding; | 258 shortcutNode.textContent = command.keybinding; |
269 } | 259 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 var shortcutNode = event.target; | 305 var shortcutNode = event.target; |
316 this.oldValue_ = shortcutNode.textContent; | 306 this.oldValue_ = shortcutNode.textContent; |
317 shortcutNode.textContent = | 307 shortcutNode.textContent = |
318 loadTimeData.getString('extensionCommandsStartTyping'); | 308 loadTimeData.getString('extensionCommandsStartTyping'); |
319 shortcutNode.parentElement.classList.add('capturing'); | 309 shortcutNode.parentElement.classList.add('capturing'); |
320 | 310 |
321 var commandClear = | 311 var commandClear = |
322 shortcutNode.parentElement.querySelector('.command-clear'); | 312 shortcutNode.parentElement.querySelector('.command-clear'); |
323 commandClear.hidden = true; | 313 commandClear.hidden = true; |
324 | 314 |
325 this.capturingElement_ = /** @type {HTMLElement} */(event.target); | 315 this.capturingElement_ = event.target; |
326 }, | 316 }, |
327 | 317 |
328 /** | 318 /** |
329 * Ends keystroke capture and either restores the old value or (if valid | 319 * Ends keystroke capture and either restores the old value or (if valid |
330 * value) sets the new value as active.. | 320 * value) sets the new value as active.. |
331 * @param {Event} event The keyboard event to consider. | 321 * @param {Event} event The keyboard event to consider. |
332 * @private | 322 * @private |
333 */ | 323 */ |
334 endCapture_: function(event) { | 324 endCapture_: function(event) { |
335 if (!this.capturingElement_) | 325 if (!this.capturingElement_) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 var commandShortcut = event.target.parentElement; | 377 var commandShortcut = event.target.parentElement; |
388 commandShortcut.classList.remove('focused'); | 378 commandShortcut.classList.remove('focused'); |
389 }, | 379 }, |
390 | 380 |
391 /** | 381 /** |
392 * The KeyDown handler. | 382 * The KeyDown handler. |
393 * @param {Event} event The keyboard event to consider. | 383 * @param {Event} event The keyboard event to consider. |
394 * @private | 384 * @private |
395 */ | 385 */ |
396 handleKeyDown_: function(event) { | 386 handleKeyDown_: function(event) { |
397 event = /** @type {KeyboardEvent} */(event); | |
398 if (event.keyCode == keyEscape) { | 387 if (event.keyCode == keyEscape) { |
399 // Escape cancels capturing. | 388 // Escape cancels capturing. |
400 this.endCapture_(event); | 389 this.endCapture_(event); |
401 var parsed = this.parseElementId_('clear', | 390 var parsed = this.parseElementId_('clear', |
402 event.target.parentElement.querySelector('.command-clear').id); | 391 event.target.parentElement.querySelector('.command-clear').id); |
403 chrome.send('setExtensionCommandShortcut', | 392 chrome.send('setExtensionCommandShortcut', |
404 [parsed.extensionId, parsed.commandName, '']); | 393 [parsed.extensionId, parsed.commandName, '']); |
405 event.preventDefault(); | 394 event.preventDefault(); |
406 event.stopPropagation(); | 395 event.stopPropagation(); |
407 return; | 396 return; |
408 } | 397 } |
409 if (event.keyCode == keyTab) { | 398 if (event.keyCode == keyTab) { |
410 // Allow tab propagation for keyboard navigation. | 399 // Allow tab propagation for keyboard navigation. |
411 return; | 400 return; |
412 } | 401 } |
413 | 402 |
414 if (!this.capturingElement_) | 403 if (!this.capturingElement_) |
415 this.startCapture_(event); | 404 this.startCapture_(event); |
416 | 405 |
417 this.handleKey_(event); | 406 this.handleKey_(event); |
418 }, | 407 }, |
419 | 408 |
420 /** | 409 /** |
421 * The KeyUp handler. | 410 * The KeyUp handler. |
422 * @param {Event} event The keyboard event to consider. | 411 * @param {Event} event The keyboard event to consider. |
423 * @private | 412 * @private |
424 */ | 413 */ |
425 handleKeyUp_: function(event) { | 414 handleKeyUp_: function(event) { |
426 event = /** @type {KeyboardEvent} */(event); | |
427 if (event.keyCode == keyTab) { | 415 if (event.keyCode == keyTab) { |
428 // Allow tab propagation for keyboard navigation. | 416 // Allow tab propagation for keyboard navigation. |
429 return; | 417 return; |
430 } | 418 } |
431 | 419 |
432 // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by | 420 // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by |
433 // releasing Shift, but we also don't want it to be easy to lose for | 421 // releasing Shift, but we also don't want it to be easy to lose for |
434 // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl | 422 // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl |
435 // as fast as the other two keys. Therefore, we process KeyUp until you | 423 // as fast as the other two keys. Therefore, we process KeyUp until you |
436 // have a valid combination and then stop processing it (meaning that once | 424 // have a valid combination and then stop processing it (meaning that once |
437 // you have a valid combination, we won't change it until the next | 425 // you have a valid combination, we won't change it until the next |
438 // KeyDown message arrives). | 426 // KeyDown message arrives). |
439 if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode)) { | 427 if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode)) { |
440 if (!event.ctrlKey && !event.altKey) { | 428 if (!event.ctrlKey && !event.altKey) { |
441 // If neither Ctrl nor Alt is pressed then it is not a valid shortcut. | 429 // If neither Ctrl nor Alt is pressed then it is not a valid shortcut. |
442 // That means we're back at the starting point so we should restart | 430 // That means we're back at the starting point so we should restart |
443 // capture. | 431 // capture. |
444 this.endCapture_(event); | 432 this.endCapture_(event); |
445 this.startCapture_(event); | 433 this.startCapture_(event); |
446 } else { | 434 } else { |
447 this.handleKey_(event); | 435 this.handleKey_(event); |
448 } | 436 } |
449 } | 437 } |
450 }, | 438 }, |
451 | 439 |
452 /** | 440 /** |
453 * A general key handler (used for both KeyDown and KeyUp). | 441 * A general key handler (used for both KeyDown and KeyUp). |
454 * @param {KeyboardEvent} event The keyboard event to consider. | 442 * @param {Event} event The keyboard event to consider. |
455 * @private | 443 * @private |
456 */ | 444 */ |
457 handleKey_: function(event) { | 445 handleKey_: function(event) { |
458 // While capturing, we prevent all events from bubbling, to prevent | 446 // While capturing, we prevent all events from bubbling, to prevent |
459 // shortcuts lacking the right modifier (F3 for example) from activating | 447 // shortcuts lacking the right modifier (F3 for example) from activating |
460 // and ending capture prematurely. | 448 // and ending capture prematurely. |
461 event.preventDefault(); | 449 event.preventDefault(); |
462 event.stopPropagation(); | 450 event.stopPropagation(); |
463 | 451 |
464 if (modifiers(event.keyCode) == Modifiers.ARE_REQUIRED && | 452 if (modifiers(event.keyCode) == Modifiers.ARE_REQUIRED && |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 */ | 516 */ |
529 createElementId_: function(namespace, extensionId, commandName) { | 517 createElementId_: function(namespace, extensionId, commandName) { |
530 return namespace + '-' + extensionId + '-' + commandName; | 518 return namespace + '-' + extensionId + '-' + commandName; |
531 }, | 519 }, |
532 | 520 |
533 /** | 521 /** |
534 * A utility function to parse a unique element id based on a namespace, | 522 * A utility function to parse a unique element id based on a namespace, |
535 * extension id and a command name. | 523 * extension id and a command name. |
536 * @param {string} namespace The namespace to prepend the id with. | 524 * @param {string} namespace The namespace to prepend the id with. |
537 * @param {string} id The id to parse. | 525 * @param {string} id The id to parse. |
538 * @return {{extensionId: string, commandName: string}} The parsed id. | 526 * @return {object} The parsed id, as an object with two members: |
| 527 * extensionID and commandName. |
539 * @private | 528 * @private |
540 */ | 529 */ |
541 parseElementId_: function(namespace, id) { | 530 parseElementId_: function(namespace, id) { |
542 var kExtensionIdLength = 32; | 531 var kExtensionIdLength = 32; |
543 return { | 532 return { |
544 extensionId: id.substring(namespace.length + 1, | 533 extensionId: id.substring(namespace.length + 1, |
545 namespace.length + 1 + kExtensionIdLength), | 534 namespace.length + 1 + kExtensionIdLength), |
546 commandName: id.substring(namespace.length + 1 + kExtensionIdLength + 1) | 535 commandName: id.substring(namespace.length + 1 + kExtensionIdLength + 1) |
547 }; | 536 }; |
548 }, | 537 }, |
549 }; | 538 }; |
550 | 539 |
551 return { | 540 return { |
552 ExtensionCommandList: ExtensionCommandList | 541 ExtensionCommandList: ExtensionCommandList |
553 }; | 542 }; |
554 }); | 543 }); |
OLD | NEW |