| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 ChromeVox options page. | 6 * @fileoverview ChromeVox options page. |
| 7 * | 7 * |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 goog.provide('cvox.OptionsPage'); | 10 goog.provide('cvox.OptionsPage'); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 /** | 56 /** |
| 57 * Initialize the options page by setting the current value of all prefs, | 57 * Initialize the options page by setting the current value of all prefs, |
| 58 * building the key bindings table, and adding event listeners. | 58 * building the key bindings table, and adding event listeners. |
| 59 * @suppress {missingProperties} Property prefs never defined on Window | 59 * @suppress {missingProperties} Property prefs never defined on Window |
| 60 */ | 60 */ |
| 61 cvox.OptionsPage.init = function() { | 61 cvox.OptionsPage.init = function() { |
| 62 cvox.OptionsPage.prefs = chrome.extension.getBackgroundPage().prefs; | 62 cvox.OptionsPage.prefs = chrome.extension.getBackgroundPage().prefs; |
| 63 cvox.OptionsPage.populateKeyMapSelect(); | 63 cvox.OptionsPage.populateKeyMapSelect(); |
| 64 cvox.OptionsPage.addKeys(); | |
| 65 cvox.OptionsPage.populateVoicesSelect(); | 64 cvox.OptionsPage.populateVoicesSelect(); |
| 66 cvox.BrailleTable.getAll(function(tables) { | 65 cvox.BrailleTable.getAll(function(tables) { |
| 67 /** @type {!Array<cvox.BrailleTable.Table>} */ | 66 /** @type {!Array<cvox.BrailleTable.Table>} */ |
| 68 cvox.OptionsPage.brailleTables = tables; | 67 cvox.OptionsPage.brailleTables = tables; |
| 69 cvox.OptionsPage.populateBrailleTablesSelect(); | 68 cvox.OptionsPage.populateBrailleTablesSelect(); |
| 70 }); | 69 }); |
| 71 chrome.storage.local.get({'brailleWordWrap': true}, function(items) { | 70 chrome.storage.local.get({'brailleWordWrap': true}, function(items) { |
| 72 $('brailleWordWrap').checked = items.brailleWordWrap; | 71 $('brailleWordWrap').checked = items.brailleWordWrap; |
| 73 }); | 72 }); |
| 74 | 73 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 87 } | 86 } |
| 88 }); | 87 }); |
| 89 | 88 |
| 90 $('selectKeys').addEventListener( | 89 $('selectKeys').addEventListener( |
| 91 'click', cvox.OptionsPage.reset, false); | 90 'click', cvox.OptionsPage.reset, false); |
| 92 | 91 |
| 93 if (cvox.PlatformUtil.matchesPlatform(cvox.PlatformFilter.WML)) { | 92 if (cvox.PlatformUtil.matchesPlatform(cvox.PlatformFilter.WML)) { |
| 94 $('version').textContent = | 93 $('version').textContent = |
| 95 chrome.app.getDetails().version; | 94 chrome.app.getDetails().version; |
| 96 } | 95 } |
| 97 | |
| 98 $('useNext').addEventListener('change', function(evt) { | |
| 99 var checked = evt.target.checked; | |
| 100 var background = | |
| 101 chrome.extension.getBackgroundPage().ChromeVoxState.instance; | |
| 102 background.toggleNext(checked); | |
| 103 }, true); | |
| 104 }; | 96 }; |
| 105 | 97 |
| 106 /** | 98 /** |
| 107 * Update the value of controls to match the current preferences. | 99 * Update the value of controls to match the current preferences. |
| 108 * This happens if the user presses a key in a tab that changes a | 100 * This happens if the user presses a key in a tab that changes a |
| 109 * pref. | 101 * pref. |
| 110 */ | 102 */ |
| 111 cvox.OptionsPage.update = function() { | 103 cvox.OptionsPage.update = function() { |
| 112 var prefs = cvox.OptionsPage.prefs.getPrefs(); | 104 var prefs = cvox.OptionsPage.prefs.getPrefs(); |
| 113 for (var key in prefs) { | 105 for (var key in prefs) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 134 if (cvox.OptionsPage.prefs.getPrefs()['currentKeyMap'] == id) { | 126 if (cvox.OptionsPage.prefs.getPrefs()['currentKeyMap'] == id) { |
| 135 option.setAttribute('selected', ''); | 127 option.setAttribute('selected', ''); |
| 136 } | 128 } |
| 137 select.appendChild(option); | 129 select.appendChild(option); |
| 138 } | 130 } |
| 139 | 131 |
| 140 select.addEventListener('change', cvox.OptionsPage.reset, true); | 132 select.addEventListener('change', cvox.OptionsPage.reset, true); |
| 141 }; | 133 }; |
| 142 | 134 |
| 143 /** | 135 /** |
| 144 * Add the input elements for the key bindings to the container element | |
| 145 * in the page. They're sorted in order of description. | |
| 146 */ | |
| 147 cvox.OptionsPage.addKeys = function() { | |
| 148 var container = $('keysContainer'); | |
| 149 var keyMap = cvox.OptionsPage.prefs.getKeyMap(); | |
| 150 | |
| 151 cvox.OptionsPage.prevTime = new Date().getTime(); | |
| 152 cvox.OptionsPage.keyCount = 0; | |
| 153 container.addEventListener('keypress', goog.bind(function(evt) { | |
| 154 if (evt.target.id == 'cvoxKey') { | |
| 155 return; | |
| 156 } | |
| 157 this.keyCount++; | |
| 158 var currentTime = new Date().getTime(); | |
| 159 if (currentTime - this.prevTime > 1000 || this.keyCount > 2) { | |
| 160 if (document.activeElement.id == 'toggleKeyPrefix') { | |
| 161 this.keySequence = new cvox.KeySequence(evt, false); | |
| 162 this.keySequence.keys['ctrlKey'][0] = true; | |
| 163 } else { | |
| 164 this.keySequence = new cvox.KeySequence(evt, true); | |
| 165 } | |
| 166 | |
| 167 this.keyCount = 1; | |
| 168 } else { | |
| 169 this.keySequence.addKeyEvent(evt); | |
| 170 } | |
| 171 | |
| 172 var keySeqStr = cvox.KeyUtil.keySequenceToString(this.keySequence, true); | |
| 173 var announce = keySeqStr.replace(/\+/g, | |
| 174 ' ' + Msgs.getMsg('then') + ' '); | |
| 175 announce = announce.replace(/>/g, | |
| 176 ' ' + Msgs.getMsg('followed_by') + ' '); | |
| 177 announce = announce.replace('Cvox', | |
| 178 ' ' + Msgs.getMsg('modifier_key') + ' '); | |
| 179 | |
| 180 // TODO(dtseng): Only basic conflict detection; it does not speak the | |
| 181 // conflicting command. Nor does it detect prefix conflicts like Cvox+L vs | |
| 182 // Cvox+L>L. | |
| 183 if (cvox.OptionsPage.prefs.setKey(document.activeElement.id, | |
| 184 this.keySequence)) { | |
| 185 document.activeElement.value = keySeqStr; | |
| 186 } else { | |
| 187 announce = Msgs.getMsg('key_conflict', [announce]); | |
| 188 } | |
| 189 cvox.OptionsPage.speak(announce, cvox.QueueMode.QUEUE); | |
| 190 this.prevTime = currentTime; | |
| 191 | |
| 192 evt.preventDefault(); | |
| 193 evt.stopPropagation(); | |
| 194 }, cvox.OptionsPage), true); | |
| 195 | |
| 196 var categories = cvox.CommandStore.categories(); | |
| 197 for (var i = 0; i < categories.length; i++) { | |
| 198 // Braille bindings can't be customized, so don't include them. | |
| 199 if (categories[i] == 'braille') { | |
| 200 continue; | |
| 201 } | |
| 202 var headerElement = document.createElement('h3'); | |
| 203 headerElement.className = 'i18n'; | |
| 204 headerElement.setAttribute('msgid', categories[i]); | |
| 205 headerElement.id = categories[i]; | |
| 206 container.appendChild(headerElement); | |
| 207 var commands = cvox.CommandStore.commandsForCategory(categories[i]); | |
| 208 for (var j = 0; j < commands.length; j++) { | |
| 209 var command = commands[j]; | |
| 210 // TODO: Someday we may want to have more than one key | |
| 211 // mapped to a command, so we'll need to figure out how to display | |
| 212 // that. For now, just take the first key. | |
| 213 var keySeqObj = keyMap.keyForCommand(command)[0]; | |
| 214 | |
| 215 // Explicitly skip toggleChromeVox in ChromeOS. | |
| 216 if (command == 'toggleChromeVox' && | |
| 217 cvox.PlatformUtil.matchesPlatform(cvox.PlatformFilter.CHROMEOS)) { | |
| 218 continue; | |
| 219 } | |
| 220 | |
| 221 var inputElement = document.createElement('input'); | |
| 222 inputElement.type = 'text'; | |
| 223 inputElement.className = 'key active-key'; | |
| 224 inputElement.id = command; | |
| 225 | |
| 226 var displayedCombo; | |
| 227 if (keySeqObj != null) { | |
| 228 displayedCombo = cvox.KeyUtil.keySequenceToString(keySeqObj, true); | |
| 229 } else { | |
| 230 displayedCombo = ''; | |
| 231 } | |
| 232 inputElement.value = displayedCombo; | |
| 233 | |
| 234 // Don't allow the user to change the sticky mode or stop speaking key. | |
| 235 if (command == 'toggleStickyMode' || command == 'stopSpeech') { | |
| 236 inputElement.disabled = true; | |
| 237 } | |
| 238 var message = cvox.CommandStore.messageForCommand(command); | |
| 239 if (!message) { | |
| 240 // TODO(dtseng): missing message id's. | |
| 241 message = command; | |
| 242 } | |
| 243 | |
| 244 var labelElement = document.createElement('label'); | |
| 245 labelElement.className = 'i18n'; | |
| 246 labelElement.setAttribute('msgid', message); | |
| 247 labelElement.setAttribute('for', inputElement.id); | |
| 248 | |
| 249 var divElement = document.createElement('div'); | |
| 250 divElement.className = 'key-container'; | |
| 251 container.appendChild(divElement); | |
| 252 divElement.appendChild(inputElement); | |
| 253 divElement.appendChild(labelElement); | |
| 254 } | |
| 255 var brElement = document.createElement('br'); | |
| 256 container.appendChild(brElement); | |
| 257 } | |
| 258 | |
| 259 if ($('cvoxKey') == null) { | |
| 260 // Add the cvox key field | |
| 261 var inputElement = document.createElement('input'); | |
| 262 inputElement.type = 'text'; | |
| 263 inputElement.className = 'key'; | |
| 264 inputElement.id = 'cvoxKey'; | |
| 265 | |
| 266 var labelElement = document.createElement('label'); | |
| 267 labelElement.className = 'i18n'; | |
| 268 labelElement.setAttribute('msgid', 'options_cvox_modifier_key'); | |
| 269 labelElement.setAttribute('for', 'cvoxKey'); | |
| 270 | |
| 271 var modifierSectionSibling = | |
| 272 $('modifier_keys').nextSibling; | |
| 273 var modifierSectionParent = modifierSectionSibling.parentNode; | |
| 274 modifierSectionParent.insertBefore(labelElement, modifierSectionSibling); | |
| 275 modifierSectionParent.insertBefore(inputElement, labelElement); | |
| 276 var cvoxKey = $('cvoxKey'); | |
| 277 cvoxKey.value = localStorage['cvoxKey']; | |
| 278 | |
| 279 cvoxKey.addEventListener('keydown', function(evt) { | |
| 280 if (!this.modifierSeq_) { | |
| 281 this.modifierCount_ = 0; | |
| 282 this.modifierSeq_ = new cvox.KeySequence(evt, false); | |
| 283 } else { | |
| 284 this.modifierSeq_.addKeyEvent(evt); | |
| 285 } | |
| 286 | |
| 287 // Never allow non-modified keys. | |
| 288 if (!this.modifierSeq_.isAnyModifierActive()) { | |
| 289 // Indicate error and instructions excluding tab. | |
| 290 if (evt.keyCode != 9) { | |
| 291 cvox.OptionsPage.speak( | |
| 292 Msgs.getMsg('modifier_entry_error'), | |
| 293 cvox.QueueMode.FLUSH, {}); | |
| 294 } | |
| 295 this.modifierSeq_ = null; | |
| 296 } else { | |
| 297 this.modifierCount_++; | |
| 298 } | |
| 299 | |
| 300 // Don't trap tab or shift. | |
| 301 if (!evt.shiftKey && evt.keyCode != 9) { | |
| 302 evt.preventDefault(); | |
| 303 evt.stopPropagation(); | |
| 304 } | |
| 305 }, true); | |
| 306 | |
| 307 cvoxKey.addEventListener('keyup', function(evt) { | |
| 308 if (this.modifierSeq_) { | |
| 309 this.modifierCount_--; | |
| 310 | |
| 311 if (this.modifierCount_ == 0) { | |
| 312 var modifierStr = | |
| 313 cvox.KeyUtil.keySequenceToString(this.modifierSeq_, true, true); | |
| 314 evt.target.value = modifierStr; | |
| 315 cvox.OptionsPage.speak( | |
| 316 Msgs.getMsg('modifier_entry_set', [modifierStr]), | |
| 317 cvox.QueueMode.QUEUE); | |
| 318 localStorage['cvoxKey'] = modifierStr; | |
| 319 this.modifierSeq_ = null; | |
| 320 } | |
| 321 evt.preventDefault(); | |
| 322 evt.stopPropagation(); | |
| 323 } | |
| 324 }, true); | |
| 325 } | |
| 326 }; | |
| 327 | |
| 328 /** | |
| 329 * Populates the voices select with options. | 136 * Populates the voices select with options. |
| 330 */ | 137 */ |
| 331 cvox.OptionsPage.populateVoicesSelect = function() { | 138 cvox.OptionsPage.populateVoicesSelect = function() { |
| 332 var select = $('voices'); | 139 var select = $('voices'); |
| 333 | 140 |
| 334 function setVoiceList() { | 141 function setVoiceList() { |
| 335 var selectedVoiceName = | 142 var selectedVoiceName = |
| 336 chrome.extension.getBackgroundPage()['getCurrentVoice'](); | 143 chrome.extension.getBackgroundPage()['getCurrentVoice'](); |
| 337 chrome.tts.getVoices(function(voices) { | 144 chrome.tts.getVoices(function(voices) { |
| 338 select.innerHTML = ''; | 145 select.innerHTML = ''; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 var selectKeyMap = $('cvox_keymaps'); | 330 var selectKeyMap = $('cvox_keymaps'); |
| 524 var id = selectKeyMap.options[selectKeyMap.selectedIndex].id; | 331 var id = selectKeyMap.options[selectKeyMap.selectedIndex].id; |
| 525 | 332 |
| 526 var msgs = Msgs; | 333 var msgs = Msgs; |
| 527 var announce = cvox.OptionsPage.prefs.getPrefs()['currentKeyMap'] == id ? | 334 var announce = cvox.OptionsPage.prefs.getPrefs()['currentKeyMap'] == id ? |
| 528 msgs.getMsg('keymap_reset', [msgs.getMsg(id)]) : | 335 msgs.getMsg('keymap_reset', [msgs.getMsg(id)]) : |
| 529 msgs.getMsg('keymap_switch', [msgs.getMsg(id)]); | 336 msgs.getMsg('keymap_switch', [msgs.getMsg(id)]); |
| 530 cvox.OptionsPage.updateStatus_(announce); | 337 cvox.OptionsPage.updateStatus_(announce); |
| 531 | 338 |
| 532 cvox.OptionsPage.prefs.switchToKeyMap(id); | 339 cvox.OptionsPage.prefs.switchToKeyMap(id); |
| 533 $('keysContainer').innerHTML = ''; | |
| 534 cvox.OptionsPage.addKeys(); | |
| 535 Msgs.addTranslatedMessagesToDom(document); | 340 Msgs.addTranslatedMessagesToDom(document); |
| 536 }; | 341 }; |
| 537 | 342 |
| 538 /** | 343 /** |
| 539 * Updates the status live region. | 344 * Updates the status live region. |
| 540 * @param {string} status The new status. | 345 * @param {string} status The new status. |
| 541 * @private | 346 * @private |
| 542 */ | 347 */ |
| 543 cvox.OptionsPage.updateStatus_ = function(status) { | 348 cvox.OptionsPage.updateStatus_ = function(status) { |
| 544 $('status').innerText = status; | 349 $('status').innerText = status; |
| 545 }; | 350 }; |
| 546 | 351 |
| 547 | 352 |
| 548 /** | 353 /** |
| 549 * Hides all elements not matching the current platform. | 354 * Hides all elements not matching the current platform. |
| 550 */ | 355 */ |
| 551 cvox.OptionsPage.hidePlatformSpecifics = function() { | 356 cvox.OptionsPage.hidePlatformSpecifics = function() { |
| 552 if (!cvox.ChromeVox.isChromeOS) { | 357 if (!cvox.ChromeVox.isChromeOS) { |
| 553 var elements = document.body.querySelectorAll('.chromeos'); | 358 var elements = document.body.querySelectorAll('.chromeos'); |
| 554 for (var i = 0, el; el = elements[i]; i++) { | 359 for (var i = 0, el; el = elements[i]; i++) { |
| 555 el.setAttribute('aria-hidden', 'true'); | 360 el.setAttribute('aria-hidden', 'true'); |
| 556 el.style.display = 'none'; | 361 el.style.display = 'none'; |
| 557 } | 362 } |
| 558 } | 363 } |
| 559 }; | 364 }; |
| 560 | 365 |
| 561 | 366 |
| 562 /** | 367 /** |
| 563 * Calls a {@code cvox.TtsInterface.speak} method in the background page to | |
| 564 * speak an utterance. See that method for further details. | |
| 565 * @param {string} textString The string of text to be spoken. | |
| 566 * @param {cvox.QueueMode} queueMode The queue mode to use. | |
| 567 * @param {Object=} properties Speech properties to use for this utterance. | |
| 568 */ | |
| 569 cvox.OptionsPage.speak = function(textString, queueMode, properties) { | |
| 570 var speak = | |
| 571 /** @type Function} */ (chrome.extension.getBackgroundPage()['speak']); | |
| 572 speak.apply(null, arguments); | |
| 573 }; | |
| 574 | |
| 575 /** | |
| 576 * @return {cvox.BrailleTranslatorManager} | 368 * @return {cvox.BrailleTranslatorManager} |
| 577 */ | 369 */ |
| 578 cvox.OptionsPage.getBrailleTranslatorManager = function() { | 370 cvox.OptionsPage.getBrailleTranslatorManager = function() { |
| 579 return chrome.extension.getBackgroundPage()['braille_translator_manager']; | 371 return chrome.extension.getBackgroundPage()['braille_translator_manager']; |
| 580 }; | 372 }; |
| 581 | 373 |
| 582 document.addEventListener('DOMContentLoaded', function() { | 374 document.addEventListener('DOMContentLoaded', function() { |
| 583 cvox.OptionsPage.init(); | 375 cvox.OptionsPage.init(); |
| 584 }, false); | 376 }, false); |
| OLD | NEW |