Merge pull request #204 from toasted-nutbread/settings-improvements

Settings improvements
This commit is contained in:
Alex Yatskov 2019-09-08 19:34:39 -07:00 committed by GitHub
commit cc53510883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 147 additions and 116 deletions

View File

@ -17,16 +17,16 @@
*/ */
async function apiOptionsSet(options) { function apiOptionsGetSync() {
utilBackend().onOptionsUpdated(options);
}
async function apiOptionsGet() {
return utilBackend().options; return utilBackend().options;
} }
async function apiOptionsGet() {
return apiOptionsGetSync();
}
async function apiTermsFind(text) { async function apiTermsFind(text) {
const options = utilBackend().options; const options = apiOptionsGetSync();
const translator = utilBackend().translator; const translator = utilBackend().translator;
const searcher = { const searcher = {
@ -48,13 +48,13 @@ async function apiTermsFind(text) {
} }
async function apiKanjiFind(text) { async function apiKanjiFind(text) {
const options = utilBackend().options; const options = apiOptionsGetSync();
const definitions = await utilBackend().translator.findKanji(text, dictEnabledSet(options)); const definitions = await utilBackend().translator.findKanji(text, dictEnabledSet(options));
return definitions.slice(0, options.general.maxResults); return definitions.slice(0, options.general.maxResults);
} }
async function apiDefinitionAdd(definition, mode, context) { async function apiDefinitionAdd(definition, mode, context) {
const options = utilBackend().options; const options = apiOptionsGetSync();
if (mode !== 'kanji') { if (mode !== 'kanji') {
await audioInject( await audioInject(
@ -83,7 +83,7 @@ async function apiDefinitionsAddable(definitions, modes) {
const notes = []; const notes = [];
for (const definition of definitions) { for (const definition of definitions) {
for (const mode of modes) { for (const mode of modes) {
const note = await dictNoteFormat(definition, mode, utilBackend().options); const note = await dictNoteFormat(definition, mode, apiOptionsGetSync());
notes.push(note); notes.push(note);
} }
} }
@ -131,10 +131,9 @@ async function apiCommandExec(command) {
}, },
toggle: async () => { toggle: async () => {
const options = utilBackend().options; const options = apiOptionsGetSync();
options.general.enable = !options.general.enable; options.general.enable = !options.general.enable;
await optionsSave(options); await optionsSave(options);
await apiOptionsSet(options);
} }
}; };

View File

@ -28,7 +28,7 @@ class Backend {
async prepare() { async prepare() {
await this.translator.prepare(); await this.translator.prepare();
await apiOptionsSet(await optionsLoad()); this.onOptionsUpdated(await optionsLoad());
if (chrome.commands !== null && typeof chrome.commands === 'object') { if (chrome.commands !== null && typeof chrome.commands === 'object') {
chrome.commands.onCommand.addListener(this.onCommand.bind(this)); chrome.commands.onCommand.addListener(this.onCommand.bind(this));
@ -41,7 +41,8 @@ class Backend {
} }
onOptionsUpdated(options) { onOptionsUpdated(options) {
this.options = utilIsolate(options); options = utilIsolate(options);
this.options = options;
if (!options.general.enable) { if (!options.general.enable) {
this.setExtensionBadgeBackgroundColor('#555555'); this.setExtensionBadgeBackgroundColor('#555555');
@ -53,16 +54,12 @@ class Backend {
this.setExtensionBadgeText(''); this.setExtensionBadgeText('');
} }
if (options.anki.enable) { this.anki = options.anki.enable ? new AnkiConnect(options.anki.server) : new AnkiNull();
this.anki = new AnkiConnect(options.anki.server);
} else {
this.anki = new AnkiNull();
}
const callback = () => this.checkLastError(chrome.runtime.lastError); const callback = () => this.checkLastError(chrome.runtime.lastError);
chrome.tabs.query({}, tabs => { chrome.tabs.query({}, tabs => {
for (const tab of tabs) { for (const tab of tabs) {
chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: options}, callback); chrome.tabs.sendMessage(tab.id, {action: 'optionsSet', params: {options}}, callback);
} }
}); });
} }
@ -85,10 +82,6 @@ class Backend {
forward(apiOptionsGet(), callback); forward(apiOptionsGet(), callback);
}, },
optionsSet: ({options, callback}) => {
forward(apiOptionsSet(options), callback);
},
kanjiFind: ({text, callback}) => { kanjiFind: ({text, callback}) => {
forward(apiKanjiFind(text), callback); forward(apiKanjiFind(text), callback);
}, },
@ -148,7 +141,7 @@ class Backend {
chrome.browserAction.setBadgeBackgroundColor({color}); chrome.browserAction.setBadgeBackgroundColor({color});
} }
} }
setExtensionBadgeText(text) { setExtensionBadgeText(text) {
if (typeof chrome.browserAction.setBadgeText === 'function') { if (typeof chrome.browserAction.setBadgeText === 'function') {
chrome.browserAction.setBadgeText({text}); chrome.browserAction.setBadgeText({text});

View File

@ -17,6 +17,57 @@
*/ */
function optionsApplyUpdates(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;
}
const optionsVersionUpdates = [
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 = profileCreateDefaultFieldTemplates();
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 = profileCreateDefaultFieldTemplates();
}
},
(options) => {
if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) {
options.anki.fieldTemplates = profileCreateDefaultFieldTemplates();
}
}
];
function optionsFieldTemplates() { function optionsFieldTemplates() {
return ` return `
{{#*inline "glossary-single"}} {{#*inline "glossary-single"}}
@ -183,8 +234,8 @@ function optionsFieldTemplates() {
`.trim(); `.trim();
} }
function optionsSetDefaults(options) { function optionsCreateDefaults() {
const defaults = { return {
general: { general: {
enable: true, enable: true,
audioSource: 'jpod101', audioSource: 'jpod101',
@ -238,6 +289,10 @@ function optionsSetDefaults(options) {
fieldTemplates: optionsFieldTemplates() fieldTemplates: optionsFieldTemplates()
} }
}; };
}
function optionsSetDefaults(options) {
const defaults = optionsCreateDefaults();
const combine = (target, source) => { const combine = (target, source) => {
for (const key in source) { for (const key in source) {
@ -258,70 +313,29 @@ function optionsSetDefaults(options) {
} }
function optionsVersion(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();
}
}
];
optionsSetDefaults(options); optionsSetDefaults(options);
if (!options.hasOwnProperty('version')) { return optionsApplyUpdates(options, optionsVersionUpdates);
options.version = fixups.length;
}
while (options.version < fixups.length) {
fixups[options.version++]();
}
return options;
} }
function optionsLoad() { function optionsLoad() {
return new Promise((resolve, reject) => { 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 => { }).then(optionsStr => {
return optionsStr ? JSON.parse(optionsStr) : {}; if (typeof optionsStr === 'string') {
}).catch(error => { const options = JSON.parse(optionsStr);
if (typeof options === 'object' && options !== null && !Array.isArray(options)) {
return options;
}
}
return {};
}).catch(() => {
return {}; return {};
}).then(options => { }).then(options => {
return optionsVersion(options); return optionsVersion(options);
@ -329,9 +343,9 @@ function optionsLoad() {
} }
function optionsSave(options) { function optionsSave(options) {
return new Promise((resolve, reject) => { return new Promise((resolve) => {
chrome.storage.local.set({options: JSON.stringify(options)}, resolve); chrome.storage.local.set({options: JSON.stringify(options)}, resolve);
}).then(() => { }).then(() => {
apiOptionsSet(options); utilBackend().onOptionsUpdated(options);
}); });
} }

View File

@ -30,6 +30,10 @@
padding-bottom: 1em; padding-bottom: 1em;
} }
.label-light {
font-weight: normal;
}
#custom-popup-css { #custom-popup-css {
width: 100%; width: 100%;
min-height: 34px; min-height: 34px;
@ -49,6 +53,16 @@
[data-browser=firefox-mobile] [data-show-for-browser~=firefox-mobile] { [data-browser=firefox-mobile] [data-show-for-browser~=firefox-mobile] {
display: initial; display: initial;
} }
@media screen and (max-width: 740px) {
.col-xs-6 {
float: none;
width: 100%;
}
.col-xs-6+.col-xs-6 {
margin-top: 15px;
}
}
</style> </style>
</head> </head>
<body> <body>
@ -107,6 +121,16 @@
</select> </select>
</div> </div>
<div class="form-group options-advanced">
<label for="audio-playback-volume">Audio playback volume <span class="label-light">(percent)</span></label>
<input type="number" min="0" max="100" id="audio-playback-volume" class="form-control">
</div>
<div class="form-group options-advanced">
<label for="max-displayed-results">Maximum displayed results</label>
<input type="number" min="1" id="max-displayed-results" class="form-control">
</div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">
@ -130,36 +154,41 @@
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label for="audio-playback-volume">Audio playback volume (percent)</label>
<input type="number" min="0" max="100" id="audio-playback-volume" class="form-control">
</div>
<div class="form-group options-advanced">
<label for="max-displayed-results">Maximum displayed results</label>
<input type="number" min="1" id="max-displayed-results" class="form-control">
</div>
<div class="form-group options-advanced">
<label>Popup size (width &times; height, in pixels)</label>
<div class="row"> <div class="row">
<div class="col-xs-6"><input type="number" min="1" id="popup-width" class="form-control"></div> <div class="col-xs-6">
<div class="col-xs-6"><input type="number" min="1" id="popup-height" class="form-control"></div> <label for="popup-display-mode">Popup width <span class="label-light">(in pixels)</span></label>
<input type="number" min="1" id="popup-width" class="form-control">
</div>
<div class="col-xs-6">
<label for="popup-display-mode">Popup height <span class="label-light">(in pixels)</span></label>
<input type="number" min="1" id="popup-height" class="form-control">
</div>
</div> </div>
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label>Popup offset (horizontal, vertical; in pixels)</label>
<div class="row"> <div class="row">
<div class="col-xs-6"><input type="number" min="0" id="popup-horizontal-offset" class="form-control"></div> <div class="col-xs-6">
<div class="col-xs-6"><input type="number" min="0" id="popup-vertical-offset" class="form-control"></div> <label for="popup-display-mode">Horizontal popup offset <span class="label-light">(in pixels)</span></label>
<input type="number" min="0" id="popup-horizontal-offset" class="form-control">
</div>
<div class="col-xs-6">
<label for="popup-display-mode">Vertical popup offset <span class="label-light">(in pixels)</span></label>
<input type="number" min="0" id="popup-vertical-offset" class="form-control">
</div>
</div> </div>
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label>Popup offset for vertical text (horizontal, vertical; in pixels)</label>
<div class="row"> <div class="row">
<div class="col-xs-6"><input type="number" min="0" id="popup-horizontal-offset2" class="form-control"></div> <div class="col-xs-6">
<div class="col-xs-6"><input type="number" min="0" id="popup-vertical-offset2" class="form-control"></div> <label for="popup-display-mode">Horizontal popup offset for vertical text <span class="label-light">(in pixels)</span></label>
<input type="number" min="0" id="popup-horizontal-offset2" class="form-control">
</div>
<div class="col-xs-6">
<label for="popup-display-mode">Vertical popup offset for vertical text <span class="label-light">(in pixels)</span></label>
<input type="number" min="0" id="popup-vertical-offset2" class="form-control">
</div>
</div> </div>
</div> </div>
@ -205,12 +234,12 @@
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label for="scan-delay">Scan delay (in milliseconds)</label> <label for="scan-delay">Scan delay <span class="label-light">(in milliseconds)</span></label>
<input type="number" min="1" id="scan-delay" class="form-control"> <input type="number" min="1" id="scan-delay" class="form-control">
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label for="scan-length">Scan length (in characters)</label> <label for="scan-length">Scan length <span class="label-light">(in characters)</span></label>
<input type="number" min="1" id="scan-length" class="form-control"> <input type="number" min="1" id="scan-length" class="form-control">
</div> </div>
@ -326,12 +355,12 @@
<div id="anki-general"> <div id="anki-general">
<div class="form-group"> <div class="form-group">
<label for="card-tags">Card tags (comma or space separated)</label> <label for="card-tags">Card tags <span class="label-light">(comma or space separated)</span></label>
<input type="text" id="card-tags" class="form-control"> <input type="text" id="card-tags" class="form-control">
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label for="sentence-detection-extent">Sentence detection extent (in characters)</label> <label for="sentence-detection-extent">Sentence detection extent <span class="label-light">(in characters)</span></label>
<input type="number" min="1" id="sentence-detection-extent" class="form-control"> <input type="number" min="1" id="sentence-detection-extent" class="form-control">
</div> </div>
@ -349,7 +378,7 @@
</div> </div>
<div class="form-group options-advanced"> <div class="form-group options-advanced">
<label for="screenshot-quality">Screenshot quality (JPEG only)</label> <label for="screenshot-quality">Screenshot quality <span class="label-light">(JPEG only)</span></label>
<input type="number" min="0" max="100" step="1" id="screenshot-quality" class="form-control"> <input type="number" min="0" max="100" step="1" id="screenshot-quality" class="form-control">
</div> </div>
@ -413,7 +442,7 @@
their Anki cards. If you encounter problems with your changes you can always <a href="#" id="field-templates-reset">reset to default</a> their Anki cards. If you encounter problems with your changes you can always <a href="#" id="field-templates-reset">reset to default</a>
template settings. template settings.
</p> </p>
<textarea class="form-control" rows="10" id="field-templates"></textarea> <textarea autocomplete="off" spellcheck="false" wrap="soft" class="form-control" rows="10" id="field-templates"></textarea>
</div> </div>
</div> </div>
</div> </div>

View File

@ -17,10 +17,6 @@
*/ */
function apiOptionsSet(options) {
return utilInvoke('optionsSet', {options});
}
function apiOptionsGet() { function apiOptionsGet() {
return utilInvoke('optionsGet'); return utilInvoke('optionsGet');
} }

View File

@ -261,7 +261,7 @@ class Frontend {
onBgMessage({action, params}, sender, callback) { onBgMessage({action, params}, sender, callback) {
const handlers = { const handlers = {
optionsSet: options => { optionsSet: ({options}) => {
this.options = options; this.options = options;
if (!this.options.enable) { if (!this.options.enable) {
this.searchClear(); this.searchClear();