aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/bg/js/backend.js174
-rw-r--r--ext/bg/js/util.js2
2 files changed, 124 insertions, 52 deletions
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js
index 9d1fa6c1..e0814c17 100644
--- a/ext/bg/js/backend.js
+++ b/ext/bg/js/backend.js
@@ -28,7 +28,6 @@
* Mecab
* Translator
* conditionsTestValue
- * dictConfigured
* dictTermsSort
* handlebarsRenderDynamic
* jp
@@ -67,8 +66,6 @@ class Backend {
url: window.location.href
};
- this.isPrepared = false;
-
this.clipboardPasteTarget = document.querySelector('#clipboard-paste-target');
this.popupWindow = null;
@@ -77,6 +74,11 @@ class Backend {
this.messageToken = yomichan.generateId(16);
+ this._defaultBrowserActionTitle = null;
+ this._isPrepared = false;
+ this._prepareError = false;
+ this._badgePrepareDelayTimer = null;
+
this._messageHandlers = new Map([
['yomichanCoreReady', {handler: this._onApiYomichanCoreReady.bind(this), async: false}],
['optionsSchemaGet', {handler: this._onApiOptionsSchemaGet.bind(this), async: false}],
@@ -121,41 +123,60 @@ class Backend {
}
async prepare() {
- await this.database.prepare();
- await this.translator.prepare();
-
- this.optionsSchema = await requestJson(chrome.runtime.getURL('/bg/data/options-schema.json'), 'GET');
- this.defaultAnkiFieldTemplates = await requestText(chrome.runtime.getURL('/bg/data/default-anki-field-templates.handlebars'), 'GET');
- this.options = await optionsLoad();
try {
+ this._defaultBrowserActionTitle = await this._getBrowserIconTitle();
+ this._badgePrepareDelayTimer = setTimeout(() => {
+ this._badgePrepareDelayTimer = null;
+ this._updateBadge();
+ }, 1000);
+ this._updateBadge();
+
+ await this.database.prepare();
+ await this.translator.prepare();
+
+ this.optionsSchema = await requestJson(chrome.runtime.getURL('/bg/data/options-schema.json'), 'GET');
+ this.defaultAnkiFieldTemplates = await requestText(chrome.runtime.getURL('/bg/data/default-anki-field-templates.handlebars'), 'GET');
+ this.options = await optionsLoad();
this.options = JsonSchema.getValidValueOrDefault(this.optionsSchema, this.options);
- } catch (e) {
- // This shouldn't happen, but catch errors just in case of bugs
- logError(e);
- }
- this.onOptionsUpdated('background');
+ this.onOptionsUpdated('background');
- if (isObject(chrome.commands) && isObject(chrome.commands.onCommand)) {
- chrome.commands.onCommand.addListener(this._runCommand.bind(this));
- }
- if (isObject(chrome.tabs) && isObject(chrome.tabs.onZoomChange)) {
- chrome.tabs.onZoomChange.addListener(this._onZoomChange.bind(this));
- }
- chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
+ if (isObject(chrome.commands) && isObject(chrome.commands.onCommand)) {
+ chrome.commands.onCommand.addListener(this._runCommand.bind(this));
+ }
+ if (isObject(chrome.tabs) && isObject(chrome.tabs.onZoomChange)) {
+ chrome.tabs.onZoomChange.addListener(this._onZoomChange.bind(this));
+ }
+ chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
- this.isPrepared = true;
+ const options = this.getOptions(this.optionsContext);
+ if (options.general.showGuide) {
+ chrome.tabs.create({url: chrome.runtime.getURL('/bg/guide.html')});
+ }
- const options = this.getOptions(this.optionsContext);
- if (options.general.showGuide) {
- chrome.tabs.create({url: chrome.runtime.getURL('/bg/guide.html')});
- }
+ this.clipboardMonitor.on('change', this._onClipboardText.bind(this));
- this.clipboardMonitor.on('change', this._onClipboardText.bind(this));
+ this._sendMessageAllTabs('backendPrepared');
+ const callback = () => this.checkLastError(chrome.runtime.lastError);
+ chrome.runtime.sendMessage({action: 'backendPrepared'}, callback);
- this._sendMessageAllTabs('backendPrepared');
- const callback = () => this.checkLastError(chrome.runtime.lastError);
- chrome.runtime.sendMessage({action: 'backendPrepared'}, callback);
+ this._isPrepared = true;
+ } catch (e) {
+ this._prepareError = true;
+ logError(e);
+ throw e;
+ } finally {
+ if (this._badgePrepareDelayTimer !== null) {
+ clearTimeout(this._badgePrepareDelayTimer);
+ this._badgePrepareDelayTimer = null;
+ }
+
+ this._updateBadge();
+ }
+ }
+
+ isPrepared() {
+ return this._isPrepared;
}
_sendMessageAllTabs(action, params={}) {
@@ -207,15 +228,7 @@ class Backend {
applyOptions() {
const options = this.getOptions(this.optionsContext);
- if (!options.general.enable) {
- this.setExtensionBadgeBackgroundColor('#555555');
- this.setExtensionBadgeText('off');
- } else if (!dictConfigured(options)) {
- this.setExtensionBadgeBackgroundColor('#f0ad4e');
- this.setExtensionBadgeText('!');
- } else {
- this.setExtensionBadgeText('');
- }
+ this._updateBadge();
this.anki.setServer(options.anki.server);
this.anki.setEnabled(options.anki.enable);
@@ -295,18 +308,6 @@ class Backend {
return true;
}
- setExtensionBadgeBackgroundColor(color) {
- if (typeof chrome.browserAction.setBadgeBackgroundColor === 'function') {
- chrome.browserAction.setBadgeBackgroundColor({color});
- }
- }
-
- setExtensionBadgeText(text) {
- if (typeof chrome.browserAction.setBadgeText === 'function') {
- chrome.browserAction.setBadgeText({text});
- }
- }
-
checkLastError() {
// NOP
}
@@ -864,6 +865,77 @@ class Backend {
}
}
+ _getBrowserIconTitle() {
+ return (
+ isObject(chrome.browserAction) &&
+ typeof chrome.browserAction.getTitle === 'function' ?
+ new Promise((resolve) => chrome.browserAction.getTitle({}, resolve)) :
+ Promise.resolve('')
+ );
+ }
+
+ _updateBadge() {
+ let title = this._defaultBrowserActionTitle;
+ if (title === null || !isObject(chrome.browserAction)) {
+ // Not ready or invalid
+ return;
+ }
+
+ let text = '';
+ let color = null;
+ let status = null;
+
+ if (!this._isPrepared) {
+ if (this._prepareError) {
+ text = '!!';
+ color = '#f04e4e';
+ status = 'Error';
+ } else if (this._badgePrepareDelayTimer === null) {
+ text = '...';
+ color = '#f0ad4e';
+ status = 'Loading';
+ }
+ } else if (!this._anyOptionsMatches((options) => options.general.enable)) {
+ text = 'off';
+ color = '#555555';
+ status = 'Disabled';
+ } else if (!this._anyOptionsMatches((options) => this._isAnyDictionaryEnabled(options))) {
+ text = '!';
+ color = '#f0ad4e';
+ status = 'No dictionaries installed';
+ }
+
+ if (color !== null && typeof chrome.browserAction.setBadgeBackgroundColor === 'function') {
+ chrome.browserAction.setBadgeBackgroundColor({color});
+ }
+ if (text !== null && typeof chrome.browserAction.setBadgeText === 'function') {
+ chrome.browserAction.setBadgeText({text});
+ }
+ if (typeof chrome.browserAction.setTitle === 'function') {
+ if (status !== null) {
+ title = `${title} - ${status}`;
+ }
+ chrome.browserAction.setTitle({title});
+ }
+ }
+
+ _isAnyDictionaryEnabled(options) {
+ for (const {enabled} of Object.values(options.dictionaries)) {
+ if (enabled) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ _anyOptionsMatches(predicate) {
+ for (const {options} of this.options.profiles) {
+ const value = predicate(options);
+ if (value) { return value; }
+ }
+ return false;
+ }
+
async _renderTemplate(template, data) {
return handlebarsRenderDynamic(template, data);
}
diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js
index 5edcc193..d2fb0e49 100644
--- a/ext/bg/js/util.js
+++ b/ext/bg/js/util.js
@@ -60,7 +60,7 @@ function utilBackgroundFunctionIsolate(func) {
function utilBackend() {
const backend = chrome.extension.getBackgroundPage().yomichanBackend;
- if (!backend.isPrepared) {
+ if (!backend.isPrepared()) {
throw new Error('Backend not ready yet');
}
return backend;