From c61a87b152b91bdebe01eefdbc3fa00670a3071d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 24 May 2020 13:30:40 -0400 Subject: API refactor (#532) * Convert api.js into a class instance * Use new api.* functions * Fix missing binds * Group functions with progress callbacks together * Change style * Fix API override not working --- ext/bg/js/settings/backup.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'ext/bg/js/settings/backup.js') diff --git a/ext/bg/js/settings/backup.js b/ext/bg/js/settings/backup.js index faf4e592..5eb55502 100644 --- a/ext/bg/js/settings/backup.js +++ b/ext/bg/js/settings/backup.js @@ -16,9 +16,7 @@ */ /* global - * apiGetDefaultAnkiFieldTemplates - * apiGetEnvironmentInfo - * apiOptionsGetFull + * api * optionsGetDefault * optionsUpdateVersion * utilBackend @@ -51,9 +49,9 @@ function _getSettingsExportDateString(date, dateSeparator, dateTimeSeparator, ti } async function _getSettingsExportData(date) { - const optionsFull = await apiOptionsGetFull(); - const environment = await apiGetEnvironmentInfo(); - const fieldTemplatesDefault = await apiGetDefaultAnkiFieldTemplates(); + const optionsFull = await api.optionsGetFull(); + const environment = await api.getEnvironmentInfo(); + const fieldTemplatesDefault = await api.getDefaultAnkiFieldTemplates(); // Format options for (const {options} of optionsFull.profiles) { -- cgit v1.2.3 From 13f57cccba5a29ff9e270a3fc2b2d7fee6e46b51 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 24 May 2020 13:56:46 -0400 Subject: Settings backup refactor (#551) * Update backup.js to be a class * Move utilReadFileArrayBuffer --- ext/bg/js/settings/backup.js | 569 ++++++++++++++++++++++--------------------- ext/bg/js/settings/main.js | 4 +- ext/bg/js/util.js | 9 - 3 files changed, 292 insertions(+), 290 deletions(-) (limited to 'ext/bg/js/settings/backup.js') diff --git a/ext/bg/js/settings/backup.js b/ext/bg/js/settings/backup.js index 5eb55502..4e104e6f 100644 --- a/ext/bg/js/settings/backup.js +++ b/ext/bg/js/settings/backup.js @@ -22,355 +22,366 @@ * utilBackend * utilBackgroundIsolate * utilIsolate - * utilReadFileArrayBuffer */ -// Exporting - -let _settingsExportToken = null; -let _settingsExportRevoke = null; -const SETTINGS_EXPORT_CURRENT_VERSION = 0; - -function _getSettingsExportDateString(date, dateSeparator, dateTimeSeparator, timeSeparator, resolution) { - const values = [ - date.getUTCFullYear().toString(), - dateSeparator, - (date.getUTCMonth() + 1).toString().padStart(2, '0'), - dateSeparator, - date.getUTCDate().toString().padStart(2, '0'), - dateTimeSeparator, - date.getUTCHours().toString().padStart(2, '0'), - timeSeparator, - date.getUTCMinutes().toString().padStart(2, '0'), - timeSeparator, - date.getUTCSeconds().toString().padStart(2, '0') - ]; - return values.slice(0, resolution * 2 - 1).join(''); -} +class SettingsBackup { + constructor() { + this._settingsExportToken = null; + this._settingsExportRevoke = null; + this._currentVersion = 0; + } -async function _getSettingsExportData(date) { - const optionsFull = await api.optionsGetFull(); - const environment = await api.getEnvironmentInfo(); - const fieldTemplatesDefault = await api.getDefaultAnkiFieldTemplates(); + prepare() { + document.querySelector('#settings-export').addEventListener('click', this._onSettingsExportClick.bind(this), false); + document.querySelector('#settings-import').addEventListener('click', this._onSettingsImportClick.bind(this), false); + document.querySelector('#settings-import-file').addEventListener('change', this._onSettingsImportFileChange.bind(this), false); + document.querySelector('#settings-reset').addEventListener('click', this._onSettingsResetClick.bind(this), false); + document.querySelector('#settings-reset-modal-confirm').addEventListener('click', this._onSettingsResetConfirmClick.bind(this), false); + } - // Format options - for (const {options} of optionsFull.profiles) { - if (options.anki.fieldTemplates === fieldTemplatesDefault || !options.anki.fieldTemplates) { - delete options.anki.fieldTemplates; // Default - } + // Private + + _getSettingsExportDateString(date, dateSeparator, dateTimeSeparator, timeSeparator, resolution) { + const values = [ + date.getUTCFullYear().toString(), + dateSeparator, + (date.getUTCMonth() + 1).toString().padStart(2, '0'), + dateSeparator, + date.getUTCDate().toString().padStart(2, '0'), + dateTimeSeparator, + date.getUTCHours().toString().padStart(2, '0'), + timeSeparator, + date.getUTCMinutes().toString().padStart(2, '0'), + timeSeparator, + date.getUTCSeconds().toString().padStart(2, '0') + ]; + return values.slice(0, resolution * 2 - 1).join(''); } - const data = { - version: SETTINGS_EXPORT_CURRENT_VERSION, - date: _getSettingsExportDateString(date, '-', ' ', ':', 6), - url: chrome.runtime.getURL('/'), - manifest: chrome.runtime.getManifest(), - environment, - userAgent: navigator.userAgent, - options: optionsFull - }; - - return data; -} + async _getSettingsExportData(date) { + const optionsFull = await api.optionsGetFull(); + const environment = await api.getEnvironmentInfo(); + const fieldTemplatesDefault = await api.getDefaultAnkiFieldTemplates(); -function _saveBlob(blob, fileName) { - if (typeof navigator === 'object' && typeof navigator.msSaveBlob === 'function') { - if (navigator.msSaveBlob(blob)) { - return; + // Format options + for (const {options} of optionsFull.profiles) { + if (options.anki.fieldTemplates === fieldTemplatesDefault || !options.anki.fieldTemplates) { + delete options.anki.fieldTemplates; // Default + } } - } - const blobUrl = URL.createObjectURL(blob); + const data = { + version: this._currentVersion, + date: this._getSettingsExportDateString(date, '-', ' ', ':', 6), + url: chrome.runtime.getURL('/'), + manifest: chrome.runtime.getManifest(), + environment, + userAgent: navigator.userAgent, + options: optionsFull + }; - const a = document.createElement('a'); - a.href = blobUrl; - a.download = fileName; - a.rel = 'noopener'; - a.target = '_blank'; + return data; + } - const revoke = () => { - URL.revokeObjectURL(blobUrl); - a.href = ''; - _settingsExportRevoke = null; - }; - _settingsExportRevoke = revoke; + _saveBlob(blob, fileName) { + if (typeof navigator === 'object' && typeof navigator.msSaveBlob === 'function') { + if (navigator.msSaveBlob(blob)) { + return; + } + } - a.dispatchEvent(new MouseEvent('click')); - setTimeout(revoke, 60000); -} + const blobUrl = URL.createObjectURL(blob); -async function _onSettingsExportClick() { - if (_settingsExportRevoke !== null) { - _settingsExportRevoke(); - _settingsExportRevoke = null; - } + const a = document.createElement('a'); + a.href = blobUrl; + a.download = fileName; + a.rel = 'noopener'; + a.target = '_blank'; - const date = new Date(Date.now()); + const revoke = () => { + URL.revokeObjectURL(blobUrl); + a.href = ''; + this._settingsExportRevoke = null; + }; + this._settingsExportRevoke = revoke; - const token = {}; - _settingsExportToken = token; - const data = await _getSettingsExportData(date); - if (_settingsExportToken !== token) { - // A new export has been started - return; + a.dispatchEvent(new MouseEvent('click')); + setTimeout(revoke, 60000); } - _settingsExportToken = null; - const fileName = `yomichan-settings-${_getSettingsExportDateString(date, '-', '-', '-', 6)}.json`; - const blob = new Blob([JSON.stringify(data, null, 4)], {type: 'application/json'}); - _saveBlob(blob, fileName); -} - - -// Importing + async _onSettingsExportClick() { + if (this._settingsExportRevoke !== null) { + this._settingsExportRevoke(); + this._settingsExportRevoke = null; + } -async function _settingsImportSetOptionsFull(optionsFull) { - return utilIsolate(utilBackend().setFullOptions( - utilBackgroundIsolate(optionsFull) - )); -} + const date = new Date(Date.now()); -function _showSettingsImportError(error) { - yomichan.logError(error); - document.querySelector('#settings-import-error-modal-message').textContent = `${error}`; - $('#settings-import-error-modal').modal('show'); -} + const token = {}; + this._settingsExportToken = token; + const data = await this._getSettingsExportData(date); + if (this._settingsExportToken !== token) { + // A new export has been started + return; + } + this._settingsExportToken = null; -async function _showSettingsImportWarnings(warnings) { - const modalNode = $('#settings-import-warning-modal'); - const buttons = document.querySelectorAll('.settings-import-warning-modal-import-button'); - const messageContainer = document.querySelector('#settings-import-warning-modal-message'); - if (modalNode.length === 0 || buttons.length === 0 || messageContainer === null) { - return {result: false}; + const fileName = `yomichan-settings-${this._getSettingsExportDateString(date, '-', '-', '-', 6)}.json`; + const blob = new Blob([JSON.stringify(data, null, 4)], {type: 'application/json'}); + this._saveBlob(blob, fileName); } - // Set message - const fragment = document.createDocumentFragment(); - for (const warning of warnings) { - const node = document.createElement('li'); - node.textContent = `${warning}`; - fragment.appendChild(node); + _readFileArrayBuffer(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = () => reject(reader.error); + reader.readAsArrayBuffer(file); + }); } - messageContainer.textContent = ''; - messageContainer.appendChild(fragment); - - // Show modal - modalNode.modal('show'); - - // Wait for modal to close - return new Promise((resolve) => { - const onButtonClick = (e) => { - e.preventDefault(); - complete({ - result: true, - sanitize: e.currentTarget.dataset.importSanitize === 'true' - }); - modalNode.modal('hide'); - }; - const onModalHide = () => { - complete({result: false}); - }; - let completed = false; - const complete = (result) => { - if (completed) { return; } - completed = true; + // Importing - modalNode.off('hide.bs.modal', onModalHide); - for (const button of buttons) { - button.removeEventListener('click', onButtonClick, false); - } + async _settingsImportSetOptionsFull(optionsFull) { + return utilIsolate(utilBackend().setFullOptions( + utilBackgroundIsolate(optionsFull) + )); + } - resolve(result); - }; + _showSettingsImportError(error) { + yomichan.logError(error); + document.querySelector('#settings-import-error-modal-message').textContent = `${error}`; + $('#settings-import-error-modal').modal('show'); + } - // Hook events - modalNode.on('hide.bs.modal', onModalHide); - for (const button of buttons) { - button.addEventListener('click', onButtonClick, false); + async _showSettingsImportWarnings(warnings) { + const modalNode = $('#settings-import-warning-modal'); + const buttons = document.querySelectorAll('.settings-import-warning-modal-import-button'); + const messageContainer = document.querySelector('#settings-import-warning-modal-message'); + if (modalNode.length === 0 || buttons.length === 0 || messageContainer === null) { + return {result: false}; } - }); -} -function _isLocalhostUrl(urlString) { - try { - const url = new URL(urlString); - switch (url.hostname.toLowerCase()) { - case 'localhost': - case '127.0.0.1': - case '[::1]': - switch (url.protocol.toLowerCase()) { - case 'http:': - case 'https:': - return true; - } - break; + // Set message + const fragment = document.createDocumentFragment(); + for (const warning of warnings) { + const node = document.createElement('li'); + node.textContent = `${warning}`; + fragment.appendChild(node); } - } catch (e) { - // NOP - } - return false; -} + messageContainer.textContent = ''; + messageContainer.appendChild(fragment); + + // Show modal + modalNode.modal('show'); + + // Wait for modal to close + return new Promise((resolve) => { + const onButtonClick = (e) => { + e.preventDefault(); + complete({ + result: true, + sanitize: e.currentTarget.dataset.importSanitize === 'true' + }); + modalNode.modal('hide'); + }; + const onModalHide = () => { + complete({result: false}); + }; + + let completed = false; + const complete = (result) => { + if (completed) { return; } + completed = true; + + modalNode.off('hide.bs.modal', onModalHide); + for (const button of buttons) { + button.removeEventListener('click', onButtonClick, false); + } -function _settingsImportSanitizeProfileOptions(options, dryRun) { - const warnings = []; + resolve(result); + }; - const anki = options.anki; - if (isObject(anki)) { - const fieldTemplates = anki.fieldTemplates; - if (typeof fieldTemplates === 'string') { - warnings.push('anki.fieldTemplates contains a non-default value'); - if (!dryRun) { - delete anki.fieldTemplates; - } - } - const server = anki.server; - if (typeof server === 'string' && server.length > 0 && !_isLocalhostUrl(server)) { - warnings.push('anki.server uses a non-localhost URL'); - if (!dryRun) { - delete anki.server; + // Hook events + modalNode.on('hide.bs.modal', onModalHide); + for (const button of buttons) { + button.addEventListener('click', onButtonClick, false); } - } + }); } - const audio = options.audio; - if (isObject(audio)) { - const customSourceUrl = audio.customSourceUrl; - if (typeof customSourceUrl === 'string' && customSourceUrl.length > 0 && !_isLocalhostUrl(customSourceUrl)) { - warnings.push('audio.customSourceUrl uses a non-localhost URL'); - if (!dryRun) { - delete audio.customSourceUrl; + _isLocalhostUrl(urlString) { + try { + const url = new URL(urlString); + switch (url.hostname.toLowerCase()) { + case 'localhost': + case '127.0.0.1': + case '[::1]': + switch (url.protocol.toLowerCase()) { + case 'http:': + case 'https:': + return true; + } + break; } + } catch (e) { + // NOP } + return false; } - return warnings; -} - -function _settingsImportSanitizeOptions(optionsFull, dryRun) { - const warnings = new Set(); + _settingsImportSanitizeProfileOptions(options, dryRun) { + const warnings = []; - const profiles = optionsFull.profiles; - if (Array.isArray(profiles)) { - for (const profile of profiles) { - if (!isObject(profile)) { continue; } - const options = profile.options; - if (!isObject(options)) { continue; } - - const warnings2 = _settingsImportSanitizeProfileOptions(options, dryRun); - for (const warning of warnings2) { - warnings.add(warning); + const anki = options.anki; + if (isObject(anki)) { + const fieldTemplates = anki.fieldTemplates; + if (typeof fieldTemplates === 'string') { + warnings.push('anki.fieldTemplates contains a non-default value'); + if (!dryRun) { + delete anki.fieldTemplates; + } + } + const server = anki.server; + if (typeof server === 'string' && server.length > 0 && !this._isLocalhostUrl(server)) { + warnings.push('anki.server uses a non-localhost URL'); + if (!dryRun) { + delete anki.server; + } } } - } - return warnings; -} + const audio = options.audio; + if (isObject(audio)) { + const customSourceUrl = audio.customSourceUrl; + if (typeof customSourceUrl === 'string' && customSourceUrl.length > 0 && !this._isLocalhostUrl(customSourceUrl)) { + warnings.push('audio.customSourceUrl uses a non-localhost URL'); + if (!dryRun) { + delete audio.customSourceUrl; + } + } + } -function _utf8Decode(arrayBuffer) { - try { - return new TextDecoder('utf-8').decode(arrayBuffer); - } catch (e) { - const binaryString = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); - return decodeURIComponent(escape(binaryString)); + return warnings; } -} -async function _importSettingsFile(file) { - const dataString = _utf8Decode(await utilReadFileArrayBuffer(file)); - const data = JSON.parse(dataString); + _settingsImportSanitizeOptions(optionsFull, dryRun) { + const warnings = new Set(); - // Type check - if (!isObject(data)) { - throw new Error(`Invalid data type: ${typeof data}`); - } + const profiles = optionsFull.profiles; + if (Array.isArray(profiles)) { + for (const profile of profiles) { + if (!isObject(profile)) { continue; } + const options = profile.options; + if (!isObject(options)) { continue; } - // Version check - const version = data.version; - if (!( - typeof version === 'number' && - Number.isFinite(version) && - version === Math.floor(version) - )) { - throw new Error(`Invalid version: ${version}`); - } + const warnings2 = this._settingsImportSanitizeProfileOptions(options, dryRun); + for (const warning of warnings2) { + warnings.add(warning); + } + } + } - if (!( - version >= 0 && - version <= SETTINGS_EXPORT_CURRENT_VERSION - )) { - throw new Error(`Unsupported version: ${version}`); + return warnings; } - // Verify options exists - let optionsFull = data.options; - if (!isObject(optionsFull)) { - throw new Error(`Invalid options type: ${typeof optionsFull}`); + _utf8Decode(arrayBuffer) { + try { + return new TextDecoder('utf-8').decode(arrayBuffer); + } catch (e) { + const binaryString = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)); + return decodeURIComponent(escape(binaryString)); + } } - // Upgrade options - optionsFull = optionsUpdateVersion(optionsFull, {}); + async _importSettingsFile(file) { + const dataString = this._utf8Decode(await this._readFileArrayBuffer(file)); + const data = JSON.parse(dataString); - // Check for warnings - const sanitizationWarnings = _settingsImportSanitizeOptions(optionsFull, true); + // Type check + if (!isObject(data)) { + throw new Error(`Invalid data type: ${typeof data}`); + } - // Show sanitization warnings - if (sanitizationWarnings.size > 0) { - const {result, sanitize} = await _showSettingsImportWarnings(sanitizationWarnings); - if (!result) { return; } + // Version check + const version = data.version; + if (!( + typeof version === 'number' && + Number.isFinite(version) && + version === Math.floor(version) + )) { + throw new Error(`Invalid version: ${version}`); + } - if (sanitize !== false) { - _settingsImportSanitizeOptions(optionsFull, false); + if (!( + version >= 0 && + version <= this._currentVersion + )) { + throw new Error(`Unsupported version: ${version}`); } - } - // Assign options - await _settingsImportSetOptionsFull(optionsFull); + // Verify options exists + let optionsFull = data.options; + if (!isObject(optionsFull)) { + throw new Error(`Invalid options type: ${typeof optionsFull}`); + } - // Reload settings page - window.location.reload(); -} + // Upgrade options + optionsFull = optionsUpdateVersion(optionsFull, {}); -function _onSettingsImportClick() { - document.querySelector('#settings-import-file').click(); -} + // Check for warnings + const sanitizationWarnings = this._settingsImportSanitizeOptions(optionsFull, true); -function _onSettingsImportFileChange(e) { - const files = e.target.files; - if (files.length === 0) { return; } + // Show sanitization warnings + if (sanitizationWarnings.size > 0) { + const {result, sanitize} = await this._showSettingsImportWarnings(sanitizationWarnings); + if (!result) { return; } - const file = files[0]; - e.target.value = null; - _importSettingsFile(file).catch(_showSettingsImportError); -} + if (sanitize !== false) { + this._settingsImportSanitizeOptions(optionsFull, false); + } + } + // Assign options + await this._settingsImportSetOptionsFull(optionsFull); -// Resetting + // Reload settings page + window.location.reload(); + } -function _onSettingsResetClick() { - $('#settings-reset-modal').modal('show'); -} + _onSettingsImportClick() { + document.querySelector('#settings-import-file').click(); + } -async function _onSettingsResetConfirmClick() { - $('#settings-reset-modal').modal('hide'); + async _onSettingsImportFileChange(e) { + const files = e.target.files; + if (files.length === 0) { return; } - // Get default options - const optionsFull = optionsGetDefault(); + const file = files[0]; + e.target.value = null; + try { + await this._importSettingsFile(file); + } catch (error) { + this._showSettingsImportError(error); + } + } - // Assign options - await _settingsImportSetOptionsFull(optionsFull); + // Resetting - // Reload settings page - window.location.reload(); -} + _onSettingsResetClick() { + $('#settings-reset-modal').modal('show'); + } + async _onSettingsResetConfirmClick() { + $('#settings-reset-modal').modal('hide'); -// Setup + // Get default options + const optionsFull = optionsGetDefault(); -function backupInitialize() { - document.querySelector('#settings-export').addEventListener('click', _onSettingsExportClick, false); - document.querySelector('#settings-import').addEventListener('click', _onSettingsImportClick, false); - document.querySelector('#settings-import-file').addEventListener('change', _onSettingsImportFileChange, false); - document.querySelector('#settings-reset').addEventListener('click', _onSettingsResetClick, false); - document.querySelector('#settings-reset-modal-confirm').addEventListener('click', _onSettingsResetConfirmClick, false); + // Assign options + await this._settingsImportSetOptionsFull(optionsFull); + + // Reload settings page + window.location.reload(); + } } diff --git a/ext/bg/js/settings/main.js b/ext/bg/js/settings/main.js index 60b9e008..f96167af 100644 --- a/ext/bg/js/settings/main.js +++ b/ext/bg/js/settings/main.js @@ -16,13 +16,13 @@ */ /* global + * SettingsBackup * ankiInitialize * ankiTemplatesInitialize * ankiTemplatesUpdateValue * api * appearanceInitialize * audioSettingsInitialize - * backupInitialize * dictSettingsInitialize * getOptionsContext * onAnkiOptionsChanged @@ -302,7 +302,7 @@ async function onReady() { await dictSettingsInitialize(); ankiInitialize(); ankiTemplatesInitialize(); - backupInitialize(); + new SettingsBackup().prepare(); storageInfoInitialize(); diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 8f86e47a..edc19c6e 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -65,12 +65,3 @@ function utilBackend() { } return backend; } - -function utilReadFileArrayBuffer(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result); - reader.onerror = () => reject(reader.error); - reader.readAsArrayBuffer(file); - }); -} -- cgit v1.2.3 From 63a3e56367b95f7ea64a5701d17179de60ed8718 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 30 May 2020 09:33:13 -0400 Subject: Use SettingsController (#576) * Use settingsController internally in settings/main.js * Replace modifyingProfileChange with SettingsController.optionsContextChanged * Update ClipboardPopupsController to use SettingsController * Store reference to checkbox * Use this._settingsController for everything * Change where current profile is initially assigned from * Remove some unnecessary async calls * Move setup calls * Update AnkiTemplatesController to use SettingsController * Cache default field templates * Update AnkiController to use SettingsController * Update AudioController to use SettingsController * Update SettingsBackup to use SettingsController * Update DictionaryController to use SettingsController * Update GenericSettingController to use SettingsController * Update ProfileController to use SettingsController * Remove unused * Remove unused * Replace some uses of api.options* functions * Fix missing awaits * Fix invalid function --- ext/bg/js/settings/anki-templates.js | 35 ++++---- ext/bg/js/settings/anki.js | 53 +++++------ ext/bg/js/settings/audio.js | 33 ++++--- ext/bg/js/settings/backup.js | 12 +-- ext/bg/js/settings/clipboard-popups-controller.js | 34 ++++--- ext/bg/js/settings/dictionaries.js | 54 ++++++----- ext/bg/js/settings/dom-settings-binder.js | 1 - ext/bg/js/settings/generic-setting-controller.js | 28 +++--- ext/bg/js/settings/main.js | 97 +++----------------- ext/bg/js/settings/popup-preview.js | 9 +- ext/bg/js/settings/profiles.js | 105 +++++++++------------- ext/bg/js/settings/settings-controller.js | 5 ++ 12 files changed, 192 insertions(+), 274 deletions(-) (limited to 'ext/bg/js/settings/backup.js') diff --git a/ext/bg/js/settings/anki-templates.js b/ext/bg/js/settings/anki-templates.js index dd128ab8..4ceff835 100644 --- a/ext/bg/js/settings/anki-templates.js +++ b/ext/bg/js/settings/anki-templates.js @@ -18,19 +18,20 @@ /* global * AnkiNoteBuilder * api - * getOptionsContext - * getOptionsMutable - * settingsSaveOptions */ class AnkiTemplatesController { - constructor(ankiController) { + constructor(settingsController, ankiController) { + this._settingsController = settingsController; this._ankiController = ankiController; this._cachedDefinitionValue = null; this._cachedDefinitionText = null; + this._defaultFieldTemplates = null; } - prepare() { + async prepare() { + this._defaultFieldTemplates = await api.getDefaultAnkiFieldTemplates(); + const markers = new Set([ ...this._ankiController.getFieldMarkers('terms'), ...this._ankiController.getFieldMarkers('kanji') @@ -48,21 +49,22 @@ class AnkiTemplatesController { $('#field-templates-reset').on('click', this._onReset.bind(this)); $('#field-templates-reset-confirm').on('click', this._onResetConfirm.bind(this)); - this.updateValue(); + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + + const options = await this._settingsController.getOptions(); + this._onOptionsChanged({options}); } - async updateValue() { - const optionsContext = getOptionsContext(); - const options = await api.optionsGet(optionsContext); + // Private + + _onOptionsChanged({options}) { let templates = options.anki.fieldTemplates; - if (typeof templates !== 'string') { templates = await api.getDefaultAnkiFieldTemplates(); } + if (typeof templates !== 'string') { templates = this._defaultFieldTemplates; } $('#field-templates').val(templates); this._onValidateCompile(); } - // Private - _onReset(e) { e.preventDefault(); $('#field-template-reset-modal').modal('show'); @@ -89,10 +91,9 @@ class AnkiTemplatesController { } // Overwrite - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); + const options = await this._settingsController.getOptionsMutable(); options.anki.fieldTemplates = templates; - await settingsSaveOptions(); + await this._settingsController.save(); // Compile this._onValidateCompile(); @@ -133,10 +134,10 @@ class AnkiTemplatesController { const exceptions = []; let result = `No definition found for ${text}`; try { - const optionsContext = getOptionsContext(); + const optionsContext = this._settingsController.getOptionsContext(); const definition = await this._getDefinition(text, optionsContext); if (definition !== null) { - const options = await api.optionsGet(optionsContext); + const options = await this._settingsController.getOptions(); const context = { document: { title: document.title diff --git a/ext/bg/js/settings/anki.js b/ext/bg/js/settings/anki.js index d110ef39..d099239d 100644 --- a/ext/bg/js/settings/anki.js +++ b/ext/bg/js/settings/anki.js @@ -17,38 +17,25 @@ /* global * api - * getOptionsContext - * getOptionsMutable - * settingsSaveOptions * utilBackgroundIsolate */ class AnkiController { - prepare() { + constructor(settingsController) { + this._settingsController = settingsController; + } + + async prepare() { $('#anki-fields-container input,#anki-fields-container select,#anki-fields-container textarea').change(this._onFieldsChanged.bind(this)); for (const node of document.querySelectorAll('#anki-terms-model,#anki-kanji-model')) { node.addEventListener('change', this._onModelChanged.bind(this), false); } - this.optionsChanged(); - } + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - async optionsChanged(options=null) { - if (options === null) { - const optionsContext = getOptionsContext(); - options = await getOptionsMutable(optionsContext); - } - - if (!options.anki.enable) { - return; - } - - await this._deckAndModelPopulate(options); - await Promise.all([ - this._fieldsPopulate('terms', options), - this._fieldsPopulate('kanji', options) - ]); + const options = await this._settingsController.getOptions(); + this._onOptionsChanged({options}); } getFieldMarkers(type) { @@ -103,6 +90,18 @@ class AnkiController { // Private + async _onOptionsChanged({options}) { + if (!options.anki.enable) { + return; + } + + await this._deckAndModelPopulate(options); + await Promise.all([ + this._fieldsPopulate('terms', options), + this._fieldsPopulate('kanji', options) + ]); + } + _fieldsToDict(elements) { const result = {}; for (const element of elements) { @@ -277,17 +276,15 @@ class AnkiController { fields[name] = ''; } - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); + const options = await this._settingsController.getOptionsMutable(); options.anki[tabId].fields = utilBackgroundIsolate(fields); - await settingsSaveOptions(); + await this._settingsController.save(); await this._fieldsPopulate(tabId, options); } async _onFieldsChanged() { - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); + const options = await this._settingsController.getOptionsMutable(); options.anki.terms.deck = $('#anki-terms-deck').val(); options.anki.terms.model = $('#anki-terms-model').val(); @@ -296,8 +293,6 @@ class AnkiController { options.anki.kanji.model = $('#anki-kanji-model').val(); options.anki.kanji.fields = utilBackgroundIsolate(this._fieldsToDict(document.querySelectorAll('#kanji .anki-field-value'))); - await settingsSaveOptions(); - - await this.optionsChanged(options); + await this._settingsController.save(); } } diff --git a/ext/bg/js/settings/audio.js b/ext/bg/js/settings/audio.js index 5c1cb131..1a41a498 100644 --- a/ext/bg/js/settings/audio.js +++ b/ext/bg/js/settings/audio.js @@ -17,13 +17,11 @@ /* global * AudioSystem - * getOptionsContext - * getOptionsMutable - * settingsSaveOptions */ class AudioController { - constructor() { + constructor(settingsController) { + this._settingsController = settingsController; this._audioSystem = null; this._settingsAudioSources = null; this._audioSourceContainer = null; @@ -37,27 +35,36 @@ class AudioController { useCache: true }); - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); - - this._settingsAudioSources = options.audio.sources; this._audioSourceContainer = document.querySelector('.audio-source-list'); this._audioSourceAddButton = document.querySelector('.audio-source-add'); this._audioSourceContainer.textContent = ''; this._audioSourceAddButton.addEventListener('click', this._onAddAudioSource.bind(this), false); - for (const audioSource of toIterable(this._settingsAudioSources)) { - this._createAudioSourceEntry(audioSource); - } - this._prepareTextToSpeech(); + + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + + this._onOptionsChanged(); } // Private + async _onOptionsChanged() { + const options = await this._settingsController.getOptionsMutable(); + + for (const entry of [...this._audioSourceEntries]) { + this._removeAudioSourceEntry(entry); + } + + this._settingsAudioSources = options.audio.sources; + for (const audioSource of toIterable(this._settingsAudioSources)) { + this._createAudioSourceEntry(audioSource); + } + } + async _save() { - await settingsSaveOptions(); + await this._settingsController.save(); } _prepareTextToSpeech() { diff --git a/ext/bg/js/settings/backup.js b/ext/bg/js/settings/backup.js index 4e104e6f..e93e15bf 100644 --- a/ext/bg/js/settings/backup.js +++ b/ext/bg/js/settings/backup.js @@ -19,13 +19,11 @@ * api * optionsGetDefault * optionsUpdateVersion - * utilBackend - * utilBackgroundIsolate - * utilIsolate */ class SettingsBackup { - constructor() { + constructor(settingsController) { + this._settingsController = settingsController; this._settingsExportToken = null; this._settingsExportRevoke = null; this._currentVersion = 0; @@ -59,7 +57,7 @@ class SettingsBackup { } async _getSettingsExportData(date) { - const optionsFull = await api.optionsGetFull(); + const optionsFull = await this._settingsController.getOptionsFull(); const environment = await api.getEnvironmentInfo(); const fieldTemplatesDefault = await api.getDefaultAnkiFieldTemplates(); @@ -143,9 +141,7 @@ class SettingsBackup { // Importing async _settingsImportSetOptionsFull(optionsFull) { - return utilIsolate(utilBackend().setFullOptions( - utilBackgroundIsolate(optionsFull) - )); + await this._settingsController.setOptionsFull(optionsFull); } _showSettingsImportError(error) { diff --git a/ext/bg/js/settings/clipboard-popups-controller.js b/ext/bg/js/settings/clipboard-popups-controller.js index cb9e857f..77fae305 100644 --- a/ext/bg/js/settings/clipboard-popups-controller.js +++ b/ext/bg/js/settings/clipboard-popups-controller.js @@ -15,29 +15,37 @@ * along with this program. If not, see . */ -/* globals - * getOptionsContext - * getOptionsMutable - * settingsSaveOptions - */ - class ClipboardPopupsController { - prepare() { - document.querySelector('#enable-clipboard-popups').addEventListener('change', this._onEnableClipboardPopupsChanged.bind(this), false); + constructor(settingsController) { + this._settingsController = settingsController; + this._checkbox = document.querySelector('#enable-clipboard-popups'); } - async _onEnableClipboardPopupsChanged(e) { - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); + async prepare() { + this._checkbox.addEventListener('change', this._onEnableClipboardPopupsChanged.bind(this), false); + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + + const options = await this._settingsController.getOptions(); + this._onOptionsChanged({options}); + } + // Private + + _onOptionsChanged({options}) { + this._checkbox.checked = options.general.enableClipboardPopups; + } + + async _onEnableClipboardPopupsChanged(e) { const enableClipboardPopups = e.target.checked; + const options = await this._settingsController.getOptionsMutable(); + if (enableClipboardPopups) { options.general.enableClipboardPopups = await new Promise((resolve) => { chrome.permissions.request( {permissions: ['clipboardRead']}, (granted) => { if (!granted) { - $('#enable-clipboard-popups').prop('checked', false); + this._checkbox.checked = false; } resolve(granted); } @@ -47,6 +55,6 @@ class ClipboardPopupsController { options.general.enableClipboardPopups = false; } - await settingsSaveOptions(); + await this._settingsController.save(); } } diff --git a/ext/bg/js/settings/dictionaries.js b/ext/bg/js/settings/dictionaries.js index dd6dd1c1..94a71233 100644 --- a/ext/bg/js/settings/dictionaries.js +++ b/ext/bg/js/settings/dictionaries.js @@ -18,15 +18,12 @@ /* global * PageExitPrevention * api - * getOptionsContext - * getOptionsFullMutable - * getOptionsMutable - * settingsSaveOptions * utilBackgroundIsolate */ -class SettingsDictionaryListUI { +class SettingsDictionaryListUI extends EventDispatcher { constructor(container, template, extraContainer, extraTemplate) { + super(); this.container = container; this.template = template; this.extraContainer = extraContainer; @@ -309,7 +306,7 @@ class SettingsDictionaryEntryUI { this.isDeleting = false; progress.hidden = true; - this.onDatabaseUpdated(); + this.parent.trigger('databaseUpdated'); } } @@ -384,7 +381,8 @@ class SettingsDictionaryExtraUI { } class DictionaryController { - constructor(storageController) { + constructor(settingsController, storageController) { + this._settingsController = settingsController; this._storageController = storageController; this._dictionaryUI = null; this._dictionaryErrorToStringOverrides = [ @@ -410,7 +408,8 @@ class DictionaryController { document.querySelector('#dict-groups-extra'), document.querySelector('#dict-extra-template') ); - this._dictionaryUI.save = settingsSaveOptions; + this._dictionaryUI.save = () => this._settingsController.save(); + this._dictionaryUI.on('databaseUpdated', this._onDatabaseUpdated.bind(this)); document.querySelector('#dict-purge-button').addEventListener('click', this._onPurgeButtonClick.bind(this), false); document.querySelector('#dict-purge-confirm').addEventListener('click', this._onPurgeConfirmButtonClick.bind(this), false); @@ -419,26 +418,25 @@ class DictionaryController { 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); - await this.optionsChanged(); + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + + await this._onOptionsChanged(); await this._onDatabaseUpdated(); } - async optionsChanged() { - if (this._dictionaryUI === null) { return; } + // Private - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); + async _onOptionsChanged() { + const options = await this._settingsController.getOptionsMutable(); this._dictionaryUI.setOptionsDictionaries(options.dictionaries); - const optionsFull = await api.optionsGetFull(); + const optionsFull = await this._settingsController.getOptionsFull(); document.querySelector('#database-enable-prefix-wildcard-searches').checked = optionsFull.global.database.prefixWildcardsSupported; await this._updateMainDictionarySelectValue(); } - // Private - _updateMainDictionarySelectOptions(dictionaries) { const select = document.querySelector('#dict-main'); select.textContent = ''; // Empty @@ -460,8 +458,7 @@ class DictionaryController { } async _updateMainDictionarySelectValue() { - const optionsContext = getOptionsContext(); - const options = await api.optionsGet(optionsContext); + const options = await this._settingsController.getOptions(); const value = options.general.mainDictionary; @@ -589,10 +586,9 @@ class DictionaryController { missingNodeOption.parentNode.removeChild(missingNodeOption); } - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); + const options = await this._settingsController.getOptionsMutable(); options.general.mainDictionary = value; - await settingsSaveOptions(); + await this._settingsController.save(); } _onImportButtonClick() { @@ -622,11 +618,12 @@ class DictionaryController { this._dictionarySpinnerShow(true); await api.purgeDatabase(); - for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) { + const optionsFull = await this._settingsController.getOptionsFullMutable(); + for (const {options} of toIterable(optionsFull.profiles)) { options.dictionaries = utilBackgroundIsolate({}); options.general.mainDictionary = ''; } - await settingsSaveOptions(); + await this._settingsController.save(); this._onDatabaseUpdated(); } catch (err) { @@ -665,7 +662,7 @@ class DictionaryController { this._storageController.updateStats(); }; - const optionsFull = await api.optionsGetFull(); + const optionsFull = await this._settingsController.getOptionsFull(); const importDetails = { prefixWildcardsSupported: optionsFull.global.database.prefixWildcardsSupported @@ -680,7 +677,8 @@ class DictionaryController { const archiveContent = await this._dictReadFile(files[i]); const {result, errors} = await api.importDictionaryArchive(archiveContent, importDetails, updateProgress); - for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) { + const optionsFull2 = await this._settingsController.getOptionsFullMutable(); + for (const {options} of toIterable(optionsFull2.profiles)) { const dictionaryOptions = SettingsDictionaryListUI.createDictionaryOptions(); dictionaryOptions.enabled = true; options.dictionaries[result.title] = dictionaryOptions; @@ -689,7 +687,7 @@ class DictionaryController { } } - await settingsSaveOptions(); + await this._settingsController.save(); if (errors.length > 0) { const errors2 = errors.map((error) => jsonToError(error)); @@ -714,10 +712,10 @@ class DictionaryController { } async _onDatabaseEnablePrefixWildcardSearchesChanged(e) { - const optionsFull = await getOptionsFullMutable(); + 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 settingsSaveOptions(); + await this._settingsController.save(); } } diff --git a/ext/bg/js/settings/dom-settings-binder.js b/ext/bg/js/settings/dom-settings-binder.js index 4b63859f..07da4f37 100644 --- a/ext/bg/js/settings/dom-settings-binder.js +++ b/ext/bg/js/settings/dom-settings-binder.js @@ -18,7 +18,6 @@ /* global * DOMDataBinder * api - * getOptionsContext */ class DOMSettingsBinder { diff --git a/ext/bg/js/settings/generic-setting-controller.js b/ext/bg/js/settings/generic-setting-controller.js index 4a20bf65..d7d40c5d 100644 --- a/ext/bg/js/settings/generic-setting-controller.js +++ b/ext/bg/js/settings/generic-setting-controller.js @@ -16,24 +16,26 @@ */ /* globals - * getOptionsContext - * getOptionsMutable - * settingsSaveOptions * utilBackgroundIsolate */ class GenericSettingController { - prepare() { - $('input, select, textarea').not('.anki-model').not('.ignore-form-changes *').change(this._onFormOptionsChanged.bind(this)); + constructor(settingsController) { + this._settingsController = settingsController; } - optionsChanged(options) { - this._formWrite(options); + async prepare() { + $('input, select, textarea').not('.anki-model').not('.ignore-form-changes *').change(this._onFormOptionsChanged.bind(this)); + + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + + const options = await this._settingsController.getOptions(); + this._onOptionsChanged({options}); } // Private - async _formWrite(options) { + _onOptionsChanged({options}) { $('#enable').prop('checked', options.general.enable); $('#show-usage-guide').prop('checked', options.general.showGuide); $('#compact-tags').prop('checked', options.general.compactTags); @@ -107,7 +109,7 @@ class GenericSettingController { this._formUpdateVisibility(options); } - async _formRead(options) { + _formRead(options) { options.general.enable = $('#enable').prop('checked'); options.general.showGuide = $('#show-usage-guide').prop('checked'); options.general.compactTags = $('#compact-tags').prop('checked'); @@ -180,12 +182,10 @@ class GenericSettingController { } async _onFormOptionsChanged() { - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); - - await this._formRead(options); - await settingsSaveOptions(); + const options = await this._settingsController.getOptionsMutable(); + this._formRead(options); this._formUpdateVisibility(options); + await this._settingsController.save(); } _formUpdateVisibility(options) { diff --git a/ext/bg/js/settings/main.js b/ext/bg/js/settings/main.js index d6f55bde..cf74c0fc 100644 --- a/ext/bg/js/settings/main.js +++ b/ext/bg/js/settings/main.js @@ -28,71 +28,8 @@ * SettingsController * StorageController * api - * utilBackend - * utilBackgroundIsolate */ -let profileIndex = 0; - -function getOptionsContext() { - return {index: getProfileIndex()}; -} - -function getProfileIndex() { - return profileIndex; -} - -function setProfileIndex(value) { - profileIndex = value; -} - - -function getOptionsMutable(optionsContext) { - return utilBackend().getOptions( - utilBackgroundIsolate(optionsContext) - ); -} - -function getOptionsFullMutable() { - return utilBackend().getFullOptions(); -} - - -function settingsGetSource() { - return new Promise((resolve) => { - chrome.tabs.getCurrent((tab) => resolve(`settings${tab ? tab.id : ''}`)); - }); -} - -async function settingsSaveOptions() { - const source = await settingsGetSource(); - await api.optionsSave(source); -} - -async function onOptionsUpdated({source}) { - const thisSource = await settingsGetSource(); - if (source === thisSource) { return; } - - const optionsContext = getOptionsContext(); - const options = await getOptionsMutable(optionsContext); - - document.querySelector('#enable-clipboard-popups').checked = options.general.enableClipboardPopups; - if (ankiTemplatesController !== null) { - ankiTemplatesController.updateValue(); - } - if (dictionaryController !== null) { - dictionaryController.optionsChanged(); - } - if (ankiController !== null) { - ankiController.optionsChanged(); - } - - if (genericSettingController !== null) { - genericSettingController.optionsChanged(options); - } -} - - function showExtensionInformation() { const node = document.getElementById('extension-info'); if (node === null) { return; } @@ -124,40 +61,34 @@ async function setupEnvironmentInfo() { document.documentElement.dataset.operatingSystem = platform.os; } -let ankiController = null; -let ankiTemplatesController = null; -let dictionaryController = null; -let genericSettingController = null; async function onReady() { api.forwardLogsToBackend(); await yomichan.prepare(); - const settingsController = new SettingsController(); - settingsController.prepare(); - setupEnvironmentInfo(); showExtensionInformation(); + settingsPopulateModifierKeys(); + + const optionsFull = await api.optionsGetFull(); + const settingsController = new SettingsController(optionsFull.profileCurrent); + settingsController.prepare(); const storageController = new StorageController(); storageController.prepare(); - await settingsPopulateModifierKeys(); - genericSettingController = new GenericSettingController(); + const genericSettingController = new GenericSettingController(settingsController); genericSettingController.prepare(); - new ClipboardPopupsController().prepare(); - new PopupPreviewController().prepare(); - new AudioController().prepare(); - await (new ProfileController()).prepare(); - dictionaryController = new DictionaryController(storageController); + new ClipboardPopupsController(settingsController).prepare(); + new PopupPreviewController(settingsController).prepare(); + new AudioController(settingsController).prepare(); + new ProfileController(settingsController).prepare(); + const dictionaryController = new DictionaryController(settingsController, storageController); dictionaryController.prepare(); - ankiController = new AnkiController(); + const ankiController = new AnkiController(settingsController); ankiController.prepare(); - ankiTemplatesController = new AnkiTemplatesController(ankiController); - ankiTemplatesController.prepare(); - new SettingsBackup().prepare(); - - yomichan.on('optionsUpdated', onOptionsUpdated); + new AnkiTemplatesController(settingsController, ankiController).prepare(); + new SettingsBackup(settingsController).prepare(); } $(document).ready(() => onReady()); diff --git a/ext/bg/js/settings/popup-preview.js b/ext/bg/js/settings/popup-preview.js index d5519959..d4145b76 100644 --- a/ext/bg/js/settings/popup-preview.js +++ b/ext/bg/js/settings/popup-preview.js @@ -16,12 +16,12 @@ */ /* global - * getOptionsContext * wanakana */ class PopupPreviewController { - constructor() { + constructor(settingsController) { + this._settingsController = settingsController; this._previewVisible = false; this._targetOrigin = chrome.runtime.getURL('/').replace(/\/$/, ''); this._frame = null; @@ -58,7 +58,7 @@ class PopupPreviewController { text.addEventListener('input', this._onTextChange.bind(this), false); customCss.addEventListener('input', this._onCustomCssChange.bind(this), false); customOuterCss.addEventListener('input', this._onCustomOuterCssChange.bind(this), false); - yomichan.on('modifyingProfileChange', this._onOptionsContextChange.bind(this)); + this._settingsController.on('optionsContextChanged', this._onOptionsContextChange.bind(this)); frame.src = '/bg/settings-popup-preview.html'; frame.id = 'settings-popup-preview-frame'; @@ -88,7 +88,8 @@ class PopupPreviewController { } _onOptionsContextChange() { - this._invoke('updateOptionsContext', {optionsContext: getOptionsContext()}); + const optionsContext = this._settingsController.getOptionsContext(); + this._invoke('updateOptionsContext', {optionsContext}); } _setText(text) { diff --git a/ext/bg/js/settings/profiles.js b/ext/bg/js/settings/profiles.js index e2c558e9..2449ab44 100644 --- a/ext/bg/js/settings/profiles.js +++ b/ext/bg/js/settings/profiles.js @@ -17,34 +17,19 @@ /* global * ConditionsUI - * api * conditionsClearCaches - * getOptionsFullMutable - * getProfileIndex - * onOptionsUpdated * profileConditionsDescriptor * profileConditionsDescriptorPromise - * setProfileIndex - * settingsSaveOptions * utilBackgroundIsolate */ class ProfileController { - constructor() { + constructor(settingsController) { + this._settingsController = settingsController; this._conditionsContainer = null; } async prepare() { - const optionsFull = await getOptionsFullMutable(); - setProfileIndex(optionsFull.profileCurrent); - - this._setupEventListeners(); - await this._updateTarget(optionsFull); - } - - // Private - - _setupEventListeners() { $('#profile-target').change(this._onTargetProfileChanged.bind(this)); $('#profile-name').change(this._onNameChanged.bind(this)); $('#profile-add').click(this._onAdd.bind(this)); @@ -55,6 +40,17 @@ class ProfileController { $('#profile-move-up').click(() => this._onMove(-1)); $('#profile-move-down').click(() => this._onMove(1)); $('.profile-form').find('input, select, textarea').not('.profile-form-manual').change(this._onInputChanged.bind(this)); + + this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); + + this._onOptionsChanged(); + } + + // Private + + async _onOptionsChanged() { + const optionsFull = await this._settingsController.getOptionsFullMutable(); + await this._formWrite(optionsFull); } _tryGetIntegerValue(selector, min, max) { @@ -69,7 +65,7 @@ class ProfileController { } async _formRead(optionsFull) { - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; const profile = optionsFull.profiles[currentProfileIndex]; // Current profile @@ -83,7 +79,7 @@ class ProfileController { } async _formWrite(optionsFull) { - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; const profile = optionsFull.profiles[currentProfileIndex]; this._populateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent, null); @@ -108,7 +104,7 @@ class ProfileController { $('#profile-add-condition-group') ); this._conditionsContainer.save = () => { - settingsSaveOptions(); + this._settingsController.save(); conditionsClearCaches(profileConditionsDescriptor); }; this._conditionsContainer.isolate = utilBackgroundIsolate; @@ -129,11 +125,6 @@ class ProfileController { select.val(`${currentValue}`); } - async _updateTarget(optionsFull) { - await this._formWrite(optionsFull); - await onOptionsUpdated({source: null}); - } - _createCopyName(name, profiles, maxUniqueAttempts) { let space, index, prefix, suffix; const match = /^([\w\W]*\(Copy)((\s+)(\d+))?(\)\s*)$/.exec(name); @@ -174,39 +165,32 @@ class ProfileController { return; } - const optionsFull = await getOptionsFullMutable(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); await this._formRead(optionsFull); - await settingsSaveOptions(); + await this._settingsController.save(); } async _onTargetProfileChanged() { - const optionsFull = await getOptionsFullMutable(); - const currentProfileIndex = getProfileIndex(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); + const currentProfileIndex = this._settingsController.profileIndex; const index = this._tryGetIntegerValue('#profile-target', 0, optionsFull.profiles.length); if (index === null || currentProfileIndex === index) { return; } - setProfileIndex(index); - - await this._updateTarget(optionsFull); - - yomichan.trigger('modifyingProfileChange'); + this._settingsController.profileIndex = index; } async _onAdd() { - const optionsFull = await getOptionsFullMutable(); - const currentProfileIndex = getProfileIndex(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); + const currentProfileIndex = this._settingsController.profileIndex; const profile = utilBackgroundIsolate(optionsFull.profiles[currentProfileIndex]); profile.name = this._createCopyName(profile.name, optionsFull.profiles, 100); optionsFull.profiles.push(profile); - setProfileIndex(optionsFull.profiles.length - 1); - - await this._updateTarget(optionsFull); - await settingsSaveOptions(); + this._settingsController.profileIndex = optionsFull.profiles.length - 1; - yomichan.trigger('modifyingProfileChange'); + await this._settingsController.save(); } async _onRemove(e) { @@ -214,12 +198,12 @@ class ProfileController { return await this._onRemoveConfirm(); } - const optionsFull = await api.optionsGetFull(); + const optionsFull = await this._settingsController.getOptionsFull(); if (optionsFull.profiles.length <= 1) { return; } - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; const profile = optionsFull.profiles[currentProfileIndex]; $('#profile-remove-modal-profile-name').text(profile.name); @@ -229,36 +213,33 @@ class ProfileController { async _onRemoveConfirm() { $('#profile-remove-modal').modal('hide'); - const optionsFull = await getOptionsFullMutable(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); if (optionsFull.profiles.length <= 1) { return; } - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; optionsFull.profiles.splice(currentProfileIndex, 1); if (currentProfileIndex >= optionsFull.profiles.length) { - setProfileIndex(optionsFull.profiles.length - 1); + this._settingsController.profileIndex = optionsFull.profiles.length - 1; } if (optionsFull.profileCurrent >= optionsFull.profiles.length) { optionsFull.profileCurrent = optionsFull.profiles.length - 1; } - await this._updateTarget(optionsFull); - await settingsSaveOptions(); - - yomichan.trigger('modifyingProfileChange'); + await this._settingsController.save(); } _onNameChanged() { - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; $('#profile-active, #profile-target').find(`[value="${currentProfileIndex}"]`).text(this.value); } async _onMove(offset) { - const optionsFull = await getOptionsFullMutable(); - const currentProfileIndex = getProfileIndex(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); + const currentProfileIndex = this._settingsController.profileIndex; const index = currentProfileIndex + offset; if (index < 0 || index >= optionsFull.profiles.length) { return; @@ -272,21 +253,18 @@ class ProfileController { optionsFull.profileCurrent = index; } - setProfileIndex(index); - - await this._updateTarget(optionsFull); - await settingsSaveOptions(); + this._settingsController.profileIndex = index; - yomichan.trigger('modifyingProfileChange'); + await this._settingsController.save(); } async _onCopy() { - const optionsFull = await api.optionsGetFull(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); if (optionsFull.profiles.length <= 1) { return; } - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; this._populateSelect($('#profile-copy-source'), optionsFull.profiles, currentProfileIndex === 0 ? 1 : 0, [currentProfileIndex]); $('#profile-copy-modal').modal('show'); } @@ -294,9 +272,9 @@ class ProfileController { async _onCopyConfirm() { $('#profile-copy-modal').modal('hide'); - const optionsFull = await getOptionsFullMutable(); + const optionsFull = await this._settingsController.getOptionsFullMutable(); const index = this._tryGetIntegerValue('#profile-copy-source', 0, optionsFull.profiles.length); - const currentProfileIndex = getProfileIndex(); + const currentProfileIndex = this._settingsController.profileIndex; if (index === null || index === currentProfileIndex) { return; } @@ -304,7 +282,6 @@ class ProfileController { const profileOptions = utilBackgroundIsolate(optionsFull.profiles[index].options); optionsFull.profiles[currentProfileIndex].options = profileOptions; - await this._updateTarget(optionsFull); - await settingsSaveOptions(); + await this._settingsController.save(); } } diff --git a/ext/bg/js/settings/settings-controller.js b/ext/bg/js/settings/settings-controller.js index 61230226..9f903f48 100644 --- a/ext/bg/js/settings/settings-controller.js +++ b/ext/bg/js/settings/settings-controller.js @@ -65,6 +65,11 @@ class SettingsController extends EventDispatcher { return utilBackend().getFullOptions(); } + async setOptionsFull(optionsFull) { + utilBackend().setFullOptions(utilBackgroundIsolate(optionsFull)); + await this.save(); + } + getOptionsContext() { return {index: this._profileIndex}; } -- cgit v1.2.3 From 976a200ffc65e94f0246392f6b29505f1eb4f16c Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 30 May 2020 16:23:56 -0400 Subject: Backup update (#582) * Add function to assign all settings * Update how settings backups are restored * Remove page reload * Update profile index after importing --- ext/bg/js/backend.js | 17 +++++++---------- ext/bg/js/settings/backup.js | 8 +------- ext/bg/js/settings/settings-controller.js | 17 +++++++++++------ ext/mixed/js/api.js | 4 ++++ 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'ext/bg/js/settings/backup.js') diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 80b00d5f..08ce82a2 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -122,7 +122,8 @@ class Backend { ['logIndicatorClear', {async: false, contentScript: true, handler: this._onApiLogIndicatorClear.bind(this)}], ['createActionPort', {async: false, contentScript: true, handler: this._onApiCreateActionPort.bind(this)}], ['modifySettings', {async: true, contentScript: true, handler: this._onApiModifySettings.bind(this)}], - ['getSettings', {async: false, contentScript: true, handler: this._onApiGetSettings.bind(this)}] + ['getSettings', {async: false, contentScript: true, handler: this._onApiGetSettings.bind(this)}], + ['setAllSettings', {async: true, contentScript: false, handler: this._onApiSetAllSettings.bind(this)}] ]); this._messageHandlersWithProgress = new Map([ ['importDictionaryArchive', {async: true, contentScript: false, handler: this._onApiImportDictionaryArchive.bind(this)}], @@ -317,15 +318,6 @@ class Backend { return useSchema ? JsonSchema.createProxy(options, this.optionsSchema) : options; } - setFullOptions(options) { - try { - this.options = JsonSchema.getValidValueOrDefault(this.optionsSchema, utilIsolate(options)); - } catch (e) { - // This shouldn't happen, but catch errors just in case of bugs - yomichan.logError(e); - } - } - getOptions(optionsContext, useSchema=false) { return this.getProfile(optionsContext, useSchema).options; } @@ -860,6 +852,11 @@ class Backend { return results; } + async _onApiSetAllSettings({value, source}) { + this.options = JsonSchema.getValidValueOrDefault(this.optionsSchema, value); + await this._onApiOptionsSave({source}); + } + // Command handlers _createActionListenerPort(port, sender, handlers) { diff --git a/ext/bg/js/settings/backup.js b/ext/bg/js/settings/backup.js index e93e15bf..13f90886 100644 --- a/ext/bg/js/settings/backup.js +++ b/ext/bg/js/settings/backup.js @@ -141,7 +141,7 @@ class SettingsBackup { // Importing async _settingsImportSetOptionsFull(optionsFull) { - await this._settingsController.setOptionsFull(optionsFull); + await this._settingsController.setAllSettings(optionsFull); } _showSettingsImportError(error) { @@ -340,9 +340,6 @@ class SettingsBackup { // Assign options await this._settingsImportSetOptionsFull(optionsFull); - - // Reload settings page - window.location.reload(); } _onSettingsImportClick() { @@ -376,8 +373,5 @@ class SettingsBackup { // Assign options await this._settingsImportSetOptionsFull(optionsFull); - - // Reload settings page - window.location.reload(); } } diff --git a/ext/bg/js/settings/settings-controller.js b/ext/bg/js/settings/settings-controller.js index 9224aedf..4c902dff 100644 --- a/ext/bg/js/settings/settings-controller.js +++ b/ext/bg/js/settings/settings-controller.js @@ -38,9 +38,7 @@ class SettingsController extends EventDispatcher { set profileIndex(value) { if (this._profileIndex === value) { return; } - this._profileIndex = value; - this.trigger('optionsContextChanged'); - this._onOptionsUpdatedInternal(); + this._setProfileIndex(value); } prepare() { @@ -69,9 +67,10 @@ class SettingsController extends EventDispatcher { return utilBackend().getFullOptions(); } - async setOptionsFull(optionsFull) { - utilBackend().setFullOptions(utilBackgroundIsolate(optionsFull)); - await this.save(); + async setAllSettings(value) { + const profileIndex = value.profileCurrent; + await api.setAllSettings(value, this._source); + this._setProfileIndex(profileIndex); } async getGlobalSettings(targets) { @@ -104,6 +103,12 @@ class SettingsController extends EventDispatcher { // Private + _setProfileIndex(value) { + this._profileIndex = value; + this.trigger('optionsContextChanged'); + this._onOptionsUpdatedInternal(); + } + _onOptionsUpdated({source}) { if (source === this._source) { return; } this._onOptionsUpdatedInternal(); diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index 2d5ad9e7..075ea545 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -176,6 +176,10 @@ const api = (() => { return this._invoke('getSettings', {targets}); } + setAllSettings(value, source) { + return this._invoke('setAllSettings', {value, source}); + } + // Invoke functions with progress importDictionaryArchive(archiveContent, details, onProgress) { -- cgit v1.2.3