From 6498556ec7ddd3e0896ef47cce297bcbf938defb Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Apr 2020 20:45:23 -0400 Subject: [PATCH 1/7] Update isPrepared to be consistent with DisplaySearch's isPrepared --- ext/bg/js/backend.js | 12 ++++++++---- ext/bg/js/util.js | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 9d1fa6c1..f5bd36f5 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -67,8 +67,6 @@ class Backend { url: window.location.href }; - this.isPrepared = false; - this.clipboardPasteTarget = document.querySelector('#clipboard-paste-target'); this.popupWindow = null; @@ -77,6 +75,8 @@ class Backend { this.messageToken = yomichan.generateId(16); + this._isPrepared = false; + this._messageHandlers = new Map([ ['yomichanCoreReady', {handler: this._onApiYomichanCoreReady.bind(this), async: false}], ['optionsSchemaGet', {handler: this._onApiOptionsSchemaGet.bind(this), async: false}], @@ -144,8 +144,6 @@ class Backend { } 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')}); @@ -156,6 +154,12 @@ class Backend { this._sendMessageAllTabs('backendPrepared'); const callback = () => this.checkLastError(chrome.runtime.lastError); chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); + + this._isPrepared = true; + } + + isPrepared() { + return this._isPrepared; } _sendMessageAllTabs(action, params={}) { 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; From c9704b5c5e3b8f78888adaa2dcd4fa54f28c9db1 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Apr 2020 20:46:11 -0400 Subject: [PATCH 2/7] Update when/how badge state is changed --- ext/bg/js/backend.js | 96 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index f5bd36f5..1589524b 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -75,6 +75,7 @@ class Backend { this.messageToken = yomichan.generateId(16); + this._defaultBrowserActionTitle = null; this._isPrepared = false; this._messageHandlers = new Map([ @@ -121,6 +122,8 @@ class Backend { } async prepare() { + this._defaultBrowserActionTitle = await this._getBrowserIconTitle(); + this._updateBadge(); await this.database.prepare(); await this.translator.prepare(); @@ -156,6 +159,7 @@ class Backend { chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); this._isPrepared = true; + this._updateBadge(); } isPrepared() { @@ -211,15 +215,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); @@ -299,18 +295,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 } @@ -868,6 +852,76 @@ class Backend { } } + _getBrowserIconTitle() { + return ( + chrome.browserAction !== null && + typeof chrome.browserAction === 'object' && + typeof chrome.browserAction.getTitle === 'function' ? + new Promise((resolve) => chrome.browserAction.getTitle({}, resolve)) : + Promise.resolve('') + ); + } + + _updateBadge() { + let title = this._defaultBrowserActionTitle; + if ( + title === null || + chrome.browserAction === null || + typeof chrome.browserAction !== 'object' + ) { + // Not ready or invalid + return; + } + + let text = ''; + let color = null; + let status = null; + + if (!this._isPrepared) { + 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); } From 5c5c70326d797b819cff33390e04dde93c63669c Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Apr 2020 20:53:18 -0400 Subject: [PATCH 3/7] Add a delay before showing the loading state Intended to prevent flickering when startup is quick --- ext/bg/js/backend.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 1589524b..9cfa621a 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -77,6 +77,7 @@ class Backend { this._defaultBrowserActionTitle = null; this._isPrepared = false; + this._badgePrepareDelayTimer = null; this._messageHandlers = new Map([ ['yomichanCoreReady', {handler: this._onApiYomichanCoreReady.bind(this), async: false}], @@ -123,6 +124,10 @@ class Backend { async prepare() { this._defaultBrowserActionTitle = await this._getBrowserIconTitle(); + this._badgePrepareDelayTimer = setTimeout(() => { + this._badgePrepareDelayTimer = null; + this._updateBadge(); + }, 1000); this._updateBadge(); await this.database.prepare(); await this.translator.prepare(); @@ -158,6 +163,11 @@ class Backend { const callback = () => this.checkLastError(chrome.runtime.lastError); chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); + if (this._badgePrepareDelayTimer !== null) { + clearTimeout(this._badgePrepareDelayTimer); + this._badgePrepareDelayTimer = null; + } + this._isPrepared = true; this._updateBadge(); } @@ -878,9 +888,11 @@ class Backend { let status = null; if (!this._isPrepared) { - text = '...'; - color = '#f0ad4e'; - status = 'Loading'; + if (this._badgePrepareDelayTimer === null) { + text = '...'; + color = '#f0ad4e'; + status = 'Loading'; + } } else if (!this._anyOptionsMatches((options) => options.general.enable)) { text = 'off'; color = '#555555'; From dee7d924a8555226721bbbdb045b86a21426f60b Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Apr 2020 20:58:52 -0400 Subject: [PATCH 4/7] Show error status for prepare() errors --- ext/bg/js/backend.js | 94 ++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 9cfa621a..9f466647 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -77,6 +77,7 @@ class Backend { this._defaultBrowserActionTitle = null; this._isPrepared = false; + this._prepareError = false; this._badgePrepareDelayTimer = null; this._messageHandlers = new Map([ @@ -123,53 +124,56 @@ class Backend { } async prepare() { - 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(); 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); + + 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)); + + 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._sendMessageAllTabs('backendPrepared'); + const callback = () => this.checkLastError(chrome.runtime.lastError); + chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); + + this._isPrepared = true; } catch (e) { - // This shouldn't happen, but catch errors just in case of bugs + this._prepareError = true; logError(e); + throw e; + } finally { + if (this._badgePrepareDelayTimer !== null) { + clearTimeout(this._badgePrepareDelayTimer); + this._badgePrepareDelayTimer = null; + } + + this._updateBadge(); } - - 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)); - - 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._sendMessageAllTabs('backendPrepared'); - const callback = () => this.checkLastError(chrome.runtime.lastError); - chrome.runtime.sendMessage({action: 'backendPrepared'}, callback); - - if (this._badgePrepareDelayTimer !== null) { - clearTimeout(this._badgePrepareDelayTimer); - this._badgePrepareDelayTimer = null; - } - - this._isPrepared = true; - this._updateBadge(); } isPrepared() { @@ -888,7 +892,11 @@ class Backend { let status = null; if (!this._isPrepared) { - if (this._badgePrepareDelayTimer === null) { + if (this._prepareError !== null) { + text = '!!'; + color = '#f04e4e'; + status = 'Error'; + } else if (this._badgePrepareDelayTimer === null) { text = '...'; color = '#f0ad4e'; status = 'Loading'; From 66ef7301198e4baa827fafe002818896a8bb6483 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Fri, 17 Apr 2020 19:19:38 -0400 Subject: [PATCH 5/7] Update style, use isObject --- ext/bg/js/backend.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 9f466647..aacebd2c 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -868,21 +868,16 @@ class Backend { _getBrowserIconTitle() { return ( - chrome.browserAction !== null && - typeof chrome.browserAction === 'object' && + isObject(chrome.browserAction) && typeof chrome.browserAction.getTitle === 'function' ? - new Promise((resolve) => chrome.browserAction.getTitle({}, resolve)) : - Promise.resolve('') + new Promise((resolve) => chrome.browserAction.getTitle({}, resolve)) : + Promise.resolve('') ); } _updateBadge() { let title = this._defaultBrowserActionTitle; - if ( - title === null || - chrome.browserAction === null || - typeof chrome.browserAction !== 'object' - ) { + if (title === null || !isObject(chrome.browserAction)) { // Not ready or invalid return; } From 4638985b16951b1b1b3895ca0bf52575f1f0bd6b Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Fri, 17 Apr 2020 22:16:51 -0400 Subject: [PATCH 6/7] Remove unused global --- ext/bg/js/backend.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index aacebd2c..8c0b531f 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -28,7 +28,6 @@ * Mecab * Translator * conditionsTestValue - * dictConfigured * dictTermsSort * handlebarsRenderDynamic * jp From 51d756eefc26402e4d6f9635acc77ba7f642d15b Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 18 Apr 2020 21:15:15 -0400 Subject: [PATCH 7/7] Fix _prepareError check --- ext/bg/js/backend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 8c0b531f..e0814c17 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -886,7 +886,7 @@ class Backend { let status = null; if (!this._isPrepared) { - if (this._prepareError !== null) { + if (this._prepareError) { text = '!!'; color = '#f04e4e'; status = 'Error';