summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-09-15 19:35:44 -0400
committerGitHub <noreply@github.com>2020-09-15 19:35:44 -0400
commitf997f017422bba2527e620000e3a938b916f25ac (patch)
tree659653476f599a437e1d16132ceed28ecbdf59b7
parent8d2847756271a1b4eb06a27b044b4096bd21f55c (diff)
Dictionary controller refactor (#831)
* Create new DictionaryController * Update input disabling when modifying the database
-rw-r--r--ext/bg/css/settings.css5
-rw-r--r--ext/bg/js/settings/dictionary-controller.js608
-rw-r--r--ext/bg/js/settings/dictionary-import-controller.js5
-rw-r--r--ext/bg/settings.html11
-rw-r--r--ext/mixed/js/dom-data-binder.js3
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) {