diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 0c901c68..2c741dd7 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -125,7 +125,8 @@ class Backend { ['modifySettings', {async: true, contentScript: true, handler: this._onApiModifySettings.bind(this)}], ['getSettings', {async: false, contentScript: true, handler: this._onApiGetSettings.bind(this)}], ['setAllSettings', {async: true, contentScript: false, handler: this._onApiSetAllSettings.bind(this)}], - ['getOrCreateSearchPopup', {async: true, contentScript: true, handler: this._onApiGetOrCreateSearchPopup.bind(this)}] + ['getOrCreateSearchPopup', {async: true, contentScript: true, handler: this._onApiGetOrCreateSearchPopup.bind(this)}], + ['isTabSearchPopup', {async: true, contentScript: true, handler: this._onApiIsTabSearchPopup.bind(this)}] ]); this._messageHandlersWithProgress = new Map([ ['deleteDictionary', {async: true, contentScript: false, handler: this._onApiDeleteDictionary.bind(this)}] @@ -800,6 +801,12 @@ class Backend { return {tabId: tab.id, windowId: tab.windowId}; } + async _onApiIsTabSearchPopup({tabId}) { + const baseUrl = chrome.runtime.getURL('/bg/search.html'); + const tab = typeof tabId === 'number' ? await this._checkTabUrl(tabId, (url) => url.startsWith(baseUrl)) : null; + return (tab !== null); + } + // Command handlers async _onCommandSearch(params) { @@ -883,19 +890,9 @@ class Backend { // Reuse same tab const baseUrl = chrome.runtime.getURL('/bg/search.html'); if (this._searchPopupTabId !== null) { - const tabId = this._searchPopupTabId; - const tab = await new Promise((resolve) => { - chrome.tabs.get( - tabId, - (result) => { resolve(chrome.runtime.lastError ? null : result); } - ); - }); + const tab = await this._checkTabUrl(this._searchPopupTabId, (url) => url.startsWith(baseUrl)); if (tab !== null) { - const url = await this._getTabUrl(tabId); - const isValidTab = (url !== null && url.startsWith(baseUrl)); - if (isValidTab) { - return {tab, created: false}; - } + return {tab, created: false}; } this._searchPopupTabId = null; } @@ -1521,4 +1518,18 @@ class Backend { chrome.tabs.sendMessage(...args, callback); }); } + + async _checkTabUrl(tabId, urlPredicate) { + const tab = await new Promise((resolve) => { + chrome.tabs.get( + tabId, + (result) => { resolve(chrome.runtime.lastError ? null : result); } + ); + }); + if (tab === null) { return null; } + + const url = await this._getTabUrl(tabId); + const isValidTab = urlPredicate(url); + return isValidTab ? tab : null; + } } diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index e58000e8..a6ac227e 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -201,6 +201,10 @@ const api = (() => { return this._invoke('getOrCreateSearchPopup', isObject(details) ? details : {}); } + isTabSearchPopup(tabId) { + return this._invoke('isTabSearchPopup', {tabId}); + } + // Invoke functions with progress deleteDictionary(dictionaryName, onProgress) {