Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: chrome/browser/resources/extensions/extension_command_list.js

Issue 10514003: Config UI for Extension Commands (part 1). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 cr.define('options', function() { 5 cr.define('options', function() {
6 'use strict'; 6 'use strict';
7 7
8 /** 8 /**
9 * Creates a new list of extension commands. 9 * Creates a new list of extension commands.
10 * @param {Object=} opt_propertyBag Optional properties. 10 * @param {Object=} opt_propertyBag Optional properties.
11 * @constructor 11 * @constructor
12 * @extends {cr.ui.div} 12 * @extends {cr.ui.div}
13 */ 13 */
14 var ExtensionCommandList = cr.ui.define('div'); 14 var ExtensionCommandList = cr.ui.define('div');
15 15
16 /**
17 * Returns whether the passed in |keyCode| is a valid extension command
18 * char or not. This is restricted to A-Z and 0-9 (ignoring modifiers) at
19 * the moment.
20 * @param {int} keyCode The keycode to consider.
21 * @return {boolean} Returns whether the char is valid.
22 */
23 function validChar(keyCode) {
24 return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
25 (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
26 }
27
28 /**
29 * Convert a keystroke event to string form, while taking into account
30 * (ignoring) invalid extension commands.
31 * @param {Event} event The keyboard event to convert.
32 * @return {string} The keystroke as a string.
33 */
34 function keystrokeToString(event) {
35 var output = '';
36 if (event.ctrlKey)
37 output = 'Ctrl + ';
38 if (!event.ctrlKey && event.altKey)
39 output += 'Alt + ';
40 if (event.shiftKey)
41 output += 'Shift + ';
42 if (validChar(event.keyCode))
43 output += String.fromCharCode('A'.charCodeAt(0) + event.keyCode - 65);
44 return output;
45 }
46
16 ExtensionCommandList.prototype = { 47 ExtensionCommandList.prototype = {
17 __proto__: HTMLDivElement.prototype, 48 __proto__: HTMLDivElement.prototype,
18 49
50 /**
51 * While capturing, this records the current (last) keyboard event generated
52 * by the user. Will be |null| after capture and during capture when no
53 * keyboard event has been generated.
54 * @type: {keyboard event}.
55 * @private
56 */
57 currentKeyEvent_: null,
58
59 /**
60 * While capturing, this keeps track of the previous selection so we can
61 * revert back to if no valid assignment is made during capture.
62 * @type: {string}.
63 * @private
64 */
65 oldValue_: '',
66
67 /**
68 * While capturing, this keeps track of which element the user asked to
69 * change.
70 * @type: {HTMLElement}.
71 * @private
72 */
73 capturingElement_: null,
74
19 /** @inheritDoc */ 75 /** @inheritDoc */
20 decorate: function() { 76 decorate: function() {
21 this.textContent = ''; 77 this.textContent = '';
22 78
23 // Iterate over the extension data and add each item to the list. 79 // Iterate over the extension data and add each item to the list.
24 this.data_.commands.forEach(this.createNodeForExtension_.bind(this)); 80 this.data_.commands.forEach(this.createNodeForExtension_.bind(this));
25 }, 81 },
26 82
27 /** 83 /**
28 * Synthesizes and initializes an HTML element for the extension command 84 * Synthesizes and initializes an HTML element for the extension command
(...skipping 23 matching lines...) Expand all
52 * @private 108 * @private
53 */ 109 */
54 createNodeForCommand_: function(command) { 110 createNodeForCommand_: function(command) {
55 var template = $('template-collection-extension-commands').querySelector( 111 var template = $('template-collection-extension-commands').querySelector(
56 '.extension-command-list-command-item-wrapper'); 112 '.extension-command-list-command-item-wrapper');
57 var node = template.cloneNode(true); 113 var node = template.cloneNode(true);
58 114
59 var description = node.querySelector('.command-description'); 115 var description = node.querySelector('.command-description');
60 description.textContent = command.description; 116 description.textContent = command.description;
61 117
62 var shortcut = node.querySelector('.command-shortcut'); 118 var command_shortcut = node.querySelector('.command-shortcut');
119 command_shortcut.addEventListener('mouseup',
120 this.startCapture_.bind(this));
121 command_shortcut.addEventListener('blur', this.endCapture_.bind(this));
122 command_shortcut.addEventListener('keydown',
123 this.handleKeyDown_.bind(this));
124 command_shortcut.addEventListener('keyup', this.handleKeyUp_.bind(this));
125
63 if (!command.active) { 126 if (!command.active) {
64 shortcut.textContent = 127 command_shortcut.textContent =
65 loadTimeData.getString('extensionCommandsInactive'); 128 loadTimeData.getString('extensionCommandsInactive');
66 shortcut.classList.add('inactive-keybinding'); 129 command_shortcut.classList.add('inactive-keybinding');
67 } else { 130 } else {
68 shortcut.textContent = command.keybinding; 131 command_shortcut.textContent = command.keybinding;
69 } 132 }
70 133
71 this.appendChild(node); 134 this.appendChild(node);
72 }, 135 },
136
137 /**
138 * Starts keystroke capture to determine which key to use for a particular
139 * extension command.
140 * @param {Event} event The keyboard event to consider.
141 * @private
142 */
143 startCapture_: function(event) {
144 if (this.capturingElement_)
145 return; // Already capturing.
146
147 chrome.send('setShortcutHandlingSuspended', [true]);
148
149 this.oldValue_ = event.target.textContent;
150 event.target.textContent =
151 loadTimeData.getString('extensionCommandsStartTyping');
152 event.target.classList.add('capturing');
153
154 this.capturingElement_ = event.target;
155 },
156
157 /**
158 * Ends keystroke capture and either restores the old value or (if valid
159 * value) sets the new value as active..
160 * @param {Event} event The keyboard event to consider.
161 * @private
162 */
163 endCapture_: function(event) {
164 if (!this.capturingElement_)
165 return; // Not capturing.
166
167 chrome.send('setShortcutHandlingSuspended', [false]);
168
169 this.capturingElement_.classList.remove('capturing');
170 this.capturingElement_.classList.remove('contains-chars');
171 if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode))
172 this.capturingElement_.textContent = this.oldValue_;
173
174 if (this.oldValue_ == '')
175 this.capturingElement_.classList.remove('clearable');
176 else
177 this.capturingElement_.classList.add('clearable');
178
179 this.oldValue_ = '';
180 this.capturingElement_ = null;
181 this.currentKeyEvent_ = null;
182 },
183
184 /**
185 * The KeyDown handler.
186 * @param {Event} event The keyboard event to consider.
187 * @private
188 */
189 handleKeyDown_: function(event) {
190 if (!this.capturingElement_)
191 this.startCapture_(event);
192
193 this.handleKey_(event);
194 },
195
196 /**
197 * The KeyUp handler.
198 * @param {Event} event The keyboard event to consider.
199 * @private
200 */
201 handleKeyUp_: function(event) {
202 // We want to make it easy to change from Ctrl+Shift+ to just Ctrl+ by
203 // releasing Shift, but we also don't want it to be easy to lose for
204 // example Ctrl+Shift+F to Ctrl+ just because you didn't release Ctrl
205 // as fast as the other two keys. Therefore, we process KeyUp until you
206 // have a valid combination and then stop processing it (meaning that once
207 // you have a valid combination, we won't change it until the next
208 // KeyDown message arrives).
209 if (!this.currentKeyEvent_ || !validChar(this.currentKeyEvent_.keyCode)) {
210 if (!event.ctrlKey && !event.altKey) {
211 // If neither Ctrl nor Alt is pressed then it is not a valid shortcut.
212 // That means we're back at the starting point so we should restart
213 // capture.
214 this.endCapture_(event);
215 this.startCapture_(event);
216 } else {
217 this.handleKey_(event);
218 }
219 }
220 },
221
222 /**
223 * A general key handler (used for both KeyDown and KeyUp).
224 * @param {Event} event The keyboard event to consider.
225 * @private
226 */
227 handleKey_: function(event) {
228 // While capturing, we prevent all events from bubbling, to prevent
229 // shortcuts lacking the right modifier (F3 for example) from activating
230 // and ending capture prematurely.
231 event.preventDefault();
232 event.stopPropagation();
233
234 if (!event.ctrlKey && !event.altKey)
235 return; // Ctrl or Alt is a must.
236
237 var keystroke = keystrokeToString(event);
238 event.target.textContent = keystroke;
239 event.target.classList.add('contains-chars');
240
241 if (validChar(event.keyCode)) {
242 this.oldValue_ = keystroke; // Forget what the old value was.
243 chrome.send('setExtensionCommandShortcut', ['id', keystroke]);
244 this.endCapture_(event);
245 }
246
247 this.currentKeyEvent_ = event;
248 },
73 }; 249 };
74 250
75 return { 251 return {
76 ExtensionCommandList: ExtensionCommandList 252 ExtensionCommandList: ExtensionCommandList
77 }; 253 };
78 }); 254 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698