From f457ff3ed1264ba84ea86a9933060936bb5ec4d6 Mon Sep 17 00:00:00 2001 From: Khai Truong Date: Wed, 31 Jul 2024 00:11:57 +0700 Subject: [PATCH] move edit alias to kebab menu --- ext/css/settings.css | 4 + ext/js/dom/dom-data-binder.js | 39 +-------- .../pages/settings/dictionary-controller.js | 82 +++++++++++++------ ext/settings.html | 15 ++++ ext/templates-settings.html | 3 +- ext/welcome.html | 15 ++++ types/ext/dom-data-binder.d.ts | 6 +- 7 files changed, 100 insertions(+), 64 deletions(-) diff --git a/ext/css/settings.css b/ext/css/settings.css index 2e97a6d07d..7e6c4bc158 100644 --- a/ext/css/settings.css +++ b/ext/css/settings.css @@ -2404,6 +2404,10 @@ input[type=number].dictionary-priority { overflow: auto; } +#dictionary-alias-input { + width: 100%; +} + #dictionary-move-up>span.icon-button-inner, #dictionary-move-down>span.icon-button-inner { width: 26px; diff --git a/ext/js/dom/dom-data-binder.js b/ext/js/dom/dom-data-binder.js index c40c6a45c0..4ca3aded97 100644 --- a/ext/js/dom/dom-data-binder.js +++ b/ext/js/dom/dom-data-binder.js @@ -175,7 +175,7 @@ export class DOMDataBinder { const metadata = this._createElementMetadata(element); if (typeof metadata === 'undefined') { return void 0; } const type = this._getNormalizedElementType(element); - const eventType = this._getElementEventType(element); + const eventType = 'change'; /** @type {import('dom-data-binder').ElementObserver} */ const observer = { element, @@ -212,13 +212,6 @@ export class DOMDataBinder { if (!observer.hasValue) { return; } - // When contenteditable is made empty or inputted from empty, - // the value is reset back to original state - // because there is a removal / addition of text node. - // This is a workaround to prevent the value from being reset back when typing. - if (this._isElementContentEditable(element)) { - return; - } this._setElementValue(element, observer.value); } @@ -249,7 +242,7 @@ export class DOMDataBinder { case 'select': /** @type {HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement} */ (element).value = typeof value === 'string' ? value : `${value}`; break; - case 'contenteditable': + case 'element': element.textContent = typeof value === 'string' ? value : `${value}`; break; } @@ -287,22 +280,9 @@ export class DOMDataBinder { return /** @type {HTMLTextAreaElement} */ (element).value; case 'select': return /** @type {HTMLSelectElement} */ (element).value; - case 'contenteditable': + case 'element': return element.textContent; } - return null; - } - - - /** - * @param {Element} element - * @returns {import('dom-data-binder').EventType} - */ - _getElementEventType(element) { - if (this._isElementContentEditable(element)) { - return 'blur'; - } - return 'change'; } /** @@ -310,9 +290,6 @@ export class DOMDataBinder { * @returns {import('dom-data-binder').NormalizedElementType} */ _getNormalizedElementType(element) { - if (this._isElementContentEditable(element)) { - return 'contenteditable'; - } switch (element.nodeName.toUpperCase()) { case 'INPUT': { @@ -332,14 +309,6 @@ export class DOMDataBinder { case 'SELECT': return 'select'; } - return null; - } - - /** - * @param {Element} element - * @returns {boolean} - */ - _isElementContentEditable(element) { - return element instanceof HTMLElement && element.isContentEditable; + return 'element'; } } diff --git a/ext/js/pages/settings/dictionary-controller.js b/ext/js/pages/settings/dictionary-controller.js index b524c308d6..4788bff64a 100644 --- a/ext/js/pages/settings/dictionary-controller.js +++ b/ext/js/pages/settings/dictionary-controller.js @@ -86,8 +86,6 @@ class DictionaryEntry { this._outdatedButton.hidden = (version >= 3); this._priorityInput.dataset.setting = `dictionaries[${index}].priority`; this._enabledCheckbox.dataset.setting = `dictionaries[${index}].enabled`; - this._eventListeners.addEventListener(this._aliasNode, 'blur', this._onAliasBlur.bind(this), false); - this._eventListeners.addEventListener(this._aliasNode, 'keydown', this._onAliasKeyDown.bind(this), false); this._eventListeners.addEventListener(this._enabledCheckbox, 'settingChanged', this._onEnabledChanged.bind(this), false); this._eventListeners.addEventListener(this._menuButton, 'menuOpen', this._onMenuOpen.bind(this), false); this._eventListeners.addEventListener(this._menuButton, 'menuClose', this._onMenuClose.bind(this), false); @@ -179,29 +177,9 @@ class DictionaryEntry { case 'moveTo': this._showMoveToModal(); break; - } - } - - /** - * - */ - _onAliasBlur() { - let newAlias = (this._aliasNode.textContent ?? '').trim() - if (!newAlias) { - newAlias = this.dictionaryTitle; - } - this._aliasNode.textContent = newAlias; - } - - /** - * @param {KeyboardEvent} e - */ - _onAliasKeyDown(e) { - // if enter then blur - const {code, key} = e; - if (code === 'Enter' || key === 'Enter' || code === 'NumpadEnter') { - e.preventDefault(); - this._aliasNode.blur(); + case 'setAlias': + this._showSetAliasModal(); + break; } } @@ -369,6 +347,23 @@ class DictionaryEntry { modal.setVisible(true); } + + /** */ + _showSetAliasModal() { + const {title} = this._dictionaryInfo; + const modal = this._dictionaryController.modalController.getModal('dictionary-set-alias'); + if (modal === null) { return; } + /** @type {HTMLInputElement} */ + const input = querySelectorNotNull(modal.node, '#dictionary-alias-input'); + /** @type {HTMLElement} */ + const titleNode = querySelectorNotNull(modal.node, '.dictionary-title'); + + modal.node.dataset.index = `${this._index}`; + titleNode.textContent = title; + input.value = this._aliasNode.textContent || title; + + modal.setVisible(true); + } } class DictionaryExtraInfo { @@ -528,6 +523,11 @@ export class DictionaryController { /** @type {HTMLButtonElement} */ const dictionaryMoveButton = querySelectorNotNull(document, '#dictionary-move-button'); + /** @type {HTMLButtonElement} */ + const dictiontaryResetAliasButton = querySelectorNotNull(document, '#dictionary-reset-alias-button'); + /** @type {HTMLButtonElement} */ + const dictionarySetAliasButton = querySelectorNotNull(document, '#dictionary-set-alias-button'); + this._settingsController.application.on('databaseUpdated', this._onDatabaseUpdated.bind(this)); this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); this._allCheckbox.addEventListener('change', this._onAllCheckboxChange.bind(this), false); @@ -535,6 +535,10 @@ export class DictionaryController { dictionaryUpdateButton.addEventListener('click', this._onDictionaryConfirmUpdate.bind(this), false); dictionaryMoveButton.addEventListener('click', this._onDictionaryMoveButtonClick.bind(this), false); + + dictionarySetAliasButton.addEventListener('click', this._onDictionarySetAliasButtonClick.bind(this), false); + dictiontaryResetAliasButton.addEventListener('click', this._onDictionaryResetAliasButtonClick.bind(this), false); + if (this._checkUpdatesButton !== null) { this._checkUpdatesButton.addEventListener('click', this._onCheckUpdatesButtonClick.bind(this), false); } @@ -890,6 +894,34 @@ export class DictionaryController { void this.moveDictionaryOptions(indexNumber, target); } + /** */ + _onDictionaryResetAliasButtonClick() { + const modal = /** @type {import('./modal.js').Modal} */ (this._modalController.getModal('dictionary-set-alias')); + const index = modal.node.dataset.index ?? ''; + const indexNumber = Number.parseInt(index, 10); + if (Number.isNaN(indexNumber)) { return; } + + /** @type {HTMLInputElement} */ + const input = querySelectorNotNull(modal.node, '#dictionary-alias-input'); + input.value = this._dictionaryEntries[indexNumber].dictionaryTitle; + } + + /** */ + _onDictionarySetAliasButtonClick() { + const modal = /** @type {import('./modal.js').Modal} */ (this._modalController.getModal('dictionary-set-alias')); + const index = modal.node.dataset.index ?? ''; + const indexNumber = Number.parseInt(index, 10); + if (Number.isNaN(indexNumber)) { return; } + + /** @type {HTMLInputElement} */ + const input = querySelectorNotNull(modal.node, '#dictionary-alias-input'); + const inputValue = input.value.trim(); + if (!inputValue) return; + const aliasNode = this._dictionaryEntries[indexNumber]._aliasNode; + aliasNode.textContent = inputValue; + aliasNode.dispatchEvent(new Event('change', {bubbles: true})); + } + /** * @param {import('dictionary-importer').Summary[]} dictionaries */ diff --git a/ext/settings.html b/ext/settings.html index 33e12ab7fe..c858b374c3 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -2820,6 +2820,21 @@
or click here to upload
+ + + +