Commit 8f3a9c04 authored by Jing Wang's avatar Jing Wang Committed by Commit Bot

Implement the new options page for US English and Pinyin.

The feature is behind the flag imeOptionsInSettings.

Now we have real data displayed in these two options pages, and changing
the options there will actually change values in prefs.

US English and Pinyin are two representative input methods, so I first
implement their pages. Add other pages should be easy after these two
are done.

Screenshots of the implemented UI:
US English: https://screenshot.googleplex.com/eZNEF5mjste
Pinyin: https://screenshot.googleplex.com/X0aDrc8SkiE

Test: tested with Chrome on Linux
Bug: 1086786
Change-Id: I083369526805c15f73049b23ce07edce76fe246e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2228439
Commit-Queue: Jing Wang <jiwan@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarRegan Hsu <hsuregan@chromium.org>
Reviewed-by: default avatarDarren Shen <shend@chromium.org>
Cr-Commit-Position: refs/heads/master@{#781683}
parent aafc290f
......@@ -297,6 +297,80 @@
Show emoji suggestions
</message>
<!-- Input Method Options Section -->
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_BASIC" desc="The label for the section in input method options page containing basic options.">
Basics
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_ADVANCED" desc="The label for the section in input method options page containing advanced options.">
Advanced
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PHYSICAL_KEYBOARD" desc="The label for the section in input method options page containing physical keyboard options.">
Physical keyboard
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_VIRTUAL_KEYBOARD" desc="The label for the section in input method options page containing the virtual keyboard options.">
On-screen keyboard
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_DOUBLE_SPACE_PERIOD" desc="The label for the input method option to enable double-space to type period (when an user types two consecutive space, it outputs a period).">
Double-space to type period
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_GESTURE_TYPING" desc="The label for the input method option to enable gesture typing.">
Enable glide typing
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_PREDICTION" desc="The label for the input method option to enable next-word prediction.">
Enable next-word prediction
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_SOUND_ON_KEYPRESS" desc="The label for the input method option to enable sound on keypress.">
Sound on keypress
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_CAPITALIZATION" desc="The label for the input method option to enable auto-capitalization.">
Auto-capitalization
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION" desc="The label for the input method option to enable auto correction.">
Auto-correction
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_XKB_LAYOUT" desc="The label for the input method option to let the users choose their keyboard layout.">
Keyboard layout
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_EDIT_USER_DICT" desc="The label for the input method option to let the users edit their personal dictionary.">
Edit dictionary entries
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_CHINESE_PUNCTUATION" desc="The label for the pinyin input method option for whether to output full-width or half-with punctuation.">
Initial punctuation width is Full
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_DEFAULT_CHINESE" desc="The label for the pinyin input method option for whether to use Chinese or English as the default input language.">
Initial input language is Chinese
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_ENABLE_FUZZY" desc="The label for the pinyin input method option to enable fuzzy-pinyin.">
Enable Fuzzy-Pinyin mode
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_ENABLE_LOWER_PAGING" desc="The label for the pinyin input method option for whether to use , and . for paging candidates.">
Use <ph name="COMMA">,</ph> and <ph name="PERIOD">.</ph> keys to page a candidate list
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_ENABLE_UPPER_PAGING" desc="The label for the pinyin input method option for whether to use - and = for paging candidates.">
Use <ph name="MINUS">-</ph> and <ph name="EQUAL">=</ph> keys to page a candidate list
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_FULL_WIDTH_CHARACTER" desc="The label for the pinyin input method option for whether to output latin letters and numbers as full-width or half-width character.">
Initial character width is Full
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION_OFF" desc="The label for the choice to disable auto correction.">
Off
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION_MODEST" desc="The label for the choice to use modest auto correction.">
Modest
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION_AGGRESSIVE" desc="The label for the choice to use aggressive auto correction.">
Aggressive
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_US" desc="The label for the choice to use US keyboard.">
US
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_DVORAK" desc="The label for the choice to use Dvorak keyboard.">
Dvorak
</message>
<message name="IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_COLEMAK" desc="The label for the choice to use Colemak keyboard.">
Colemak
</message>
<!-- Device Page (OS Settings) -->
<message name="IDS_OS_SETTINGS_TOUCHPAD_REVERSE_SCROLL_LABEL">
Reverse scrolling <ph name="LINK_BEGIN">&lt;a&gt;</ph>Learn more<ph name="LINK_END">&lt;/a&gt;</ph>
......
ee85ca17888d54eece9a0f809c8a9b5be4638782
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
b501bb176acbd1deeb4d565a43cd78fd36ee5482
\ No newline at end of file
ee85ca17888d54eece9a0f809c8a9b5be4638782
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
104cd0b81cf6003e041e74f3a9ff0d2b43b05c32
\ No newline at end of file
104cd0b81cf6003e041e74f3a9ff0d2b43b05c32
\ No newline at end of file
104cd0b81cf6003e041e74f3a9ff0d2b43b05c32
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
ee85ca17888d54eece9a0f809c8a9b5be4638782
\ No newline at end of file
3290ac8ed6a6047da26beb2a8a2a31c1d89241ac
\ No newline at end of file
ee85ca17888d54eece9a0f809c8a9b5be4638782
\ No newline at end of file
......@@ -292,6 +292,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetWhitelistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_whitelist)[chromeos::prefs::kEmojiSuggestionEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_whitelist)[::prefs::kLanguageInputMethodSpecificSettings] =
settings_api::PrefType::PREF_TYPE_DICTIONARY;
#endif
// Nearby Share.
......
......@@ -3,10 +3,13 @@
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
import("//ui/webui/resources/tools/js_modulizer.gni")
import("../os_settings.gni")
js_type_check("closure_compile") {
deps = [
":input_method_options_page",
":input_method_util",
":manage_input_methods_page",
":os_add_languages_dialog",
":os_languages_page",
......@@ -19,11 +22,18 @@ js_type_check("closure_compile") {
js_library("input_method_options_page") {
deps = [
":input_method_util",
"../..:router",
"../../languages_page:languages_types",
"../../prefs",
"//ui/webui/resources/js:i18n_behavior",
]
}
js_library("input_method_util") {
deps = [ "//ui/webui/resources/js:cr" ]
}
js_library("manage_input_methods_page") {
deps = [
"../../languages_page:languages_types",
......@@ -52,6 +62,7 @@ js_library("os_languages_section") {
js_library("os_languages_page") {
deps = [
":input_method_util",
"..:metrics_recorder",
"..:os_route",
"../..:lifetime_browser_proxy",
......@@ -83,6 +94,7 @@ js_library("os_add_languages_dialog") {
# is_polymer3 = true
# deps = [
# ":input_method_options_page.m",
# ":input_method_util.m",
# ":manage_input_methods_page.m",
# ":os_add_languages_dialog.m",
# ":os_languages_page.m",
......@@ -90,6 +102,14 @@ js_library("os_add_languages_dialog") {
# ]
#}
js_library("input_method_util.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_util.m.js" ]
deps = [
# TODO: Fill those in.
]
extra_deps = [ ":modulize" ]
}
js_library("input_method_options_page.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_languages_page/input_method_options_page.m.js" ]
deps = [
......@@ -136,6 +156,7 @@ group("polymer3_elements") {
public_deps = [
":input_method_options_page_module",
":manage_input_methods_page_module",
":modulize",
":os_add_languages_dialog_module",
":os_languages_page_module",
":os_languages_section_module",
......@@ -171,3 +192,8 @@ polymer_modulizer("input_method_options_page") {
html_file = "input_method_options_page.html"
html_type = "dom-module"
}
js_modulizer("modulize") {
input_files = [ "input_method_util.js" ]
namespace_rewrites = os_settings_namespace_rewrites
}
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="../../controls/settings_toggle_button.html">
<link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="input_method_util.html">
<link rel="import" href="../../settings_shared_css.html">
<link rel="import" href="../../prefs/prefs_behavior.html">
<dom-module id="settings-input-method-options-page">
<template>
<style include="settings-shared">
<style include="settings-shared md-select">
h2 {
padding-inline-start: var(--cr-section-padding);
}
</style>
<div route-path="default">
<h2>Physical keyboard (TODO: i18n)</h2>
<div class="list-frame vertical-list">
<settings-toggle-button class="list-item"
label="Auto-capitalization (TODO: i18n)">
</settings-toggle-button>
</div>
<h2>On-screen keyboard (TODO: i18n)</h2>
<div class="list-frame vertical-list">
<settings-toggle-button class="list-item"
label="Auto-capitalization (TODO: i18n)">
</settings-toggle-button>
</div>
<template is="dom-repeat" items="[[optionSections_]]" as="section">
<h2>[[section.title]]</h2>
<div class="list-frame">
<template is="dom-repeat" items="[[section.options]]" as="option">
<div class="list-item" actionable>
<div class="start" id="option-label" aria-hidden="true">
[[option.label]]
</div>
<template is="dom-if" if="[[isToggleButton_(option.uiType)]]">
<cr-toggle checked="{{option.value}}"
on-click="onToggleButtonOrDropdownChange_"
aria-labelledby="option-label">
</cr-toggle>
</template>
<template is="dom-if" if="[[isDropdown_(option.uiType)]]">
<select class="md-select" value="{{option.value::change}}"
on-change="onToggleButtonOrDropdownChange_"
aria-labelledby="option-label">
<template is="dom-repeat" items="[[option.menuItems]]">
<option selected="[[item.selected]]" value="[[item.value]]">
[[item.label]]
</option>
</template>
</select>
</template>
<template is="dom-if" if="[[isLink_(option.uiType)]]">
<cr-icon-button class="icon-external"
on-click="onExternalLinkClick_"
aria-labelledby="option-label">
</cr-icon-button>
</template>
</div>
</template>
</div>
</template>
</div>
</template>
<script src="input_method_options_page.js"></script>
......
......@@ -6,11 +6,12 @@
* @fileoverview 'settings-input-method-options-page' is the settings sub-page
* to allow users to change options for each input method.
*/
Polymer({
is: 'settings-input-method-options-page',
behaviors: [
I18nBehavior,
PrefsBehavior,
settings.RouteObserverBehavior,
],
......@@ -18,13 +19,42 @@ Polymer({
/** @type {!LanguageHelper} */
languageHelper: Object,
/** Preferences state. */
prefs: {
type: Object,
notify: true,
},
/**
* Input method ID.
* @private
*/
id_: String,
/**
* Input method engine ID.
* @private
*/
engineId_: String,
/**
* The content to be displayed in the page, auto generated every time when
* the user enters the page.
* @private {!Array<!{title: string, options:!Array<!Object<string, *>>}>}
*/
optionSections_: {
type: Array,
value: [],
},
},
/**
* The root path of input method options in Prefs.
* @const {string}
* @private
*/
PREFS_PATH: 'settings.language.input_method_specific_settings',
/**
* settings.RouteObserverBehavior
* @param {!settings.Route} route
......@@ -35,6 +65,7 @@ Polymer({
if (route != settings.routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS) {
this.id_ = '';
this.parentNode.pageTitle = '';
this.optionSections_ = [];
return;
}
......@@ -42,5 +73,168 @@ Polymer({
this.id_ = queryParams.get('id') || '';
this.parentNode.pageTitle =
this.languageHelper.getInputMethodDisplayName(this.id_);
this.engineId_ =
settings.input_method_util.getFirstPartyInputMethodEngineId(this.id_);
this.populateOptionSections_();
},
/**
* Get menu items for an option, and enrich the items with selected status and
* i18n label.
* @param {settings.input_method_util.OptionType} name
* @param {*} value
*/
getMenuItems(name, value) {
return settings.input_method_util.getOptionMenuItems(name).map(menuItem => {
menuItem['selected'] = menuItem['value'] === value;
menuItem['label'] = this.i18n(menuItem['name']);
return menuItem;
});
},
/**
* Generate the sections of options according to the engine ID and Prefs.
* @private
*/
populateOptionSections_() {
const options = settings.input_method_util.generateOptions(this.engineId_);
const prefValue = this.getPref(this.PREFS_PATH).value;
const prefix = this.getPrefsPrefix_();
const currentSettings = prefix in prefValue ? prefValue[prefix] : {};
const makeOption = (name) => {
const uiType = settings.input_method_util.getOptionUiType(name);
const value = name in currentSettings ?
currentSettings[name] :
settings.input_method_util.OPTION_DEFAULT[name];
return {
name: name,
uiType: uiType,
value: value,
label: this.i18n(settings.input_method_util.getOptionLabelName(name)),
menuItems: this.getMenuItems(name, value),
url: settings.input_method_util.getOptionUrl(name),
};
};
// If there is no option name in a section, this section, including the
// section title, should not be displayed.
this.optionSections_ =
options.filter(section => section.optionNames.length > 0)
.map(section => {
return {
title: this.getSectionTitleI18n_(section.title),
options: section.optionNames.map(makeOption),
};
});
},
/**
* @return {string} Prefs prefix for the current engine ID, which is usually
* just the engine ID itself, but pinyin and zhuyin are special for legacy
* compatibility reason.
* @private
*/
getPrefsPrefix_() {
if (this.engineId_ ===
settings.input_method_util.InputToolCode.PINYIN_CHINESE_SIMPLIFIED) {
return 'pinyin';
} else if (
this.engineId_ ===
settings.input_method_util.InputToolCode.ZHUYIN_CHINESE_TRADITIONAL) {
return 'zhuyin';
}
return this.engineId_;
},
/**
* Handler for toggle button and dropdown change. Update the value of the
* changing option in Cros prefs.
* @param {!{model: !{option: Object}}} e
* @private
*/
onToggleButtonOrDropdownChange_(e) {
// Get the existing settings dictionary, in order to update it later.
// |PrefsBehavior.setPrefValue| will update Cros Prefs only if the reference
// of variable has changed, so we need to copy the current content into a
// new variable.
const updatedSettings = {};
Object.assign(updatedSettings, this.getPref(this.PREFS_PATH)['value']);
const prefix = this.getPrefsPrefix_();
if (!(prefix in updatedSettings)) {
updatedSettings[prefix] = {};
}
// The value of dropdown is not updated immediately when the event is fired.
// Wait for the polymer state to update to make sure we write the latest
// to Cros Prefs.
Polymer.RenderStatus.afterNextRender(this, () => {
let newValue = e.model.option.value;
// The value of dropdown in html is always string, but some of the prefs
// values are used as integer or enum by IME, so we need to store numbers
// for them to function correctly.
if (settings.input_method_util.isNumberValue(e.model.option.name)) {
newValue = parseInt(newValue, 10);
}
updatedSettings[prefix][e.model.option.name] = newValue;
this.setPrefValue(this.PREFS_PATH, updatedSettings);
});
},
/**
* Opens external link in Chrome.
* @param {!{model: !{option: !{url: string}}}} e
* @private
*/
onExternalLinkClick_(e) {
window.open(e.model.option.url);
},
/**
* @param {string} section the name of the section.
* @return {string} the i18n string for the section title.
* @private
*/
getSectionTitleI18n_(section) {
switch (section) {
case 'basic':
return this.i18n('inputMethodOptionsBasicSectionTitle');
case 'advanced':
return this.i18n('inputMethodOptionsAdvancedSectionTitle');
case 'physicalKeyboard':
return this.i18n('inputMethodOptionsPhysicalKeyboardSectionTitle');
case 'virtualKeyboard':
return this.i18n('inputMethodOptionsVirtualKeyboardSectionTitle');
default:
assertNotReached();
}
},
/**
* @param {!settings.input_method_util.UiType} item
* @return {boolean} true if |item| is a toggle button.
* @private
*/
isToggleButton_(item) {
return item === settings.input_method_util.UiType.TOGGLE_BUTTON;
},
/**
* @param {!settings.input_method_util.UiType} item
* @return {boolean} true if |item| is a dropdown.
* @private
*/
isDropdown_(item) {
return item === settings.input_method_util.UiType.DROPDOWN;
},
/**
* @param {!settings.input_method_util.UiType} item
* @return {boolean} true if |item| is an external link.
* @private
*/
isLink_(item) {
return item === settings.input_method_util.UiType.LINK;
},
});
<link rel="import" href="chrome://resources/html/cr.html">
<script src="input_method_util.js"></script>
......@@ -17,6 +17,7 @@
<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="input_method_util.html">
<link rel="import" href="os_add_languages_dialog.html">
<link rel="import" href="../localized_link/localized_link.html">
<link rel="import" href="../../controls/controlled_radio_button.html">
......@@ -216,17 +217,18 @@
$i18n{inputMethodEnabled}
</div>
</div>
<template is="dom-if" if="[[imeOptionsInSettings_]]">
<template is="dom-if" if="[[hasOptionsPageInSettings_(item.id)]]">
<div class="internal-wrapper" hidden="[[!item.hasOptionsPage]]">
<cr-icon-button class="subpage-arrow"
on-click="onInputMethodOptionsTap_"></cr-icon-button>
on-click="navigateToOptionsPageInSettings_">
</cr-icon-button>
</div>
</template>
<template is="dom-if" if="[[!imeOptionsInSettings_]]">
<template is="dom-if" if="[[!hasOptionsPageInSettings_(item.id)]]">
<div class="external-wrapper" hidden="[[!item.hasOptionsPage]]">
<div class="separator"></div>
<cr-icon-button class="icon-external"
on-click="onInputMethodOptionsTap_"></cr-icon-button>
on-click="openExtensionOptionsPage_"></cr-icon-button>
</div>
</template>
</div>
......
......@@ -66,14 +66,6 @@ cr.define('settings', function() {
return loadTimeData.getBoolean('isGuest');
},
},
/** @private */
imeOptionsInSettings_: {
type: Boolean,
value() {
return loadTimeData.getBoolean('imeOptionsInSettings');
},
}
},
/** @private {boolean} */
......@@ -225,15 +217,32 @@ cr.define('settings', function() {
* @param {!{model: !{item: chrome.languageSettingsPrivate.InputMethod}}} e
* @private
*/
onInputMethodOptionsTap_(e) {
if (this.imeOptionsInSettings_) {
const params = new URLSearchParams;
params.append('id', e.model.item.id);
settings.Router.getInstance().navigateTo(
settings.routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS, params);
} else {
this.languageHelper.openInputMethodOptions(e.model.item.id);
}
openExtensionOptionsPage_(e) {
this.languageHelper.openInputMethodOptions(e.model.item.id);
},
/**
* @param {string} id Input method ID.
* @return {boolean} True if there is a options page in ChromeOS settings
* for the input method ID.
* @private
*/
hasOptionsPageInSettings_(id) {
return loadTimeData.getBoolean('imeOptionsInSettings') &&
settings.input_method_util.hasOptionsPageInSettings(id);
},
/**
* Navigate to the input method options page in ChromeOS settings.
* @param {!{model: !{item: chrome.languageSettingsPrivate.InputMethod}}} e
* @private
*/
navigateToOptionsPageInSettings_(e) {
const params = new URLSearchParams;
params.append('id', e.model.item.id);
settings.Router.getInstance().navigateTo(
settings.routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS, params);
},
/**
......
......@@ -93,7 +93,8 @@
<settings-subpage
associated-control="[[$$('#languagesSubpageTrigger')]]">
<settings-input-method-options-page
language-helper="[[languageHelper]]">
language-helper="[[languageHelper]]"
prefs="{{prefs}}">
</settings-input-method-options-page>
</settings-subpage>
</template>
......
......@@ -659,6 +659,12 @@
<structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_OPTIONS_PAGE_JS"
file="chromeos/os_languages_page/input_method_options_page.js"
compress="false" type="chrome_html" />
<structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_UTIL_HTML"
file="chromeos/os_languages_page/input_method_util.html"
compress="false" type="chrome_html" />
<structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_UTIL_JS"
file="chromeos/os_languages_page/input_method_util.js"
compress="false" type="chrome_html" />
<structure name="IDR_OS_SETTINGS_LANGUAGES_SMART_INPUTS_PAGE_HTML"
file="chromeos/os_languages_page/smart_inputs_page.html"
compress="false" type="chrome_html" />
......
......@@ -122,6 +122,60 @@ void AddSmartInputsStrings(content::WebUIDataSource* html_source) {
html_source->AddBoolean("allowEmojiSuggestion", IsEmojiSuggestionAllowed());
}
void AddInputMethodOptionsStrings(content::WebUIDataSource* html_source) {
static constexpr webui::LocalizedString kLocalizedStrings[] = {
{"inputMethodOptionsBasicSectionTitle",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_BASIC},
{"inputMethodOptionsAdvancedSectionTitle",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_ADVANCED},
{"inputMethodOptionsPhysicalKeyboardSectionTitle",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PHYSICAL_KEYBOARD},
{"inputMethodOptionsVirtualKeyboardSectionTitle",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_VIRTUAL_KEYBOARD},
{"inputMethodOptionsEnableDoubleSpacePeriod",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_DOUBLE_SPACE_PERIOD},
{"inputMethodOptionsEnableGestureTyping",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_GESTURE_TYPING},
{"inputMethodOptionsEnablePrediction",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_PREDICTION},
{"inputMethodOptionsEnableSoundOnKeypress",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_SOUND_ON_KEYPRESS},
{"inputMethodOptionsEnableCapitalization",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_ENABLE_CAPITALIZATION},
{"inputMethodOptionsAutoCorrection",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION},
{"inputMethodOptionsXkbLayout",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_XKB_LAYOUT},
{"inputMethodOptionsEditUserDict",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_EDIT_USER_DICT},
{"inputMethodOptionsPinyinChinesePunctuation",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_CHINESE_PUNCTUATION},
{"inputMethodOptionsPinyinDefaultChinese",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_DEFAULT_CHINESE},
{"inputMethodOptionsPinyinEnableFuzzy",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_ENABLE_FUZZY},
{"inputMethodOptionsPinyinEnableLowerPaging",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_ENABLE_LOWER_PAGING},
{"inputMethodOptionsPinyinEnableUpperPaging",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_ENABLE_UPPER_PAGING},
{"inputMethodOptionsPinyinFullWidthCharacter",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_PINYIN_FULL_WIDTH_CHARACTER},
{"inputMethodOptionsAutoCorrectionOff",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION_OFF},
{"inputMethodOptionsAutoCorrectionModest",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION_MODEST},
{"inputMethodOptionsAutoCorrectionAggressive",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_AUTO_CORRECTION_AGGRESSIVE},
{"inputMethodOptionsUsKeyboard",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_US},
{"inputMethodOptionsDvorakKeyboard",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_DVORAK},
{"inputMethodOptionsColemakKeyboard",
IDS_SETTINGS_INPUT_METHOD_OPTIONS_KEYBOARD_COLEMAK},
};
AddLocalizedStringsBulk(html_source, kLocalizedStrings);
}
} // namespace
LanguagesSection::LanguagesSection(Profile* profile,
......@@ -174,6 +228,7 @@ void LanguagesSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
};
AddLocalizedStringsBulk(html_source, kLocalizedStrings);
AddSmartInputsStrings(html_source);
AddInputMethodOptionsStrings(html_source);
html_source->AddString(
"languagesLearnMoreURL",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Suite of tests for the OS Settings input method options page.
*/
const FIRST_PARTY_INPUT_METHOD_ID_PREFIX =
'_comp_ime_jkghodnilhceideoidjikpgommlajknk';
const PREFS_KEY = 'settings.language.input_method_specific_settings';
class FakeLanguageHelper {
getInputMethodDisplayName(_) {
return 'fake display name';
}
}
function getFakePrefs() {
return [{
key: PREFS_KEY,
type: chrome.settingsPrivate.PrefType.DICTIONARY,
value: {
'xkb:us::eng': {
physicalKeyboardAutoCorrectionLevel: 0,
physicalKeyboardEnableCapitalization: false,
}
},
}];
}
suite('InputMethodOptionsPage', function() {
let optionsPage = null;
let settingsPrivate = null;
suiteSetup(async function() {
PolymerTest.clearBody();
CrSettingsPrefs.deferInitialization = true;
const settingsPrefs = document.createElement('settings-prefs');
settingsPrivate = new settings.FakeSettingsPrivate(getFakePrefs());
settingsPrefs.initialize(settingsPrivate);
document.body.appendChild(settingsPrefs);
await CrSettingsPrefs.initialized;
optionsPage = document.createElement('settings-input-method-options-page');
document.body.appendChild(optionsPage);
optionsPage.languageHelper = new FakeLanguageHelper();
optionsPage.prefs = settingsPrefs.prefs;
});
/**
* @param {string} id Input method ID.
*/
function createOptionsPage(id) {
const params = new URLSearchParams;
params.append('id', id);
settings.Router.getInstance().navigateTo(
settings.routes.OS_LANGUAGES_INPUT_METHOD_OPTIONS, params);
Polymer.dom.flush();
}
test('US English page', () => {
createOptionsPage(FIRST_PARTY_INPUT_METHOD_ID_PREFIX + 'xkb:us::eng');
const titles = optionsPage.shadowRoot.querySelectorAll('h2');
assertTrue(!!titles);
assertEquals(titles.length, 2);
assertEquals(titles[0].textContent, 'Physical keyboard');
assertEquals(titles[1].textContent, 'On-screen keyboard');
});
test('Pinyin page', () => {
createOptionsPage(FIRST_PARTY_INPUT_METHOD_ID_PREFIX + 'zh-t-i0-pinyin');
const titles = optionsPage.shadowRoot.querySelectorAll('h2');
assertTrue(!!titles);
assertEquals(titles.length, 2);
assertEquals(titles[0].textContent, 'Basics');
assertEquals(titles[1].textContent, 'Advanced');
});
test('updates options in prefs', async () => {
createOptionsPage(FIRST_PARTY_INPUT_METHOD_ID_PREFIX + 'xkb:us::eng');
const options = optionsPage.shadowRoot.querySelectorAll('.list-item');
assertTrue(!!options);
assertEquals(options.length, 9);
assertEquals(
options[0].querySelector('.start').textContent.trim(),
'Auto-correction');
const select = options[0].querySelector('select');
assertEquals(select.value, '0');
select.value = '1';
select.dispatchEvent(new CustomEvent('change'));
await test_util.waitAfterNextRender(select);
assertEquals(
optionsPage.getPref(PREFS_KEY)
.value['xkb:us::eng']['physicalKeyboardAutoCorrectionLevel'],
1);
assertEquals(
options[1].querySelector('.start').textContent.trim(),
'Auto-capitalization');
const toggleButton = options[1].querySelector('cr-toggle');
assertEquals(toggleButton.checked, false);
toggleButton.click();
await test_util.waitAfterNextRender(toggleButton);
assertEquals(toggleButton.checked, true);
assertEquals(
optionsPage.getPref(PREFS_KEY)
.value['xkb:us::eng']['physicalKeyboardEnableCapitalization'],
true);
});
});
......@@ -32,6 +32,7 @@ cr.define('os_languages_page_tests', function() {
testing.Test.disableAnimationsAndTransitions();
PolymerTest.clearBody();
CrSettingsPrefs.deferInitialization = true;
loadTimeData.overrideValues({imeOptionsInSettings: true});
});
setup(async () => {
......@@ -285,23 +286,46 @@ cr.define('os_languages_page_tests', function() {
});
});
test(TestNames.InputMethods, function() {
const inputMethodsList = languagesPage.$.inputMethodsList;
assertTrue(!!inputMethodsList);
suite(TestNames.InputMethods, function() {
test('displays input method list', function() {
const inputMethodsList = languagesPage.$.inputMethodsList;
assertTrue(!!inputMethodsList);
// The test input methods should appear.
const items =
inputMethodsList.querySelectorAll('.list-item .display-name');
assertEquals(2, items.length);
assertEquals('US keyboard', items[0].textContent.trim());
assertEquals('US Dvorak keyboard', items[1].textContent.trim());
// The test input methods should appear.
const items = inputMethodsList.querySelectorAll('.list-item');
assertEquals(3, items.length); // Two items for input methods and one
// item for manage input methods.
assertEquals(
'US keyboard',
items[0].querySelector('.display-name').textContent.trim());
assertTrue(!!items[0].querySelector('.internal-wrapper'));
assertFalse(!!items[0].querySelector('.external-wrapper'));
assertEquals(
'US Dvorak keyboard',
items[1].querySelector('.display-name').textContent.trim());
assertTrue(!!items[1].querySelector('.external-wrapper'));
assertFalse(!!items[1].querySelector('.internal-wrapper'));
const manageInputMethodsButton =
inputMethodsList.querySelector('#manageInputMethods');
assertTrue(!!manageInputMethodsButton);
const manageInputMethodsButton =
inputMethodsList.querySelector('#manageInputMethods');
assertTrue(!!manageInputMethodsButton);
// settings-manage-input-methods-page is owned by os-languages-section,
// not os-languages-page, and hence isn't tested here.
});
// settings-manage-input-methods-page is owned by os-languages-section,
// not os-languages-page, and hence isn't tested here.
test('navigates to input method options page', function() {
const inputMethodsList = languagesPage.$.inputMethodsList;
const items = inputMethodsList.querySelectorAll('.list-item');
items[0].querySelector('.subpage-arrow').click();
const router = settings.Router.getInstance();
assertEquals(
router.getCurrentRoute().getAbsolutePath(),
'chrome://os-settings/osLanguages/inputMethodOptions');
assertEquals(
router.getQueryParameters().get('id'),
'_comp_ime_jkghodnilhceideoidjikpgommlajknkxkb:us::eng');
});
});
});
......
......@@ -1336,6 +1336,29 @@ TEST_F('OSSettingsSmartInputsPageTest', 'AllJsTests', () => {
mocha.run();
});
// eslint-disable-next-line no-var
var OSSettingsInputMethodOptionsPageTest = class extends OSSettingsBrowserTest {
/** @override */
get browsePreload() {
return super.browsePreload +
'chromeos/os_language_page/input_method_options_page.html';
}
/** @override */
get extraLibraries() {
return super.extraLibraries.concat([
BROWSER_SETTINGS_PATH + '../fake_chrome_event.js',
BROWSER_SETTINGS_PATH + 'fake_settings_private.js',
BROWSER_SETTINGS_PATH + '../test_util.js',
'input_method_options_page_test.js',
]);
}
};
TEST_F('OSSettingsInputMethodOptionsPageTest', 'AllJsTests', () => {
mocha.run();
});
// Tests for the Reset section.
// eslint-disable-next-line no-var
var OSSettingsResetPageTest = class extends OSSettingsBrowserTest {
......
......@@ -134,7 +134,7 @@ cr.define('settings', function() {
/** @type {!Array<!chrome.languageSettingsPrivate.InputMethod>} */
this.componentExtensionImes = [
{
id: '_comp_ime_fgoepimhcoialccpbmpnnblemnepkkaoxkb:us::eng',
id: '_comp_ime_jkghodnilhceideoidjikpgommlajknkxkb:us::eng',
displayName: 'US keyboard',
languageCodes: ['en', 'en-US'],
enabled: true,
......@@ -459,7 +459,7 @@ cr.define('settings', function() {
fakePrefs.push({
key: 'settings.language.preload_engines',
type: chrome.settingsPrivate.PrefType.STRING,
value: '_comp_ime_fgoepimhcoialccpbmpnnblemnepkkaoxkb:us::eng,' +
value: '_comp_ime_jkghodnilhceideoidjikpgommlajknkxkb:us::eng,' +
'_comp_ime_fgoepimhcoialccpbmpnnblemnepkkaoxkb:us:dvorak:eng',
});
fakePrefs.push({
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment