| 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,9 +13,65 @@
|
| */
|
| var ExtensionCommandList = cr.ui.define('div');
|
|
|
| + /**
|
| + * 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.
|
| + * @return {boolean} Returns whether the char is valid.
|
| + */
|
| + function validChar(keyCode) {
|
| + return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
|
| + (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
|
| + }
|
| +
|
| + /**
|
| + * Convert a keystroke event to string form, while taking into account
|
| + * (ignoring) invalid extension commands.
|
| + * @param {Event} event The keyboard event to convert.
|
| + * @return {string} The keystroke as a string.
|
| + */
|
| + function keystrokeToString(event) {
|
| + var output = '';
|
| + if (event.ctrlKey)
|
| + output = 'Ctrl + ';
|
| + if (!event.ctrlKey && event.altKey)
|
| + output += 'Alt + ';
|
| + if (event.shiftKey)
|
| + output += 'Shift + ';
|
| + if (validChar(event.keyCode))
|
| + output += String.fromCharCode('A'.charCodeAt(0) + event.keyCode - 65);
|
| + return output;
|
| + }
|
| +
|
| ExtensionCommandList.prototype = {
|
| __proto__: HTMLDivElement.prototype,
|
|
|
| + /**
|
| + * 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.
|
| + * @type: {keyboard event}.
|
| + * @private
|
| + */
|
| + 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.
|
| + * @type: {string}.
|
| + * @private
|
| + */
|
| + oldValue_: '',
|
| +
|
| + /**
|
| + * While capturing, this keeps track of which element the user asked to
|
| + * change.
|
| + * @type: {HTMLElement}.
|
| + * @private
|
| + */
|
| + capturingElement_: null,
|
| +
|
| /** @inheritDoc */
|
| decorate: function() {
|
| this.textContent = '';
|
| @@ -59,17 +115,137 @@
|
| 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);
|
| },
|
| +
|
| + /**
|
| + * 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 (this.capturingElement_)
|
| + return; // Already capturing.
|
| +
|
| + chrome.send('setShortcutHandlingSuspended', [true]);
|
| +
|
| + this.oldValue_ = event.target.textContent;
|
| + event.target.textContent =
|
| + loadTimeData.getString('extensionCommandsStartTyping');
|
| + event.target.classList.add('capturing');
|
| +
|
| + this.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 (!this.capturingElement_)
|
| + return; // Not capturing.
|
| +
|
| + chrome.send('setShortcutHandlingSuspended', [false]);
|
| +
|
| + this.capturingElement_.classList.remove('capturing');
|
| + this.capturingElement_.classList.remove('contains-chars');
|
| + if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode))
|
| + this.capturingElement_.textContent = this.oldValue_;
|
| +
|
| + if (this.oldValue_ == '')
|
| + this.capturingElement_.classList.remove('clearable');
|
| + else
|
| + this.capturingElement_.classList.add('clearable');
|
| +
|
| + this.oldValue_ = '';
|
| + this.capturingElement_ = null;
|
| + this.currentKeyEvent_ = null;
|
| + },
|
| +
|
| + /**
|
| + * The KeyDown handler.
|
| + * @param {Event} event The keyboard event to consider.
|
| + * @private
|
| + */
|
| + handleKeyDown_: function(event) {
|
| + if (!this.capturingElement_)
|
| + 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 lose 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 (!this.currentKeyEvent_ || !validChar(this.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();
|
| + event.stopPropagation();
|
| +
|
| + if (!event.ctrlKey && !event.altKey)
|
| + return; // Ctrl or Alt is a must.
|
| +
|
| + var keystroke = keystrokeToString(event);
|
| + event.target.textContent = keystroke;
|
| + event.target.classList.add('contains-chars');
|
| +
|
| + if (validChar(event.keyCode)) {
|
| + this.oldValue_ = keystroke; // Forget what the old value was.
|
| + chrome.send('setExtensionCommandShortcut', ['id', keystroke]);
|
| + this.endCapture_(event);
|
| + }
|
| +
|
| + this.currentKeyEvent_ = event;
|
| + },
|
| };
|
|
|
| return {
|
|
|