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