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 @@
on-keys-pressed="onKeysPress_">
</iron-a11y-keys>
<cr-input id="newWord" value="{{newWordValue_}}"
invalid="[[isNewWordInvalid_(newWordState_)]]"
error-message="[[getErrorMessage_(newWordState_)]]"
spellcheck="false">
<cr-button on-click="onAddWordTap_" id="addWord" slot="suffix"
disabled="[[disableAddButton_]]">
......
......@@ -14,6 +14,18 @@
// #import {LanguagesBrowserProxyImpl} from '../../languages_page/languages_browser_proxy.m.js';
// 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({
is: 'os-settings-edit-dictionary-page',
......@@ -55,7 +67,14 @@ Polymer({
disableAddButton_: {
type: Boolean,
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({
}
},
/**
* @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}
* @private
*/
shouldDisableAddButton_() {
return !this.getTrimmedNewWord_().length;
return this.newWordState_ !== NewWordState.VALID_WORD;
},
/**
* @return {string}
* @private
*/
getTrimmedNewWord_() {
return this.newWordValue_.trim();
getErrorMessage_() {
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', () => {
'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', () => {
assertTrue(!!editDictPage);
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