OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // TODO(kochi): Generalize the notification as a component and put it |
| 6 // in js/cr/ui/notification.js . |
| 7 |
| 8 cr.define('options', function() { |
| 9 const OptionsPage = options.OptionsPage; |
| 10 const LanguageList = options.LanguageList; |
| 11 |
| 12 // Some input methods like Chinese Pinyin have config pages. |
| 13 // This is the map of the input method names to their config page names. |
| 14 const INPUT_METHOD_ID_TO_CONFIG_PAGE_NAME = { |
| 15 'mozc': 'languageMozc', |
| 16 'mozc-chewing': 'languageChewing', |
| 17 'mozc-dv': 'languageMozc', |
| 18 'mozc-hangul': 'languageHangul', |
| 19 'mozc-jp': 'languageMozc', |
| 20 'pinyin': 'languagePinyin', |
| 21 'pinyin-dv': 'languagePinyin', |
| 22 }; |
| 23 |
| 24 ///////////////////////////////////////////////////////////////////////////// |
| 25 // LanguageOptions class: |
| 26 |
| 27 /** |
| 28 * Encapsulated handling of ChromeOS language options page. |
| 29 * @constructor |
| 30 */ |
| 31 function LanguageOptions(model) { |
| 32 OptionsPage.call(this, 'languages', templateData.languagePageTabTitle, |
| 33 'languagePage'); |
| 34 } |
| 35 |
| 36 cr.addSingletonGetter(LanguageOptions); |
| 37 |
| 38 // Inherit LanguageOptions from OptionsPage. |
| 39 LanguageOptions.prototype = { |
| 40 __proto__: OptionsPage.prototype, |
| 41 |
| 42 /** |
| 43 * Initializes LanguageOptions page. |
| 44 * Calls base class implementation to starts preference initialization. |
| 45 */ |
| 46 initializePage: function() { |
| 47 OptionsPage.prototype.initializePage.call(this); |
| 48 |
| 49 var languageOptionsList = $('language-options-list'); |
| 50 LanguageList.decorate(languageOptionsList); |
| 51 |
| 52 languageOptionsList.addEventListener('change', |
| 53 this.handleLanguageOptionsListChange_.bind(this)); |
| 54 languageOptionsList.addEventListener('save', |
| 55 this.handleLanguageOptionsListSave_.bind(this)); |
| 56 |
| 57 this.addEventListener('visibleChange', |
| 58 this.handleVisibleChange_.bind(this)); |
| 59 |
| 60 if (cr.isChromeOS) { |
| 61 this.initializeInputMethodList_(); |
| 62 this.initializeLanguageCodeToInputMethodIdsMap_(); |
| 63 } |
| 64 Preferences.getInstance().addEventListener(this.spellCheckDictionaryPref, |
| 65 this.handleSpellCheckDictionaryPrefChange_.bind(this)); |
| 66 |
| 67 // Set up add button. |
| 68 $('language-options-add-button').onclick = function(e) { |
| 69 // Add the language without showing the overlay if it's specified in |
| 70 // the URL hash (ex. lang_add=ja). Used for automated testing. |
| 71 var match = document.location.hash.match(/\blang_add=([\w-]+)/); |
| 72 if (match) { |
| 73 var addLanguageCode = match[1]; |
| 74 $('language-options-list').addLanguage(addLanguageCode); |
| 75 } else { |
| 76 OptionsPage.navigateToPage('addLanguage'); |
| 77 } |
| 78 }; |
| 79 |
| 80 if (cr.isChromeOS) { |
| 81 // Listen to user clicks on the add language list. |
| 82 var addLanguageList = $('add-language-overlay-language-list'); |
| 83 addLanguageList.addEventListener('click', |
| 84 this.handleAddLanguageListClick_.bind(this)); |
| 85 } else { |
| 86 // Listen to add language dialog ok button. |
| 87 var addLanguageOkButton = $('add-language-overlay-ok-button'); |
| 88 addLanguageOkButton.addEventListener('click', |
| 89 this.handleAddLanguageOkButtonClick_.bind(this)); |
| 90 |
| 91 // Show experimental features if enabled. |
| 92 if (templateData.experimentalSpellCheckFeatures == 'true') |
| 93 $('auto-spell-correction-option').hidden = false; |
| 94 |
| 95 // Handle spell check enable/disable. |
| 96 if (!cr.isMac) { |
| 97 Preferences.getInstance().addEventListener( |
| 98 this.enableSpellCheckPref, |
| 99 this.updateEnableSpellCheck_.bind(this)); |
| 100 } |
| 101 } |
| 102 |
| 103 // Listen to user clicks on the "Change touch keyboard settings..." |
| 104 // button (if it exists). |
| 105 var virtualKeyboardButton = $('language-options-virtual-keyboard'); |
| 106 if (virtualKeyboardButton) { |
| 107 // TODO(yusukes): would be better to hide the button if no virtual |
| 108 // keyboard is registered. |
| 109 virtualKeyboardButton.onclick = function(e) { |
| 110 OptionsPage.navigateToPage('virtualKeyboards'); |
| 111 }; |
| 112 } |
| 113 }, |
| 114 |
| 115 // The preference is a boolean that enables/disables spell checking. |
| 116 enableSpellCheckPref: 'browser.enable_spellchecking', |
| 117 // The preference is a CSV string that describes preload engines |
| 118 // (i.e. active input methods). |
| 119 preloadEnginesPref: 'settings.language.preload_engines', |
| 120 // The list of preload engines, like ['mozc', 'pinyin']. |
| 121 preloadEngines_: [], |
| 122 // The preference is a string that describes the spell check |
| 123 // dictionary language, like "en-US". |
| 124 spellCheckDictionaryPref: 'spellcheck.dictionary', |
| 125 spellCheckDictionary_: "", |
| 126 // The map of language code to input method IDs, like: |
| 127 // {'ja': ['mozc', 'mozc-jp'], 'zh-CN': ['pinyin'], ...} |
| 128 languageCodeToInputMethodIdsMap_: {}, |
| 129 |
| 130 /** |
| 131 * Initializes the input method list. |
| 132 */ |
| 133 initializeInputMethodList_: function() { |
| 134 var inputMethodList = $('language-options-input-method-list'); |
| 135 var inputMethodListData = templateData.inputMethodList; |
| 136 |
| 137 // Add all input methods, but make all of them invisible here. We'll |
| 138 // change the visibility in handleLanguageOptionsListChange_() based |
| 139 // on the selected language. Note that we only have less than 100 |
| 140 // input methods, so creating DOM nodes at once here should be ok. |
| 141 for (var i = 0; i < inputMethodListData.length; i++) { |
| 142 var inputMethod = inputMethodListData[i]; |
| 143 var input = document.createElement('input'); |
| 144 input.type = 'checkbox'; |
| 145 input.inputMethodId = inputMethod.id; |
| 146 // Listen to user clicks. |
| 147 input.addEventListener('click', |
| 148 this.handleCheckboxClick_.bind(this)); |
| 149 var label = document.createElement('label'); |
| 150 label.appendChild(input); |
| 151 // Adding a space between the checkbox and the text. This is a bit |
| 152 // dirty, but we rely on a space character for all other checkboxes. |
| 153 label.appendChild(document.createTextNode( |
| 154 ' ' + inputMethod.displayName)); |
| 155 label.style.display = 'none'; |
| 156 label.languageCodeSet = inputMethod.languageCodeSet; |
| 157 // Add the configure button if the config page is present for this |
| 158 // input method. |
| 159 if (inputMethod.id in INPUT_METHOD_ID_TO_CONFIG_PAGE_NAME) { |
| 160 var pageName = INPUT_METHOD_ID_TO_CONFIG_PAGE_NAME[inputMethod.id]; |
| 161 var button = this.createConfigureInputMethodButton_(inputMethod.id, |
| 162 pageName); |
| 163 label.appendChild(button); |
| 164 } |
| 165 |
| 166 inputMethodList.appendChild(label); |
| 167 } |
| 168 // Listen to pref change once the input method list is initialized. |
| 169 Preferences.getInstance().addEventListener(this.preloadEnginesPref, |
| 170 this.handlePreloadEnginesPrefChange_.bind(this)); |
| 171 }, |
| 172 |
| 173 /** |
| 174 * Creates a configure button for the given input method ID. |
| 175 * @param {string} inputMethodId Input method ID (ex. "pinyin"). |
| 176 * @param {string} pageName Name of the config page (ex. "languagePinyin"). |
| 177 * @private |
| 178 */ |
| 179 createConfigureInputMethodButton_: function(inputMethodId, pageName) { |
| 180 var button = document.createElement('button'); |
| 181 button.textContent = localStrings.getString('configure'); |
| 182 button.onclick = function(e) { |
| 183 // Prevent the default action (i.e. changing the checked property |
| 184 // of the checkbox). The button click here should not be handled |
| 185 // as checkbox click. |
| 186 e.preventDefault(); |
| 187 chrome.send('inputMethodOptionsOpen', [inputMethodId]); |
| 188 OptionsPage.navigateToPage(pageName); |
| 189 } |
| 190 return button; |
| 191 }, |
| 192 |
| 193 /** |
| 194 * Handles OptionsPage's visible property change event. |
| 195 * @param {Event} e Property change event. |
| 196 * @private |
| 197 */ |
| 198 handleVisibleChange_: function(e) { |
| 199 if (this.visible) { |
| 200 $('language-options-list').redraw(); |
| 201 chrome.send('languageOptionsOpen'); |
| 202 } |
| 203 }, |
| 204 |
| 205 /** |
| 206 * Handles languageOptionsList's change event. |
| 207 * @param {Event} e Change event. |
| 208 * @private |
| 209 */ |
| 210 handleLanguageOptionsListChange_: function(e) { |
| 211 var languageOptionsList = $('language-options-list'); |
| 212 var languageCode = languageOptionsList.getSelectedLanguageCode(); |
| 213 // Select the language if it's specified in the URL hash (ex. lang=ja). |
| 214 // Used for automated testing. |
| 215 var match = document.location.hash.match(/\blang=([\w-]+)/); |
| 216 if (match) { |
| 217 var specifiedLanguageCode = match[1]; |
| 218 if (languageOptionsList.selectLanguageByCode(specifiedLanguageCode)) { |
| 219 languageCode = specifiedLanguageCode; |
| 220 } |
| 221 } |
| 222 this.updateSelectedLanguageName_(languageCode); |
| 223 if (cr.isWindows || cr.isChromeOS) |
| 224 this.updateUiLanguageButton_(languageCode); |
| 225 if (!cr.isMac) |
| 226 this.updateSpellCheckLanguageButton_(languageCode); |
| 227 if (cr.isChromeOS) |
| 228 this.updateInputMethodList_(languageCode); |
| 229 this.updateLanguageListInAddLanguageOverlay_(); |
| 230 }, |
| 231 |
| 232 /** |
| 233 * Handles languageOptionsList's save event. |
| 234 * @param {Event} e Save event. |
| 235 * @private |
| 236 */ |
| 237 handleLanguageOptionsListSave_: function(e) { |
| 238 if (cr.isChromeOS) { |
| 239 // Sort the preload engines per the saved languages before save. |
| 240 this.preloadEngines_ = this.sortPreloadEngines_(this.preloadEngines_); |
| 241 this.savePreloadEnginesPref_(); |
| 242 } |
| 243 }, |
| 244 |
| 245 /** |
| 246 * Sorts preloadEngines_ by languageOptionsList's order. |
| 247 * @param {Array} preloadEngines List of preload engines. |
| 248 * @return {Array} Returns sorted preloadEngines. |
| 249 * @private |
| 250 */ |
| 251 sortPreloadEngines_: function(preloadEngines) { |
| 252 // For instance, suppose we have two languages and associated input |
| 253 // methods: |
| 254 // |
| 255 // - Korean: hangul |
| 256 // - Chinese: pinyin |
| 257 // |
| 258 // The preloadEngines preference should look like "hangul,pinyin". |
| 259 // If the user reverse the order, the preference should be reorderd |
| 260 // to "pinyin,hangul". |
| 261 var languageOptionsList = $('language-options-list'); |
| 262 var languageCodes = languageOptionsList.getLanguageCodes(); |
| 263 |
| 264 // Convert the list into a dictonary for simpler lookup. |
| 265 var preloadEngineSet = {}; |
| 266 for (var i = 0; i < preloadEngines.length; i++) { |
| 267 preloadEngineSet[preloadEngines[i]] = true; |
| 268 } |
| 269 |
| 270 // Create the new preload engine list per the language codes. |
| 271 var newPreloadEngines = []; |
| 272 for (var i = 0; i < languageCodes.length; i++) { |
| 273 var languageCode = languageCodes[i]; |
| 274 var inputMethodIds = this.languageCodeToInputMethodIdsMap_[ |
| 275 languageCode]; |
| 276 // Check if we have active input methods associated with the language. |
| 277 for (var j = 0; j < inputMethodIds.length; j++) { |
| 278 var inputMethodId = inputMethodIds[j]; |
| 279 if (inputMethodId in preloadEngineSet) { |
| 280 // If we have, add it to the new engine list. |
| 281 newPreloadEngines.push(inputMethodId); |
| 282 // And delete it from the set. This is necessary as one input |
| 283 // method can be associated with more than one language thus |
| 284 // we should avoid having duplicates in the new list. |
| 285 delete preloadEngineSet[inputMethodId]; |
| 286 } |
| 287 } |
| 288 } |
| 289 |
| 290 return newPreloadEngines; |
| 291 }, |
| 292 |
| 293 /** |
| 294 * Initializes the map of language code to input method IDs. |
| 295 * @private |
| 296 */ |
| 297 initializeLanguageCodeToInputMethodIdsMap_: function() { |
| 298 var inputMethodList = templateData.inputMethodList; |
| 299 for (var i = 0; i < inputMethodList.length; i++) { |
| 300 var inputMethod = inputMethodList[i]; |
| 301 for (var languageCode in inputMethod.languageCodeSet) { |
| 302 if (languageCode in this.languageCodeToInputMethodIdsMap_) { |
| 303 this.languageCodeToInputMethodIdsMap_[languageCode].push( |
| 304 inputMethod.id); |
| 305 } else { |
| 306 this.languageCodeToInputMethodIdsMap_[languageCode] = |
| 307 [inputMethod.id]; |
| 308 } |
| 309 } |
| 310 } |
| 311 }, |
| 312 |
| 313 /** |
| 314 * Updates the currently selected language name. |
| 315 * @param {string} languageCode Language code (ex. "fr"). |
| 316 * @private |
| 317 */ |
| 318 updateSelectedLanguageName_: function(languageCode) { |
| 319 var languageDisplayName = LanguageList.getDisplayNameFromLanguageCode( |
| 320 languageCode); |
| 321 var languageNativeDisplayName = |
| 322 LanguageList.getNativeDisplayNameFromLanguageCode(languageCode); |
| 323 // If the native name is different, add it. |
| 324 if (languageDisplayName != languageNativeDisplayName) { |
| 325 languageDisplayName += ' - ' + languageNativeDisplayName; |
| 326 } |
| 327 // Update the currently selected language name. |
| 328 var languageName = $('language-options-language-name'); |
| 329 if (languageDisplayName) { |
| 330 languageName.hidden = false; |
| 331 languageName.textContent = languageDisplayName; |
| 332 } else { |
| 333 languageName.hidden = true; |
| 334 } |
| 335 }, |
| 336 |
| 337 /** |
| 338 * Updates the UI language button. |
| 339 * @param {string} languageCode Language code (ex. "fr"). |
| 340 * @private |
| 341 */ |
| 342 updateUiLanguageButton_: function(languageCode) { |
| 343 var uiLanguageButton = $('language-options-ui-language-button'); |
| 344 // Check if the language code matches the current UI language. |
| 345 if (languageCode == templateData.currentUiLanguageCode) { |
| 346 // If it matches, the button just says that the UI language is |
| 347 // currently in use. |
| 348 uiLanguageButton.textContent = |
| 349 localStrings.getString('is_displayed_in_this_language'); |
| 350 // Make it look like a text label. |
| 351 uiLanguageButton.className = 'text-button'; |
| 352 // Remove the event listner. |
| 353 uiLanguageButton.onclick = undefined; |
| 354 } else if (languageCode in templateData.uiLanguageCodeSet) { |
| 355 // If the language is supported as UI language, users can click on |
| 356 // the button to change the UI language. |
| 357 if (cr.commandLine && cr.commandLine.options['--bwsi']) { |
| 358 // In the guest mode for ChromeOS, changing UI language does not make |
| 359 // sense because it does not take effect after browser restart. |
| 360 uiLanguageButton.hidden = true; |
| 361 } else { |
| 362 uiLanguageButton.textContent = |
| 363 localStrings.getString('display_in_this_language'); |
| 364 uiLanguageButton.className = ''; |
| 365 // Send the change request to Chrome. |
| 366 uiLanguageButton.onclick = function(e) { |
| 367 chrome.send('uiLanguageChange', [languageCode]); |
| 368 } |
| 369 } |
| 370 if (cr.isChromeOS) { |
| 371 $('language-options-ui-restart-button').onclick = function(e) { |
| 372 chrome.send('uiLanguageRestart'); |
| 373 } |
| 374 } |
| 375 } else { |
| 376 // If the language is not supported as UI language, the button |
| 377 // just says that Chromium OS cannot be displayed in this language. |
| 378 uiLanguageButton.textContent = |
| 379 localStrings.getString('cannot_be_displayed_in_this_language'); |
| 380 uiLanguageButton.className = 'text-button'; |
| 381 uiLanguageButton.onclick = undefined; |
| 382 } |
| 383 uiLanguageButton.style.display = 'block'; |
| 384 $('language-options-ui-notification-bar').style.display = 'none'; |
| 385 }, |
| 386 |
| 387 /** |
| 388 * Updates the spell check language button. |
| 389 * @param {string} languageCode Language code (ex. "fr"). |
| 390 * @private |
| 391 */ |
| 392 updateSpellCheckLanguageButton_: function(languageCode) { |
| 393 var display = 'block'; |
| 394 var spellCheckLanguageButton = $( |
| 395 'language-options-spell-check-language-button'); |
| 396 // Check if the language code matches the current spell check language. |
| 397 if (languageCode == this.spellCheckDictionary_) { |
| 398 // If it matches, the button just says that the spell check language is |
| 399 // currently in use. |
| 400 spellCheckLanguageButton.textContent = |
| 401 localStrings.getString('is_used_for_spell_checking'); |
| 402 // Make it look like a text label. |
| 403 spellCheckLanguageButton.className = 'text-button'; |
| 404 // Remove the event listner. |
| 405 spellCheckLanguageButton.onclick = undefined; |
| 406 } else if (languageCode in templateData.spellCheckLanguageCodeSet) { |
| 407 // If the language is supported as spell check language, users can |
| 408 // click on the button to change the spell check language. |
| 409 spellCheckLanguageButton.textContent = |
| 410 localStrings.getString('use_this_for_spell_checking'); |
| 411 spellCheckLanguageButton.className = ''; |
| 412 spellCheckLanguageButton.languageCode = languageCode; |
| 413 // Add an event listner to the click event. |
| 414 spellCheckLanguageButton.addEventListener('click', |
| 415 this.handleSpellCheckLanguageButtonClick_.bind(this)); |
| 416 } else if (!languageCode) { |
| 417 display = 'none'; |
| 418 } else { |
| 419 // If the language is not supported as spell check language, the |
| 420 // button just says that this language cannot be used for spell |
| 421 // checking. |
| 422 spellCheckLanguageButton.textContent = |
| 423 localStrings.getString('cannot_be_used_for_spell_checking'); |
| 424 spellCheckLanguageButton.className = 'text-button'; |
| 425 spellCheckLanguageButton.onclick = undefined; |
| 426 } |
| 427 spellCheckLanguageButton.style.display = display; |
| 428 $('language-options-ui-notification-bar').style.display = 'none'; |
| 429 }, |
| 430 |
| 431 /** |
| 432 * Updates the input method list. |
| 433 * @param {string} languageCode Language code (ex. "fr"). |
| 434 * @private |
| 435 */ |
| 436 updateInputMethodList_: function(languageCode) { |
| 437 // Give one of the checkboxes or buttons focus, if it's specified in the |
| 438 // URL hash (ex. focus=mozc). Used for automated testing. |
| 439 var focusInputMethodId = -1; |
| 440 var match = document.location.hash.match(/\bfocus=([\w:-]+)\b/); |
| 441 if (match) { |
| 442 focusInputMethodId = match[1]; |
| 443 } |
| 444 // Change the visibility of the input method list. Input methods that |
| 445 // matches |languageCode| will become visible. |
| 446 var inputMethodList = $('language-options-input-method-list'); |
| 447 var labels = inputMethodList.querySelectorAll('label'); |
| 448 for (var i = 0; i < labels.length; i++) { |
| 449 var label = labels[i]; |
| 450 if (languageCode in label.languageCodeSet) { |
| 451 label.style.display = 'block'; |
| 452 var input = label.childNodes[0]; |
| 453 // Give it focus if the ID matches. |
| 454 if (input.inputMethodId == focusInputMethodId) { |
| 455 input.focus(); |
| 456 } |
| 457 } else { |
| 458 label.style.display = 'none'; |
| 459 } |
| 460 } |
| 461 |
| 462 if (focusInputMethodId == 'add') { |
| 463 $('language-options-add-button').focus(); |
| 464 } |
| 465 }, |
| 466 |
| 467 /** |
| 468 * Updates the language list in the add language overlay. |
| 469 * @param {string} languageCode Language code (ex. "fr"). |
| 470 * @private |
| 471 */ |
| 472 updateLanguageListInAddLanguageOverlay_: function(languageCode) { |
| 473 // Change the visibility of the language list in the add language |
| 474 // overlay. Languages that are already active will become invisible, |
| 475 // so that users don't add the same language twice. |
| 476 var languageOptionsList = $('language-options-list'); |
| 477 var languageCodes = languageOptionsList.getLanguageCodes(); |
| 478 var languageCodeSet = {}; |
| 479 for (var i = 0; i < languageCodes.length; i++) { |
| 480 languageCodeSet[languageCodes[i]] = true; |
| 481 } |
| 482 var addLanguageList = $('add-language-overlay-language-list'); |
| 483 var lis = addLanguageList.querySelectorAll('li'); |
| 484 for (var i = 0; i < lis.length; i++) { |
| 485 // The first child button knows the language code. |
| 486 var button = lis[i].childNodes[0]; |
| 487 if (button.languageCode in languageCodeSet) { |
| 488 lis[i].style.display = 'none'; |
| 489 } else { |
| 490 lis[i].style.display = 'block'; |
| 491 } |
| 492 } |
| 493 }, |
| 494 |
| 495 /** |
| 496 * Handles preloadEnginesPref change. |
| 497 * @param {Event} e Change event. |
| 498 * @private |
| 499 */ |
| 500 handlePreloadEnginesPrefChange_: function(e) { |
| 501 var value = e.value.value; |
| 502 this.preloadEngines_ = this.filterBadPreloadEngines_(value.split(',')); |
| 503 this.updateCheckboxesFromPreloadEngines_(); |
| 504 $('language-options-list').updateDeletable(); |
| 505 }, |
| 506 |
| 507 /** |
| 508 * Handles input method checkbox's click event. |
| 509 * @param {Event} e Click event. |
| 510 * @private |
| 511 */ |
| 512 handleCheckboxClick_ : function(e) { |
| 513 var checkbox = e.target; |
| 514 if (this.preloadEngines_.length == 1 && !checkbox.checked) { |
| 515 // Don't allow disabling the last input method. |
| 516 this.showNotification_( |
| 517 localStrings.getString('please_add_another_input_method'), |
| 518 localStrings.getString('ok_button')); |
| 519 checkbox.checked = true; |
| 520 return; |
| 521 } |
| 522 if (checkbox.checked) { |
| 523 chrome.send('inputMethodEnable', [checkbox.inputMethodId]); |
| 524 } else { |
| 525 chrome.send('inputMethodDisable', [checkbox.inputMethodId]); |
| 526 } |
| 527 this.updatePreloadEnginesFromCheckboxes_(); |
| 528 this.preloadEngines_ = this.sortPreloadEngines_(this.preloadEngines_); |
| 529 this.savePreloadEnginesPref_(); |
| 530 }, |
| 531 |
| 532 /** |
| 533 * Handles add language list's click event. |
| 534 * @param {Event} e Click event. |
| 535 */ |
| 536 handleAddLanguageListClick_ : function(e) { |
| 537 var languageOptionsList = $('language-options-list'); |
| 538 var languageCode = e.target.languageCode; |
| 539 // languageCode can be undefined, if click was made on some random |
| 540 // place in the overlay, rather than a button. Ignore it. |
| 541 if (!languageCode) { |
| 542 return; |
| 543 } |
| 544 languageOptionsList.addLanguage(languageCode); |
| 545 var inputMethodIds = this.languageCodeToInputMethodIdsMap_[languageCode]; |
| 546 // Enable the first input method for the language added. |
| 547 if (inputMethodIds && inputMethodIds[0] && |
| 548 // Don't add the input method it's already present. This can |
| 549 // happen if the same input method is shared among multiple |
| 550 // languages (ex. English US keyboard is used for English US and |
| 551 // Filipino). |
| 552 this.preloadEngines_.indexOf(inputMethodIds[0]) == -1) { |
| 553 this.preloadEngines_.push(inputMethodIds[0]); |
| 554 this.updateCheckboxesFromPreloadEngines_(); |
| 555 this.savePreloadEnginesPref_(); |
| 556 } |
| 557 OptionsPage.closeOverlay(); |
| 558 }, |
| 559 |
| 560 /** |
| 561 * Handles add language dialog ok button. |
| 562 */ |
| 563 handleAddLanguageOkButtonClick_ : function() { |
| 564 var languagesSelect = $('add-language-overlay-language-list'); |
| 565 var selectedIndex = languagesSelect.selectedIndex; |
| 566 if (selectedIndex >= 0) { |
| 567 var selection = languagesSelect.options[selectedIndex]; |
| 568 $('language-options-list').addLanguage(String(selection.value)); |
| 569 OptionsPage.closeOverlay(); |
| 570 } |
| 571 }, |
| 572 |
| 573 /** |
| 574 * Checks if languageCode is deletable or not. |
| 575 * @param {String} languageCode the languageCode to check for deletability. |
| 576 */ |
| 577 languageIsDeletable: function(languageCode) { |
| 578 // Don't allow removing the language if it's as UI language. |
| 579 if (languageCode == templateData.currentUiLanguageCode) |
| 580 return false; |
| 581 return (!cr.isChromeOS || |
| 582 this.canDeleteLanguage_(languageCode)); |
| 583 }, |
| 584 |
| 585 /** |
| 586 * Handles browse.enable_spellchecking change. |
| 587 * @param {Event} e Change event. |
| 588 * @private |
| 589 */ |
| 590 updateEnableSpellCheck_: function() { |
| 591 var value = !$('enable-spell-check').checked; |
| 592 |
| 593 $('language-options-spell-check-language-button').disabled = value; |
| 594 }, |
| 595 |
| 596 /** |
| 597 * Handles spellCheckDictionaryPref change. |
| 598 * @param {Event} e Change event. |
| 599 * @private |
| 600 */ |
| 601 handleSpellCheckDictionaryPrefChange_: function(e) { |
| 602 var languageCode = e.value.value |
| 603 this.spellCheckDictionary_ = languageCode; |
| 604 var languageOptionsList = $('language-options-list'); |
| 605 var selectedLanguageCode = languageOptionsList.getSelectedLanguageCode(); |
| 606 this.updateSpellCheckLanguageButton_(selectedLanguageCode); |
| 607 }, |
| 608 |
| 609 /** |
| 610 * Handles spellCheckLanguageButton click. |
| 611 * @param {Event} e Click event. |
| 612 * @private |
| 613 */ |
| 614 handleSpellCheckLanguageButtonClick_: function(e) { |
| 615 var languageCode = e.target.languageCode; |
| 616 // Save the preference. |
| 617 Preferences.setStringPref(this.spellCheckDictionaryPref, |
| 618 languageCode); |
| 619 chrome.send('spellCheckLanguageChange', [languageCode]); |
| 620 }, |
| 621 |
| 622 /** |
| 623 * Checks whether it's possible to remove the language specified by |
| 624 * languageCode and returns true if possible. This function returns false |
| 625 * if the removal causes the number of preload engines to be zero. |
| 626 * |
| 627 * @param {string} languageCode Language code (ex. "fr"). |
| 628 * @return {boolean} Returns true on success. |
| 629 * @private |
| 630 */ |
| 631 canDeleteLanguage_: function(languageCode) { |
| 632 // First create the set of engines to be removed from input methods |
| 633 // associated with the language code. |
| 634 var enginesToBeRemovedSet = {}; |
| 635 var inputMethodIds = this.languageCodeToInputMethodIdsMap_[languageCode]; |
| 636 for (var i = 0; i < inputMethodIds.length; i++) { |
| 637 enginesToBeRemovedSet[inputMethodIds[i]] = true; |
| 638 } |
| 639 |
| 640 // Then eliminate engines that are also used for other active languages. |
| 641 // For instance, if "xkb:us::eng" is used for both English and Filipino. |
| 642 var languageCodes = $('language-options-list').getLanguageCodes(); |
| 643 for (var i = 0; i < languageCodes.length; i++) { |
| 644 // Skip the target language code. |
| 645 if (languageCodes[i] == languageCode) { |
| 646 continue; |
| 647 } |
| 648 // Check if input methods used in this language are included in |
| 649 // enginesToBeRemovedSet. If so, eliminate these from the set, so |
| 650 // we don't remove this time. |
| 651 var inputMethodIdsForAnotherLanguage = |
| 652 this.languageCodeToInputMethodIdsMap_[languageCodes[i]]; |
| 653 for (var j = 0; j < inputMethodIdsForAnotherLanguage.length; j++) { |
| 654 var inputMethodId = inputMethodIdsForAnotherLanguage[j]; |
| 655 if (inputMethodId in enginesToBeRemovedSet) { |
| 656 delete enginesToBeRemovedSet[inputMethodId]; |
| 657 } |
| 658 } |
| 659 } |
| 660 |
| 661 // Update the preload engine list with the to-be-removed set. |
| 662 var newPreloadEngines = []; |
| 663 for (var i = 0; i < this.preloadEngines_.length; i++) { |
| 664 if (!(this.preloadEngines_[i] in enginesToBeRemovedSet)) { |
| 665 newPreloadEngines.push(this.preloadEngines_[i]); |
| 666 } |
| 667 } |
| 668 // Don't allow this operation if it causes the number of preload |
| 669 // engines to be zero. |
| 670 return (newPreloadEngines.length > 0); |
| 671 }, |
| 672 |
| 673 /** |
| 674 * Saves the preload engines preference. |
| 675 * @private |
| 676 */ |
| 677 savePreloadEnginesPref_: function() { |
| 678 Preferences.setStringPref(this.preloadEnginesPref, |
| 679 this.preloadEngines_.join(',')); |
| 680 }, |
| 681 |
| 682 /** |
| 683 * Updates the checkboxes in the input method list from the preload |
| 684 * engines preference. |
| 685 * @private |
| 686 */ |
| 687 updateCheckboxesFromPreloadEngines_: function() { |
| 688 // Convert the list into a dictonary for simpler lookup. |
| 689 var dictionary = {}; |
| 690 for (var i = 0; i < this.preloadEngines_.length; i++) { |
| 691 dictionary[this.preloadEngines_[i]] = true; |
| 692 } |
| 693 |
| 694 var inputMethodList = $('language-options-input-method-list'); |
| 695 var checkboxes = inputMethodList.querySelectorAll('input'); |
| 696 for (var i = 0; i < checkboxes.length; i++) { |
| 697 checkboxes[i].checked = (checkboxes[i].inputMethodId in dictionary); |
| 698 } |
| 699 }, |
| 700 |
| 701 /** |
| 702 * Updates the preload engines preference from the checkboxes in the |
| 703 * input method list. |
| 704 * @private |
| 705 */ |
| 706 updatePreloadEnginesFromCheckboxes_: function() { |
| 707 this.preloadEngines_ = []; |
| 708 var inputMethodList = $('language-options-input-method-list'); |
| 709 var checkboxes = inputMethodList.querySelectorAll('input'); |
| 710 for (var i = 0; i < checkboxes.length; i++) { |
| 711 if (checkboxes[i].checked) { |
| 712 this.preloadEngines_.push(checkboxes[i].inputMethodId); |
| 713 } |
| 714 } |
| 715 var languageOptionsList = $('language-options-list'); |
| 716 languageOptionsList.updateDeletable(); |
| 717 }, |
| 718 |
| 719 /** |
| 720 * Filters bad preload engines in case bad preload engines are |
| 721 * stored in the preference. Removes duplicates as well. |
| 722 * @param {Array} preloadEngines List of preload engines. |
| 723 * @private |
| 724 */ |
| 725 filterBadPreloadEngines_: function(preloadEngines) { |
| 726 // Convert the list into a dictonary for simpler lookup. |
| 727 var dictionary = {}; |
| 728 for (var i = 0; i < templateData.inputMethodList.length; i++) { |
| 729 dictionary[templateData.inputMethodList[i].id] = true; |
| 730 } |
| 731 |
| 732 var filteredPreloadEngines = []; |
| 733 var seen = {}; |
| 734 for (var i = 0; i < preloadEngines.length; i++) { |
| 735 // Check if the preload engine is present in the |
| 736 // dictionary, and not duplicate. Otherwise, skip it. |
| 737 if (preloadEngines[i] in dictionary && !(preloadEngines[i] in seen)) { |
| 738 filteredPreloadEngines.push(preloadEngines[i]); |
| 739 seen[preloadEngines[i]] = true; |
| 740 } |
| 741 } |
| 742 return filteredPreloadEngines; |
| 743 }, |
| 744 |
| 745 // TODO(kochi): This is an adapted copy from new_tab.js. |
| 746 // If this will go as final UI, refactor this to share the component with |
| 747 // new new tab page. |
| 748 /** |
| 749 * Shows notification |
| 750 * @private |
| 751 */ |
| 752 notificationTimeout_: null, |
| 753 showNotification_ : function(text, actionText, opt_delay) { |
| 754 var notificationElement = $('notification'); |
| 755 var actionLink = notificationElement.querySelector('.link-color'); |
| 756 var delay = opt_delay || 10000; |
| 757 |
| 758 function show() { |
| 759 window.clearTimeout(this.notificationTimeout_); |
| 760 notificationElement.classList.add('show'); |
| 761 document.body.classList.add('notification-shown'); |
| 762 } |
| 763 |
| 764 function hide() { |
| 765 window.clearTimeout(this.notificationTimeout_); |
| 766 notificationElement.classList.remove('show'); |
| 767 document.body.classList.remove('notification-shown'); |
| 768 // Prevent tabbing to the hidden link. |
| 769 actionLink.tabIndex = -1; |
| 770 // Setting tabIndex to -1 only prevents future tabbing to it. If, |
| 771 // however, the user switches window or a tab and then moves back to |
| 772 // this tab the element may gain focus. We therefore make sure that we |
| 773 // blur the element so that the element focus is not restored when |
| 774 // coming back to this window. |
| 775 actionLink.blur(); |
| 776 } |
| 777 |
| 778 function delayedHide() { |
| 779 this.notificationTimeout_ = window.setTimeout(hide, delay); |
| 780 } |
| 781 |
| 782 notificationElement.firstElementChild.textContent = text; |
| 783 actionLink.textContent = actionText; |
| 784 |
| 785 actionLink.onclick = hide; |
| 786 actionLink.onkeydown = function(e) { |
| 787 if (e.keyIdentifier == 'Enter') { |
| 788 hide(); |
| 789 } |
| 790 }; |
| 791 notificationElement.onmouseover = show; |
| 792 notificationElement.onmouseout = delayedHide; |
| 793 actionLink.onfocus = show; |
| 794 actionLink.onblur = delayedHide; |
| 795 // Enable tabbing to the link now that it is shown. |
| 796 actionLink.tabIndex = 0; |
| 797 |
| 798 show(); |
| 799 delayedHide(); |
| 800 } |
| 801 }; |
| 802 |
| 803 /** |
| 804 * Chrome callback for when the UI language preference is saved. |
| 805 */ |
| 806 LanguageOptions.uiLanguageSaved = function() { |
| 807 $('language-options-ui-language-button').style.display = 'none'; |
| 808 $('language-options-ui-notification-bar').style.display = 'block'; |
| 809 }; |
| 810 |
| 811 // Export |
| 812 return { |
| 813 LanguageOptions: LanguageOptions |
| 814 }; |
| 815 }); |
OLD | NEW |