diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/bg/css/settings.css | 5 | ||||
-rw-r--r-- | ext/bg/js/settings/dictionary-controller.js | 608 | ||||
-rw-r--r-- | ext/bg/js/settings/dictionary-import-controller.js | 5 | ||||
-rw-r--r-- | ext/bg/settings.html | 11 | ||||
-rw-r--r-- | ext/mixed/js/dom-data-binder.js | 3 |
5 files changed, 251 insertions, 381 deletions
diff --git a/ext/bg/css/settings.css b/ext/bg/css/settings.css index 17bb4ac0..4a49b98d 100644 --- a/ext/bg/css/settings.css +++ b/ext/bg/css/settings.css @@ -377,6 +377,11 @@ html:root[data-operating-system=openbsd] [data-hide-for-operating-system~=openbs display: none; } +#dict-groups { + display: flex; + flex-flow: column; +} + .dict-details-container { margin: 0.5em 0; } diff --git a/ext/bg/js/settings/dictionary-controller.js b/ext/bg/js/settings/dictionary-controller.js index eccb0e88..75022d1f 100644 --- a/ext/bg/js/settings/dictionary-controller.js +++ b/ext/bg/js/settings/dictionary-controller.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2020 Yomichan Authors + * Copyright (C) 2020 Yomichan Authors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,202 +16,90 @@ */ /* global + * ObjectPropertyAccessor * api - * utilBackgroundIsolate */ -class SettingsDictionaryListUI extends EventDispatcher { - constructor(container, template, extraContainer, extraTemplate) { - super(); - this.container = container; - this.template = template; - this.extraContainer = extraContainer; - this.extraTemplate = extraTemplate; - this.optionsDictionaries = null; - this.dictionaries = null; - this.dictionaryEntries = []; - this.extra = null; - - document.querySelector('#dict-delete-confirm').addEventListener('click', this.onDictionaryConfirmDelete.bind(this), false); +class DictionaryEntry { + constructor(dictionaryController, node, dictionaryInfo) { + this._dictionaryController = dictionaryController; + this._node = node; + this._dictionaryInfo = dictionaryInfo; + this._dictionaryTitle = dictionaryInfo.title; + this._eventListeners = new EventListenerCollection(); + this._enabledCheckbox = node.querySelector('.dict-enabled'); + this._allowSecondarySearchesCheckbox = node.querySelector('.dict-allow-secondary-searches'); + this._priorityInput = node.querySelector('.dict-priority'); + this._deleteButton = node.querySelector('.dict-delete-button'); + this._detailsToggleLink = node.querySelector('.dict-details-toggle-link'); + this._detailsContainer = node.querySelector('.dict-details'); + this._detailsTable = node.querySelector('.dict-details-table'); } - setOptionsDictionaries(optionsDictionaries) { - this.optionsDictionaries = optionsDictionaries; - if (this.dictionaries !== null) { - this.setDictionaries(this.dictionaries); - } + get node() { + return this._node; } - setDictionaries(dictionaries) { - for (const dictionaryEntry of this.dictionaryEntries) { - dictionaryEntry.cleanup(); - } - - this.dictionaryEntries = []; - this.dictionaries = toIterable(dictionaries); - - if (this.optionsDictionaries === null) { - return; - } - - let changed = false; - for (const dictionaryInfo of this.dictionaries) { - if (this.createEntry(dictionaryInfo)) { - changed = true; - } - } - - this.updateDictionaryOrder(); - - const titles = this.dictionaryEntries.map((e) => e.dictionaryInfo.title); - const removeKeys = Object.keys(this.optionsDictionaries).filter((key) => titles.indexOf(key) < 0); - if (removeKeys.length > 0) { - for (const key of toIterable(removeKeys)) { - delete this.optionsDictionaries[key]; - } - changed = true; - } - - if (changed) { - this.save(); - } + get dictionaryTitle() { + return this._dictionaryTitle; } - createEntry(dictionaryInfo) { - const title = dictionaryInfo.title; - let changed = false; - let optionsDictionary; - const optionsDictionaries = this.optionsDictionaries; - if (hasOwn(optionsDictionaries, title)) { - optionsDictionary = optionsDictionaries[title]; - } else { - optionsDictionary = SettingsDictionaryListUI.createDictionaryOptions(); - optionsDictionaries[title] = optionsDictionary; - changed = true; - } + prepare() { + const node = this._node; + const dictionaryInfo = this._dictionaryInfo; + const {title, revision, prefixWildcardsSupported} = dictionaryInfo; - const content = document.importNode(this.template.content, true).firstChild; + if (dictionaryInfo.version < 3) { + node.querySelector('.dict-outdated').hidden = false; + } - this.dictionaryEntries.push(new SettingsDictionaryEntryUI(this, dictionaryInfo, content, optionsDictionary)); + node.querySelector('.dict-title').textContent = title; + node.querySelector('.dict-revision').textContent = `rev.${revision}`; + node.querySelector('.dict-prefix-wildcard-searches-supported').checked = !!prefixWildcardsSupported; - return changed; - } + this._setupDetails(dictionaryInfo); - static createDictionaryOptions() { - return utilBackgroundIsolate({ - priority: 0, - enabled: false, - allowSecondarySearches: false - }); - } + this._enabledCheckbox.dataset.setting = ObjectPropertyAccessor.getPathString(['dictionaries', title, 'enabled']); + this._allowSecondarySearchesCheckbox.dataset.setting = ObjectPropertyAccessor.getPathString(['dictionaries', title, 'allowSecondarySearches']); + this._priorityInput.dataset.setting = ObjectPropertyAccessor.getPathString(['dictionaries', title, 'priority']); - createExtra(totalCounts, remainders, totalRemainder) { - const content = document.importNode(this.extraTemplate.content, true).firstChild; - this.extraContainer.appendChild(content); - return new SettingsDictionaryExtraUI(this, totalCounts, remainders, totalRemainder, content); + this._eventListeners.addEventListener(this._deleteButton, 'click', this._onDeleteButtonClicked.bind(this), false); + this._eventListeners.addEventListener(this._detailsToggleLink, 'click', this._onDetailsToggleLinkClicked.bind(this), false); + this._eventListeners.addEventListener(this._priorityInput, 'settingChanged', this._onPriorityChanged.bind(this), false); } - setCounts(dictionaryCounts, totalCounts) { - const remainders = Object.assign({}, totalCounts); - const keys = Object.keys(remainders); - - for (let i = 0, ii = Math.min(this.dictionaryEntries.length, dictionaryCounts.length); i < ii; ++i) { - const counts = dictionaryCounts[i]; - this.dictionaryEntries[i].setCounts(counts); - - for (const key of keys) { - remainders[key] -= counts[key]; - } - } - - let totalRemainder = 0; - for (const key of keys) { - totalRemainder += remainders[key]; - } - - if (this.extra !== null) { - this.extra.cleanup(); - this.extra = null; - } - - if (totalRemainder > 0) { - this.extra = this.createExtra(totalCounts, remainders, totalRemainder); + cleanup() { + this._eventListeners.removeAllEventListeners(); + const node = this._node; + if (node.parentNode !== null) { + node.parentNode.removeChild(node); } } - updateDictionaryOrder() { - const sortInfo = this.dictionaryEntries.map((e, i) => [e, i]); - sortInfo.sort((a, b) => { - const i = b[0].optionsDictionary.priority - a[0].optionsDictionary.priority; - return (i !== 0 ? i : a[1] - b[1]); - }); - - for (const [e] of sortInfo) { - this.container.appendChild(e.content); - } + setCounts(counts) { + const node = this._node.querySelector('.dict-counts'); + node.textContent = JSON.stringify({info: this._dictionaryInfo, counts}, null, 4); + node.hidden = false; } - save() { - // Overwrite - } + // Private - preventPageExit() { - // Overwrite - return {end: () => {}}; + _onDeleteButtonClicked(e) { + e.preventDefault(); + this._dictionaryController.deleteDictionary(this._dictionaryTitle); } - onDictionaryConfirmDelete(e) { + _onDetailsToggleLinkClicked(e) { e.preventDefault(); - const n = document.querySelector('#dict-delete-modal'); - const title = n.dataset.dict; - delete n.dataset.dict; - $(n).modal('hide'); - - const index = this.dictionaryEntries.findIndex((entry) => entry.dictionaryInfo.title === title); - if (index >= 0) { - this.dictionaryEntries[index].deleteDictionary(); - } + this._detailsContainer.hidden = !this._detailsContainer.hidden; } -} - -class SettingsDictionaryEntryUI { - constructor(parent, dictionaryInfo, content, optionsDictionary) { - this.parent = parent; - this.dictionaryInfo = dictionaryInfo; - this.optionsDictionary = optionsDictionary; - this.counts = null; - this.eventListeners = new EventListenerCollection(); - this.isDeleting = false; - - this.content = content; - this.enabledCheckbox = this.content.querySelector('.dict-enabled'); - this.allowSecondarySearchesCheckbox = this.content.querySelector('.dict-allow-secondary-searches'); - this.priorityInput = this.content.querySelector('.dict-priority'); - this.deleteButton = this.content.querySelector('.dict-delete-button'); - this.detailsToggleLink = this.content.querySelector('.dict-details-toggle-link'); - this.detailsContainer = this.content.querySelector('.dict-details'); - this.detailsTable = this.content.querySelector('.dict-details-table'); - - if (this.dictionaryInfo.version < 3) { - this.content.querySelector('.dict-outdated').hidden = false; - } - - this.setupDetails(dictionaryInfo); - this.content.querySelector('.dict-title').textContent = this.dictionaryInfo.title; - this.content.querySelector('.dict-revision').textContent = `rev.${this.dictionaryInfo.revision}`; - this.content.querySelector('.dict-prefix-wildcard-searches-supported').checked = !!this.dictionaryInfo.prefixWildcardsSupported; - - this.applyValues(); - - this.eventListeners.addEventListener(this.enabledCheckbox, 'change', this.onEnabledChanged.bind(this), false); - this.eventListeners.addEventListener(this.allowSecondarySearchesCheckbox, 'change', this.onAllowSecondarySearchesChanged.bind(this), false); - this.eventListeners.addEventListener(this.priorityInput, 'change', this.onPriorityChanged.bind(this), false); - this.eventListeners.addEventListener(this.deleteButton, 'click', this.onDeleteButtonClicked.bind(this), false); - this.eventListeners.addEventListener(this.detailsToggleLink, 'click', this.onDetailsToggleLinkClicked.bind(this), false); + _onPriorityChanged(e) { + const {detail: {value}} = e; + this._node.style.order = `${-value}`; } - setupDetails(dictionaryInfo) { + _setupDetails(dictionaryInfo) { const targets = [ ['Author', 'author'], ['URL', 'url'], @@ -219,6 +107,7 @@ class SettingsDictionaryEntryUI { ['Attribution', 'attribution'] ]; + const fragment = document.createDocumentFragment(); let count = 0; for (const [label, key] of targets) { const info = dictionaryInfo[key]; @@ -238,281 +127,252 @@ class SettingsDictionaryEntryUI { n3.textContent = info; n1.appendChild(n3); - this.detailsTable.appendChild(n1); + fragment.appendChild(n1); ++count; } - if (count === 0) { - this.detailsContainer.hidden = true; - this.detailsToggleLink.hidden = true; - } - } - - cleanup() { - if (this.content !== null) { - if (this.content.parentNode !== null) { - this.content.parentNode.removeChild(this.content); - } - this.content = null; + if (count > 0) { + this._detailsTable.appendChild(fragment); + } else { + this._detailsContainer.hidden = true; + this._detailsToggleLink.hidden = true; } - this.dictionaryInfo = null; - this.eventListeners.removeAllEventListeners(); - } - - setCounts(counts) { - this.counts = counts; - const node = this.content.querySelector('.dict-counts'); - node.textContent = JSON.stringify({ - info: this.dictionaryInfo, - counts - }, null, 4); - node.removeAttribute('hidden'); - } - - save() { - this.parent.save(); } +} - applyValues() { - this.enabledCheckbox.checked = this.optionsDictionary.enabled; - this.allowSecondarySearchesCheckbox.checked = this.optionsDictionary.allowSecondarySearches; - this.priorityInput.value = `${this.optionsDictionary.priority}`; +class DictionaryController { + constructor(settingsController) { + this._settingsController = settingsController; + this._dictionaries = null; + this._dictionaryEntries = []; + this._databaseStateToken = null; + this._checkingIntegrity = false; + this._warningNode = null; + this._mainDictionarySelect = null; + this._checkIntegrityButton = null; + this._dictionaryEntryContainer = null; + this._integrityExtraInfoContainer = null; + this._deleteDictionaryModal = null; + this._integrityExtraInfoNode = null; + this._isDeleting = false; } - async deleteDictionary() { - if (this.isDeleting) { - return; - } + async prepare() { + this._warningNode = document.querySelector('#dict-warning'); + this._mainDictionarySelect = document.querySelector('#dict-main'); + this._checkIntegrityButton = document.querySelector('#dict-check-integrity'); + this._dictionaryEntryContainer = document.querySelector('#dict-groups'); + this._integrityExtraInfoContainer = document.querySelector('#dict-groups-extra'); + this._deleteDictionaryModal = document.querySelector('#dict-delete-modal'); - const progress = this.content.querySelector('.progress'); - progress.hidden = false; - const progressBar = this.content.querySelector('.progress-bar'); - this.isDeleting = true; + yomichan.on('databaseUpdated', this._onDatabaseUpdated.bind(this)); - const prevention = this.parent.preventPageExit(); - try { - const onProgress = ({processed, count, storeCount, storesProcesed}) => { - let percent = 0.0; - if (count > 0 && storesProcesed > 0) { - percent = (processed / count) * (storesProcesed / storeCount) * 100.0; - } - progressBar.style.width = `${percent}%`; - }; + document.querySelector('#dict-delete-confirm').addEventListener('click', this._onDictionaryConfirmDelete.bind(this), false); + this._checkIntegrityButton.addEventListener('click', this._onCheckIntegrityButtonClick.bind(this), false); - await api.deleteDictionary(this.dictionaryInfo.title, onProgress); - } catch (e) { - this.dictionaryErrorsShow([e]); - } finally { - prevention.end(); - this.isDeleting = false; - progress.hidden = true; - } + await this._onDatabaseUpdated(); } - onEnabledChanged(e) { - this.optionsDictionary.enabled = !!e.target.checked; - this.save(); + deleteDictionary(dictionaryTitle) { + if (this._isDeleting) { return; } + const modal = this._deleteDictionaryModal; + modal.dataset.dictionaryTitle = dictionaryTitle; + modal.querySelector('#dict-remove-modal-dict-name').textContent = dictionaryTitle; + this._setModalVisible(modal, true); } - onAllowSecondarySearchesChanged(e) { - this.optionsDictionary.allowSecondarySearches = !!e.target.checked; - this.save(); - } + // Private - onPriorityChanged(e) { - let value = Number.parseFloat(e.target.value); - if (Number.isNaN(value)) { - value = this.optionsDictionary.priority; - } else { - this.optionsDictionary.priority = value; - this.save(); + async _onDatabaseUpdated() { + const token = {}; + this._databaseStateToken = token; + this._dictionaries = null; + const dictionaries = await api.getDictionaryInfo(); + if (this._databaseStateToken !== token) { return; } + this._dictionaries = dictionaries; + + this._warningNode.hidden = (dictionaries.length > 0); + this._updateMainDictionarySelectOptions(dictionaries); + + for (const entry of this._dictionaryEntries) { + entry.cleanup(); } + this._dictionaryEntries = []; - e.target.value = `${value}`; - - this.parent.updateDictionaryOrder(); + for (const dictionary of dictionaries) { + this._createDictionaryEntry(dictionary); + } } - onDeleteButtonClicked(e) { + _onDictionaryConfirmDelete(e) { e.preventDefault(); - if (this.isDeleting) { - return; - } + const modal = this._deleteDictionaryModal; + this._setModalVisible(modal, false); + + const title = modal.dataset.dictionaryTitle; + if (typeof title !== 'string') { return; } + delete modal.dataset.dictionaryTitle; - const title = this.dictionaryInfo.title; - const n = document.querySelector('#dict-delete-modal'); - n.dataset.dict = title; - document.querySelector('#dict-remove-modal-dict-name').textContent = title; - $(n).modal('show'); + this._deleteDictionary(title); } - onDetailsToggleLinkClicked(e) { + _onCheckIntegrityButtonClick(e) { e.preventDefault(); - - this.detailsContainer.hidden = !this.detailsContainer.hidden; + this._checkIntegrity(); } -} -class SettingsDictionaryExtraUI { - constructor(parent, totalCounts, remainders, totalRemainder, content) { - this.parent = parent; - this.content = content; + _setModalVisible(node, visible) { + $(node).modal(visible ? 'show' : 'hide'); + } - this.content.querySelector('.dict-total-count').textContent = `${totalRemainder} item${totalRemainder !== 1 ? 's' : ''}`; + _updateMainDictionarySelectOptions(dictionaries) { + const fragment = document.createDocumentFragment(); - const node = this.content.querySelector('.dict-counts'); - node.textContent = JSON.stringify({ - counts: totalCounts, - remainders: remainders - }, null, 4); - node.removeAttribute('hidden'); - } + let option = document.createElement('option'); + option.className = 'text-muted'; + option.value = ''; + option.textContent = 'Not selected'; + fragment.appendChild(option); - cleanup() { - if (this.content !== null) { - if (this.content.parentNode !== null) { - this.content.parentNode.removeChild(this.content); - } - this.content = null; + for (const {title, sequenced} of dictionaries) { + if (!sequenced) { continue; } + option = document.createElement('option'); + option.value = title; + option.textContent = title; + fragment.appendChild(option); } - } -} -class DictionaryController { - constructor(settingsController) { - this._settingsController = settingsController; - this._dictionaryUI = null; + const select = this._mainDictionarySelect; + select.textContent = ''; // Empty + select.appendChild(fragment); } - async prepare() { - this._dictionaryUI = new SettingsDictionaryListUI( - document.querySelector('#dict-groups'), - document.querySelector('#dict-template'), - document.querySelector('#dict-groups-extra'), - document.querySelector('#dict-extra-template') - ); - this._dictionaryUI.save = () => this._settingsController.save(); - this._dictionaryUI.preventPageExit = this._preventPageExit.bind(this); + async _checkIntegrity() { + if (this._dictionaries === null || this._checkingIntegrity || this._isDeleting) { return; } - document.querySelector('#dict-main').addEventListener('change', this._onDictionaryMainChanged.bind(this), false); - document.querySelector('#database-enable-prefix-wildcard-searches').addEventListener('change', this._onDatabaseEnablePrefixWildcardSearchesChanged.bind(this), false); + try { + this._checkingIntegrity = true; + this._setButtonsEnabled(false); - this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + const token = this._databaseStateToken; + const dictionaryTitles = this._dictionaries.map(({title}) => title); + const {counts, total} = await api.getDictionaryCounts(dictionaryTitles, true); + if (this._databaseStateToken !== token) { return; } - yomichan.on('databaseUpdated', this._onDatabaseUpdated.bind(this)); + for (let i = 0, ii = Math.min(counts.length, this._dictionaryEntries.length); i < ii; ++i) { + const entry = this._dictionaryEntries[i]; + entry.setCounts(counts[i]); + } - await this._onOptionsChanged(); - await this._onDatabaseUpdated(); + this._setCounts(counts, total); + } finally { + this._setButtonsEnabled(true); + this._checkingIntegrity = false; + } } - // Private - - async _onOptionsChanged() { - const options = await this._settingsController.getOptionsMutable(); + _setCounts(dictionaryCounts, totalCounts) { + const remainders = Object.assign({}, totalCounts); + const keys = Object.keys(remainders); - this._dictionaryUI.setOptionsDictionaries(options.dictionaries); + for (const counts of dictionaryCounts) { + for (const key of keys) { + remainders[key] -= counts[key]; + } + } - const optionsFull = await this._settingsController.getOptionsFull(); - document.querySelector('#database-enable-prefix-wildcard-searches').checked = optionsFull.global.database.prefixWildcardsSupported; + let totalRemainder = 0; + for (const key of keys) { + totalRemainder += remainders[key]; + } - await this._updateMainDictionarySelectValue(); + this._cleanupExtra(); + if (totalRemainder > 0) { + this.extra = this._createExtra(totalCounts, remainders, totalRemainder); + } } - _updateMainDictionarySelectOptions(dictionaries) { - const select = document.querySelector('#dict-main'); - select.textContent = ''; // Empty + _createExtra(totalCounts, remainders, totalRemainder) { + const node = this._instantiateTemplate('#dict-extra-template'); + this._integrityExtraInfoNode = node; - let option = document.createElement('option'); - option.className = 'text-muted'; - option.value = ''; - option.textContent = 'Not selected'; - select.appendChild(option); + node.querySelector('.dict-total-count').textContent = `${totalRemainder} item${totalRemainder !== 1 ? 's' : ''}`; - for (const {title, sequenced} of toIterable(dictionaries)) { - if (!sequenced) { continue; } + const n = node.querySelector('.dict-counts'); + n.textContent = JSON.stringify({counts: totalCounts, remainders}, null, 4); + n.hidden = false; - option = document.createElement('option'); - option.value = title; - option.textContent = title; - select.appendChild(option); - } + this._integrityExtraInfoContainer.appendChild(node); } - async _updateMainDictionarySelectValue() { - const options = await this._settingsController.getOptions(); + _cleanupExtra() { + const node = this._integrityExtraInfoNode; + if (node === null) { return; } + this._integrityExtraInfoNode = null; - const value = options.general.mainDictionary; + const parent = node.parentNode; + if (parent === null) { return; } - const select = document.querySelector('#dict-main'); - let selectValue = null; - for (const child of select.children) { - if (child.nodeName.toUpperCase() === 'OPTION' && child.value === value) { - selectValue = value; - break; - } - } + parent.removeChild(node); + } - let missingNodeOption = select.querySelector('option[data-not-installed=true]'); - if (selectValue === null) { - if (missingNodeOption === null) { - missingNodeOption = document.createElement('option'); - missingNodeOption.className = 'text-muted'; - missingNodeOption.value = value; - missingNodeOption.textContent = `${value} (Not installed)`; - missingNodeOption.dataset.notInstalled = 'true'; - select.appendChild(missingNodeOption); - } - } else { - if (missingNodeOption !== null) { - missingNodeOption.parentNode.removeChild(missingNodeOption); - } - } + _createDictionaryEntry(dictionary) { + const node = this._instantiateTemplate('#dict-template'); + this._dictionaryEntryContainer.appendChild(node); - select.value = value; + const entry = new DictionaryEntry(this, node, dictionary); + this._dictionaryEntries.push(entry); + entry.prepare(); } - async _onDatabaseUpdated() { + async _deleteDictionary(dictionaryTitle) { + if (this._isDeleting || this._checkingIntegrity) { return; } + + const index = this._dictionaryEntries.findIndex((entry) => entry.dictionaryTitle === dictionaryTitle); + if (index < 0) { return; } + + const entry = this._dictionaryEntries[index]; + const node = entry.node; + const progress = node.querySelector('.progress'); + const progressBar = node.querySelector('.progress-bar'); + const prevention = this._settingsController.preventPageExit(); try { - const dictionaries = await api.getDictionaryInfo(); - this._dictionaryUI.setDictionaries(dictionaries); + this._isDeleting = true; + this._setButtonsEnabled(false); - document.querySelector('#dict-warning').hidden = (dictionaries.length > 0); + progress.hidden = false; - this._updateMainDictionarySelectOptions(dictionaries); - await this._updateMainDictionarySelectValue(); + const onProgress = ({processed, count, storeCount, storesProcesed}) => { + let percent = 0.0; + if (count > 0 && storesProcesed > 0) { + percent = (processed / count) * (storesProcesed / storeCount) * 100.0; + } + progressBar.style.width = `${percent}%`; + }; - const {counts, total} = await api.getDictionaryCounts(dictionaries.map((v) => v.title), true); - this._dictionaryUI.setCounts(counts, total); + await api.deleteDictionary(dictionaryTitle, onProgress); } catch (e) { yomichan.logError(e); + } finally { + prevention.end(); + progress.hidden = true; + this._setButtonsEnabled(true); + this._isDeleting = false; } } - async _onDictionaryMainChanged(e) { - const select = e.target; - const value = select.value; - - const missingNodeOption = select.querySelector('option[data-not-installed=true]'); - if (missingNodeOption !== null && missingNodeOption.value !== value) { - missingNodeOption.parentNode.removeChild(missingNodeOption); + _setButtonsEnabled(value) { + value = !value; + for (const node of document.querySelectorAll('.dictionary-modifying-input')) { + node.disabled = value; } - - const options = await this._settingsController.getOptionsMutable(); - options.general.mainDictionary = value; - await this._settingsController.save(); - } - - async _onDatabaseEnablePrefixWildcardSearchesChanged(e) { - const optionsFull = await this._settingsController.getOptionsFullMutable(); - const v = !!e.target.checked; - if (optionsFull.global.database.prefixWildcardsSupported === v) { return; } - optionsFull.global.database.prefixWildcardsSupported = !!e.target.checked; - await this._settingsController.save(); } - _preventPageExit() { - return this._settingsController.preventPageExit(); + _instantiateTemplate(templateSelector) { + const template = document.querySelector(templateSelector); + const content = document.importNode(template.content, true); + return content.firstChild; } } diff --git a/ext/bg/js/settings/dictionary-import-controller.js b/ext/bg/js/settings/dictionary-import-controller.js index cce695d0..dd4889dc 100644 --- a/ext/bg/js/settings/dictionary-import-controller.js +++ b/ext/bg/js/settings/dictionary-import-controller.js @@ -304,8 +304,9 @@ class DictionaryImportController { _setButtonsEnabled(value) { value = !value; - this._purgeButton.disabled = value; - this._importFileButton.disabled = value; + for (const node of document.querySelectorAll('.dictionary-modifying-input')) { + node.disabled = value; + } } async _getPreparedDictionaryDatabase() { diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 8eeda187..f46282e5 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -653,7 +653,7 @@ <div class="form-group" id="dict-main-group"> <label for="dict-main">Main dictionary for merged mode</label> - <select class="form-control" id="dict-main"></select> + <select class="form-control" id="dict-main" data-setting="general.mainDictionary"></select> </div> <div class="text-danger" id="dict-purge" hidden>Dictionary data is being purged, please be patient...</div> @@ -678,8 +678,9 @@ for use with this extension and to learn about importing proprietary EPWING dictionaries. </p> <div> - <button class="btn btn-primary" id="dict-file-button">Import Dictionary</button> - <button class="btn btn-danger" id="dict-purge-button">Purge Database</button> + <button class="btn btn-primary dictionary-modifying-input" id="dict-file-button">Import Dictionary</button> + <button class="btn btn-danger dictionary-modifying-input" id="dict-purge-button">Purge Database</button> + <button class="btn btn-default dictionary-modifying-input" id="dict-check-integrity">Check integrity</button> </div> <div hidden><input type="file" id="dict-file" accept=".zip,application/zip" multiple></div> </div> @@ -727,7 +728,7 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <button type="button" class="btn btn-danger" id="dict-delete-confirm">Delete Dictionary</button> + <button type="button" class="btn btn-danger dictionary-modifying-input" id="dict-delete-confirm">Delete Dictionary</button> </div> </div> </div> @@ -756,7 +757,7 @@ </div> <div class="dict-delete-table"> <div> - <button class="btn btn-default dict-delete-button">Delete Dictionary</button> + <button class="btn btn-default dict-delete-button dictionary-modifying-input">Delete Dictionary</button> </div> <div> <div class="progress" hidden> diff --git a/ext/mixed/js/dom-data-binder.js b/ext/mixed/js/dom-data-binder.js index d46e8087..93fe956e 100644 --- a/ext/mixed/js/dom-data-binder.js +++ b/ext/mixed/js/dom-data-binder.js @@ -303,6 +303,9 @@ class DOMDataBinder { element.value = value; break; } + + const event = new CustomEvent('settingChanged', {detail: {value}}); + element.dispatchEvent(event); } _getElementValue(element) { |