summaryrefslogtreecommitdiff
path: root/ext/bg/js/settings
diff options
context:
space:
mode:
Diffstat (limited to 'ext/bg/js/settings')
-rw-r--r--ext/bg/js/settings/anki.js10
-rw-r--r--ext/bg/js/settings/audio.js9
-rw-r--r--ext/bg/js/settings/backup.js2
-rw-r--r--ext/bg/js/settings/conditions-ui.js163
-rw-r--r--ext/bg/js/settings/dictionaries.js32
-rw-r--r--ext/bg/js/settings/main.js23
-rw-r--r--ext/bg/js/settings/popup-preview-frame-main.js26
-rw-r--r--ext/bg/js/settings/popup-preview-frame.js57
-rw-r--r--ext/bg/js/settings/popup-preview.js23
-rw-r--r--ext/bg/js/settings/profiles.js14
10 files changed, 285 insertions, 74 deletions
diff --git a/ext/bg/js/settings/anki.js b/ext/bg/js/settings/anki.js
index b32a9517..ff1277ed 100644
--- a/ext/bg/js/settings/anki.js
+++ b/ext/bg/js/settings/anki.js
@@ -16,13 +16,13 @@
*/
/* global
+ * apiGetAnkiDeckNames
+ * apiGetAnkiModelFieldNames
+ * apiGetAnkiModelNames
* getOptionsContext
* getOptionsMutable
* onFormOptionsChanged
* settingsSaveOptions
- * utilAnkiGetDeckNames
- * utilAnkiGetModelFieldNames
- * utilAnkiGetModelNames
* utilBackgroundIsolate
*/
@@ -107,7 +107,7 @@ async function _ankiDeckAndModelPopulate(options) {
const kanjiModel = {value: options.anki.kanji.model, selector: '#anki-kanji-model'};
try {
_ankiSpinnerShow(true);
- const [deckNames, modelNames] = await Promise.all([utilAnkiGetDeckNames(), utilAnkiGetModelNames()]);
+ const [deckNames, modelNames] = await Promise.all([apiGetAnkiDeckNames(), apiGetAnkiModelNames()]);
deckNames.sort();
modelNames.sort();
termsDeck.values = deckNames;
@@ -180,7 +180,7 @@ async function _onAnkiModelChanged(e) {
let fieldNames;
try {
const modelName = node.value;
- fieldNames = await utilAnkiGetModelFieldNames(modelName);
+ fieldNames = await apiGetAnkiModelFieldNames(modelName);
_ankiSetError(null);
} catch (error) {
_ankiSetError(error);
diff --git a/ext/bg/js/settings/audio.js b/ext/bg/js/settings/audio.js
index 3c6e126c..ac2d82f3 100644
--- a/ext/bg/js/settings/audio.js
+++ b/ext/bg/js/settings/audio.js
@@ -18,7 +18,6 @@
/* global
* AudioSourceUI
* AudioSystem
- * apiAudioGetUri
* getOptionsContext
* getOptionsMutable
* settingsSaveOptions
@@ -29,10 +28,8 @@ let audioSystem = null;
async function audioSettingsInitialize() {
audioSystem = new AudioSystem({
- getAudioUri: async (definition, source) => {
- const optionsContext = getOptionsContext();
- return await apiAudioGetUri(definition, source, optionsContext);
- }
+ audioUriBuilder: null,
+ useCache: true
});
const optionsContext = getOptionsContext();
@@ -115,7 +112,7 @@ function textToSpeechTest() {
const text = document.querySelector('#text-to-speech-voice-test').dataset.speechText || '';
const voiceUri = document.querySelector('#text-to-speech-voice').value;
- const audio = audioSystem.createTextToSpeechAudio({text, voiceUri});
+ const audio = audioSystem.createTextToSpeechAudio(text, voiceUri);
audio.volume = 1.0;
audio.play();
} catch (e) {
diff --git a/ext/bg/js/settings/backup.js b/ext/bg/js/settings/backup.js
index bdfef658..faf4e592 100644
--- a/ext/bg/js/settings/backup.js
+++ b/ext/bg/js/settings/backup.js
@@ -133,7 +133,7 @@ async function _settingsImportSetOptionsFull(optionsFull) {
}
function _showSettingsImportError(error) {
- logError(error);
+ yomichan.logError(error);
document.querySelector('#settings-import-error-modal-message').textContent = `${error}`;
$('#settings-import-error-modal').modal('show');
}
diff --git a/ext/bg/js/settings/conditions-ui.js b/ext/bg/js/settings/conditions-ui.js
index 84498b42..031689a7 100644
--- a/ext/bg/js/settings/conditions-ui.js
+++ b/ext/bg/js/settings/conditions-ui.js
@@ -16,6 +16,7 @@
*/
/* global
+ * DOM
* conditionsNormalizeOptionValue
*/
@@ -103,11 +104,11 @@ ConditionsUI.Container = class Container {
if (hasOwn(conditionDescriptor.operators, operator)) {
const operatorDescriptor = conditionDescriptor.operators[operator];
if (hasOwn(operatorDescriptor, 'defaultValue')) {
- return {value: operatorDescriptor.defaultValue, fromOperator: true};
+ return {value: this.isolate(operatorDescriptor.defaultValue), fromOperator: true};
}
}
if (hasOwn(conditionDescriptor, 'defaultValue')) {
- return {value: conditionDescriptor.defaultValue, fromOperator: false};
+ return {value: this.isolate(conditionDescriptor.defaultValue), fromOperator: false};
}
}
return {fromOperator: false};
@@ -177,7 +178,8 @@ ConditionsUI.Condition = class Condition {
this.parent = parent;
this.condition = condition;
this.container = ConditionsUI.instantiateTemplate('#condition-template').appendTo(parent.container);
- this.input = this.container.find('input');
+ this.input = this.container.find('.condition-input');
+ this.inputInner = null;
this.typeSelect = this.container.find('.condition-type');
this.operatorSelect = this.container.find('.condition-operator');
this.removeButton = this.container.find('.condition-remove');
@@ -186,14 +188,13 @@ ConditionsUI.Condition = class Condition {
this.updateOperators();
this.updateInput();
- this.input.on('change', this.onInputChanged.bind(this));
this.typeSelect.on('change', this.onConditionTypeChanged.bind(this));
this.operatorSelect.on('change', this.onConditionOperatorChanged.bind(this));
this.removeButton.on('click', this.onRemoveClicked.bind(this));
}
cleanup() {
- this.input.off('change');
+ this.inputInner.off('change');
this.typeSelect.off('change');
this.operatorSelect.off('change');
this.removeButton.off('click');
@@ -204,6 +205,10 @@ ConditionsUI.Condition = class Condition {
this.parent.save();
}
+ isolate(object) {
+ return this.parent.isolate(object);
+ }
+
updateTypes() {
const conditionDescriptors = this.parent.parent.conditionDescriptors;
const optionGroup = this.typeSelect.find('optgroup');
@@ -236,21 +241,48 @@ ConditionsUI.Condition = class Condition {
updateInput() {
const conditionDescriptors = this.parent.parent.conditionDescriptors;
const {type, operator} = this.condition;
- const props = new Map([
- ['placeholder', ''],
- ['type', 'text']
- ]);
const objects = [];
+ let inputType = null;
if (hasOwn(conditionDescriptors, type)) {
const conditionDescriptor = conditionDescriptors[type];
objects.push(conditionDescriptor);
+ if (hasOwn(conditionDescriptor, 'type')) {
+ inputType = conditionDescriptor.type;
+ }
if (hasOwn(conditionDescriptor.operators, operator)) {
const operatorDescriptor = conditionDescriptor.operators[operator];
objects.push(operatorDescriptor);
+ if (hasOwn(operatorDescriptor, 'type')) {
+ inputType = operatorDescriptor.type;
+ }
}
}
+ this.input.empty();
+ if (inputType === 'select') {
+ this.inputInner = this.createSelectElement(objects);
+ } else if (inputType === 'keyMulti') {
+ this.inputInner = this.createInputKeyMultiElement(objects);
+ } else {
+ this.inputInner = this.createInputElement(objects);
+ }
+ this.inputInner.appendTo(this.input);
+ this.inputInner.on('change', this.onInputChanged.bind(this));
+
+ const {valid, value} = this.validateValue(this.condition.value);
+ this.inputInner.toggleClass('is-invalid', !valid);
+ this.inputInner.val(value);
+ }
+
+ createInputElement(objects) {
+ const inputInner = ConditionsUI.instantiateTemplate('#condition-input-text-template');
+
+ const props = new Map([
+ ['placeholder', ''],
+ ['type', 'text']
+ ]);
+
for (const object of objects) {
if (hasOwn(object, 'placeholder')) {
props.set('placeholder', object.placeholder);
@@ -266,35 +298,124 @@ ConditionsUI.Condition = class Condition {
}
for (const [prop, value] of props.entries()) {
- this.input.prop(prop, value);
+ inputInner.prop(prop, value);
}
- const {valid} = this.validateValue(this.condition.value);
- this.input.toggleClass('is-invalid', !valid);
- this.input.val(this.condition.value);
+ return inputInner;
}
- validateValue(value) {
+ createInputKeyMultiElement(objects) {
+ const inputInner = this.createInputElement(objects);
+
+ inputInner.prop('readonly', true);
+
+ let values = [];
+ let keySeparator = ' + ';
+ for (const object of objects) {
+ if (hasOwn(object, 'values')) {
+ values = object.values;
+ }
+ if (hasOwn(object, 'keySeparator')) {
+ keySeparator = object.keySeparator;
+ }
+ }
+
+ const pressedKeyIndices = new Set();
+
+ const onKeyDown = ({originalEvent}) => {
+ const pressedKeyEventName = DOM.getKeyFromEvent(originalEvent);
+ if (pressedKeyEventName === 'Escape' || pressedKeyEventName === 'Backspace') {
+ pressedKeyIndices.clear();
+ inputInner.val('');
+ inputInner.change();
+ return;
+ }
+
+ const pressedModifiers = DOM.getActiveModifiers(originalEvent);
+ // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
+ // https://askubuntu.com/questions/567731/why-is-shift-alt-being-mapped-to-meta
+ // It works with mouse events on some platforms, so try to determine if metaKey is pressed
+ // hack; only works when Shift and Alt are not pressed
+ const isMetaKeyChrome = (
+ pressedKeyEventName === 'Meta' &&
+ getSetDifference(new Set(['shift', 'alt']), pressedModifiers).size !== 0
+ );
+ if (isMetaKeyChrome) {
+ pressedModifiers.add('meta');
+ }
+
+ for (const modifier of pressedModifiers) {
+ const foundIndex = values.findIndex(({optionValue}) => optionValue === modifier);
+ if (foundIndex !== -1) {
+ pressedKeyIndices.add(foundIndex);
+ }
+ }
+
+ const inputValue = [...pressedKeyIndices].map((i) => values[i].name).join(keySeparator);
+ inputInner.val(inputValue);
+ inputInner.change();
+ };
+
+ inputInner.on('keydown', onKeyDown);
+
+ return inputInner;
+ }
+
+ createSelectElement(objects) {
+ const inputInner = ConditionsUI.instantiateTemplate('#condition-input-select-template');
+
+ const data = new Map([
+ ['values', []],
+ ['defaultValue', null]
+ ]);
+
+ for (const object of objects) {
+ if (hasOwn(object, 'values')) {
+ data.set('values', object.values);
+ }
+ if (hasOwn(object, 'defaultValue')) {
+ data.set('defaultValue', this.isolate(object.defaultValue));
+ }
+ }
+
+ for (const {optionValue, name} of data.get('values')) {
+ const option = ConditionsUI.instantiateTemplate('#condition-input-option-template');
+ option.attr('value', optionValue);
+ option.text(name);
+ option.appendTo(inputInner);
+ }
+
+ const defaultValue = data.get('defaultValue');
+ if (defaultValue !== null) {
+ inputInner.val(this.isolate(defaultValue));
+ }
+
+ return inputInner;
+ }
+
+ validateValue(value, isInput=false) {
const conditionDescriptors = this.parent.parent.conditionDescriptors;
let valid = true;
+ let inputTransformedValue = null;
try {
- value = conditionsNormalizeOptionValue(
+ [value, inputTransformedValue] = conditionsNormalizeOptionValue(
conditionDescriptors,
this.condition.type,
this.condition.operator,
- value
+ value,
+ isInput
);
} catch (e) {
valid = false;
}
- return {valid, value};
+ return {valid, value, inputTransformedValue};
}
onInputChanged() {
- const {valid, value} = this.validateValue(this.input.val());
- this.input.toggleClass('is-invalid', !valid);
- this.input.val(value);
- this.condition.value = value;
+ const {valid, value, inputTransformedValue} = this.validateValue(this.inputInner.val(), true);
+ this.inputInner.toggleClass('is-invalid', !valid);
+ this.inputInner.val(value);
+ this.condition.value = inputTransformedValue !== null ? inputTransformedValue : value;
this.save();
}
diff --git a/ext/bg/js/settings/dictionaries.js b/ext/bg/js/settings/dictionaries.js
index 1a6d452b..632c01ea 100644
--- a/ext/bg/js/settings/dictionaries.js
+++ b/ext/bg/js/settings/dictionaries.js
@@ -17,8 +17,13 @@
/* global
* PageExitPrevention
+ * apiDeleteDictionary
+ * apiGetDictionaryCounts
+ * apiGetDictionaryInfo
+ * apiImportDictionaryArchive
* apiOptionsGet
* apiOptionsGetFull
+ * apiPurgeDatabase
* getOptionsContext
* getOptionsFullMutable
* getOptionsMutable
@@ -26,11 +31,6 @@
* storageEstimate
* storageUpdateStats
* utilBackgroundIsolate
- * utilDatabaseDeleteDictionary
- * utilDatabaseGetDictionaryCounts
- * utilDatabaseGetDictionaryInfo
- * utilDatabaseImport
- * utilDatabasePurge
*/
let dictionaryUI = null;
@@ -312,7 +312,7 @@ class SettingsDictionaryEntryUI {
progressBar.style.width = `${percent}%`;
};
- await utilDatabaseDeleteDictionary(this.dictionaryInfo.title, onProgress, {rate: 1000});
+ await apiDeleteDictionary(this.dictionaryInfo.title, onProgress);
} catch (e) {
dictionaryErrorsShow([e]);
} finally {
@@ -431,7 +431,7 @@ async function onDictionaryOptionsChanged() {
async function onDatabaseUpdated() {
try {
- const dictionaries = await utilDatabaseGetDictionaryInfo();
+ const dictionaries = await apiGetDictionaryInfo();
dictionaryUI.setDictionaries(dictionaries);
document.querySelector('#dict-warning').hidden = (dictionaries.length > 0);
@@ -439,7 +439,7 @@ async function onDatabaseUpdated() {
updateMainDictionarySelectOptions(dictionaries);
await updateMainDictionarySelectValue();
- const {counts, total} = await utilDatabaseGetDictionaryCounts(dictionaries.map((v) => v.title), true);
+ const {counts, total} = await apiGetDictionaryCounts(dictionaries.map((v) => v.title), true);
dictionaryUI.setCounts(counts, total);
} catch (e) {
dictionaryErrorsShow([e]);
@@ -554,7 +554,7 @@ function dictionaryErrorsShow(errors) {
if (errors !== null && errors.length > 0) {
const uniqueErrors = new Map();
for (let e of errors) {
- logError(e);
+ yomichan.logError(e);
e = dictionaryErrorToString(e);
let count = uniqueErrors.get(e);
if (typeof count === 'undefined') {
@@ -618,7 +618,7 @@ async function onDictionaryPurge(e) {
dictionaryErrorsShow(null);
dictionarySpinnerShow(true);
- await utilDatabasePurge();
+ await apiPurgeDatabase();
for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) {
options.dictionaries = utilBackgroundIsolate({});
options.general.mainDictionary = '';
@@ -679,7 +679,8 @@ async function onDictionaryImport(e) {
dictImportInfo.textContent = `(${i + 1} of ${ii})`;
}
- const {result, errors} = await utilDatabaseImport(files[i], updateProgress, importDetails);
+ const archiveContent = await dictReadFile(files[i]);
+ const {result, errors} = await apiImportDictionaryArchive(archiveContent, importDetails, updateProgress);
for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) {
const dictionaryOptions = SettingsDictionaryListUI.createDictionaryOptions();
dictionaryOptions.enabled = true;
@@ -713,6 +714,15 @@ async function onDictionaryImport(e) {
}
}
+function dictReadFile(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onload = () => resolve(reader.result);
+ reader.onerror = () => reject(reader.error);
+ reader.readAsBinaryString(file);
+ });
+}
+
async function onDatabaseEnablePrefixWildcardSearchesChanged(e) {
const optionsFull = await getOptionsFullMutable();
diff --git a/ext/bg/js/settings/main.js b/ext/bg/js/settings/main.js
index 308e92eb..61395b1c 100644
--- a/ext/bg/js/settings/main.js
+++ b/ext/bg/js/settings/main.js
@@ -21,6 +21,8 @@
* ankiInitialize
* ankiTemplatesInitialize
* ankiTemplatesUpdateValue
+ * apiForwardLogsToBackend
+ * apiGetEnvironmentInfo
* apiOptionsSave
* appearanceInitialize
* audioSettingsInitialize
@@ -130,6 +132,7 @@ async function formRead(options) {
options.anki.tags = utilBackgroundIsolate($('#card-tags').val().split(/[,; ]+/));
options.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10);
options.anki.server = $('#interface-server').val();
+ options.anki.duplicateScope = $('#duplicate-scope').val();
options.anki.screenshot.format = $('#screenshot-format').val();
options.anki.screenshot.quality = parseInt($('#screenshot-quality').val(), 10);
@@ -211,6 +214,7 @@ async function formWrite(options) {
$('#card-tags').val(options.anki.tags.join(' '));
$('#sentence-detection-extent').val(options.anki.sentenceExt);
$('#interface-server').val(options.anki.server);
+ $('#duplicate-scope').val(options.anki.duplicateScope);
$('#screenshot-format').val(options.anki.screenshot.format);
$('#screenshot-quality').val(options.anki.screenshot.quality);
@@ -282,12 +286,31 @@ function showExtensionInformation() {
node.textContent = `${manifest.name} v${manifest.version}`;
}
+async function settingsPopulateModifierKeys() {
+ const scanModifierKeySelect = document.querySelector('#scan-modifier-key');
+ scanModifierKeySelect.textContent = '';
+
+ const environment = await apiGetEnvironmentInfo();
+ const modifierKeys = [
+ {value: 'none', name: 'None'},
+ ...environment.modifiers.keys
+ ];
+ for (const {value, name} of modifierKeys) {
+ const option = document.createElement('option');
+ option.value = value;
+ option.textContent = name;
+ scanModifierKeySelect.appendChild(option);
+ }
+}
+
async function onReady() {
+ apiForwardLogsToBackend();
await yomichan.prepare();
showExtensionInformation();
+ await settingsPopulateModifierKeys();
formSetupEventListeners();
appearanceInitialize();
await audioSettingsInitialize();
diff --git a/ext/bg/js/settings/popup-preview-frame-main.js b/ext/bg/js/settings/popup-preview-frame-main.js
new file mode 100644
index 00000000..8228125f
--- /dev/null
+++ b/ext/bg/js/settings/popup-preview-frame-main.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019-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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* global
+ * SettingsPopupPreview
+ * apiForwardLogsToBackend
+ */
+
+(() => {
+ apiForwardLogsToBackend();
+ new SettingsPopupPreview();
+})();
diff --git a/ext/bg/js/settings/popup-preview-frame.js b/ext/bg/js/settings/popup-preview-frame.js
index fba114e2..8901a0c4 100644
--- a/ext/bg/js/settings/popup-preview-frame.js
+++ b/ext/bg/js/settings/popup-preview-frame.js
@@ -18,8 +18,9 @@
/* global
* Frontend
* Popup
- * PopupProxyHost
+ * PopupFactory
* TextSourceRange
+ * apiFrameInformationGet
* apiOptionsGet
*/
@@ -32,46 +33,46 @@ class SettingsPopupPreview {
this.popupShown = false;
this.themeChangeTimeout = null;
this.textSource = null;
+ this.optionsContext = null;
this._targetOrigin = chrome.runtime.getURL('/').replace(/\/$/, '');
this._windowMessageHandlers = new Map([
+ ['prepare', ({optionsContext}) => this.prepare(optionsContext)],
['setText', ({text}) => this.setText(text)],
['setCustomCss', ({css}) => this.setCustomCss(css)],
- ['setCustomOuterCss', ({css}) => this.setCustomOuterCss(css)]
+ ['setCustomOuterCss', ({css}) => this.setCustomOuterCss(css)],
+ ['updateOptionsContext', ({optionsContext}) => this.updateOptionsContext(optionsContext)]
]);
- }
- static create() {
- const instance = new SettingsPopupPreview();
- instance.prepare();
- return instance;
+ window.addEventListener('message', this.onMessage.bind(this), false);
}
- async prepare() {
- // Setup events
- window.addEventListener('message', this.onMessage.bind(this), false);
+ async prepare(optionsContext) {
+ this.optionsContext = optionsContext;
+ // Setup events
document.querySelector('#theme-dark-checkbox').addEventListener('change', this.onThemeDarkCheckboxChanged.bind(this), false);
// Overwrite API functions
window.apiOptionsGet = this.apiOptionsGet.bind(this);
// Overwrite frontend
- const popupHost = new PopupProxyHost();
- await popupHost.prepare();
+ const {frameId} = await apiFrameInformationGet();
+
+ const popupFactory = new PopupFactory(frameId);
+ await popupFactory.prepare();
- this.popup = popupHost.getOrCreatePopup();
+ this.popup = popupFactory.getOrCreatePopup();
this.popup.setChildrenSupported(false);
this.popupSetCustomOuterCssOld = this.popup.setCustomOuterCss;
this.popup.setCustomOuterCss = this.popupSetCustomOuterCss.bind(this);
this.frontend = new Frontend(this.popup);
-
- this.frontend.setEnabled = () => {};
- this.frontend.searchClear = () => {};
-
+ this.frontend.getOptionsContext = async () => this.optionsContext;
await this.frontend.prepare();
+ this.frontend.setDisabledOverride(true);
+ this.frontend.canClearSelection = false;
// Update search
this.updateSearch();
@@ -122,7 +123,7 @@ class SettingsPopupPreview {
}
this.themeChangeTimeout = setTimeout(() => {
this.themeChangeTimeout = null;
- this.frontend.popup.updateTheme();
+ this.popup.updateTheme();
}, 300);
}
@@ -143,12 +144,18 @@ class SettingsPopupPreview {
setCustomCss(css) {
if (this.frontend === null) { return; }
- this.frontend.popup.setCustomCss(css);
+ this.popup.setCustomCss(css);
}
setCustomOuterCss(css) {
if (this.frontend === null) { return; }
- this.frontend.popup.setCustomOuterCss(css, false);
+ this.popup.setCustomOuterCss(css, false);
+ }
+
+ async updateOptionsContext(optionsContext) {
+ this.optionsContext = optionsContext;
+ await this.frontend.updateOptions();
+ await this.updateSearch();
}
async updateSearch() {
@@ -163,23 +170,17 @@ class SettingsPopupPreview {
const source = new TextSourceRange(range, range.toString(), null, null);
try {
- await this.frontend.onSearchSource(source, 'script');
- this.frontend.setCurrentTextSource(source);
+ await this.frontend.setTextSource(source);
} finally {
source.cleanup();
}
this.textSource = source;
await this.frontend.showContentCompleted();
- if (this.frontend.popup.isVisibleSync()) {
+ if (this.popup.isVisibleSync()) {
this.popupShown = true;
}
this.setInfoVisible(!this.popupShown);
}
}
-
-SettingsPopupPreview.instance = SettingsPopupPreview.create();
-
-
-
diff --git a/ext/bg/js/settings/popup-preview.js b/ext/bg/js/settings/popup-preview.js
index 091872be..fdc3dd94 100644
--- a/ext/bg/js/settings/popup-preview.js
+++ b/ext/bg/js/settings/popup-preview.js
@@ -15,6 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+/* global
+ * getOptionsContext
+ * wanakana
+ */
function appearanceInitialize() {
let previewVisible = false;
@@ -37,7 +41,7 @@ function showAppearancePreview() {
frame.src = '/bg/settings-popup-preview.html';
frame.id = 'settings-popup-preview-frame';
- window.wanakana.bind(text[0]);
+ wanakana.bind(text[0]);
const targetOrigin = chrome.runtime.getURL('/').replace(/\/$/, '');
@@ -57,6 +61,23 @@ function showAppearancePreview() {
frame.contentWindow.postMessage({action, params}, targetOrigin);
});
+ const updateOptionsContext = () => {
+ const action = 'updateOptionsContext';
+ const params = {
+ optionsContext: getOptionsContext()
+ };
+ frame.contentWindow.postMessage({action, params}, targetOrigin);
+ };
+ yomichan.on('modifyingProfileChange', updateOptionsContext);
+
+ frame.addEventListener('load', () => {
+ const action = 'prepare';
+ const params = {
+ optionsContext: getOptionsContext()
+ };
+ frame.contentWindow.postMessage({action, params}, targetOrigin);
+ });
+
container.append(frame);
buttonContainer.remove();
settings.css('display', '');
diff --git a/ext/bg/js/settings/profiles.js b/ext/bg/js/settings/profiles.js
index 867b17aa..bdf5a13d 100644
--- a/ext/bg/js/settings/profiles.js
+++ b/ext/bg/js/settings/profiles.js
@@ -23,6 +23,7 @@
* getOptionsFullMutable
* getOptionsMutable
* profileConditionsDescriptor
+ * profileConditionsDescriptorPromise
* settingsSaveOptions
* utilBackgroundIsolate
*/
@@ -98,6 +99,7 @@ async function profileFormWrite(optionsFull) {
profileConditionsContainer.cleanup();
}
+ await profileConditionsDescriptorPromise;
profileConditionsContainer = new ConditionsUI.Container(
profileConditionsDescriptor,
'popupLevel',
@@ -128,7 +130,7 @@ function profileOptionsPopulateSelect(select, profiles, currentValue, ignoreIndi
}
async function profileOptionsUpdateTarget(optionsFull) {
- profileFormWrite(optionsFull);
+ await profileFormWrite(optionsFull);
const optionsContext = getOptionsContext();
const options = await getOptionsMutable(optionsContext);
@@ -190,6 +192,8 @@ async function onTargetProfileChanged() {
currentProfileIndex = index;
await profileOptionsUpdateTarget(optionsFull);
+
+ yomichan.trigger('modifyingProfileChange');
}
async function onProfileAdd() {
@@ -197,9 +201,13 @@ async function onProfileAdd() {
const profile = utilBackgroundIsolate(optionsFull.profiles[currentProfileIndex]);
profile.name = profileOptionsCreateCopyName(profile.name, optionsFull.profiles, 100);
optionsFull.profiles.push(profile);
+
currentProfileIndex = optionsFull.profiles.length - 1;
+
await profileOptionsUpdateTarget(optionsFull);
await settingsSaveOptions();
+
+ yomichan.trigger('modifyingProfileChange');
}
async function onProfileRemove(e) {
@@ -238,6 +246,8 @@ async function onProfileRemoveConfirm() {
await profileOptionsUpdateTarget(optionsFull);
await settingsSaveOptions();
+
+ yomichan.trigger('modifyingProfileChange');
}
function onProfileNameChanged() {
@@ -263,6 +273,8 @@ async function onProfileMove(offset) {
await profileOptionsUpdateTarget(optionsFull);
await settingsSaveOptions();
+
+ yomichan.trigger('modifyingProfileChange');
}
async function onProfileCopy() {