diff options
Diffstat (limited to 'ext/mixed/js/yomichan.js')
-rw-r--r-- | ext/mixed/js/yomichan.js | 306 |
1 files changed, 0 insertions, 306 deletions
diff --git a/ext/mixed/js/yomichan.js b/ext/mixed/js/yomichan.js deleted file mode 100644 index 61301e30..00000000 --- a/ext/mixed/js/yomichan.js +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2020-2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -// Set up chrome alias if it's not available (Edge Legacy) -if ((() => { - let hasChrome = false; - let hasBrowser = false; - try { - hasChrome = (typeof chrome === 'object' && chrome !== null && typeof chrome.runtime !== 'undefined'); - } catch (e) { - // NOP - } - try { - hasBrowser = (typeof browser === 'object' && browser !== null && typeof browser.runtime !== 'undefined'); - } catch (e) { - // NOP - } - return (hasBrowser && !hasChrome); -})()) { - chrome = browser; -} - -const yomichan = (() => { - class Yomichan extends EventDispatcher { - constructor() { - super(); - - this._extensionName = 'Yomichan'; - try { - const manifest = chrome.runtime.getManifest(); - this._extensionName = `${manifest.name} v${manifest.version}`; - } catch (e) { - // NOP - } - - this._isExtensionUnloaded = false; - this._isTriggeringExtensionUnloaded = false; - this._isReady = false; - - const {promise, resolve} = deferPromise(); - this._isBackendReadyPromise = promise; - this._isBackendReadyPromiseResolve = resolve; - - this._messageHandlers = new Map([ - ['isReady', {async: false, handler: this._onMessageIsReady.bind(this)}], - ['backendReady', {async: false, handler: this._onMessageBackendReady.bind(this)}], - ['getUrl', {async: false, handler: this._onMessageGetUrl.bind(this)}], - ['optionsUpdated', {async: false, handler: this._onMessageOptionsUpdated.bind(this)}], - ['databaseUpdated', {async: false, handler: this._onMessageDatabaseUpdated.bind(this)}], - ['zoomChanged', {async: false, handler: this._onMessageZoomChanged.bind(this)}] - ]); - } - - // Public - - get isExtensionUnloaded() { - return this._isExtensionUnloaded; - } - - prepare() { - chrome.runtime.onMessage.addListener(this._onMessage.bind(this)); - } - - backendReady() { - this.sendMessage({action: 'requestBackendReadySignal'}); - return this._isBackendReadyPromise; - } - - ready() { - this._isReady = true; - this.sendMessage({action: 'yomichanReady'}); - } - - isExtensionUrl(url) { - try { - return url.startsWith(chrome.runtime.getURL('/')); - } catch (e) { - return false; - } - } - - getTemporaryListenerResult(eventHandler, userCallback, timeout=null) { - if (!( - typeof eventHandler.addListener === 'function' && - typeof eventHandler.removeListener === 'function' - )) { - throw new Error('Event handler type not supported'); - } - - return new Promise((resolve, reject) => { - const runtimeMessageCallback = ({action, params}, sender, sendResponse) => { - let timeoutId = null; - if (timeout !== null) { - timeoutId = setTimeout(() => { - timeoutId = null; - eventHandler.removeListener(runtimeMessageCallback); - reject(new Error(`Listener timed out in ${timeout} ms`)); - }, timeout); - } - - const cleanupResolve = (value) => { - if (timeoutId !== null) { - clearTimeout(timeoutId); - timeoutId = null; - } - eventHandler.removeListener(runtimeMessageCallback); - sendResponse(); - resolve(value); - }; - - userCallback({action, params}, {resolve: cleanupResolve, sender}); - }; - - eventHandler.addListener(runtimeMessageCallback); - }); - } - - logWarning(error) { - this.log(error, 'warn'); - } - - logError(error) { - this.log(error, 'error'); - } - - log(error, level, context=null) { - if (!isObject(context)) { - context = this._getLogContext(); - } - - let errorString; - try { - errorString = error.toString(); - if (/^\[object \w+\]$/.test(errorString)) { - errorString = JSON.stringify(error); - } - } catch (e) { - errorString = `${error}`; - } - - let errorStack; - try { - errorStack = (typeof error.stack === 'string' ? error.stack.trimRight() : ''); - } catch (e) { - errorStack = ''; - } - - let errorData; - try { - errorData = error.data; - } catch (e) { - // NOP - } - - if (errorStack.startsWith(errorString)) { - errorString = errorStack; - } else if (errorStack.length > 0) { - errorString += `\n${errorStack}`; - } - - let message = `${this._extensionName} has encountered a problem.`; - message += `\nOriginating URL: ${context.url}\n`; - message += errorString; - if (typeof errorData !== 'undefined') { - message += `\nData: ${JSON.stringify(errorData, null, 4)}`; - } - message += '\n\nIssues can be reported at https://github.com/FooSoft/yomichan/issues'; - - switch (level) { - case 'info': console.info(message); break; - case 'debug': console.debug(message); break; - case 'warn': console.warn(message); break; - case 'error': console.error(message); break; - default: console.log(message); break; - } - - this.trigger('log', {error, level, context}); - } - - sendMessage(...args) { - try { - return chrome.runtime.sendMessage(...args); - } catch (e) { - this.triggerExtensionUnloaded(); - throw e; - } - } - - connect(...args) { - try { - return chrome.runtime.connect(...args); - } catch (e) { - this.triggerExtensionUnloaded(); - throw e; - } - } - - getMessageResponseResult(response) { - let error = chrome.runtime.lastError; - if (error) { - throw new Error(error.message); - } - if (!isObject(response)) { - throw new Error('Tab did not respond'); - } - error = response.error; - if (error) { - throw deserializeError(error); - } - return response.result; - } - - invokeMessageHandler({handler, async}, params, callback, ...extraArgs) { - try { - let promiseOrResult = handler(params, ...extraArgs); - if (async === 'dynamic') { - ({async, result: promiseOrResult} = promiseOrResult); - } - if (async) { - promiseOrResult.then( - (result) => { callback({result}); }, - (error) => { callback({error: serializeError(error)}); } - ); - return true; - } else { - callback({result: promiseOrResult}); - return false; - } - } catch (error) { - callback({error: serializeError(error)}); - return false; - } - } - - triggerExtensionUnloaded() { - this._isExtensionUnloaded = true; - if (this._isTriggeringExtensionUnloaded) { return; } - try { - this._isTriggeringExtensionUnloaded = true; - this.trigger('extensionUnloaded'); - } finally { - this._isTriggeringExtensionUnloaded = false; - } - } - - // Private - - _getUrl() { - return location.href; - } - - _getLogContext() { - return {url: this._getUrl()}; - } - - _onMessage({action, params}, sender, callback) { - const messageHandler = this._messageHandlers.get(action); - if (typeof messageHandler === 'undefined') { return false; } - return this.invokeMessageHandler(messageHandler, params, callback, sender); - } - - _onMessageIsReady() { - return this._isReady; - } - - _onMessageBackendReady() { - if (this._isBackendReadyPromiseResolve === null) { return; } - this._isBackendReadyPromiseResolve(); - this._isBackendReadyPromiseResolve = null; - } - - _onMessageGetUrl() { - return {url: this._getUrl()}; - } - - _onMessageOptionsUpdated({source}) { - this.trigger('optionsUpdated', {source}); - } - - _onMessageDatabaseUpdated({type, cause}) { - this.trigger('databaseUpdated', {type, cause}); - } - - _onMessageZoomChanged({oldZoomFactor, newZoomFactor}) { - this.trigger('zoomChanged', {oldZoomFactor, newZoomFactor}); - } - } - - return new Yomichan(); -})(); - -yomichan.prepare(); |