| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @fileoverview 'cr-settings-languages-model' provides convenient access to |
| 7 * Chrome's language and input method settings. |
| 8 * |
| 9 * @group Chrome Settings Elements |
| 10 * @element cr-settings-languages-model |
| 11 */ |
| 12 |
| 13 /** |
| 14 * @typedef {{spellCheckEnabled: boolean}} |
| 15 */ |
| 16 var LanguageState; |
| 17 |
| 18 /** |
| 19 * @typedef {{language: !chrome.languageSettingsPrivate.Language, |
| 20 * state: !LanguageState}} |
| 21 */ |
| 22 var LanguageInfo; |
| 23 |
| 24 /** |
| 25 * The model includes: |
| 26 * supportedLanguages: an array of languages, ordered alphabetically. |
| 27 * enabledLanguages: an array of enabled language info and state, ordered by |
| 28 * preference. |
| 29 * As well as hash map equivalents: supportedLanguageMap, enabledLanguageMap. |
| 30 * @typedef {{ |
| 31 * supportedLanguages: !Array<!chrome.languageSettingsPrivate.Language>, |
| 32 * supportedLanguageMap: !Object<!chrome.languageSettingsPrivate.Language>, |
| 33 * enabledLanguages: !Array<!LanguageInfo>, |
| 34 * enabledLanguageMap: !Object<!LanguageInfo> |
| 35 * }} |
| 36 */ |
| 37 var LanguagesModel; |
| 38 |
| 39 (function() { |
| 40 'use strict'; |
| 41 |
| 42 /** Exposes the singleton model to hosts. */ |
| 43 Polymer({ |
| 44 is: 'cr-settings-languages-model', |
| 45 |
| 46 properties: { |
| 47 /** |
| 48 * Shared languages model. |
| 49 * @type {(LanguagesModel|undefined)} |
| 50 */ |
| 51 model: { |
| 52 type: Object, |
| 53 notify: true, |
| 54 readOnly: true, |
| 55 }, |
| 56 |
| 57 /** |
| 58 * Shared private state. |
| 59 * @type {!Element} |
| 60 */ |
| 61 privateModel_: { |
| 62 type: Object, |
| 63 value: document.createElement('cr-settings-languages-model-private'), |
| 64 }, |
| 65 }, |
| 66 |
| 67 ready: function() { |
| 68 this.squelching_(function() { |
| 69 // This notifies the host via Polymer. |
| 70 this._setModel(this.privateModel_.model); |
| 71 }); |
| 72 this.listen(this.privateModel_, 'model-changed', 'privateModelChanged_'); |
| 73 }, |
| 74 |
| 75 /** |
| 76 * On supported systems, sets the prospective UI language to the chosen |
| 77 * language. This dosen't affect the actual UI language until a restart. |
| 78 * @param {string} languageCode |
| 79 */ |
| 80 setUILanguage: function(languageCode) { |
| 81 this.privateModel_.setUILanguage(languageCode); |
| 82 }, |
| 83 |
| 84 /** |
| 85 * Enables the language, making it available for spell check and input. |
| 86 * @param {string} languageCode |
| 87 * */ |
| 88 enableLanguage: function(languageCode) { |
| 89 this.privateModel_.enableLanguage(languageCode); |
| 90 }, |
| 91 |
| 92 /** |
| 93 * Disables the language. |
| 94 * @param {string} languageCode |
| 95 */ |
| 96 disableLanguage: function(languageCode) { |
| 97 this.privateModel_.disableLanguage(languageCode); |
| 98 }, |
| 99 |
| 100 /** |
| 101 * Enables or disables spell check for the given language. |
| 102 * @param {string} languageCode |
| 103 * @param {boolean} enable |
| 104 */ |
| 105 toggleSpellCheck: function(languageCode, enable) { |
| 106 this.privateModel_.toggleSpellCheck(languageCode, enable); |
| 107 }, |
| 108 |
| 109 /** |
| 110 * Forwards changes reported by privateModel_ to the host. |
| 111 * @private |
| 112 */ |
| 113 privateModelChanged_: function(e) { |
| 114 // Squelch because we've defeated Polymer's internal dirty-checking. |
| 115 this.squelching_(function() { |
| 116 // Forward notification to host. |
| 117 this.fire(e.type, e.detail, {bubbles: false}); |
| 118 }); |
| 119 }, |
| 120 |
| 121 /** |
| 122 * Sets a "squelch" switch before calling the function, so functions can |
| 123 * return early when the switch is active. |
| 124 * @param {!function()} fn |
| 125 * @private |
| 126 */ |
| 127 squelching_: function(fn) { |
| 128 this.squelch_ = true; |
| 129 fn.call(this); |
| 130 // We can unset squelch_ now because change notifications are synchronous. |
| 131 this.squelch_ = false; |
| 132 }, |
| 133 }); |
| 134 |
| 135 var preferredLanguagesPath; |
| 136 if (cr.isChromeOS) |
| 137 preferredLanguagesPath = 'prefs.settings.language.preferred_languages.value'; |
| 138 else |
| 139 preferredLanguagesPath = 'prefs.intl.accept_languages.value'; |
| 140 |
| 141 /** |
| 142 * Privately used element that contains, listens to and updates the shared |
| 143 * languages model. |
| 144 */ |
| 145 Polymer({ |
| 146 is: 'cr-settings-languages-model-private', |
| 147 |
| 148 properties: { |
| 149 /** |
| 150 * @type {(LanguagesModel|undefined)} |
| 151 */ |
| 152 model: { |
| 153 type: Object, |
| 154 notify: true, |
| 155 }, |
| 156 |
| 157 /** |
| 158 * Object containing all preferences, for use by Polymer controls. |
| 159 */ |
| 160 prefs: { |
| 161 type: Object, |
| 162 notify: true, |
| 163 }, |
| 164 }, |
| 165 |
| 166 observers: [ |
| 167 'preferredLanguagesPrefChanged_(' + preferredLanguagesPath + ')', |
| 168 'spellCheckDictionariesPrefChanged_(prefs.spellcheck.dictionaries.value.*)', |
| 169 ], |
| 170 |
| 171 /** @override */ |
| 172 created: function() { |
| 173 chrome.languageSettingsPrivate.getLanguageList(function(languageList) { |
| 174 // Wait until prefs are initialized before creating the model, so we can |
| 175 // include information about enabled languages. |
| 176 CrSettingsPrefs.initialized.then(function() { |
| 177 this.createModel_(languageList); |
| 178 this.initialized_ = true; |
| 179 }.bind(this)); |
| 180 }.bind(this)); |
| 181 }, |
| 182 |
| 183 /** |
| 184 * Constructs the model with the given language list. |
| 185 * @param {!Array<!chrome.languageSettingsPrivate.Language>} |
| 186 * supportedLanguages |
| 187 */ |
| 188 createModel_: function(supportedLanguages) { |
| 189 // Create a hash table of supported languages. |
| 190 var supportedLanguageMap = {}; |
| 191 for (var i = 0; i < supportedLanguages.length; i++) |
| 192 supportedLanguageMap[supportedLanguages[i].code] = supportedLanguages[i]; |
| 193 |
| 194 // Create a list and map of enabled language info. |
| 195 var enabledLanguages = this.getEnabledLanguages_(supportedLanguageMap); |
| 196 var enabledLanguageMap = {}; |
| 197 for (var i = 0; i < enabledLanguages.length; i++) { |
| 198 var languageInfo = enabledLanguages[i]; |
| 199 enabledLanguageMap[languageInfo.language.code] = languageInfo; |
| 200 } |
| 201 |
| 202 // Initialize the Polymer model. |
| 203 this.model = { |
| 204 supportedLanguages: supportedLanguages, |
| 205 supportedLanguageMap: supportedLanguageMap, |
| 206 enabledLanguages: enabledLanguages, |
| 207 enabledLanguageMap: enabledLanguageMap, |
| 208 }; |
| 209 }, |
| 210 |
| 211 /** |
| 212 * Returns a list of LanguageInfos for each enabled language in the supported |
| 213 * languages list. |
| 214 * @private |
| 215 * @param {!Object<!chrome.languageSettingsPrivate.Language>} |
| 216 * supportedLanguageMap |
| 217 * @return {!Array<!LanguageInfo>} |
| 218 */ |
| 219 getEnabledLanguages_: function(supportedLanguageMap) { |
| 220 var languageCodes = this.get(preferredLanguagesPath).split(','); |
| 221 var enabledLanguages = []; |
| 222 var spellCheckMap = this.getSpellCheckMap_(); |
| 223 for (var i = 0; i < languageCodes.length; i++) { |
| 224 var code = languageCodes[i]; |
| 225 var language = supportedLanguageMap[code]; |
| 226 if (!language) |
| 227 continue; |
| 228 var state = {spellCheckEnabled: !!spellCheckMap[code]}; |
| 229 enabledLanguages.push({language: language, state: state}); |
| 230 } |
| 231 return enabledLanguages; |
| 232 }, |
| 233 |
| 234 /** |
| 235 * Creates a map whose keys are languages enabled for spell check. |
| 236 * @return {!Object<boolean>} |
| 237 */ |
| 238 getSpellCheckMap_: function() { |
| 239 var spellCheckPref = /** @type {chrome.settingsPrivate.PrefObject} */( |
| 240 this.get('prefs.spellcheck.dictionaries')); |
| 241 var spellCheckCodes = spellCheckPref.value; |
| 242 var spellCheckMap = {}; |
| 243 for (var i = 0; i < spellCheckCodes.length; i++) |
| 244 spellCheckMap[spellCheckCodes[i]] = true; |
| 245 return spellCheckMap; |
| 246 }, |
| 247 |
| 248 /** @private */ |
| 249 preferredLanguagesPrefChanged_: function() { |
| 250 if (!this.initialized_) |
| 251 return; |
| 252 |
| 253 var enabledLanguages = |
| 254 this.getEnabledLanguages_(this.model.supportedLanguageMap); |
| 255 this.set('model.enabledLanguages', enabledLanguages); |
| 256 var enabledLanguageMap = {}; |
| 257 for (var i = 0; i < enabledLanguages.length; i++) { |
| 258 var languageInfo = enabledLanguages[i]; |
| 259 enabledLanguageMap[languageInfo.language.code] = languageInfo; |
| 260 } |
| 261 this.set('model.enabledLanguageMap', enabledLanguageMap); |
| 262 }, |
| 263 |
| 264 /** |
| 265 * Updates the spellCheckEnabled state of each enabled language. |
| 266 * @private |
| 267 */ |
| 268 spellCheckDictionariesPrefChanged_: function() { |
| 269 if (!this.initialized_) |
| 270 return; |
| 271 |
| 272 var spellCheckMap = this.getSpellCheckMap_(); |
| 273 for (var i = 0; i < this.model.enabledLanguages.length; i++) { |
| 274 this.set('model.enabledLanguages.' + i + '.state.spellCheckEnabled', |
| 275 !!spellCheckMap[this.model.enabledLanguages[i].language.code]); |
| 276 } |
| 277 }, |
| 278 |
| 279 /** |
| 280 * On supported systems, sets the prospective UI language to the chosen |
| 281 * language. This dosen't affect the actual UI language until a restart. |
| 282 * @param {string} languageCode |
| 283 */ |
| 284 setUILanguage: function(languageCode) { |
| 285 // Set the prospective UI language. This won't take effect until a restart. |
| 286 if (cr.isWindows) |
| 287 this.set('prefs.intl.app_locale.value', languageCode); |
| 288 else if (cr.isChromeOS) |
| 289 chrome.send('setUILanguage', [languageCode]); |
| 290 }, |
| 291 |
| 292 /** |
| 293 * Enables the language, making it available for spell check and input. |
| 294 * @param {string} languageCode |
| 295 */ |
| 296 enableLanguage: function(languageCode) { |
| 297 var languageCodes = this.get(preferredLanguagesPath); |
| 298 var index = languageCodes.split(',').indexOf(languageCode); |
| 299 if (index > -1) |
| 300 return; |
| 301 this.set(preferredLanguagesPath, languageCodes + ',' + languageCode); |
| 302 }, |
| 303 |
| 304 /** |
| 305 * Disables the language. |
| 306 * @param {string} languageCode |
| 307 */ |
| 308 disableLanguage: function(languageCode) { |
| 309 // Don't disable the UI language. |
| 310 var appLocale = this.get('prefs.intl.app_locale.value') || |
| 311 navigator.language; |
| 312 if (languageCode == appLocale) |
| 313 return; |
| 314 |
| 315 var languageCodes = this.get(preferredLanguagesPath).split(','); |
| 316 // Don't disable the only enabled language. |
| 317 if (languageCodes.length == 1) |
| 318 return; |
| 319 |
| 320 // Remove the language from spell check. |
| 321 var spellCheckIndex = |
| 322 this.get('prefs.spellcheck.dictionaries.value').indexOf(languageCode); |
| 323 if (spellCheckIndex != -1) |
| 324 this.splice('prefs.spellcheck.dictionaries.value', spellCheckIndex, 1); |
| 325 |
| 326 var languageIndex = languageCodes.indexOf(languageCode); |
| 327 if (languageIndex == -1) |
| 328 return; |
| 329 languageCodes.splice(languageIndex, 1); |
| 330 this.set(preferredLanguagesPath, languageCodes.join(',')); |
| 331 }, |
| 332 |
| 333 /** |
| 334 * Enables or disables spell check for the given language. |
| 335 * @param {string} languageCode |
| 336 * @param {boolean} enable |
| 337 */ |
| 338 toggleSpellCheck: function(languageCode, enable) { |
| 339 var spellCheckPref = /** @type {chrome.settingsPrivate.PrefObject} */( |
| 340 this.get('prefs.spellcheck.dictionaries')); |
| 341 if (enable) { |
| 342 if (spellCheckPref.value.indexOf(languageCode) == -1) |
| 343 this.push('prefs.spellcheck.dictionaries.value', languageCode); |
| 344 } else { |
| 345 // TODO: need update externs before committing |
| 346 this.arrayDelete('prefs.spellcheck.dictionaries.value', languageCode); |
| 347 } |
| 348 }, |
| 349 }); |
| 350 })(); |
| OLD | NEW |