Chromium Code Reviews| Index: chrome/browser/resources/extensions/extension_command_list.js |
| =================================================================== |
| --- chrome/browser/resources/extensions/extension_command_list.js (revision 140271) |
| +++ chrome/browser/resources/extensions/extension_command_list.js (working copy) |
| @@ -13,6 +13,25 @@ |
| */ |
| var ExtensionCommandList = cr.ui.define('div'); |
| + /** |
| + * While capturing, this records the current (last) keyboard event generated |
| + * by the user. Will be |null| after capture and during capture when no |
| + * keyboard event has been generated. |
| + */ |
| + var currentKeyEvent = null; |
| + |
| + /** |
| + * While capturing, this keeps track of the previous selection so we can |
| + * revert back to if no valid assignment is made during capture. |
| + */ |
| + var oldValue = ''; |
| + |
| + /** |
| + * While capturing, this keeps track of which element the user asked to |
| + * change. |
| + */ |
| + var capturingElement = null; |
| + |
| ExtensionCommandList.prototype = { |
| __proto__: HTMLDivElement.prototype, |
| @@ -59,17 +78,167 @@ |
| var description = node.querySelector('.command-description'); |
| description.textContent = command.description; |
| - var shortcut = node.querySelector('.command-shortcut'); |
| + var command_shortcut = node.querySelector('.command-shortcut'); |
| + command_shortcut.addEventListener('mouseup', |
| + this.startCapture_.bind(this)); |
| + command_shortcut.addEventListener('blur', this.endCapture_.bind(this)); |
| + command_shortcut.addEventListener('keydown', |
| + this.handleKeyDown_.bind(this)); |
| + command_shortcut.addEventListener('keyup', this.handleKeyUp_.bind(this)); |
| + |
| if (!command.active) { |
| - shortcut.textContent = |
| + command_shortcut.textContent = |
| loadTimeData.getString('extensionCommandsInactive'); |
| - shortcut.classList.add('inactive-keybinding'); |
| + command_shortcut.classList.add('inactive-keybinding'); |
| } else { |
| - shortcut.textContent = command.keybinding; |
| + command_shortcut.textContent = command.keybinding; |
| } |
| this.appendChild(node); |
| }, |
| + |
| + /** |
| + * Convert a keystroke event to string form, while taking into account |
| + * (ignoring) invalid extension commands. |
| + * @param {Event} event The keyboard event to convert. |
| + * @private |
| + */ |
| + keystrokeToString_: function(event) { |
| + var output = event.ctrlKey ? 'Ctrl + ' : ''; |
| + if (!event.ctrlKey) |
| + output += event.altKey ? 'Alt + ' : ''; |
| + output += event.shiftKey ? 'Shift + ' : ''; |
|
Evan Stade
2012/06/05 00:20:37
imo, it's easier to read
if (event.fooKey)
outp
|
| + if (this.validChar_(event.keyCode)) |
| + output += String.fromCharCode('A'.charCodeAt(0) + event.keyCode - 65); |
| + return output; |
| + }, |
| + |
| + /** |
| + * Returns whether the passed in |keyCode| is a valid extension command |
| + * char or not. This is restricted to A-Z and 0-9 (ignoring modifiers) at |
| + * the moment. |
| + * @param {int} keyCode The keycode to consider. |
| + * @private |
| + */ |
| + validChar_: function(keyCode) { |
| + return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || |
| + (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0)); |
| + }, |
| + |
| + /** |
| + * Starts keystroke capture to determine which key to use for a particular |
| + * extension command. |
| + * @param {Event} event The keyboard event to consider. |
| + * @private |
| + */ |
| + startCapture_: function(event) { |
| + if (capturingElement !== null) |
| + return; // Already capturing. |
| + |
| + chrome.send('setShortcutHandlingSuspended', [true]); |
| + |
| + oldValue = event.target.textContent; |
| + event.target.textContent = |
| + loadTimeData.getString('extensionCommandsStartTyping'); |
| + event.target.classList.add('capturing'); |
| + |
| + capturingElement = event.target; |
| + }, |
| + |
| + /** |
| + * Ends keystroke capture and either restores the old value or (if valid |
| + * value) sets the new value as active.. |
| + * @param {Event} event The keyboard event to consider. |
| + * @private |
| + */ |
| + endCapture_: function(event) { |
| + if (capturingElement === null) |
| + return; // Not capturing. |
| + |
| + chrome.send('setShortcutHandlingSuspended', [false]); |
| + |
| + capturingElement.classList.remove('capturing'); |
| + capturingElement.classList.remove('contains-chars'); |
| + if (currentKeyEvent == null || |
| + !this.validChar_(currentKeyEvent.keyCode)) |
| + capturingElement.textContent = oldValue; |
| + |
| + if (oldValue == '') |
| + capturingElement.classList.remove('clearable'); |
| + else |
| + capturingElement.classList.add('clearable'); |
| + |
| + oldValue = ''; |
| + capturingElement = null; |
| + currentKeyEvent = null; |
| + }, |
| + |
| + /** |
| + * The KeyDown handler. |
| + * @param {Event} event The keyboard event to consider. |
| + * @private |
| + */ |
| + handleKeyDown_: function(event) { |
| + if (capturingElement === null) |
| + this.startCapture_(event); |
| + |
| + this.handleKey_(event); |
| + }, |
| + |
| + /** |
| + * The KeyUp handler. |
| + * @param {Event} event The keyboard event to consider. |
| + * @private |
| + */ |
| + handleKeyUp_: function(event) { |
| + // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by |
| + // releasing Shift, but we also don't want it to be easy to loose for |
| + // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl |
| + // as fast as the other two keys. Therefore, we process KeyUp until you |
| + // have a valid combination and then stop processing it (meaning that once |
| + // you have a valid combination, we won't change it until the next |
| + // KeyDown message arrives). |
| + if (currentKeyEvent === null || |
| + !this.validChar_(currentKeyEvent.keyCode)) { |
| + if (!event.ctrlKey && !event.altKey) { |
| + // If neither Ctrl nor Alt is pressed then it is not a valid shortcut. |
| + // That means we're back at the starting point so we should restart |
| + // capture. |
| + this.endCapture_(event); |
| + this.startCapture_(event); |
| + } else { |
| + this.handleKey_(event); |
| + } |
| + } |
| + }, |
| + |
| + /** |
| + * A general key handler (used for both KeyDown and KeyUp). |
| + * @param {Event} event The keyboard event to consider. |
| + * @private |
| + */ |
| + handleKey_: function(event) { |
| + // While capturing, we prevent all events from bubbling, to prevent |
| + // shortcuts lacking the right modifier (F3 for example) from activating |
| + // and ending capture prematurely. |
| + event.preventDefault(); |
| + |
| + if (!event.ctrlKey && !event.altKey) |
| + return true; // Ctrl or Alt is a must. |
| + |
| + var keystroke = this.keystrokeToString_(event); |
| + event.target.textContent = keystroke; |
| + event.target.classList.add('contains-chars'); |
| + currentKeyEvent = event; |
| + |
| + if (this.validChar_(event.keyCode)) { |
| + oldValue = keystroke; // Forget what the old value was. |
| + chrome.send('setExtensionCommandShortcut', ['id', keystroke]); |
| + this.endCapture_(event); |
| + } |
| + |
| + return false; |
| + }, |
| }; |
| return { |