Index: chrome/browser/resources/settings/languages_page/languages.js |
diff --git a/chrome/browser/resources/settings/languages_page/languages.js b/chrome/browser/resources/settings/languages_page/languages.js |
index bedacd7524846abf3e78be9fd8b78c0af980990a..fb15e44b0c08497eea698e38a5e5a8c7e112d90c 100644 |
--- a/chrome/browser/resources/settings/languages_page/languages.js |
+++ b/chrome/browser/resources/settings/languages_page/languages.js |
@@ -9,9 +9,9 @@ |
* Instances of this element have a 'languages' property, which reflects the |
* current language settings. The 'languages' property is read-only, meaning |
* hosts using this element cannot change it directly. Instead, changes to |
- * language settings should be made using this element's public functions. |
+ * language settings should be made using the LanguageHelperImpl singleton. |
* |
- * Use two-way binding syntax to propagate changes from child to host, so that |
+ * Use upward binding syntax to propagate changes from child to host, so that |
* changes made internally to 'languages' propagate to your host element: |
* |
* <template> |
@@ -24,26 +24,7 @@ |
* @element settings-languages |
*/ |
-/** @typedef {{spellCheckEnabled: boolean, translateEnabled: boolean}} */ |
-var LanguageState; |
- |
-/** |
- * @typedef {{language: !chrome.languageSettingsPrivate.Language, |
- * state: !LanguageState}} |
- */ |
-var LanguageInfo; |
- |
-/** |
- * supportedLanguages: an array of languages, ordered alphabetically. |
- * enabledLanguages: an array of enabled language info and state, ordered by |
- * preference. |
- * @typedef {{ |
- * supportedLanguages: !Array<!chrome.languageSettingsPrivate.Language>, |
- * enabledLanguages: !Array<!LanguageInfo>, |
- * translateTarget: string |
- * }} |
- */ |
-var LanguagesModel; |
+var SettingsLanguagesSingletonElement; |
(function() { |
'use strict'; |
@@ -66,130 +47,17 @@ var kTranslateLanguageSynonyms = { |
'jv': 'jw', |
}; |
-/** |
- * This element has a reference to the singleton, exposing the singleton's |
- * language model to the host of this element as the 'languages' property. |
- */ |
-Polymer({ |
- is: 'settings-languages', |
- |
- properties: { |
- /** |
- * Singleton element created at startup which provides the languages model. |
- * @type {!Element} |
- */ |
- singleton_: { |
- type: Object, |
- value: document.createElement('settings-languages-singleton'), |
- }, |
- |
- /** |
- * A reference to the languages model from the singleton, exposed as a |
- * read-only property so hosts can bind to it, but not change it. |
- * @type {LanguagesModel|undefined} |
- */ |
- languages: { |
- type: Object, |
- notify: true, |
- readOnly: true, |
- }, |
- }, |
- |
- ready: function() { |
- // Set the 'languages' property to reference the singleton's model. |
- this._setLanguages(this.singleton_.languages); |
- // Listen for changes to the singleton's languages property, so we know |
- // when to notify hosts of changes to (our reference to) the property. |
- this.listen( |
- this.singleton_, 'languages-changed', 'singletonLanguagesChanged_'); |
- }, |
- |
- /** |
- * Takes changes reported by the singleton and forwards them to the host, |
- * manually sending a change notification for our 'languages' property (since |
- * it's the same object as the singleton's property, but isn't bound by |
- * Polymer). |
- * @private |
- */ |
- singletonLanguagesChanged_: function(e) { |
- // Forward the change notification to the host. |
- this.fire(e.type, e.detail, {bubbles: false}); |
- }, |
- |
- // Forward public methods to the singleton. |
- |
- /** @param {string} languageCode */ |
- setUILanguage: function(languageCode) { |
- if (cr.isWindows || cr.isChromeOS) |
- this.singleton_.setUILanguage(languageCode); |
- }, |
- |
- resetUILanguage: function() { |
- if (cr.isWindows || cr.isChromeOS) |
- this.singleton_.resetUILanguage(); |
- }, |
- |
- /** @return {string} */ |
- getProspectiveUILanguage: function() { |
- return this.singleton_.getProspectiveUILanguage(); |
- }, |
- |
- /** @param {string} languageCode */ |
- enableLanguage: function(languageCode) { |
- this.singleton_.enableLanguage(languageCode); |
- }, |
- |
- /** @param {string} languageCode */ |
- disableLanguage: function(languageCode) { |
- this.singleton_.disableLanguage(languageCode); |
- }, |
- |
- /** @param {string} languageCode */ |
- enableTranslateLanguage: function(languageCode) { |
- this.singleton_.enableTranslateLanguage(languageCode); |
- }, |
- |
- /** @param {string} languageCode */ |
- disableTranslateLanguage: function(languageCode) { |
- this.singleton_.disableTranslateLanguage(languageCode); |
- }, |
- |
- /** |
- * @param {string} languageCode |
- * @return {boolean} |
- */ |
- isEnabled: function(languageCode) { |
- return this.singleton_.isEnabled(languageCode); |
- }, |
- |
- /** |
- * @param {string} languageCode |
- * @param {boolean} enable |
- */ |
- toggleSpellCheck: function(languageCode, enable) { |
- this.singleton_.toggleSpellCheck(languageCode, enable); |
- }, |
- |
- /** |
- * @param {string} languageCode |
- * @return {string} |
- */ |
- convertLanguageCodeForTranslate: function(languageCode) { |
- return this.singleton_.convertLanguageCodeForTranslate(languageCode); |
- }, |
-}); |
- |
var preferredLanguagesPrefName = cr.isChromeOS ? |
'settings.language.preferred_languages' : 'intl.accept_languages'; |
/** |
- * Singleton element created when settings-languages is registered. |
- * Generates the languages model on start-up, and updates it whenever Chrome's |
- * pref store and other settings change. These updates propagate to each |
- * <settings-language> instance so that their 'languages' property updates |
- * like any other Polymer property. |
+ * Singleton element that generates the languages model on start-up and |
+ * updates it whenever Chrome's pref store and other settings change. These |
+ * updates propagate to each <settings-language> instance so that their |
+ * 'languages' property updates like any other Polymer property. |
+ * @implements {LanguageHelper} |
*/ |
-Polymer({ |
+SettingsLanguagesSingletonElement = Polymer({ |
is: 'settings-languages-singleton', |
behaviors: [PrefsBehavior], |
@@ -267,11 +135,68 @@ Polymer({ |
}, |
/** |
+ * Updates the list of enabled languages from the preferred languages pref. |
+ * @private |
+ */ |
+ preferredLanguagesPrefChanged_: function() { |
+ if (!this.initialized_) |
+ return; |
+ |
+ var enabledLanguages = |
+ this.getEnabledLanguages_(this.languages.translateTarget); |
+ |
+ // Reset the enabled language map before updating |
+ // languages.enabledLanguages. |
+ this.enabledLanguageMap_ = {}; |
+ for (var i = 0; i < enabledLanguages.length; i++) { |
+ var languageInfo = enabledLanguages[i]; |
+ this.enabledLanguageMap_[languageInfo.language.code] = languageInfo; |
+ } |
+ this.set('languages.enabledLanguages', enabledLanguages); |
+ }, |
+ |
+ /** |
+ * Updates the spellCheckEnabled state of each enabled language. |
+ * @private |
+ */ |
+ spellCheckDictionariesPrefChanged_: function() { |
+ if (!this.initialized_) |
+ return; |
+ |
+ var spellCheckMap = this.makeMapFromArray_(/** @type {!Array<string>} */( |
+ this.getPref('spellcheck.dictionaries').value)); |
+ for (var i = 0; i < this.languages.enabledLanguages.length; i++) { |
+ var languageCode = this.languages.enabledLanguages[i].language.code; |
+ this.set('languages.enabledLanguages.' + i + '.state.spellCheckEnabled', |
+ !!spellCheckMap[languageCode]); |
+ } |
+ }, |
+ |
+ /** @private */ |
+ translateLanguagesPrefChanged_: function() { |
+ if (!this.initialized_) |
+ return; |
+ |
+ var translateBlockedPref = this.getPref('translate_blocked_languages'); |
+ var translateBlockedMap = this.makeMapFromArray_( |
+ /** @type {!Array<string>} */(translateBlockedPref.value)); |
+ |
+ for (var i = 0; i < this.languages.enabledLanguages.length; i++) { |
+ var translateCode = this.convertLanguageCodeForTranslate( |
+ this.languages.enabledLanguages[i].language.code); |
+ this.set( |
+ 'languages.enabledLanguages.' + i + '.state.translateEnabled', |
+ !translateBlockedMap[translateCode]); |
+ } |
+ }, |
+ |
+ /** |
* Constructs the languages model. |
* @param {!Array<!chrome.languageSettingsPrivate.Language>} |
* supportedLanguages |
* @param {string} translateTarget Language code of the default translate |
* target language. |
+ * @private |
*/ |
createModel_: function(supportedLanguages, translateTarget) { |
// Populate the hash map of supported languages. |
@@ -325,17 +250,19 @@ Polymer({ |
for (var i = 0; i < enabledLanguageCodes.length; i++) { |
var code = enabledLanguageCodes[i]; |
var language = this.supportedLanguageMap_[code]; |
+ // Skip unsupported languages. |
if (!language) |
continue; |
- var state = {}; |
+ var state = /** @type {LanguageState} */({}); |
state.spellCheckEnabled = !!spellCheckMap[code]; |
// Translate is considered disabled if this language maps to any translate |
// language that is blocked. |
var translateCode = this.convertLanguageCodeForTranslate(code); |
- state.translateEnabled = language.supportsTranslate && |
+ state.translateEnabled = !!language.supportsTranslate && |
!translateBlockedMap[translateCode] && |
translateCode != translateTarget; |
- enabledLanguages.push({language: language, state: state}); |
+ enabledLanguages.push(/** @type {LanguageInfo} */( |
+ {language: language, state: state})); |
} |
return enabledLanguages; |
}, |
@@ -344,6 +271,7 @@ Polymer({ |
* Creates an object whose keys are the elements of the list. |
* @param {!Array<string>} list |
* @return {!Object<boolean>} |
+ * @private |
*/ |
makeMapFromArray_: function(list) { |
var map = {}; |
@@ -352,84 +280,21 @@ Polymer({ |
return map; |
}, |
- /** |
- * Updates the list of enabled languages from the preferred languages pref. |
- * @private |
- * */ |
- preferredLanguagesPrefChanged_: function() { |
- if (!this.initialized_) |
- return; |
- |
- var enabledLanguages = |
- this.getEnabledLanguages_(this.languages.translateTarget); |
- // Reset the enabled language map. Do this before notifying of the change |
- // via languages.enabledLanguages. |
- this.enabledLanguageMap_ = {}; |
- for (var i = 0; i < enabledLanguages.length; i++) { |
- var languageInfo = enabledLanguages[i]; |
- this.enabledLanguageMap_[languageInfo.language.code] = languageInfo; |
- } |
- this.set('languages.enabledLanguages', enabledLanguages); |
- }, |
- |
- /** |
- * Updates the spellCheckEnabled state of each enabled language. |
- * @private |
- */ |
- spellCheckDictionariesPrefChanged_: function() { |
- if (!this.initialized_) |
- return; |
- |
- var spellCheckMap = this.makeMapFromArray_(/** @type {!Array<string>} */( |
- this.getPref('spellcheck.dictionaries').value)); |
- for (var i = 0; i < this.languages.enabledLanguages.length; i++) { |
- var languageCode = this.languages.enabledLanguages[i].language.code; |
- this.set('languages.enabledLanguages.' + i + '.state.spellCheckEnabled', |
- !!spellCheckMap[languageCode]); |
- } |
- }, |
- |
- translateLanguagesPrefChanged_: function() { |
- if (!this.initialized_) |
- return; |
- |
- var translateBlockedPref = this.getPref('translate_blocked_languages'); |
- var translateBlockedMap = this.makeMapFromArray_( |
- /** @type {!Array<string>} */(translateBlockedPref.value)); |
- |
- for (var i = 0; i < this.languages.enabledLanguages.length; i++) { |
- var translateCode = this.convertLanguageCodeForTranslate( |
- this.languages.enabledLanguages[i].language.code); |
- this.set( |
- 'languages.enabledLanguages.' + i + '.state.translateEnabled', |
- !translateBlockedMap[translateCode]); |
- } |
- }, |
- |
- /** |
- * Deletes the given item from the pref at the given key if the item is found. |
- * Asserts if the pref itself is not found or is not an Array type. |
- * @param {string} key |
- * @param {*} item |
- */ |
- deletePrefItem_: function(key, item) { |
- assert(this.getPref(key).type == chrome.settingsPrivate.PrefType.LIST); |
- this.arrayDelete('prefs.' + key + '.value', item); |
- }, |
+ // LanguageHelper implementation. |
+ // TODO(michaelpg): replace duplicate docs with @override once b/24294625 |
+ // is fixed. |
+<if expr="chromeos or is_win"> |
/** |
- * Windows and Chrome OS only: Sets the prospective UI language to the chosen |
- * language. This dosen't affect the actual UI language until a restart. |
+ * Sets the prospective UI language to the chosen language. This won't affect |
+ * the actual UI language until a restart. |
* @param {string} languageCode |
*/ |
setUILanguage: function(languageCode) { |
chrome.send('setUILanguage', [languageCode]); |
}, |
- /** |
- * Windows and Chrome OS only: Resets the prospective UI language back to the |
- * actual UI language. |
- */ |
+ /** Resets the prospective UI language back to the actual UI language. */ |
resetUILanguage: function() { |
chrome.send('setUILanguage', [navigator.language]); |
}, |
@@ -439,12 +304,20 @@ Polymer({ |
* restart. If the pref is not set, the current UI language is also the |
* "prospective" language. |
* @return {string} Language code of the prospective UI language. |
- * @private |
*/ |
getProspectiveUILanguage: function() { |
return /** @type {string} */(this.getPref('intl.app_locale').value) || |
navigator.language; |
}, |
+</if> |
+ |
+ /** |
+ * @param {string} languageCode |
+ * @return {boolean} True if the language is enabled. |
+ */ |
+ isLanguageEnabled: function(languageCode) { |
+ return !!this.enabledLanguageMap_[languageCode]; |
+ }, |
/** |
* Enables the language, making it available for spell check and input. |
@@ -471,17 +344,14 @@ Polymer({ |
if (!CrSettingsPrefs.isInitialized) |
return; |
- // Cannot disable the UI language. |
- assert(languageCode != this.getProspectiveUILanguage()); |
- |
- // Cannot disable the only enabled language. |
- var languageCodes = |
- this.getPref(preferredLanguagesPrefName).value.split(','); |
- assert(languageCodes.length > 1); |
+ assert(this.canDisableLanguage(languageCode)); |
// Remove the language from spell check. |
- this.deletePrefItem_('spellcheck.dictionaries', languageCode); |
+ this.arrayDelete('prefs.spellcheck.dictionaries.value', languageCode); |
+ // Remove the language from preferred languages. |
+ var languageCodes = |
+ this.getPref(preferredLanguagesPrefName).value.split(','); |
var languageIndex = languageCodes.indexOf(languageCode); |
if (languageIndex == -1) |
return; |
@@ -491,11 +361,21 @@ Polymer({ |
}, |
/** |
- * @param {string} languageCode |
- * @return {boolean} True if the language is enabled. |
+ * @param {string} languageCode Language code for an enabled language. |
+ * @return {boolean} |
*/ |
- isEnabled: function(languageCode) { |
- return !!this.enabledLanguageMap_[languageCode]; |
+ canDisableLanguage: function(languageCode) { |
+ // Cannot disable the prospective UI language. |
+ if ((cr.isChromeOS || cr.isWindows) && |
+ languageCode == this.getProspectiveUILanguage()) { |
+ return false; |
+ } |
+ |
+ // Cannot disable the only enabled language. |
+ if (this.languages.enabledLanguages.length == 1) |
+ return false; |
+ |
+ return true; |
}, |
/** |
@@ -545,7 +425,6 @@ Polymer({ |
* Accept-Language. |
* @param {string} languageCode |
* @return {string} The converted language code. |
- * @private |
*/ |
convertLanguageCodeForTranslate: function(languageCode) { |
if (languageCode in kLanguageCodeToTranslateCode) |
@@ -562,5 +441,72 @@ Polymer({ |
return main; |
}, |
+ |
+ /** |
+ * @param {string} languageCode |
+ * @return {!chrome.languageSettingsPrivate.Language|undefined} |
+ */ |
+ getLanguage: function(languageCode) { |
+ return this.supportedLanguageMap_[languageCode]; |
+ }, |
}); |
})(); |
+ |
+/** |
+ * A reference to the singleton under the guise of a LanguageHelper |
+ * implementation. This provides a limited API but implies the singleton |
+ * should not be used directly for data binding. |
+ */ |
+var LanguageHelperImpl = SettingsLanguagesSingletonElement; |
+cr.addSingletonGetter(LanguageHelperImpl); |
+ |
+/** |
+ * This element has a reference to the singleton, exposing the singleton's |
+ * |languages| model to the host of this element. |
+ */ |
+Polymer({ |
+ is: 'settings-languages', |
+ |
+ properties: { |
+ /** |
+ * Singleton element created at startup which provides the languages model. |
+ * @type {!SettingsLanguagesSingletonElement} |
+ */ |
+ singleton_: { |
+ type: Object, |
+ value: LanguageHelperImpl.getInstance(), |
+ }, |
+ |
+ /** |
+ * A reference to the languages model from the singleton, exposed as a |
+ * read-only property so hosts can bind to it, but not change it. |
+ * @type {LanguagesModel|undefined} |
+ */ |
+ languages: { |
+ type: Object, |
+ notify: true, |
+ readOnly: true, |
+ }, |
+ }, |
+ |
+ ready: function() { |
+ // Set the 'languages' property to reference the singleton's model. |
+ this._setLanguages(this.singleton_.languages); |
+ // Listen for changes to the singleton's languages property, so we know |
+ // when to notify hosts of changes to (our reference to) the property. |
+ this.listen( |
+ this.singleton_, 'languages-changed', 'singletonLanguagesChanged_'); |
+ }, |
+ |
+ /** |
+ * Takes changes reported by the singleton and forwards them to the host, |
+ * manually sending a change notification for our 'languages' property (since |
+ * it's the same object as the singleton's property, but isn't bound by |
+ * Polymer). |
+ * @private |
+ */ |
+ singletonLanguagesChanged_: function(e) { |
+ // Forward the change notification to the host. |
+ this.fire(e.type, e.detail, {bubbles: false}); |
+ }, |
+}); |