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