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

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/panel.js

Issue 1684693002: Revert of Implement ChromeVox Next menus. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@panel_view_type
Patch Set: generating revert using git Created 4 years, 10 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 /** 5 /**
6 * @fileoverview The ChromeVox panel and menus. 6 * @fileoverview ChromeVox panel.
7 *
7 */ 8 */
8 9
9 goog.provide('Panel'); 10 goog.provide('Panel');
10 11
11 goog.require('Msgs'); 12 goog.require('Msgs');
12 goog.require('PanelCommand'); 13 goog.require('PanelCommand');
13 goog.require('PanelMenu'); 14
14 goog.require('PanelMenuItem'); 15 function $(id) {
15 goog.require('cvox.ChromeVoxKbHandler'); 16 return document.getElementById(id);
16 goog.require('cvox.CommandStore'); 17 }
17 18
18 /** 19 /**
19 * Class to manage the panel. 20 * Class to manage the panel.
20 * @constructor 21 * @constructor
21 */ 22 */
22 Panel = function() { 23 Panel = function() {
23 }; 24 };
24 25
25 /** 26 /**
26 * Initialize the panel. 27 * Initialize the panel.
27 */ 28 */
28 Panel.init = function() { 29 Panel.init = function() {
29 /** @type {Element} @private */ 30 /** @type {Element} @private */
30 this.speechContainer_ = $('speech-container'); 31 this.speechContainer_ = $('speech-container');
31 32
32 /** @type {Element} @private */ 33 /** @type {Element} @private */
33 this.speechElement_ = $('speech'); 34 this.speechElement_ = $('speech');
34 35
35 /** @type {Element} @private */ 36 /** @type {Element} @private */
36 this.brailleContainer_ = $('braille-container'); 37 this.brailleContainer_ = $('braille-container');
37 38
38 /** @type {Element} @private */ 39 /** @type {Element} @private */
39 this.brailleTextElement_ = $('braille-text'); 40 this.brailleTextElement_ = $('braille-text');
40 41
41 /** @type {Element} @private */ 42 /** @type {Element} @private */
42 this.brailleCellsElement_ = $('braille-cells'); 43 this.brailleCellsElement_ = $('braille-cells');
43 44
44 /**
45 * The array of top-level menus.
46 * @type {!Array<PanelMenu>}
47 * @private
48 */
49 this.menus_ = [];
50
51 /**
52 * The currently active menu, if any.
53 * @type {PanelMenu}
54 * @private
55 */
56 this.activeMenu_ = null;
57
58 /**
59 * True if the menu button in the panel is enabled at all. It's disabled if
60 * ChromeVox Next is not active.
61 * @type {boolean}
62 * @private
63 */
64 this.menusEnabled_ = false;
65
66 /**
67 * A callback function to be executed to perform the action from selecting
68 * a menu item after the menu has been closed and focus has been restored
69 * to the page or wherever it was previously.
70 * @type {?Function}
71 * @private
72 */
73 this.pendingCallback_ = null;
74
75 Panel.updateFromPrefs(); 45 Panel.updateFromPrefs();
76
77 Msgs.addTranslatedMessagesToDom(document);
78
79 window.addEventListener('storage', function(event) { 46 window.addEventListener('storage', function(event) {
80 if (event.key == 'brailleCaptions') { 47 if (event.key == 'brailleCaptions') {
81 Panel.updateFromPrefs(); 48 Panel.updateFromPrefs();
82 } 49 }
83 }, false); 50 }, false);
84 51
85 window.addEventListener('message', function(message) { 52 window.addEventListener('message', function(message) {
86 var command = JSON.parse(message.data); 53 var command = JSON.parse(message.data);
87 Panel.exec(/** @type {PanelCommand} */(command)); 54 Panel.exec(/** @type {PanelCommand} */(command));
88 }, false); 55 }, false);
89 56
90 $('menus_button').addEventListener('mousedown', Panel.onOpenMenus, false);
91 $('options').addEventListener('click', Panel.onOptions, false); 57 $('options').addEventListener('click', Panel.onOptions, false);
92 $('close').addEventListener('click', Panel.onClose, false); 58 $('close').addEventListener('click', Panel.onClose, false);
93 59
94 document.addEventListener('keydown', Panel.onKeyDown, false); 60 // The ChromeVox menu isn't fully implemented yet, disable it.
95 document.addEventListener('mouseup', Panel.onMouseUp, false); 61 $('menu').disabled = true;
62 $('triangle').style.display = 'none';
63
64 Msgs.addTranslatedMessagesToDom(document);
96 }; 65 };
97 66
98 /** 67 /**
99 * Update the display based on prefs. 68 * Update the display based on prefs.
100 */ 69 */
101 Panel.updateFromPrefs = function() { 70 Panel.updateFromPrefs = function() {
102 if (localStorage['brailleCaptions'] === String(true)) { 71 if (localStorage['brailleCaptions'] === String(true)) {
103 this.speechContainer_.style.visibility = 'hidden'; 72 this.speechContainer_.style.visibility = 'hidden';
104 this.brailleContainer_.style.visibility = 'visible'; 73 this.brailleContainer_.style.visibility = 'visible';
105 } else { 74 } else {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 case PanelCommandType.ADD_ANNOTATION_SPEECH: 113 case PanelCommandType.ADD_ANNOTATION_SPEECH:
145 if (this.speechElement_.innerHTML != '') { 114 if (this.speechElement_.innerHTML != '') {
146 this.speechElement_.innerHTML += '&nbsp;&nbsp;'; 115 this.speechElement_.innerHTML += '&nbsp;&nbsp;';
147 } 116 }
148 this.speechElement_.innerHTML += escapeForHtml(command.data); 117 this.speechElement_.innerHTML += escapeForHtml(command.data);
149 break; 118 break;
150 case PanelCommandType.UPDATE_BRAILLE: 119 case PanelCommandType.UPDATE_BRAILLE:
151 this.brailleTextElement_.textContent = command.data.text; 120 this.brailleTextElement_.textContent = command.data.text;
152 this.brailleCellsElement_.textContent = command.data.braille; 121 this.brailleCellsElement_.textContent = command.data.braille;
153 break; 122 break;
154 case PanelCommandType.ENABLE_MENUS:
155 Panel.onEnableMenus();
156 break;
157 case PanelCommandType.DISABLE_MENUS:
158 Panel.onDisableMenus();
159 break;
160 case PanelCommandType.OPEN_MENUS:
161 Panel.onOpenMenus();
162 break;
163 } 123 }
164 }; 124 };
165 125
166 /** 126 /**
167 * Enable the ChromeVox Menus.
168 */
169 Panel.onEnableMenus = function() {
170 Panel.menusEnabled_ = true;
171 $('menus_button').disabled = false;
172 $('triangle').style.display = '';
173 };
174
175 /**
176 * Disable the ChromeVox Menus.
177 */
178 Panel.onDisableMenus = function() {
179 Panel.menusEnabled_ = false;
180 $('menus_button').disabled = true;
181 $('triangle').style.display = 'none';
182 };
183
184 /**
185 * Open / show the ChromeVox Menus.
186 * @param {Event=} opt_event An optional event that triggered this.
187 */
188 Panel.onOpenMenus = function(opt_event) {
189 // Don't open the menu if it's not enabled, such as when ChromeVox Next
190 // is not active.
191 if (!Panel.menusEnabled_)
192 return;
193
194 // Eat the event so that a mousedown isn't turned into a drag, allowing
195 // users to click-drag-release to select a menu item.
196 if (opt_event) {
197 opt_event.stopPropagation();
198 opt_event.preventDefault();
199 }
200
201 // Change the url fragment to 'fullscreen', which signals the native
202 // host code to make the window fullscreen, revealing the menus.
203 window.location = '#fullscreen';
204
205 // Clear any existing menus and clear the callback.
206 Panel.clearMenus();
207 Panel.pendingCallback_ = null;
208
209 // Build the top-level menus.
210 var jumpMenu = Panel.addMenu('Jump');
211 var speechMenu = Panel.addMenu('Speech');
212 var tabsMenu = Panel.addMenu('Tabs');
213 var chromevoxMenu = Panel.addMenu('ChromeVox');
214
215 // Create a mapping between categories from CommandStore, and our
216 // top-level menus. Some categories aren't mapped to any menu.
217 var categoryToMenu = {
218 'navigation': jumpMenu,
219 'jump_commands': jumpMenu,
220 'controlling_speech': speechMenu,
221 'modifier_keys': chromevoxMenu,
222 'help_commands': chromevoxMenu,
223
224 'information': null, // Get link URL, get page title, etc.
225 'overview': null, // Headings list, etc.
226 'tables': null, // Table navigation.
227 'braille': null,
228 'developer': null};
229
230 // Get the key map from the background page.
231 var bkgnd = chrome.extension.getBackgroundPage();
232 var keymap = bkgnd['cvox']['KeyMap']['fromCurrentKeyMap']();
233
234 // Make a copy of the key bindings, get the localized title of each
235 // command, and then sort them.
236 var sortedBindings = keymap.bindings().slice();
237 sortedBindings.forEach(goog.bind(function(binding) {
238 var command = binding.command;
239 var keySeq = binding.sequence;
240 binding.keySeq = cvox.KeyUtil.keySequenceToString(keySeq, true);
241 var titleMsgId = cvox.CommandStore.messageForCommand(command);
242 if (!titleMsgId) {
243 console.error('No localization for: ' + command);
244 binding.title = '';
245 return;
246 }
247 var title = Msgs.getMsg(titleMsgId);
248 // Convert to title case.
249 title = title.replace(/\w\S*/g, function(word) {
250 return word.charAt(0).toUpperCase() + word.substr(1);
251 });
252 binding.title = title;
253 }, this));
254 sortedBindings.sort(function(binding1, binding2) {
255 return binding1.title.localeCompare(binding2.title);
256 });
257
258 // Insert items from the bindings into the menus.
259 sortedBindings.forEach(goog.bind(function(binding) {
260 var category = cvox.CommandStore.categoryForCommand(binding.command);
261 var menu = category ? categoryToMenu[category] : null;
262 if (binding.title && menu) {
263 menu.addMenuItem(
264 binding.title,
265 binding.keySeq,
266 function() {
267 var bkgnd =
268 chrome.extension.getBackgroundPage()['global']['backgroundObj'];
269 bkgnd['onGotCommand'](binding.command);
270 });
271 }
272 }, this));
273
274 // Add all open tabs to the Tabs menu.
275 bkgnd.chrome.windows.getLastFocused(function(lastFocusedWindow) {
276 bkgnd.chrome.windows.getAll({'populate': true}, function(windows) {
277 for (var i = 0; i < windows.length; i++) {
278 var tabs = windows[i].tabs;
279 for (var j = 0; j < tabs.length; j++) {
280 var title = tabs[j].title;
281 if (tabs[j].active && windows[i].id == lastFocusedWindow.id)
282 title += ' ' + Msgs.getMsg('active_tab');
283 tabsMenu.addMenuItem(title, '', (function(win, tab) {
284 bkgnd.chrome.windows.update(win.id, {focused: true}, function() {
285 bkgnd.chrome.tabs.update(tab.id, {active: true});
286 });
287 }).bind(this, windows[i], tabs[j]));
288 }
289 }
290 });
291 });
292
293 // Add a menu item that disables / closes ChromeVox.
294 chromevoxMenu.addMenuItem(
295 Msgs.getMsg('disable_chromevox'), 'Ctrl+Alt+Z', function() {
296 Panel.onClose();
297 });
298
299 // Activate the first menu.
300 Panel.activateMenu(Panel.menus_[0]);
301 };
302
303 /**
304 * Clear any previous menus. The menus are all regenerated each time the
305 * menus are opened.
306 */
307 Panel.clearMenus = function() {
308 while (this.menus_.length) {
309 var menu = this.menus_.pop();
310 $('menu-bar').removeChild(menu.menuBarItemElement);
311 $('menus_background').removeChild(menu.menuContainerElement);
312 }
313 this.activeMenu_ = null;
314 };
315
316 /**
317 * Create a new menu with the given name and add it to the menu bar.
318 * @param {string} menuTitle The title of the new menu to add.
319 * @return {PanelMenu} The menu just created.
320 */
321 Panel.addMenu = function(menuTitle) {
322 var menu = new PanelMenu(menuTitle);
323 $('menu-bar').appendChild(menu.menuBarItemElement);
324 menu.menuBarItemElement.addEventListener('mouseover', function() {
325 Panel.activateMenu(menu);
326 }, false);
327
328 $('menus_background').appendChild(menu.menuContainerElement);
329 this.menus_.push(menu);
330 return menu;
331 };
332
333 /**
334 * Activate a menu, which implies hiding the previous active menu.
335 * @param {PanelMenu} menu The new menu to activate.
336 */
337 Panel.activateMenu = function(menu) {
338 if (menu == this.activeMenu_)
339 return;
340
341 if (this.activeMenu_) {
342 this.activeMenu_.deactivate();
343 this.activeMenu_ = null;
344 }
345
346 this.activeMenu_ = menu;
347 this.pendingCallback_ = null;
348
349 if (this.activeMenu_) {
350 this.activeMenu_.activate();
351 }
352 };
353
354 /**
355 * Advance the index of the current active menu by |delta|.
356 * @param {number} delta The number to add to the active menu index.
357 */
358 Panel.advanceActiveMenuBy = function(delta) {
359 var activeIndex = -1;
360 for (var i = 0; i < this.menus_.length; i++) {
361 if (this.activeMenu_ == this.menus_[i]) {
362 activeIndex = i;
363 break;
364 }
365 }
366
367 if (activeIndex >= 0) {
368 activeIndex += delta;
369 activeIndex = (activeIndex + this.menus_.length) % this.menus_.length;
370 } else {
371 if (delta >= 0)
372 activeIndex = 0;
373 else
374 activeIndex = this.menus_.length - 1;
375 }
376 Panel.activateMenu(this.menus_[activeIndex]);
377 };
378
379 /**
380 * Advance the index of the current active menu item by |delta|.
381 * @param {number} delta The number to add to the active menu item index.
382 */
383 Panel.advanceItemBy = function(delta) {
384 if (this.activeMenu_)
385 this.activeMenu_.advanceItemBy(delta);
386 };
387
388 /**
389 * Called when the user releases the mouse button. If it's anywhere other
390 * than on the menus button, close the menus and return focus to the page,
391 * and if the mouse was released over a menu item, execute that item's
392 * callback.
393 * @param {Event} event The mouse event.
394 */
395 Panel.onMouseUp = function(event) {
396 var target = event.target;
397 while (target && !target.classList.contains('menu-item')) {
398 // Allow the user to click and release on the menu button and leave
399 // the menu button. Otherwise releasing the mouse anywhere else will
400 // close the menu.
401 if (target.id == 'menus_button')
402 return;
403
404 target = target.parentElement;
405 }
406
407 if (target && Panel.activeMenu_)
408 Panel.pendingCallback_ = Panel.activeMenu_.getCallbackForElement(target);
409 Panel.closeMenusAndRestoreFocus();
410 };
411
412 /**
413 * Called when a key is pressed. Handle arrow keys to navigate the menus,
414 * Esc to close, and Enter/Space to activate an item.
415 * @param {Event} event The key event.
416 */
417 Panel.onKeyDown = function(event) {
418 if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
419 return;
420
421 switch (event.keyIdentifier) {
422 case 'Left':
423 Panel.advanceActiveMenuBy(-1);
424 break;
425 case 'Right':
426 Panel.advanceActiveMenuBy(1);
427 break;
428 case 'Up':
429 Panel.advanceItemBy(-1);
430 break;
431 case 'Down':
432 Panel.advanceItemBy(1);
433 break;
434 case 'U+001B': // Escape
435 Panel.closeMenusAndRestoreFocus();
436 break;
437 case 'Enter': // Enter
438 case 'U+0020': // Space
439 Panel.pendingCallback_ = Panel.getCallbackForCurrentItem();
440 Panel.closeMenusAndRestoreFocus();
441 break;
442 default:
443 // Don't mark this event as handled.
444 return;
445 }
446
447 event.preventDefault();
448 event.stopPropagation();
449 };
450
451 /**
452 * Open the ChromeVox Options. 127 * Open the ChromeVox Options.
453 */ 128 */
454 Panel.onOptions = function() { 129 Panel.onOptions = function() {
455 var bkgnd = 130 var bkgnd =
456 chrome.extension.getBackgroundPage()['global']['backgroundObj']; 131 chrome.extension.getBackgroundPage()['global']['backgroundObj'];
457 bkgnd['showOptionsPage'](); 132 bkgnd['showOptionsPage']();
458 window.location = '#'; 133 window.location = '#';
459 }; 134 };
460 135
461 /** 136 /**
462 * Exit ChromeVox. 137 * Exit ChromeVox.
463 */ 138 */
464 Panel.onClose = function() { 139 Panel.onClose = function() {
465 window.location = '#close'; 140 window.location = '#close';
466 }; 141 };
467 142
468 /**
469 * Get the callback for whatever item is currently selected.
470 * @return {Function} The callback for the current item.
471 */
472 Panel.getCallbackForCurrentItem = function() {
473 if (this.activeMenu_)
474 return this.activeMenu_.getCallbackForCurrentItem();
475 return null;
476 };
477
478 /**
479 * Close the menus and restore focus to the page. If a menu item's callback
480 * was queued, execute it once focus is restored.
481 */
482 Panel.closeMenusAndRestoreFocus = function() {
483 // Make sure we're not in full-screen mode.
484 window.location = '#';
485
486 var bkgnd =
487 chrome.extension.getBackgroundPage()['global']['backgroundObj'];
488 bkgnd['restoreCurrentRange']();
489 if (Panel.pendingCallback_)
490 Panel.pendingCallback_();
491 };
492
493 window.addEventListener('load', function() { 143 window.addEventListener('load', function() {
494 Panel.init(); 144 Panel.init();
495 }, false); 145 }, false);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698