| 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 |