From f63220b6c501b1a2697e75ba407adb21dbb980b9 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 9 Dec 2019 21:41:24 -0500 Subject: [PATCH] Move apiCommandExec implementation into Backend --- ext/bg/js/api.js | 134 +--------------------------------------- ext/bg/js/backend.js | 143 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 134 deletions(-) diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index f4818854..1c3ad110 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -65,58 +65,9 @@ function apiTemplateRender(template, data, dynamic) { return utilBackend()._onApiTemplateRender({template, data, dynamic}); } -async function apiCommandExec(command, params) { - const handlers = apiCommandExec.handlers; - if (hasOwn(handlers, command)) { - const handler = handlers[command]; - handler(params); - } +function apiCommandExec(command, params) { + return utilBackend()._onApiCommandExec({command, params}); } -apiCommandExec.handlers = { - search: async (params) => { - const url = chrome.runtime.getURL('/bg/search.html'); - if (!(params && params.newTab)) { - try { - const tab = await _apiFindTab(1000, (url2) => ( - url2 !== null && - url2.startsWith(url) && - (url2.length === url.length || url2[url.length] === '?' || url2[url.length] === '#') - )); - if (tab !== null) { - await _apiFocusTab(tab); - return; - } - } catch (e) { - // NOP - } - } - chrome.tabs.create({url}); - }, - - help: () => { - chrome.tabs.create({url: 'https://foosoft.net/projects/yomichan/'}); - }, - - options: (params) => { - if (!(params && params.newTab)) { - chrome.runtime.openOptionsPage(); - } else { - const manifest = chrome.runtime.getManifest(); - const url = chrome.runtime.getURL(manifest.options_ui.page); - chrome.tabs.create({url}); - } - }, - - toggle: async () => { - const optionsContext = { - depth: 0, - url: window.location.href - }; - const options = await apiOptionsGet(optionsContext); - options.general.enable = !options.general.enable; - await apiOptionsSave('popup'); - } -}; async function apiAudioGetUrl(definition, source, optionsContext) { return audioGetUrl(definition, source, optionsContext); @@ -208,87 +159,6 @@ async function _apiGetBrowser() { } } -function _apiGetTabUrl(tab) { - return new Promise((resolve) => { - chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => { - let url = null; - if (!chrome.runtime.lastError) { - url = (response !== null && typeof response === 'object' && !Array.isArray(response) ? response.url : null); - if (url !== null && typeof url !== 'string') { - url = null; - } - } - resolve({tab, url}); - }); - }); -} - -async function _apiFindTab(timeout, checkUrl) { - // This function works around the need to have the "tabs" permission to access tab.url. - const tabs = await new Promise((resolve) => chrome.tabs.query({}, resolve)); - let matchPromiseResolve = null; - const matchPromise = new Promise((resolve) => { matchPromiseResolve = resolve; }); - - const checkTabUrl = ({tab, url}) => { - if (checkUrl(url, tab)) { - matchPromiseResolve(tab); - } - }; - - const promises = []; - for (const tab of tabs) { - const promise = _apiGetTabUrl(tab); - promise.then(checkTabUrl); - promises.push(promise); - } - - const racePromises = [ - matchPromise, - Promise.all(promises).then(() => null) - ]; - if (typeof timeout === 'number') { - racePromises.push(new Promise((resolve) => setTimeout(() => resolve(null), timeout))); - } - - return await Promise.race(racePromises); -} - -async function _apiFocusTab(tab) { - await new Promise((resolve, reject) => { - chrome.tabs.update(tab.id, {active: true}, () => { - const e = chrome.runtime.lastError; - if (e) { reject(e); } - else { resolve(); } - }); - }); - - if (!(typeof chrome.windows === 'object' && chrome.windows !== null)) { - // Windows not supported (e.g. on Firefox mobile) - return; - } - - try { - const tabWindow = await new Promise((resolve) => { - chrome.windows.get(tab.windowId, {}, (tabWindow) => { - const e = chrome.runtime.lastError; - if (e) { reject(e); } - else { resolve(tabWindow); } - }); - }); - if (!tabWindow.focused) { - await new Promise((resolve, reject) => { - chrome.windows.update(tab.windowId, {focused: true}, () => { - const e = chrome.runtime.lastError; - if (e) { reject(e); } - else { resolve(); } - }); - }); - } - } catch (e) { - // Edge throws exception for no reason here. - } -} - async function apiClipboardGet() { const clipboardPasteTarget = utilBackend().clipboardPasteTarget; clipboardPasteTarget.innerText = ''; diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 38dbd0f1..8ae5574c 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -397,8 +397,11 @@ class Backend { ); } - _onApiCommandExec({command, params}) { - return apiCommandExec(command, params); + async _onApiCommandExec({command, params}) { + const handler = Backend._commandHandlers.get(command); + if (typeof handler !== 'function') { return false; } + + handler(this, params); } _onApiAudioGetUrl({definition, source, optionsContext}) { @@ -429,6 +432,54 @@ class Backend { return apiClipboardGet(); } + // Command handlers + + async _onCommandSearch(params) { + const url = chrome.runtime.getURL('/bg/search.html'); + if (!(params && params.newTab)) { + try { + const tab = await Backend._findTab(1000, (url2) => ( + url2 !== null && + url2.startsWith(url) && + (url2.length === url.length || url2[url.length] === '?' || url2[url.length] === '#') + )); + if (tab !== null) { + await Backend._focusTab(tab); + return; + } + } catch (e) { + // NOP + } + } + chrome.tabs.create({url}); + } + + _onCommandHelp() { + chrome.tabs.create({url: 'https://foosoft.net/projects/yomichan/'}); + } + + _onCommandOptions(params) { + if (!(params && params.newTab)) { + chrome.runtime.openOptionsPage(); + } else { + const manifest = chrome.runtime.getManifest(); + const url = chrome.runtime.getURL(manifest.options_ui.page); + chrome.tabs.create({url}); + } + } + + async _onCommandToggle() { + const optionsContext = { + depth: 0, + url: window.location.href + }; + const source = 'popup'; + + const options = await this.getOptions(optionsContext); + options.general.enable = !options.general.enable; + await this._optionsSave({source}); + } + // Utilities async _injectScreenshot(definition, fields, screenshot) { @@ -466,6 +517,87 @@ class Backend { definition.screenshotFileName = filename; } + + static _getTabUrl(tab) { + return new Promise((resolve) => { + chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => { + let url = null; + if (!chrome.runtime.lastError) { + url = (response !== null && typeof response === 'object' && !Array.isArray(response) ? response.url : null); + if (url !== null && typeof url !== 'string') { + url = null; + } + } + resolve({tab, url}); + }); + }); + } + + static async _findTab(timeout, checkUrl) { + // This function works around the need to have the "tabs" permission to access tab.url. + const tabs = await new Promise((resolve) => chrome.tabs.query({}, resolve)); + let matchPromiseResolve = null; + const matchPromise = new Promise((resolve) => { matchPromiseResolve = resolve; }); + + const checkTabUrl = ({tab, url}) => { + if (checkUrl(url, tab)) { + matchPromiseResolve(tab); + } + }; + + const promises = []; + for (const tab of tabs) { + const promise = Backend._getTabUrl(tab); + promise.then(checkTabUrl); + promises.push(promise); + } + + const racePromises = [ + matchPromise, + Promise.all(promises).then(() => null) + ]; + if (typeof timeout === 'number') { + racePromises.push(new Promise((resolve) => setTimeout(() => resolve(null), timeout))); + } + + return await Promise.race(racePromises); + } + + static async _focusTab(tab) { + await new Promise((resolve, reject) => { + chrome.tabs.update(tab.id, {active: true}, () => { + const e = chrome.runtime.lastError; + if (e) { reject(e); } + else { resolve(); } + }); + }); + + if (!(typeof chrome.windows === 'object' && chrome.windows !== null)) { + // Windows not supported (e.g. on Firefox mobile) + return; + } + + try { + const tabWindow = await new Promise((resolve) => { + chrome.windows.get(tab.windowId, {}, (tabWindow) => { + const e = chrome.runtime.lastError; + if (e) { reject(e); } + else { resolve(tabWindow); } + }); + }); + if (!tabWindow.focused) { + await new Promise((resolve, reject) => { + chrome.windows.update(tab.windowId, {focused: true}, () => { + const e = chrome.runtime.lastError; + if (e) { reject(e); } + else { resolve(); } + }); + }); + } + } catch (e) { + // Edge throws exception for no reason here. + } + } } Backend._messageHandlers = new Map([ @@ -491,5 +623,12 @@ Backend._messageHandlers = new Map([ ['clipboardGet', (self, ...args) => self._onApiClipboardGet(...args)] ]); +Backend._commandHandlers = new Map([ + ['search', (self, ...args) => self._onCommandSearch(...args)], + ['help', (self, ...args) => self._onCommandHelp(...args)], + ['options', (self, ...args) => self._onCommandOptions(...args)], + ['toggle', (self, ...args) => self._onCommandToggle(...args)] +]); + window.yomichan_backend = new Backend(); window.yomichan_backend.prepare();