diff options
Diffstat (limited to 'ext/bg/js/options.js')
-rw-r--r-- | ext/bg/js/options.js | 226 |
1 files changed, 164 insertions, 62 deletions
diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index df95aae9..e9e321df 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -17,7 +17,67 @@ */ -function optionsFieldTemplates() { +/* + * Generic options functions + */ + +function optionsGenericApplyUpdates(options, updates) { + const targetVersion = updates.length; + const currentVersion = options.version; + if (typeof currentVersion === 'number' && Number.isFinite(currentVersion)) { + for (let i = Math.max(0, Math.floor(currentVersion)); i < targetVersion; ++i) { + const update = updates[i]; + if (update !== null) { + update(options); + } + } + } + + options.version = targetVersion; + return options; +} + + +/* + * Per-profile options + */ + +const profileOptionsVersionUpdates = [ + null, + null, + null, + null, + (options) => { + options.general.audioSource = options.general.audioPlayback ? 'jpod101' : 'disabled'; + }, + (options) => { + options.general.showGuide = false; + }, + (options) => { + options.scanning.modifier = options.scanning.requireShift ? 'shift' : 'none'; + }, + (options) => { + const fieldTemplatesDefault = profileOptionsGetDefaultFieldTemplates(); + options.general.resultOutputMode = options.general.groupResults ? 'group' : 'split'; + options.anki.fieldTemplates = ( + (utilStringHashCode(options.anki.fieldTemplates) !== -805327496) ? + `{{#if merge}}${fieldTemplatesDefault}{{else}}${options.anki.fieldTemplates}{{/if}}` : + fieldTemplatesDefault + ); + }, + (options) => { + if (utilStringHashCode(options.anki.fieldTemplates) === 1285806040) { + options.anki.fieldTemplates = profileOptionsGetDefaultFieldTemplates(); + } + }, + (options) => { + if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) { + options.anki.fieldTemplates = profileOptionsGetDefaultFieldTemplates(); + } + } +]; + +function profileOptionsGetDefaultFieldTemplates() { return ` {{#*inline "glossary-single"}} {{~#unless brief~}} @@ -183,8 +243,8 @@ function optionsFieldTemplates() { `.trim(); } -function optionsSetDefaults(options) { - const defaults = { +function profileOptionsCreateDefaults() { + return { general: { enable: true, audioSource: 'jpod101', @@ -235,9 +295,13 @@ function optionsSetDefaults(options) { screenshot: {format: 'png', quality: 92}, terms: {deck: '', model: '', fields: {}}, kanji: {deck: '', model: '', fields: {}}, - fieldTemplates: optionsFieldTemplates() + fieldTemplates: profileOptionsGetDefaultFieldTemplates() } }; +} + +function profileOptionsSetDefaults(options) { + const defaults = profileOptionsCreateDefaults(); const combine = (target, source) => { for (const key in source) { @@ -257,81 +321,119 @@ function optionsSetDefaults(options) { return options; } -function optionsVersion(options) { - const fixups = [ - () => {}, - () => {}, - () => {}, - () => {}, - () => { - if (options.general.audioPlayback) { - options.general.audioSource = 'jpod101'; - } else { - options.general.audioSource = 'disabled'; - } - }, - () => { - options.general.showGuide = false; - }, - () => { - if (options.scanning.requireShift) { - options.scanning.modifier = 'shift'; - } else { - options.scanning.modifier = 'none'; - } - }, - () => { - if (options.general.groupResults) { - options.general.resultOutputMode = 'group'; - } else { - options.general.resultOutputMode = 'split'; - } - if (utilStringHashCode(options.anki.fieldTemplates) !== -805327496) { - options.anki.fieldTemplates = `{{#if merge}}${optionsFieldTemplates()}{{else}}${options.anki.fieldTemplates}{{/if}}`; - } else { - options.anki.fieldTemplates = optionsFieldTemplates(); - } - }, - () => { - if (utilStringHashCode(options.anki.fieldTemplates) === 1285806040) { - options.anki.fieldTemplates = optionsFieldTemplates(); - } - }, - () => { - if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) { - options.anki.fieldTemplates = optionsFieldTemplates(); - } +function profileOptionsUpdateVersion(options) { + profileOptionsSetDefaults(options); + return optionsGenericApplyUpdates(options, profileOptionsVersionUpdates); +} + + +/* + * Global options + * + * Each profile has an array named "conditionGroups", which is an array of condition groups + * which enable the contextual selection of profiles. The structure of the array is as follows: + * [ + * { + * conditions: [ + * { + * type: "string", + * operator: "string", + * value: "string" + * }, + * // ... + * ] + * }, + * // ... + * ] + */ + +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); } - ]; + } - optionsSetDefaults(options); - if (!options.hasOwnProperty('version')) { - options.version = fixups.length; + // Require at least one profile + if (profiles.length === 0) { + profiles.push({ + name: 'Default', + options: defaultProfileOptions, + conditionGroups: [] + }); } - while (options.version < fixups.length) { - fixups[options.version++](); + // 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; } - return options; + // Update profile options + for (const profile of profiles) { + if (!Array.isArray(profile.conditionGroups)) { + profile.conditionGroups = []; + } + profile.options = profileOptionsUpdateVersion(profile.options); + } + + // Generic updates + return optionsGenericApplyUpdates(options, optionsVersionUpdates); } function optionsLoad() { return new Promise((resolve, reject) => { - chrome.storage.local.get(null, store => resolve(store.options)); + chrome.storage.local.get(['options'], store => { + const error = chrome.runtime.lastError; + if (error) { + reject(error); + } else { + resolve(store.options); + } + }); }).then(optionsStr => { - return optionsStr ? JSON.parse(optionsStr) : {}; - }).catch(error => { + if (typeof optionsStr === 'string') { + const options = JSON.parse(optionsStr); + if (utilIsObject(options)) { + return options; + } + } + return {}; + }).catch(() => { return {}; }).then(options => { - return optionsVersion(options); + return ( + Array.isArray(options.profiles) ? + optionsUpdateVersion(options, {}) : + optionsUpdateVersion({}, options) + ); }); } function optionsSave(options) { return new Promise((resolve, reject) => { - chrome.storage.local.set({options: JSON.stringify(options)}, resolve); - }).then(() => { - apiOptionsSet(options); + chrome.storage.local.set({options: JSON.stringify(options)}, () => { + const error = chrome.runtime.lastError; + if (error) { + reject(error); + } else { + resolve(); + } + }); }); } |