Merge pull request #386 from siikamiika/simplify-backend-prepare

Simplify backend prepare
This commit is contained in:
siikamiika 2020-03-04 05:30:48 +02:00 committed by GitHub
commit 6e47b4e241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 91 additions and 61 deletions

View File

@ -39,8 +39,7 @@ class Backend {
url: window.location.href url: window.location.href
}; };
this.isPreparedResolve = null; this.isPrepared = false;
this.isPreparedPromise = new Promise((resolve) => (this.isPreparedResolve = resolve));
this.clipboardPasteTarget = document.querySelector('#clipboard-paste-target'); this.clipboardPasteTarget = document.querySelector('#clipboard-paste-target');
@ -51,6 +50,7 @@ class Backend {
this.messageToken = yomichan.generateId(16); this.messageToken = yomichan.generateId(16);
this._messageHandlers = new Map([ this._messageHandlers = new Map([
['yomichanCoreReady', this._onApiYomichanCoreReady.bind(this)],
['optionsSchemaGet', this._onApiOptionsSchemaGet.bind(this)], ['optionsSchemaGet', this._onApiOptionsSchemaGet.bind(this)],
['optionsGet', this._onApiOptionsGet.bind(this)], ['optionsGet', this._onApiOptionsGet.bind(this)],
['optionsGetFull', this._onApiOptionsGetFull.bind(this)], ['optionsGetFull', this._onApiOptionsGetFull.bind(this)],
@ -110,27 +110,31 @@ class Backend {
} }
chrome.runtime.onMessage.addListener(this.onMessage.bind(this)); chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
const options = this.getOptionsSync(this.optionsContext); this.isPrepared = true;
const options = this.getOptions(this.optionsContext);
if (options.general.showGuide) { if (options.general.showGuide) {
chrome.tabs.create({url: chrome.runtime.getURL('/bg/guide.html')}); chrome.tabs.create({url: chrome.runtime.getURL('/bg/guide.html')});
} }
this.isPreparedResolve();
this.isPreparedResolve = null;
this.isPreparedPromise = null;
this.clipboardMonitor.onClipboardText = this._onClipboardText.bind(this); this.clipboardMonitor.onClipboardText = this._onClipboardText.bind(this);
this._sendMessageAllTabs('backendPrepared');
chrome.runtime.sendMessage({action: 'backendPrepared'});
}
_sendMessageAllTabs(action, params={}) {
const callback = () => this.checkLastError(chrome.runtime.lastError);
chrome.tabs.query({}, (tabs) => {
for (const tab of tabs) {
chrome.tabs.sendMessage(tab.id, {action, params}, callback);
}
});
} }
onOptionsUpdated(source) { onOptionsUpdated(source) {
this.applyOptions(); this.applyOptions();
this._sendMessageAllTabs('optionsUpdated', {source});
const callback = () => this.checkLastError(chrome.runtime.lastError);
chrome.tabs.query({}, (tabs) => {
for (const tab of tabs) {
chrome.tabs.sendMessage(tab.id, {action: 'optionsUpdated', params: {source}}, callback);
}
});
} }
onMessage({action, params}, sender, callback) { onMessage({action, params}, sender, callback) {
@ -160,7 +164,7 @@ class Backend {
} }
applyOptions() { applyOptions() {
const options = this.getOptionsSync(this.optionsContext); const options = this.getOptions(this.optionsContext);
if (!options.general.enable) { if (!options.general.enable) {
this.setExtensionBadgeBackgroundColor('#555555'); this.setExtensionBadgeBackgroundColor('#555555');
this.setExtensionBadgeText('off'); this.setExtensionBadgeText('off');
@ -186,24 +190,15 @@ class Backend {
} }
} }
async getOptionsSchema() { getOptionsSchema() {
if (this.isPreparedPromise !== null) {
await this.isPreparedPromise;
}
return this.optionsSchema; return this.optionsSchema;
} }
async getFullOptions() { getFullOptions() {
if (this.isPreparedPromise !== null) {
await this.isPreparedPromise;
}
return this.options; return this.options;
} }
async setFullOptions(options) { setFullOptions(options) {
if (this.isPreparedPromise !== null) {
await this.isPreparedPromise;
}
try { try {
this.options = JsonSchema.getValidValueOrDefault(this.optionsSchema, utilIsolate(options)); this.options = JsonSchema.getValidValueOrDefault(this.optionsSchema, utilIsolate(options));
} catch (e) { } catch (e) {
@ -212,18 +207,11 @@ class Backend {
} }
} }
async getOptions(optionsContext) { getOptions(optionsContext) {
if (this.isPreparedPromise !== null) { return this.getProfile(optionsContext).options;
await this.isPreparedPromise;
}
return this.getOptionsSync(optionsContext);
} }
getOptionsSync(optionsContext) { getProfile(optionsContext) {
return this.getProfileSync(optionsContext).options;
}
getProfileSync(optionsContext) {
const profiles = this.options.profiles; const profiles = this.options.profiles;
if (typeof optionsContext.index === 'number') { if (typeof optionsContext.index === 'number') {
return profiles[optionsContext.index]; return profiles[optionsContext.index];
@ -290,20 +278,33 @@ class Backend {
// Message handlers // Message handlers
_onApiOptionsSchemaGet() { _onApiYomichanCoreReady(_params, sender) {
// tab ID isn't set in background (e.g. browser_action)
if (typeof sender.tab === 'undefined') {
chrome.runtime.sendMessage({action: 'backendPrepared'});
return Promise.resolve();
}
const tabId = sender.tab.id;
return new Promise((resolve) => {
chrome.tabs.sendMessage(tabId, {action: 'backendPrepared'}, resolve);
});
}
async _onApiOptionsSchemaGet() {
return this.getOptionsSchema(); return this.getOptionsSchema();
} }
_onApiOptionsGet({optionsContext}) { async _onApiOptionsGet({optionsContext}) {
return this.getOptions(optionsContext); return this.getOptions(optionsContext);
} }
_onApiOptionsGetFull() { async _onApiOptionsGetFull() {
return this.getFullOptions(); return this.getFullOptions();
} }
async _onApiOptionsSet({changedOptions, optionsContext, source}) { async _onApiOptionsSet({changedOptions, optionsContext, source}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
function getValuePaths(obj) { function getValuePaths(obj) {
const valuePaths = []; const valuePaths = [];
@ -343,20 +344,20 @@ class Backend {
} }
async _onApiOptionsSave({source}) { async _onApiOptionsSave({source}) {
const options = await this.getFullOptions(); const options = this.getFullOptions();
await optionsSave(options); await optionsSave(options);
this.onOptionsUpdated(source); this.onOptionsUpdated(source);
} }
async _onApiKanjiFind({text, optionsContext}) { async _onApiKanjiFind({text, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const definitions = await this.translator.findKanji(text, options); const definitions = await this.translator.findKanji(text, options);
definitions.splice(options.general.maxResults); definitions.splice(options.general.maxResults);
return definitions; return definitions;
} }
async _onApiTermsFind({text, details, optionsContext}) { async _onApiTermsFind({text, details, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const mode = options.general.resultOutputMode; const mode = options.general.resultOutputMode;
const [definitions, length] = await this.translator.findTerms(mode, text, details, options); const [definitions, length] = await this.translator.findTerms(mode, text, details, options);
definitions.splice(options.general.maxResults); definitions.splice(options.general.maxResults);
@ -364,7 +365,7 @@ class Backend {
} }
async _onApiTextParse({text, optionsContext}) { async _onApiTextParse({text, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const results = []; const results = [];
while (text.length > 0) { while (text.length > 0) {
const term = []; const term = [];
@ -394,7 +395,7 @@ class Backend {
} }
async _onApiTextParseMecab({text, optionsContext}) { async _onApiTextParseMecab({text, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const results = []; const results = [];
const rawResults = await this.mecab.parseText(text); const rawResults = await this.mecab.parseText(text);
for (const [mecabName, parsedLines] of Object.entries(rawResults)) { for (const [mecabName, parsedLines] of Object.entries(rawResults)) {
@ -425,7 +426,7 @@ class Backend {
} }
async _onApiDefinitionAdd({definition, mode, context, optionsContext}) { async _onApiDefinitionAdd({definition, mode, context, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const templates = this.defaultAnkiFieldTemplates; const templates = this.defaultAnkiFieldTemplates;
if (mode !== 'kanji') { if (mode !== 'kanji') {
@ -450,7 +451,7 @@ class Backend {
} }
async _onApiDefinitionsAddable({definitions, modes, optionsContext}) { async _onApiDefinitionsAddable({definitions, modes, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
const templates = this.defaultAnkiFieldTemplates; const templates = this.defaultAnkiFieldTemplates;
const states = []; const states = [];
@ -497,7 +498,7 @@ class Backend {
} }
async _onApiNoteView({noteId}) { async _onApiNoteView({noteId}) {
return this.anki.guiBrowse(`nid:${noteId}`); return await this.anki.guiBrowse(`nid:${noteId}`);
} }
async _onApiTemplateRender({template, data}) { async _onApiTemplateRender({template, data}) {
@ -509,7 +510,7 @@ class Backend {
} }
async _onApiAudioGetUrl({definition, source, optionsContext}) { async _onApiAudioGetUrl({definition, source, optionsContext}) {
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
return await audioGetUrl(definition, source, options); return await audioGetUrl(definition, source, options);
} }
@ -668,7 +669,7 @@ class Backend {
async _onCommandSearch(params) { async _onCommandSearch(params) {
const {mode='existingOrNewTab', query} = params || {}; const {mode='existingOrNewTab', query} = params || {};
const options = await this.getOptions(this.optionsContext); const options = this.getOptions(this.optionsContext);
const {popupWidth, popupHeight} = options.general; const {popupWidth, popupHeight} = options.general;
const baseUrl = chrome.runtime.getURL('/bg/search.html'); const baseUrl = chrome.runtime.getURL('/bg/search.html');
@ -752,7 +753,7 @@ class Backend {
}; };
const source = 'popup'; const source = 'popup';
const options = await this.getOptions(optionsContext); const options = this.getOptions(optionsContext);
options.general.enable = !options.general.enable; options.general.enable = !options.general.enable;
await this._onApiOptionsSave({source}); await this._onApiOptionsSave({source});
} }

View File

@ -48,7 +48,9 @@ function setupButtonEvents(selector, command, url) {
} }
} }
window.addEventListener('DOMContentLoaded', () => { window.addEventListener('DOMContentLoaded', async () => {
await yomichan.prepare();
showExtensionInfo(); showExtensionInfo();
apiGetEnvironmentInfo().then(({browser}) => { apiGetEnvironmentInfo().then(({browser}) => {

View File

@ -19,6 +19,8 @@
/*global apiOptionsGet*/ /*global apiOptionsGet*/
async function searchFrontendSetup() { async function searchFrontendSetup() {
await yomichan.prepare();
const optionsContext = { const optionsContext = {
depth: 0, depth: 0,
url: window.location.href url: window.location.href

View File

@ -68,9 +68,8 @@ class DisplaySearch extends Display {
async prepare() { async prepare() {
try { try {
const superPromise = super.prepare(); await super.prepare();
const queryParserPromise = this.queryParser.prepare(); await this.queryParser.prepare();
await Promise.all([superPromise, queryParserPromise]);
const {queryParams: {query='', mode=''}} = parseUrl(window.location.href); const {queryParams: {query='', mode=''}} = parseUrl(window.location.href);

View File

@ -120,7 +120,7 @@ async function _onSettingsExportClick() {
// Importing // Importing
async function _settingsImportSetOptionsFull(optionsFull) { async function _settingsImportSetOptionsFull(optionsFull) {
return utilIsolate(await utilBackend().setFullOptions( return utilIsolate(utilBackend().setFullOptions(
utilBackgroundIsolate(optionsFull) utilBackgroundIsolate(optionsFull)
)); ));
} }
@ -362,10 +362,10 @@ async function _onSettingsResetConfirmClick() {
// Setup // Setup
window.addEventListener('DOMContentLoaded', () => { function backupInitialize() {
document.querySelector('#settings-export').addEventListener('click', _onSettingsExportClick, false); document.querySelector('#settings-export').addEventListener('click', _onSettingsExportClick, false);
document.querySelector('#settings-import').addEventListener('click', _onSettingsImportClick, false); document.querySelector('#settings-import').addEventListener('click', _onSettingsImportClick, false);
document.querySelector('#settings-import-file').addEventListener('change', _onSettingsImportFileChange, false); document.querySelector('#settings-import-file').addEventListener('change', _onSettingsImportFileChange, false);
document.querySelector('#settings-reset').addEventListener('click', _onSettingsResetClick, false); document.querySelector('#settings-reset').addEventListener('click', _onSettingsResetClick, false);
document.querySelector('#settings-reset-modal-confirm').addEventListener('click', _onSettingsResetConfirmClick, false); document.querySelector('#settings-reset-modal-confirm').addEventListener('click', _onSettingsResetConfirmClick, false);
}, false); }

View File

@ -21,7 +21,7 @@ utilBackend, utilIsolate, utilBackgroundIsolate
ankiErrorShown, ankiFieldsToDict ankiErrorShown, ankiFieldsToDict
ankiTemplatesUpdateValue, onAnkiOptionsChanged, onDictionaryOptionsChanged ankiTemplatesUpdateValue, onAnkiOptionsChanged, onDictionaryOptionsChanged
appearanceInitialize, audioSettingsInitialize, profileOptionsSetup, dictSettingsInitialize appearanceInitialize, audioSettingsInitialize, profileOptionsSetup, dictSettingsInitialize
ankiInitialize, ankiTemplatesInitialize, storageInfoInitialize ankiInitialize, ankiTemplatesInitialize, storageInfoInitialize, backupInitialize
*/ */
function getOptionsMutable(optionsContext) { function getOptionsMutable(optionsContext) {
@ -262,6 +262,8 @@ function showExtensionInformation() {
async function onReady() { async function onReady() {
await yomichan.prepare();
showExtensionInformation(); showExtensionInformation();
formSetupEventListeners(); formSetupEventListeners();
@ -271,6 +273,7 @@ async function onReady() {
await dictSettingsInitialize(); await dictSettingsInitialize();
ankiInitialize(); ankiInitialize();
ankiTemplatesInitialize(); ankiTemplatesInitialize();
backupInitialize();
storageInfoInitialize(); storageInfoInitialize();

View File

@ -73,7 +73,11 @@ function utilStringHashCode(string) {
} }
function utilBackend() { function utilBackend() {
return chrome.extension.getBackgroundPage().yomichanBackend; const backend = chrome.extension.getBackgroundPage().yomichanBackend;
if (!backend.isPrepared) {
throw new Error('Backend not ready yet');
}
return backend;
} }
async function utilAnkiGetModelNames() { async function utilAnkiGetModelNames() {

View File

@ -19,6 +19,8 @@
/*global PopupProxyHost, PopupProxy, Frontend*/ /*global PopupProxyHost, PopupProxy, Frontend*/
async function main() { async function main() {
await yomichan.prepare();
const data = window.frontendInitializationData || {}; const data = window.frontendInitializationData || {};
const {id, depth=0, parentFrameId, ignoreNodes, url, proxy=false} = data; const {id, depth=0, parentFrameId, ignoreNodes, url, proxy=false} = data;

View File

@ -269,7 +269,11 @@ const yomichan = (() => {
constructor() { constructor() {
super(); super();
this._isBackendPreparedResolve = null;
this._isBackendPreparedPromise = new Promise((resolve) => (this._isBackendPreparedResolve = resolve));
this._messageHandlers = new Map([ this._messageHandlers = new Map([
['backendPrepared', this._onBackendPrepared.bind(this)],
['getUrl', this._onMessageGetUrl.bind(this)], ['getUrl', this._onMessageGetUrl.bind(this)],
['optionsUpdated', this._onMessageOptionsUpdated.bind(this)], ['optionsUpdated', this._onMessageOptionsUpdated.bind(this)],
['zoomChanged', this._onMessageZoomChanged.bind(this)] ['zoomChanged', this._onMessageZoomChanged.bind(this)]
@ -280,6 +284,11 @@ const yomichan = (() => {
// Public // Public
prepare() {
chrome.runtime.sendMessage({action: 'yomichanCoreReady'});
return this._isBackendPreparedPromise;
}
generateId(length) { generateId(length) {
const array = new Uint8Array(length); const array = new Uint8Array(length);
window.crypto.getRandomValues(array); window.crypto.getRandomValues(array);
@ -305,6 +314,10 @@ const yomichan = (() => {
return false; return false;
} }
_onBackendPrepared() {
this._isBackendPreparedResolve();
}
_onMessageGetUrl() { _onMessageGetUrl() {
return {url: window.location.href}; return {url: window.location.href};
} }

View File

@ -153,6 +153,7 @@ class Display {
} }
async prepare(options=null) { async prepare(options=null) {
await yomichan.prepare();
const displayGeneratorPromise = this.displayGenerator.prepare(); const displayGeneratorPromise = this.displayGenerator.prepare();
const updateOptionsPromise = this.updateOptions(options); const updateOptionsPromise = this.updateOptions(options);
await Promise.all([displayGeneratorPromise, updateOptionsPromise]); await Promise.all([displayGeneratorPromise, updateOptionsPromise]);

View File

@ -30,6 +30,9 @@ const chrome = {
}, },
getURL(path2) { getURL(path2) {
return url.pathToFileURL(path.join(__dirname, '..', 'ext', path2.replace(/^\//, ''))); return url.pathToFileURL(path.join(__dirname, '..', 'ext', path2.replace(/^\//, '')));
},
sendMessage() {
// NOP
} }
} }
}; };