From 99cec1d23fc779ae26112dcd63d86b5f6fa4bddd Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 7 Sep 2019 15:54:00 -0400 Subject: Change how formRead works The function now modifies values in-place. --- ext/bg/js/settings.js | 135 +++++++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 67 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 83f4528c..a59f7c0d 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -17,72 +17,68 @@ */ -async function formRead() { - const optionsOld = await optionsLoad(); - const optionsNew = $.extend(true, {}, optionsOld); - - optionsNew.general.showGuide = $('#show-usage-guide').prop('checked'); - optionsNew.general.compactTags = $('#compact-tags').prop('checked'); - optionsNew.general.compactGlossaries = $('#compact-glossaries').prop('checked'); - optionsNew.general.autoPlayAudio = $('#auto-play-audio').prop('checked'); - optionsNew.general.resultOutputMode = $('#result-output-mode').val(); - optionsNew.general.audioSource = $('#audio-playback-source').val(); - optionsNew.general.audioVolume = parseFloat($('#audio-playback-volume').val()); - optionsNew.general.debugInfo = $('#show-debug-info').prop('checked'); - optionsNew.general.showAdvanced = $('#show-advanced-options').prop('checked'); - optionsNew.general.maxResults = parseInt($('#max-displayed-results').val(), 10); - optionsNew.general.popupDisplayMode = $('#popup-display-mode').val(); - optionsNew.general.popupHorizontalTextPosition = $('#popup-horizontal-text-position').val(); - optionsNew.general.popupVerticalTextPosition = $('#popup-vertical-text-position').val(); - optionsNew.general.popupWidth = parseInt($('#popup-width').val(), 10); - optionsNew.general.popupHeight = parseInt($('#popup-height').val(), 10); - optionsNew.general.popupHorizontalOffset = parseInt($('#popup-horizontal-offset').val(), 0); - optionsNew.general.popupVerticalOffset = parseInt($('#popup-vertical-offset').val(), 10); - optionsNew.general.popupHorizontalOffset2 = parseInt($('#popup-horizontal-offset2').val(), 0); - optionsNew.general.popupVerticalOffset2 = parseInt($('#popup-vertical-offset2').val(), 10); - optionsNew.general.customPopupCss = $('#custom-popup-css').val(); - - optionsNew.scanning.middleMouse = $('#middle-mouse-button-scan').prop('checked'); - optionsNew.scanning.touchInputEnabled = $('#touch-input-enabled').prop('checked'); - optionsNew.scanning.selectText = $('#select-matched-text').prop('checked'); - optionsNew.scanning.alphanumeric = $('#search-alphanumeric').prop('checked'); - optionsNew.scanning.autoHideResults = $('#auto-hide-results').prop('checked'); - optionsNew.scanning.deepDomScan = $('#deep-dom-scan').prop('checked'); - optionsNew.scanning.enableOnPopupExpressions = $('#enable-scanning-of-popup-expressions').prop('checked'); - optionsNew.scanning.enableOnSearchPage = $('#enable-scanning-on-search-page').prop('checked'); - optionsNew.scanning.delay = parseInt($('#scan-delay').val(), 10); - optionsNew.scanning.length = parseInt($('#scan-length').val(), 10); - optionsNew.scanning.modifier = $('#scan-modifier-key').val(); - optionsNew.scanning.popupNestingMaxDepth = parseInt($('#popup-nesting-max-depth').val(), 10); - - optionsNew.anki.enable = $('#anki-enable').prop('checked'); - optionsNew.anki.tags = $('#card-tags').val().split(/[,; ]+/); - optionsNew.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10); - optionsNew.anki.server = $('#interface-server').val(); - optionsNew.anki.screenshot.format = $('#screenshot-format').val(); - optionsNew.anki.screenshot.quality = parseInt($('#screenshot-quality').val(), 10); - optionsNew.anki.fieldTemplates = $('#field-templates').val(); - - if (optionsOld.anki.enable && !ankiErrorShown()) { - optionsNew.anki.terms.deck = $('#anki-terms-deck').val(); - optionsNew.anki.terms.model = $('#anki-terms-model').val(); - optionsNew.anki.terms.fields = ankiFieldsToDict($('#terms .anki-field-value')); - optionsNew.anki.kanji.deck = $('#anki-kanji-deck').val(); - optionsNew.anki.kanji.model = $('#anki-kanji-model').val(); - optionsNew.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value')); +async function formRead(options) { + options.general.showGuide = $('#show-usage-guide').prop('checked'); + options.general.compactTags = $('#compact-tags').prop('checked'); + options.general.compactGlossaries = $('#compact-glossaries').prop('checked'); + options.general.autoPlayAudio = $('#auto-play-audio').prop('checked'); + options.general.resultOutputMode = $('#result-output-mode').val(); + options.general.audioSource = $('#audio-playback-source').val(); + options.general.audioVolume = parseFloat($('#audio-playback-volume').val()); + options.general.debugInfo = $('#show-debug-info').prop('checked'); + options.general.showAdvanced = $('#show-advanced-options').prop('checked'); + options.general.maxResults = parseInt($('#max-displayed-results').val(), 10); + options.general.popupDisplayMode = $('#popup-display-mode').val(); + options.general.popupHorizontalTextPosition = $('#popup-horizontal-text-position').val(); + options.general.popupVerticalTextPosition = $('#popup-vertical-text-position').val(); + options.general.popupWidth = parseInt($('#popup-width').val(), 10); + options.general.popupHeight = parseInt($('#popup-height').val(), 10); + options.general.popupHorizontalOffset = parseInt($('#popup-horizontal-offset').val(), 0); + options.general.popupVerticalOffset = parseInt($('#popup-vertical-offset').val(), 10); + options.general.popupHorizontalOffset2 = parseInt($('#popup-horizontal-offset2').val(), 0); + options.general.popupVerticalOffset2 = parseInt($('#popup-vertical-offset2').val(), 10); + options.general.customPopupCss = $('#custom-popup-css').val(); + + options.scanning.middleMouse = $('#middle-mouse-button-scan').prop('checked'); + options.scanning.touchInputEnabled = $('#touch-input-enabled').prop('checked'); + options.scanning.selectText = $('#select-matched-text').prop('checked'); + options.scanning.alphanumeric = $('#search-alphanumeric').prop('checked'); + options.scanning.autoHideResults = $('#auto-hide-results').prop('checked'); + options.scanning.deepDomScan = $('#deep-dom-scan').prop('checked'); + options.scanning.enableOnPopupExpressions = $('#enable-scanning-of-popup-expressions').prop('checked'); + options.scanning.enableOnSearchPage = $('#enable-scanning-on-search-page').prop('checked'); + options.scanning.delay = parseInt($('#scan-delay').val(), 10); + options.scanning.length = parseInt($('#scan-length').val(), 10); + options.scanning.modifier = $('#scan-modifier-key').val(); + options.scanning.popupNestingMaxDepth = parseInt($('#popup-nesting-max-depth').val(), 10); + + const optionsAnkiEnableOld = options.anki.enable; + options.anki.enable = $('#anki-enable').prop('checked'); + options.anki.tags = $('#card-tags').val().split(/[,; ]+/); + options.anki.sentenceExt = parseInt($('#sentence-detection-extent').val(), 10); + options.anki.server = $('#interface-server').val(); + options.anki.screenshot.format = $('#screenshot-format').val(); + options.anki.screenshot.quality = parseInt($('#screenshot-quality').val(), 10); + options.anki.fieldTemplates = $('#field-templates').val(); + + if (optionsAnkiEnableOld && !ankiErrorShown()) { + options.anki.terms.deck = $('#anki-terms-deck').val(); + options.anki.terms.model = $('#anki-terms-model').val(); + options.anki.terms.fields = ankiFieldsToDict($('#terms .anki-field-value')); + options.anki.kanji.deck = $('#anki-kanji-deck').val(); + options.anki.kanji.model = $('#anki-kanji-model').val(); + options.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value')); } - optionsNew.general.mainDictionary = $('#dict-main').val(); + options.general.mainDictionary = $('#dict-main').val(); $('.dict-group').each((index, element) => { const dictionary = $(element); - optionsNew.dictionaries[dictionary.data('title')] = { + options.dictionaries[dictionary.data('title')] = { priority: parseInt(dictionary.find('.dict-priority').val(), 10), enabled: dictionary.find('.dict-enabled').prop('checked'), allowSecondarySearches: dictionary.find('.dict-allow-secondary-searches').prop('checked') }; }); - - return {optionsNew, optionsOld}; } function formUpdateVisibility(options) { @@ -141,18 +137,22 @@ async function onFormOptionsChanged(e) { return; } - const {optionsNew, optionsOld} = await formRead(); - await optionsSave(optionsNew); - formUpdateVisibility(optionsNew); + const options = await optionsLoad(); + const optionsAnkiEnableOld = options.anki.enable; + const optionsAnkiServerOld = options.anki.server; + + await formRead(options); + await optionsSave(options); + formUpdateVisibility(options); try { const ankiUpdated = - optionsNew.anki.enable !== optionsOld.anki.enable || - optionsNew.anki.server !== optionsOld.anki.server; + options.anki.enable !== optionsAnkiEnableOld || + options.anki.server !== optionsAnkiServerOld; if (ankiUpdated) { ankiSpinnerShow(true); - await ankiDeckAndModelPopulate(optionsNew); + await ankiDeckAndModelPopulate(options); ankiErrorShow(); } } catch (e) { @@ -566,12 +566,13 @@ async function onAnkiModelChanged(e) { const tab = element.closest('.tab-pane'); const tabId = tab.attr('id'); - const {optionsNew, optionsOld} = await formRead(); - optionsNew.anki[tabId].fields = {}; - await optionsSave(optionsNew); + const options = await optionsLoad(); + await formRead(options); + options.anki[tabId].fields = {}; + await optionsSave(options); ankiSpinnerShow(true); - await ankiFieldsPopulate(element, optionsNew); + await ankiFieldsPopulate(element, options); ankiErrorShow(); } catch (e) { ankiErrorShow(e); -- cgit v1.2.3 From 4686a31a0a5d30a1b01e3cd2b689d1950c79c940 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 7 Sep 2019 15:59:10 -0400 Subject: Use apiOptionsGet instead of optionsLoad --- ext/bg/js/context.js | 3 ++- ext/bg/js/settings.js | 27 ++++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/context.js b/ext/bg/js/context.js index 689d6863..dfa224a7 100644 --- a/ext/bg/js/context.js +++ b/ext/bg/js/context.js @@ -22,7 +22,8 @@ $(document).ready(utilAsync(() => { $('#open-options').click(() => apiCommandExec('options')); $('#open-help').click(() => apiCommandExec('help')); - optionsLoad().then(options => { + const optionsContext = {depth: 0}; + apiOptionsGet(optionsContext).then(options => { const toggle = $('#enable-search'); toggle.prop('checked', options.general.enable).change(); toggle.bootstrapToggle(); diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index a59f7c0d..1c9198dd 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -16,6 +16,11 @@ * along with this program. If not, see . */ +function getOptionsContext() { + return { + depth: 0 + }; +} async function formRead(options) { options.general.showGuide = $('#show-usage-guide').prop('checked'); @@ -137,7 +142,8 @@ async function onFormOptionsChanged(e) { return; } - const options = await optionsLoad(); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); const optionsAnkiEnableOld = options.anki.enable; const optionsAnkiServerOld = options.anki.server; @@ -163,7 +169,8 @@ async function onFormOptionsChanged(e) { } async function onReady() { - const options = await optionsLoad(); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); $('#show-usage-guide').prop('checked', options.general.showGuide); $('#compact-tags').prop('checked', options.general.compactTags); @@ -374,7 +381,8 @@ async function onDictionaryPurge(e) { dictionarySpinnerShow(true); await utilDatabasePurge(); - const options = await optionsLoad(); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); options.dictionaries = {}; options.general.mainDictionary = ''; await optionsSave(options); @@ -414,8 +422,9 @@ async function onDictionaryImport(e) { setProgress(0.0); const exceptions = []; - const options = await optionsLoad(); const summary = await utilDatabaseImport(e.target.files[0], updateProgress, exceptions); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); options.dictionaries[summary.title] = {enabled: true, priority: 0, allowSecondarySearches: false}; if (summary.sequenced && options.general.mainDictionary === '') { options.general.mainDictionary = summary.title; @@ -566,7 +575,8 @@ async function onAnkiModelChanged(e) { const tab = element.closest('.tab-pane'); const tabId = tab.attr('id'); - const options = await optionsLoad(); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); await formRead(options); options.anki[tabId].fields = {}; await optionsSave(options); @@ -584,8 +594,11 @@ async function onAnkiModelChanged(e) { async function onAnkiFieldTemplatesReset(e) { try { e.preventDefault(); - const options = await optionsLoad(); - $('#field-templates').val(options.anki.fieldTemplates = optionsFieldTemplates()); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); + const fieldTemplates = optionsFieldTemplates(); + options.anki.fieldTemplates = fieldTemplates; + $('#field-templates').val(fieldTemplates); await optionsSave(options); } catch (e) { ankiErrorShow(e); -- cgit v1.2.3 From 05ce350792fd60c1721bff4d0fb971e2bec24818 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 7 Sep 2019 16:15:18 -0400 Subject: Use apiOptionsSave instead of optionsSave --- ext/bg/js/api.js | 9 ++++++++- ext/bg/js/backend.js | 7 +++++++ ext/bg/js/options.js | 13 +++++++++---- ext/bg/js/settings.js | 10 +++++----- 4 files changed, 29 insertions(+), 10 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 53e25348..a50353c1 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -21,6 +21,13 @@ function apiOptionsGet(optionsContext) { return utilBackend().getOptions(optionsContext); } +async function apiOptionsSave() { + const backend = utilBackend(); + const options = await backend.getFullOptions(); + await optionsSave(options); + backend.onOptionsUpdated(options); +} + async function apiTermsFind(text, optionsContext) { const options = await apiOptionsGet(optionsContext); const translator = utilBackend().translator; @@ -132,7 +139,7 @@ async function apiCommandExec(command) { const optionsContext = {depth: 0}; const options = await apiOptionsGet(optionsContext); options.general.enable = !options.general.enable; - await optionsSave(options); + await apiOptionsSave(); } }; diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 6dcf8e4d..1f00f788 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -150,6 +150,13 @@ class Backend { this.anki = options.anki.enable ? new AnkiConnect(options.anki.server) : new AnkiNull(); } + async getFullOptions() { + if (this.isPreparedPromise !== null) { + await this.isPreparedPromise; + } + return this.options; + } + async getOptions(optionsContext) { if (this.isPreparedPromise !== null) { await this.isPreparedPromise; diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 69c662e6..ea8f56d5 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -343,9 +343,14 @@ function optionsLoad() { } function optionsSave(options) { - return new Promise((resolve) => { - chrome.storage.local.set({options: JSON.stringify(options)}, resolve); - }).then(() => { - utilBackend().onOptionsUpdated(options); + return new Promise((resolve, reject) => { + chrome.storage.local.set({options: JSON.stringify(options)}, () => { + const error = chrome.runtime.lastError; + if (error) { + reject(error); + } else { + resolve(); + } + }); }); } diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 1c9198dd..e5786804 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -148,7 +148,7 @@ async function onFormOptionsChanged(e) { const optionsAnkiServerOld = options.anki.server; await formRead(options); - await optionsSave(options); + await apiOptionsSave(); formUpdateVisibility(options); try { @@ -385,7 +385,7 @@ async function onDictionaryPurge(e) { const options = await apiOptionsGet(optionsContext); options.dictionaries = {}; options.general.mainDictionary = ''; - await optionsSave(options); + await apiOptionsSave(); await dictionaryGroupsPopulate(options); await formMainDictionaryOptionsPopulate(options); @@ -435,7 +435,7 @@ async function onDictionaryImport(e) { dictionaryErrorsShow(exceptions); } - await optionsSave(options); + await apiOptionsSave(); await dictionaryGroupsPopulate(options); await formMainDictionaryOptionsPopulate(options); @@ -579,7 +579,7 @@ async function onAnkiModelChanged(e) { const options = await apiOptionsGet(optionsContext); await formRead(options); options.anki[tabId].fields = {}; - await optionsSave(options); + await apiOptionsSave(); ankiSpinnerShow(true); await ankiFieldsPopulate(element, options); @@ -599,7 +599,7 @@ async function onAnkiFieldTemplatesReset(e) { const fieldTemplates = optionsFieldTemplates(); options.anki.fieldTemplates = fieldTemplates; $('#field-templates').val(fieldTemplates); - await optionsSave(options); + await apiOptionsSave(); } catch (e) { ankiErrorShow(e); } -- cgit v1.2.3 From 36b39e2f6530bfba5019462313b29b90a2db2aec Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 8 Sep 2019 11:23:04 -0400 Subject: Create formWrite function --- ext/bg/js/settings.js | 128 ++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 62 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index e5786804..3c261b88 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -86,6 +86,71 @@ async function formRead(options) { }); } +async function formWrite(options) { + $('#show-usage-guide').prop('checked', options.general.showGuide); + $('#compact-tags').prop('checked', options.general.compactTags); + $('#compact-glossaries').prop('checked', options.general.compactGlossaries); + $('#auto-play-audio').prop('checked', options.general.autoPlayAudio); + $('#result-output-mode').val(options.general.resultOutputMode); + $('#audio-playback-source').val(options.general.audioSource); + $('#audio-playback-volume').val(options.general.audioVolume); + $('#show-debug-info').prop('checked', options.general.debugInfo); + $('#show-advanced-options').prop('checked', options.general.showAdvanced); + $('#max-displayed-results').val(options.general.maxResults); + $('#popup-display-mode').val(options.general.popupDisplayMode); + $('#popup-horizontal-text-position').val(options.general.popupHorizontalTextPosition); + $('#popup-vertical-text-position').val(options.general.popupVerticalTextPosition); + $('#popup-width').val(options.general.popupWidth); + $('#popup-height').val(options.general.popupHeight); + $('#popup-horizontal-offset').val(options.general.popupHorizontalOffset); + $('#popup-vertical-offset').val(options.general.popupVerticalOffset); + $('#popup-horizontal-offset2').val(options.general.popupHorizontalOffset2); + $('#popup-vertical-offset2').val(options.general.popupVerticalOffset2); + $('#custom-popup-css').val(options.general.customPopupCss); + + $('#middle-mouse-button-scan').prop('checked', options.scanning.middleMouse); + $('#touch-input-enabled').prop('checked', options.scanning.touchInputEnabled); + $('#select-matched-text').prop('checked', options.scanning.selectText); + $('#search-alphanumeric').prop('checked', options.scanning.alphanumeric); + $('#auto-hide-results').prop('checked', options.scanning.autoHideResults); + $('#deep-dom-scan').prop('checked', options.scanning.deepDomScan); + $('#enable-scanning-of-popup-expressions').prop('checked', options.scanning.enableOnPopupExpressions); + $('#enable-scanning-on-search-page').prop('checked', options.scanning.enableOnSearchPage); + $('#scan-delay').val(options.scanning.delay); + $('#scan-length').val(options.scanning.length); + $('#scan-modifier-key').val(options.scanning.modifier); + $('#popup-nesting-max-depth').val(options.scanning.popupNestingMaxDepth); + + $('#dict-purge-link').click(utilAsync(onDictionaryPurge)); + $('#dict-file').change(utilAsync(onDictionaryImport)); + + $('#anki-enable').prop('checked', options.anki.enable); + $('#card-tags').val(options.anki.tags.join(' ')); + $('#sentence-detection-extent').val(options.anki.sentenceExt); + $('#interface-server').val(options.anki.server); + $('#screenshot-format').val(options.anki.screenshot.format); + $('#screenshot-quality').val(options.anki.screenshot.quality); + $('#field-templates').val(options.anki.fieldTemplates); + $('#field-templates-reset').click(utilAsync(onAnkiFieldTemplatesReset)); + $('input, select, textarea').not('.anki-model').change(utilAsync(onFormOptionsChanged)); + $('.anki-model').change(utilAsync(onAnkiModelChanged)); + + try { + await dictionaryGroupsPopulate(options); + await formMainDictionaryOptionsPopulate(options); + } catch (e) { + dictionaryErrorsShow([e]); + } + + try { + await ankiDeckAndModelPopulate(options); + } catch (e) { + ankiErrorShow(e); + } + + formUpdateVisibility(options); +} + function formUpdateVisibility(options) { const general = $('#anki-general'); if (options.anki.enable) { @@ -172,68 +237,7 @@ async function onReady() { const optionsContext = getOptionsContext(); const options = await apiOptionsGet(optionsContext); - $('#show-usage-guide').prop('checked', options.general.showGuide); - $('#compact-tags').prop('checked', options.general.compactTags); - $('#compact-glossaries').prop('checked', options.general.compactGlossaries); - $('#auto-play-audio').prop('checked', options.general.autoPlayAudio); - $('#result-output-mode').val(options.general.resultOutputMode); - $('#audio-playback-source').val(options.general.audioSource); - $('#audio-playback-volume').val(options.general.audioVolume); - $('#show-debug-info').prop('checked', options.general.debugInfo); - $('#show-advanced-options').prop('checked', options.general.showAdvanced); - $('#max-displayed-results').val(options.general.maxResults); - $('#popup-display-mode').val(options.general.popupDisplayMode); - $('#popup-horizontal-text-position').val(options.general.popupHorizontalTextPosition); - $('#popup-vertical-text-position').val(options.general.popupVerticalTextPosition); - $('#popup-width').val(options.general.popupWidth); - $('#popup-height').val(options.general.popupHeight); - $('#popup-horizontal-offset').val(options.general.popupHorizontalOffset); - $('#popup-vertical-offset').val(options.general.popupVerticalOffset); - $('#popup-horizontal-offset2').val(options.general.popupHorizontalOffset2); - $('#popup-vertical-offset2').val(options.general.popupVerticalOffset2); - $('#custom-popup-css').val(options.general.customPopupCss); - - $('#middle-mouse-button-scan').prop('checked', options.scanning.middleMouse); - $('#touch-input-enabled').prop('checked', options.scanning.touchInputEnabled); - $('#select-matched-text').prop('checked', options.scanning.selectText); - $('#search-alphanumeric').prop('checked', options.scanning.alphanumeric); - $('#auto-hide-results').prop('checked', options.scanning.autoHideResults); - $('#deep-dom-scan').prop('checked', options.scanning.deepDomScan); - $('#enable-scanning-of-popup-expressions').prop('checked', options.scanning.enableOnPopupExpressions); - $('#enable-scanning-on-search-page').prop('checked', options.scanning.enableOnSearchPage); - $('#scan-delay').val(options.scanning.delay); - $('#scan-length').val(options.scanning.length); - $('#scan-modifier-key').val(options.scanning.modifier); - $('#popup-nesting-max-depth').val(options.scanning.popupNestingMaxDepth); - - $('#dict-purge-link').click(utilAsync(onDictionaryPurge)); - $('#dict-file').change(utilAsync(onDictionaryImport)); - - $('#anki-enable').prop('checked', options.anki.enable); - $('#card-tags').val(options.anki.tags.join(' ')); - $('#sentence-detection-extent').val(options.anki.sentenceExt); - $('#interface-server').val(options.anki.server); - $('#screenshot-format').val(options.anki.screenshot.format); - $('#screenshot-quality').val(options.anki.screenshot.quality); - $('#field-templates').val(options.anki.fieldTemplates); - $('#field-templates-reset').click(utilAsync(onAnkiFieldTemplatesReset)); - $('input, select, textarea').not('.anki-model').change(utilAsync(onFormOptionsChanged)); - $('.anki-model').change(utilAsync(onAnkiModelChanged)); - - try { - await dictionaryGroupsPopulate(options); - await formMainDictionaryOptionsPopulate(options); - } catch (e) { - dictionaryErrorsShow([e]); - } - - try { - await ankiDeckAndModelPopulate(options); - } catch (e) { - ankiErrorShow(e); - } - - formUpdateVisibility(options); + await formWrite(options); storageInfoInitialize(); } -- cgit v1.2.3 From 1f8c7358cb017e0c96a454d9e9a1f53eb6d4fe15 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 8 Sep 2019 12:16:12 -0400 Subject: Create function for setting up form event listeners --- ext/bg/js/settings.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 3c261b88..06dba538 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -121,9 +121,6 @@ async function formWrite(options) { $('#scan-modifier-key').val(options.scanning.modifier); $('#popup-nesting-max-depth').val(options.scanning.popupNestingMaxDepth); - $('#dict-purge-link').click(utilAsync(onDictionaryPurge)); - $('#dict-file').change(utilAsync(onDictionaryImport)); - $('#anki-enable').prop('checked', options.anki.enable); $('#card-tags').val(options.anki.tags.join(' ')); $('#sentence-detection-extent').val(options.anki.sentenceExt); @@ -131,9 +128,6 @@ async function formWrite(options) { $('#screenshot-format').val(options.anki.screenshot.format); $('#screenshot-quality').val(options.anki.screenshot.quality); $('#field-templates').val(options.anki.fieldTemplates); - $('#field-templates-reset').click(utilAsync(onAnkiFieldTemplatesReset)); - $('input, select, textarea').not('.anki-model').change(utilAsync(onFormOptionsChanged)); - $('.anki-model').change(utilAsync(onAnkiModelChanged)); try { await dictionaryGroupsPopulate(options); @@ -151,6 +145,15 @@ async function formWrite(options) { formUpdateVisibility(options); } +function formSetupEventListeners() { + $('#dict-purge-link').click(utilAsync(onDictionaryPurge)); + $('#dict-file').change(utilAsync(onDictionaryImport)); + + $('#field-templates-reset').click(utilAsync(onAnkiFieldTemplatesReset)); + $('input, select, textarea').not('.anki-model').not('.profile-form *').change(utilAsync(onFormOptionsChanged)); + $('.anki-model').change(utilAsync(onAnkiModelChanged)); +} + function formUpdateVisibility(options) { const general = $('#anki-general'); if (options.anki.enable) { @@ -237,6 +240,7 @@ async function onReady() { const optionsContext = getOptionsContext(); const options = await apiOptionsGet(optionsContext); + formSetupEventListeners(); await formWrite(options); storageInfoInitialize(); -- cgit v1.2.3 From 71b700cd22f5a57a07cd2f9a6afa823793f5f95e Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 10 Sep 2019 20:49:17 -0400 Subject: Add checkbox for options.general.enable --- ext/bg/js/settings.js | 2 ++ ext/bg/settings.html | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 06dba538..f2f08b6e 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -23,6 +23,7 @@ function getOptionsContext() { } async function formRead(options) { + options.general.enable = $('#enable').prop('checked'); options.general.showGuide = $('#show-usage-guide').prop('checked'); options.general.compactTags = $('#compact-tags').prop('checked'); options.general.compactGlossaries = $('#compact-glossaries').prop('checked'); @@ -87,6 +88,7 @@ async function formRead(options) { } async function formWrite(options) { + $('#enable').prop('checked', options.general.enable); $('#show-usage-guide').prop('checked', options.general.showGuide); $('#compact-tags').prop('checked', options.general.compactTags); $('#compact-glossaries').prop('checked', options.general.compactGlossaries); diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 8c368474..577e1a1f 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -70,6 +70,10 @@

General Options

+
+ +
+
-- cgit v1.2.3 From 84bd9ff93b15f419ce1076b7545aeb406917f9b5 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 10 Sep 2019 20:46:30 -0400 Subject: Update settings if a different source triggers optionsUpdate --- ext/bg/js/api.js | 6 +++--- ext/bg/js/backend.js | 6 +++--- ext/bg/js/settings.js | 43 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 11 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 13c0d73a..81772d08 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -21,11 +21,11 @@ function apiOptionsGet(optionsContext) { return utilBackend().getOptions(optionsContext); } -async function apiOptionsSave() { +async function apiOptionsSave(source) { const backend = utilBackend(); const options = await backend.getFullOptions(); await optionsSave(options); - backend.onOptionsUpdated(); + backend.onOptionsUpdated(source); } async function apiTermsFind(text, optionsContext) { @@ -139,7 +139,7 @@ async function apiCommandExec(command) { const optionsContext = {depth: 0}; const options = await apiOptionsGet(optionsContext); options.general.enable = !options.general.enable; - await apiOptionsSave(); + await apiOptionsSave('popup'); } }; diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 4763e85d..9a300d62 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -35,7 +35,7 @@ class Backend { async prepare() { await this.translator.prepare(); this.options = await optionsLoad(); - this.onOptionsUpdated(); + this.onOptionsUpdated('background'); if (chrome.commands !== null && typeof chrome.commands === 'object') { chrome.commands.onCommand.addListener(this.onCommand.bind(this)); @@ -52,13 +52,13 @@ class Backend { this.isPreparedPromise = null; } - onOptionsUpdated() { + onOptionsUpdated(source) { this.applyOptions(); const callback = () => this.checkLastError(chrome.runtime.lastError); chrome.tabs.query({}, tabs => { for (const tab of tabs) { - chrome.tabs.sendMessage(tab.id, {action: 'optionsUpdate', params: {}}, callback); + chrome.tabs.sendMessage(tab.id, {action: 'optionsUpdate', params: {source}}, callback); } }); } diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index f2f08b6e..7f3e5c69 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -218,7 +218,7 @@ async function onFormOptionsChanged(e) { const optionsAnkiServerOld = options.anki.server; await formRead(options); - await apiOptionsSave(); + await settingsSaveOptions(); formUpdateVisibility(options); try { @@ -246,11 +246,44 @@ async function onReady() { await formWrite(options); storageInfoInitialize(); + + chrome.runtime.onMessage.addListener(onMessage); } $(document).ready(utilAsync(onReady)); +/* + * Remote options updates + */ + +function settingsGetSource() { + return new Promise((resolve) => { + chrome.tabs.getCurrent((tab) => resolve(`settings${tab ? tab.id : ''}`)); + }); +} + +async function settingsSaveOptions() { + const source = await settingsGetSource(); + await apiOptionsSave(source); +} + +async function onOptionsUpdate({source}) { + const thisSource = await settingsGetSource(); + if (source === thisSource) { return; } + + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); + await formWrite(options); +} + +function onMessage({action, params}) { + if (action === 'optionsUpdate') { + onOptionsUpdate(params); + } +} + + /* * Dictionary */ @@ -395,7 +428,7 @@ async function onDictionaryPurge(e) { const options = await apiOptionsGet(optionsContext); options.dictionaries = {}; options.general.mainDictionary = ''; - await apiOptionsSave(); + await settingsSaveOptions(); await dictionaryGroupsPopulate(options); await formMainDictionaryOptionsPopulate(options); @@ -445,7 +478,7 @@ async function onDictionaryImport(e) { dictionaryErrorsShow(exceptions); } - await apiOptionsSave(); + await settingsSaveOptions(); await dictionaryGroupsPopulate(options); await formMainDictionaryOptionsPopulate(options); @@ -589,7 +622,7 @@ async function onAnkiModelChanged(e) { const options = await apiOptionsGet(optionsContext); await formRead(options); options.anki[tabId].fields = {}; - await apiOptionsSave(); + await settingsSaveOptions(); ankiSpinnerShow(true); await ankiFieldsPopulate(element, options); @@ -609,7 +642,7 @@ async function onAnkiFieldTemplatesReset(e) { const fieldTemplates = optionsFieldTemplates(); options.anki.fieldTemplates = fieldTemplates; $('#field-templates').val(fieldTemplates); - await apiOptionsSave(); + await settingsSaveOptions(); } catch (e) { ankiErrorShow(e); } -- cgit v1.2.3 From 6358b655aef94279133550c93a944dbe785cee44 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 14 Sep 2019 16:21:41 -0400 Subject: Isolate options objects created via settings.js Prevents dead objects created by different windows. --- ext/bg/js/settings.js | 20 ++++++++++++-------- ext/bg/js/util.js | 5 +++++ 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 7f3e5c69..3d581ba5 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -60,7 +60,7 @@ async function formRead(options) { const optionsAnkiEnableOld = options.anki.enable; options.anki.enable = $('#anki-enable').prop('checked'); - options.anki.tags = $('#card-tags').val().split(/[,; ]+/); + 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.screenshot.format = $('#screenshot-format').val(); @@ -70,20 +70,20 @@ async function formRead(options) { if (optionsAnkiEnableOld && !ankiErrorShown()) { options.anki.terms.deck = $('#anki-terms-deck').val(); options.anki.terms.model = $('#anki-terms-model').val(); - options.anki.terms.fields = ankiFieldsToDict($('#terms .anki-field-value')); + options.anki.terms.fields = utilBackgroundIsolate(ankiFieldsToDict($('#terms .anki-field-value'))); options.anki.kanji.deck = $('#anki-kanji-deck').val(); options.anki.kanji.model = $('#anki-kanji-model').val(); - options.anki.kanji.fields = ankiFieldsToDict($('#kanji .anki-field-value')); + options.anki.kanji.fields = utilBackgroundIsolate(ankiFieldsToDict($('#kanji .anki-field-value'))); } options.general.mainDictionary = $('#dict-main').val(); $('.dict-group').each((index, element) => { const dictionary = $(element); - options.dictionaries[dictionary.data('title')] = { + options.dictionaries[dictionary.data('title')] = utilBackgroundIsolate({ priority: parseInt(dictionary.find('.dict-priority').val(), 10), enabled: dictionary.find('.dict-enabled').prop('checked'), allowSecondarySearches: dictionary.find('.dict-allow-secondary-searches').prop('checked') - }; + }); }); } @@ -426,7 +426,7 @@ async function onDictionaryPurge(e) { await utilDatabasePurge(); const optionsContext = getOptionsContext(); const options = await apiOptionsGet(optionsContext); - options.dictionaries = {}; + options.dictionaries = utilBackgroundIsolate({}); options.general.mainDictionary = ''; await settingsSaveOptions(); @@ -468,7 +468,11 @@ async function onDictionaryImport(e) { const summary = await utilDatabaseImport(e.target.files[0], updateProgress, exceptions); const optionsContext = getOptionsContext(); const options = await apiOptionsGet(optionsContext); - options.dictionaries[summary.title] = {enabled: true, priority: 0, allowSecondarySearches: false}; + options.dictionaries[summary.title] = utilBackgroundIsolate({ + enabled: true, + priority: 0, + allowSecondarySearches: false + }); if (summary.sequenced && options.general.mainDictionary === '') { options.general.mainDictionary = summary.title; } @@ -621,7 +625,7 @@ async function onAnkiModelChanged(e) { const optionsContext = getOptionsContext(); const options = await apiOptionsGet(optionsContext); await formRead(options); - options.anki[tabId].fields = {}; + options.anki[tabId].fields = utilBackgroundIsolate({}); await settingsSaveOptions(); ankiSpinnerShow(true); diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 79229229..73a8396f 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -26,6 +26,11 @@ function utilIsolate(data) { return JSON.parse(JSON.stringify(data)); } +function utilBackgroundIsolate(data) { + const backgroundPage = chrome.extension.getBackgroundPage(); + return backgroundPage.utilIsolate(data); +} + function utilSetEqual(setA, setB) { if (setA.size !== setB.size) { return false; -- cgit v1.2.3 From c8171f5ec7612f0ba147d7e0887cd8c30a527827 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 7 Sep 2019 19:50:58 -0400 Subject: Add preliminary support for profiles --- ext/bg/js/backend.js | 10 +++++- ext/bg/js/options.js | 91 +++++++++++++++++++++++++++++++++++++++++++-------- ext/bg/js/settings.js | 2 +- 3 files changed, 87 insertions(+), 16 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 9a300d62..3839da39 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -165,7 +165,15 @@ class Backend { } getOptionsSync(optionsContext) { - return this.options; + return this.getProfileSync(optionsContext).options; + } + + getProfileSync(optionsContext) { + const profiles = this.options.profiles; + if (typeof optionsContext.index === 'number') { + return profiles[optionsContext.index]; + } + return this.options.profiles[this.options.profileCurrent]; } setExtensionBadgeBackgroundColor(color) { diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index 5f04ec31..3dce5221 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -17,7 +17,11 @@ */ -function optionsApplyUpdates(options, updates) { +/* + * Generic options functions + */ + +function optionsGenericApplyUpdates(options, updates) { const targetVersion = updates.length; const currentVersion = options.version; if (typeof currentVersion === 'number' && Number.isFinite(currentVersion)) { @@ -33,7 +37,12 @@ function optionsApplyUpdates(options, updates) { return options; } -const optionsVersionUpdates = [ + +/* + * Per-profile options + */ + +const profileOptionsVersionUpdates = [ null, null, null, @@ -48,7 +57,7 @@ const optionsVersionUpdates = [ options.scanning.modifier = options.scanning.requireShift ? 'shift' : 'none'; }, (options) => { - const fieldTemplatesDefault = optionsFieldTemplates(); + const fieldTemplatesDefault = profileOptionsGetDefaultFieldTemplates(); options.general.resultOutputMode = options.general.groupResults ? 'group' : 'split'; options.anki.fieldTemplates = ( (utilStringHashCode(options.anki.fieldTemplates) !== -805327496) ? @@ -58,17 +67,17 @@ const optionsVersionUpdates = [ }, (options) => { if (utilStringHashCode(options.anki.fieldTemplates) === 1285806040) { - options.anki.fieldTemplates = optionsFieldTemplates(); + options.anki.fieldTemplates = profileOptionsGetDefaultFieldTemplates(); } }, (options) => { if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) { - options.anki.fieldTemplates = optionsFieldTemplates(); + options.anki.fieldTemplates = profileOptionsGetDefaultFieldTemplates(); } } ]; -function optionsFieldTemplates() { +function profileOptionsGetDefaultFieldTemplates() { return ` {{#*inline "glossary-single"}} {{~#unless brief~}} @@ -234,7 +243,7 @@ function optionsFieldTemplates() { `.trim(); } -function optionsCreateDefaults() { +function profileOptionsCreateDefaults() { return { general: { enable: true, @@ -286,13 +295,13 @@ function optionsCreateDefaults() { screenshot: {format: 'png', quality: 92}, terms: {deck: '', model: '', fields: {}}, kanji: {deck: '', model: '', fields: {}}, - fieldTemplates: optionsFieldTemplates() + fieldTemplates: profileOptionsGetDefaultFieldTemplates() } }; } -function optionsSetDefaults(options) { - const defaults = optionsCreateDefaults(); +function profileOptionsSetDefaults(options) { + const defaults = profileOptionsCreateDefaults(); const combine = (target, source) => { for (const key in source) { @@ -312,9 +321,59 @@ function optionsSetDefaults(options) { return options; } -function optionsVersion(options) { - optionsSetDefaults(options); - return optionsApplyUpdates(options, optionsVersionUpdates); +function profileOptionsUpdateVersion(options) { + profileOptionsSetDefaults(options); + return optionsGenericApplyUpdates(options, profileOptionsVersionUpdates); +} + + +/* + * Global options + */ + +const optionsVersionUpdates = []; + +function optionsUpdateVersion(options, defaultProfileOptions) { + // Ensure profiles is an array + if (!Array.isArray(options.profiles)) { + options.profiles = []; + } + + // Remove invalid + const profiles = options.profiles; + for (let i = profiles.length - 1; i >= 0; --i) { + if (!utilIsObject(profiles[i])) { + profiles.splice(i, 1); + } + } + + // Require at least one profile + if (profiles.length === 0) { + profiles.push({ + name: 'Default', + options: defaultProfileOptions + }); + } + + // Ensure profileCurrent is valid + const profileCurrent = options.profileCurrent; + if (!( + typeof profileCurrent === 'number' && + Number.isFinite(profileCurrent) && + Math.floor(profileCurrent) === profileCurrent && + profileCurrent >= 0 && + profileCurrent < profiles.length + )) { + options.profileCurrent = 0; + } + + // Update profile options + for (const profile of profiles) { + profile.options = profileOptionsUpdateVersion(profile.options); + } + + // Generic updates + return optionsGenericApplyUpdates(options, optionsVersionUpdates); } function optionsLoad() { @@ -338,7 +397,11 @@ function optionsLoad() { }).catch(() => { return {}; }).then(options => { - return optionsVersion(options); + return ( + Array.isArray(options.profiles) ? + optionsUpdateVersion(options, {}) : + optionsUpdateVersion({}, options) + ); }); } diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 3d581ba5..88929c49 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -643,7 +643,7 @@ async function onAnkiFieldTemplatesReset(e) { e.preventDefault(); const optionsContext = getOptionsContext(); const options = await apiOptionsGet(optionsContext); - const fieldTemplates = optionsFieldTemplates(); + const fieldTemplates = profileOptionsGetDefaultFieldTemplates(); options.anki.fieldTemplates = fieldTemplates; $('#field-templates').val(fieldTemplates); await settingsSaveOptions(); -- cgit v1.2.3 From 6c571bf8284c44bf01fe20c267fe72cce235b90d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 8 Sep 2019 13:16:05 -0400 Subject: Add UI for profiles --- ext/bg/js/api.js | 6 +- ext/bg/js/settings-profiles.js | 201 +++++++++++++++++++++++++++++++++++++++++ ext/bg/js/settings.js | 11 +-- ext/bg/settings.html | 53 +++++++++++ 4 files changed, 260 insertions(+), 11 deletions(-) create mode 100644 ext/bg/js/settings-profiles.js (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 81772d08..f32b984f 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -21,9 +21,13 @@ function apiOptionsGet(optionsContext) { return utilBackend().getOptions(optionsContext); } +function apiOptionsGetFull() { + return utilBackend().getFullOptions(); +} + async function apiOptionsSave(source) { const backend = utilBackend(); - const options = await backend.getFullOptions(); + const options = await apiOptionsGetFull(); await optionsSave(options); backend.onOptionsUpdated(source); } diff --git a/ext/bg/js/settings-profiles.js b/ext/bg/js/settings-profiles.js new file mode 100644 index 00000000..dca452d2 --- /dev/null +++ b/ext/bg/js/settings-profiles.js @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * 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 . + */ + +let currentProfileIndex = 0; + +function getOptionsContext() { + return { + index: currentProfileIndex + }; +} + + +async function profileOptionsSetup() { + const optionsFull = await apiOptionsGetFull(); + currentProfileIndex = optionsFull.profileCurrent; + + profileOptionsSetupEventListeners(); + await profileOptionsUpdateTarget(optionsFull); +} + +function profileOptionsSetupEventListeners() { + $('#profile-target').change(utilAsync(onTargetProfileChanged)); + $('#profile-name').change(onProfileNameChanged); + $('#profile-add').click(utilAsync(onProfileAdd)); + $('#profile-remove').click(utilAsync(onProfileRemove)); + $('#profile-remove-confirm').click(utilAsync(onProfileRemoveConfirm)); + $('.profile-form').find('input, select, textarea').not('.profile-form-manual').change(utilAsync(onProfileOptionsChanged)); +} + +function tryGetIntegerValue(selector, min, max) { + const value = parseInt($(selector).val(), 10); + return ( + typeof value === 'number' && + Number.isFinite(value) && + Math.floor(value) === value && + value >= min && + value < max + ) ? value : null; +} + +async function profileFormRead(optionsFull) { + const profile = optionsFull.profiles[currentProfileIndex]; + + // Current profile + const index = tryGetIntegerValue('#profile-active', 0, optionsFull.profiles.length); + if (index !== null) { + optionsFull.profileCurrent = index; + } + + // Profile name + profile.name = $('#profile-name').val(); +} + +async function profileFormWrite(optionsFull) { + const profile = optionsFull.profiles[currentProfileIndex]; + + profileOptionsPopulateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent); + profileOptionsPopulateSelect($('#profile-target'), optionsFull.profiles, currentProfileIndex); + $('#profile-remove').prop('disabled', optionsFull.profiles.length <= 1); + + $('#profile-name').val(profile.name); +} + +function profileOptionsPopulateSelect(select, profiles, currentValue) { + select.empty(); + + for (let i = 0; i < profiles.length; ++i) { + const profile = profiles[i]; + select.append($(``)); + } + + select.val(`${currentValue}`); +} + +async function profileOptionsUpdateTarget(optionsFull) { + profileFormWrite(optionsFull); + + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); + await formWrite(options); +} + +function profileOptionsCreateCopyName(name, profiles, maxUniqueAttempts) { + let space, index, prefix, suffix; + const match = /^([\w\W]*\(Copy)((\s+)(\d+))?(\)\s*)$/.exec(name); + if (match === null) { + prefix = `${name} (Copy`; + space = ''; + index = ''; + suffix = ')'; + } else { + prefix = match[1]; + suffix = match[5]; + if (typeof match[2] === 'string') { + space = match[3]; + index = parseInt(match[4], 10) + 1; + } else { + space = ' '; + index = 2; + } + } + + let i = 0; + while (true) { + const newName = `${prefix}${space}${index}${suffix}`; + if (i++ >= maxUniqueAttempts || profiles.findIndex(profile => profile.name === newName) < 0) { + return newName; + } + if (typeof index !== 'number') { + index = 2; + space = ' '; + } else { + ++index; + } + } +} + +async function onProfileOptionsChanged(e) { + if (!e.originalEvent && !e.isTrigger) { + return; + } + + const optionsFull = await apiOptionsGetFull(); + await profileFormRead(optionsFull); + await apiOptionsSave(); +} + +async function onTargetProfileChanged() { + const optionsFull = await apiOptionsGetFull(); + const index = tryGetIntegerValue('#profile-target', 0, optionsFull.profiles.length); + if (index === null || currentProfileIndex === index) { + return; + } + + currentProfileIndex = index; + + await profileOptionsUpdateTarget(optionsFull); +} + +async function onProfileAdd() { + const optionsFull = await apiOptionsGetFull(); + const profile = utilIsolate(optionsFull.profiles[currentProfileIndex]); + profile.name = profileOptionsCreateCopyName(profile.name, optionsFull.profiles, 100); + optionsFull.profiles.push(profile); + currentProfileIndex = optionsFull.profiles.length - 1; + await profileOptionsUpdateTarget(optionsFull); + await apiOptionsSave(); +} + +async function onProfileRemove() { + const optionsFull = await apiOptionsGetFull(); + if (optionsFull.profiles.length <= 1) { + return; + } + + const profile = optionsFull.profiles[currentProfileIndex]; + + $('#profile-remove-modal-profile-name').text(profile.name); + $('#profile-remove-modal').modal('show'); +} + +async function onProfileRemoveConfirm() { + $('#profile-remove-modal').modal('hide'); + + const optionsFull = await apiOptionsGetFull(); + if (optionsFull.profiles.length <= 1) { + return; + } + + optionsFull.profiles.splice(currentProfileIndex, 1); + + if (currentProfileIndex >= optionsFull.profiles.length) { + --currentProfileIndex; + } + + if (optionsFull.profileCurrent >= optionsFull.profiles.length) { + optionsFull.profileCurrent = optionsFull.profiles.length - 1; + } + + await profileOptionsUpdateTarget(optionsFull); + await apiOptionsSave(); +} + +function onProfileNameChanged() { + $('#profile-active, #profile-target').find(`[value="${currentProfileIndex}"]`).text(this.value); +} diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 88929c49..b6434843 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -16,12 +16,6 @@ * along with this program. If not, see . */ -function getOptionsContext() { - return { - depth: 0 - }; -} - async function formRead(options) { options.general.enable = $('#enable').prop('checked'); options.general.showGuide = $('#show-usage-guide').prop('checked'); @@ -239,11 +233,8 @@ async function onFormOptionsChanged(e) { } async function onReady() { - const optionsContext = getOptionsContext(); - const options = await apiOptionsGet(optionsContext); - formSetupEventListeners(); - await formWrite(options); + await profileOptionsSetup(); storageInfoInitialize(); diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 7df47980..1a1bc2ed 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -67,6 +67,58 @@
+
+

Profiles

+ +

+ Profiles allow you to create multiple configurations and quickly switch between them. +

+ +
+ + +
+ +
+ +
+
+ + + + +
+ +
+ +
+
+
+ +
+ + +
+ + +
+

General Options

@@ -498,6 +550,7 @@ + -- cgit v1.2.3 From c002e1bbd21341ae758819da59b7b65b99b97f4f Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 8 Sep 2019 13:27:32 -0400 Subject: Update dictionaries for all profile options --- ext/bg/js/settings.js | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'ext/bg/js/settings.js') diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index b6434843..cb3ddd4e 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -16,6 +16,11 @@ * along with this program. If not, see . */ +async function getOptionsArray() { + const optionsFull = await apiOptionsGetFull(); + return optionsFull.profiles.map(profile => profile.options); +} + async function formRead(options) { options.general.enable = $('#enable').prop('checked'); options.general.showGuide = $('#show-usage-guide').prop('checked'); @@ -415,12 +420,14 @@ async function onDictionaryPurge(e) { dictionarySpinnerShow(true); await utilDatabasePurge(); - const optionsContext = getOptionsContext(); - const options = await apiOptionsGet(optionsContext); - options.dictionaries = utilBackgroundIsolate({}); - options.general.mainDictionary = ''; + for (const options of await getOptionsArray()) { + options.dictionaries = utilBackgroundIsolate({}); + options.general.mainDictionary = ''; + } await settingsSaveOptions(); + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); await dictionaryGroupsPopulate(options); await formMainDictionaryOptionsPopulate(options); } catch (e) { @@ -457,24 +464,25 @@ async function onDictionaryImport(e) { const exceptions = []; const summary = await utilDatabaseImport(e.target.files[0], updateProgress, exceptions); - const optionsContext = getOptionsContext(); - const options = await apiOptionsGet(optionsContext); - options.dictionaries[summary.title] = utilBackgroundIsolate({ - enabled: true, - priority: 0, - allowSecondarySearches: false - }); - if (summary.sequenced && options.general.mainDictionary === '') { - options.general.mainDictionary = summary.title; + for (const options of await getOptionsArray()) { + options.dictionaries[summary.title] = utilBackgroundIsolate({ + enabled: true, + priority: 0, + allowSecondarySearches: false + }); + if (summary.sequenced && options.general.mainDictionary === '') { + options.general.mainDictionary = summary.title; + } } + await settingsSaveOptions(); if (exceptions.length > 0) { exceptions.push(`Dictionary may not have been imported properly: ${exceptions.length} error${exceptions.length === 1 ? '' : 's'} reported.`); dictionaryErrorsShow(exceptions); } - await settingsSaveOptions(); - + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); await dictionaryGroupsPopulate(options); await formMainDictionaryOptionsPopulate(options); } catch (e) { -- cgit v1.2.3