Commit 1ce0c7c3 authored by My Nguyen's avatar My Nguyen Committed by Commit Bot

[OsSettingsLanguages] Add word validation for edit dictionary

Copied over from languages_page/edit_dictionary_page.js
Mock: http://go/cros-lang-settings-ux-slide#slide=29

Duplicated word: http://screen/7ptBk8NJEDqhzEc
Length limit reached: http://screen/5XQF6ePt4ctSgia

Bug: 1113439
Change-Id: If17744293c18d6cb2b33c51373452bbe6d9a9848
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2397056
Commit-Queue: My Nguyen <myy@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarRegan Hsu <hsuregan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806536}
parent f7507615
...@@ -56,6 +56,8 @@ ...@@ -56,6 +56,8 @@
on-keys-pressed="onKeysPress_"> on-keys-pressed="onKeysPress_">
</iron-a11y-keys> </iron-a11y-keys>
<cr-input id="newWord" value="{{newWordValue_}}" <cr-input id="newWord" value="{{newWordValue_}}"
invalid="[[isNewWordInvalid_(newWordState_)]]"
error-message="[[getErrorMessage_(newWordState_)]]"
spellcheck="false"> spellcheck="false">
<cr-button on-click="onAddWordTap_" id="addWord" slot="suffix" <cr-button on-click="onAddWordTap_" id="addWord" slot="suffix"
disabled="[[disableAddButton_]]"> disabled="[[disableAddButton_]]">
......
...@@ -14,6 +14,18 @@ ...@@ -14,6 +14,18 @@
// #import {LanguagesBrowserProxyImpl} from '../../languages_page/languages_browser_proxy.m.js'; // #import {LanguagesBrowserProxyImpl} from '../../languages_page/languages_browser_proxy.m.js';
// clang-format on // clang-format on
// Max valid word size, keep in sync with kMaxCustomDictionaryWordBytes in
// //components/spellcheck/common/spellcheck_common.h
const MAX_CUSTOM_DICTIONARY_WORD_BYTES = 99;
/** @enum {number} */
const NewWordState = {
NO_WORD: 0,
VALID_WORD: 1,
WORD_ALREADY_ADDED: 2,
WORD_TOO_LONG: 3,
};
Polymer({ Polymer({
is: 'os-settings-edit-dictionary-page', is: 'os-settings-edit-dictionary-page',
...@@ -55,7 +67,14 @@ Polymer({ ...@@ -55,7 +67,14 @@ Polymer({
disableAddButton_: { disableAddButton_: {
type: Boolean, type: Boolean,
value: true, value: true,
computed: 'shouldDisableAddButton_(newWordValue_)', computed: 'shouldDisableAddButton_(newWordState_)',
},
/** @private */
newWordState_: {
type: Number,
value: NewWordState.NO_WORD,
computed: 'updateNewWordState_(newWordValue_, words_.*)',
} }
}, },
...@@ -104,20 +123,62 @@ Polymer({ ...@@ -104,20 +123,62 @@ Polymer({
} }
}, },
/**
* @return {string}
* @private
*/
getTrimmedNewWord_() {
return this.newWordValue_.trim();
},
/**
* @return {NewWordState}
* @private
*/
updateNewWordState_() {
const trimmedNewWord = this.getTrimmedNewWord_();
if (!trimmedNewWord.length) {
return NewWordState.NO_WORD;
}
if (this.words_.includes(trimmedNewWord)) {
return NewWordState.WORD_ALREADY_ADDED;
}
if (new Blob([trimmedNewWord]).size > MAX_CUSTOM_DICTIONARY_WORD_BYTES) {
return NewWordState.WORD_TOO_LONG;
}
return NewWordState.VALID_WORD;
},
/** /**
* @return {boolean} * @return {boolean}
* @private * @private
*/ */
shouldDisableAddButton_() { shouldDisableAddButton_() {
return !this.getTrimmedNewWord_().length; return this.newWordState_ !== NewWordState.VALID_WORD;
}, },
/** /**
* @return {string} * @return {string}
* @private * @private
*/ */
getTrimmedNewWord_() { getErrorMessage_() {
return this.newWordValue_.trim(); switch (this.newWordState_) {
case NewWordState.WORD_TOO_LONG:
return this.i18n('addDictionaryWordLengthError');
case NewWordState.WORD_ALREADY_ADDED:
return this.i18n('addDictionaryWordDuplicateError');
default:
return '';
}
},
/**
* @return {boolean}
* @private
*/
isNewWordInvalid_() {
return this.newWordState_ === NewWordState.WORD_TOO_LONG ||
this.newWordState_ === NewWordState.WORD_ALREADY_ADDED;
}, },
/** /**
......
...@@ -96,6 +96,65 @@ suite('edit dictionary page', () => { ...@@ -96,6 +96,65 @@ suite('edit dictionary page', () => {
'none'); // Make sure add-word button actually clickable. 'none'); // Make sure add-word button actually clickable.
}); });
test('shows error when adding duplicate word', () => {
const WORD = 'unique';
loadTimeData.overrideValues({
addDictionaryWordDuplicateError: 'duplicate',
});
// add word
languageSettingsPrivate.onCustomDictionaryChanged.callListeners([WORD], []);
editDictPage.$.newWord.value = `${WORD} ${WORD}`;
Polymer.dom.flush();
assertFalse(editDictPage.$.addWord.disabled);
assertFalse(editDictPage.$.newWord.invalid);
assertEquals(editDictPage.$.newWord.errorMessage, '');
// add duplicate word
editDictPage.$.newWord.value = WORD;
Polymer.dom.flush();
assertTrue(editDictPage.$.addWord.disabled);
assertTrue(editDictPage.$.newWord.invalid);
assertEquals(editDictPage.$.newWord.errorMessage, 'duplicate');
// remove word
languageSettingsPrivate.onCustomDictionaryChanged.callListeners([], [WORD]);
Polymer.dom.flush();
assertFalse(editDictPage.$.addWord.disabled);
assertFalse(editDictPage.$.newWord.invalid);
assertEquals(editDictPage.$.newWord.errorMessage, '');
});
test('shows error when adding word bigger than 99 bytes', () => {
const OK_WORD = 'u'.repeat(99);
const TOO_LONG_WORD = 'u'.repeat(100);
// This emoji has length 2 and bytesize 4.
const TOO_BIG_WORD = '😎'.repeat(25);
loadTimeData.overrideValues({
addDictionaryWordLengthError: 'too long',
});
editDictPage.$.newWord.value = OK_WORD;
Polymer.dom.flush();
assertFalse(editDictPage.$.addWord.disabled);
assertFalse(editDictPage.$.newWord.invalid);
assertEquals(editDictPage.$.newWord.errorMessage, '');
editDictPage.$.newWord.value = TOO_LONG_WORD;
Polymer.dom.flush();
assertTrue(editDictPage.$.addWord.disabled);
assertTrue(editDictPage.$.newWord.invalid);
assertEquals(editDictPage.$.newWord.errorMessage, 'too long');
editDictPage.$.newWord.value = TOO_BIG_WORD;
Polymer.dom.flush();
assertTrue(editDictPage.$.addWord.disabled);
assertTrue(editDictPage.$.newWord.invalid);
assertEquals(editDictPage.$.newWord.errorMessage, 'too long');
});
test('shows message when empty', () => { test('shows message when empty', () => {
assertTrue(!!editDictPage); assertTrue(!!editDictPage);
return languageSettingsPrivate.whenCalled('getSpellcheckWords').then(() => { return languageSettingsPrivate.whenCalled('getSpellcheckWords').then(() => {
......
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