diff options
Diffstat (limited to 'ext/js')
| -rw-r--r-- | ext/js/app/popup-factory.js | 1 | ||||
| -rw-r--r-- | ext/js/background/backend.js | 105 | ||||
| -rw-r--r-- | ext/js/comm/api.js | 4 | ||||
| -rw-r--r-- | ext/js/comm/cross-frame-api.js | 31 | ||||
| -rw-r--r-- | ext/js/core.js | 4 | ||||
| -rw-r--r-- | ext/js/dom/dom-text-scanner.js | 4 | ||||
| -rw-r--r-- | ext/js/dom/sandbox/css-style-applier.js | 4 | ||||
| -rw-r--r-- | ext/js/language/translator.js | 6 | ||||
| -rw-r--r-- | ext/js/yomichan.js | 28 | 
9 files changed, 89 insertions, 98 deletions
| diff --git a/ext/js/app/popup-factory.js b/ext/js/app/popup-factory.js index eeb31a1b..c3c98162 100644 --- a/ext/js/app/popup-factory.js +++ b/ext/js/app/popup-factory.js @@ -71,6 +71,7 @@ class PopupFactory {       * @param {?number} [details.depth] A specific depth value to assign to the popup.       * @param {boolean} [details.popupWindow] Whether or not a separate popup window should be used, rather than an iframe.       * @param {boolean} [details.childrenSupported] Whether or not the popup is able to show child popups. +     * @returns {Popup|PopupWindow|PopupProxy} The new or existing popup.       */      async getOrCreatePopup({          frameId=null, diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index dd233abb..565f4abf 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -139,7 +139,8 @@ class Backend {              ['textHasJapaneseCharacters',    {async: false, contentScript: true,  handler: this._onApiTextHasJapaneseCharacters.bind(this)}],              ['getTermFrequencies',           {async: true,  contentScript: true,  handler: this._onApiGetTermFrequencies.bind(this)}],              ['findAnkiNotes',                {async: true,  contentScript: true,  handler: this._onApiFindAnkiNotes.bind(this)}], -            ['loadExtensionScripts',         {async: true,  contentScript: true,  handler: this._onApiLoadExtensionScripts.bind(this)}] +            ['loadExtensionScripts',         {async: true,  contentScript: true,  handler: this._onApiLoadExtensionScripts.bind(this)}], +            ['openCrossFramePort',           {async: false, contentScript: true,  handler: this._onApiOpenCrossFramePort.bind(this)}]          ]);          this._messageHandlersWithProgress = new Map([          ]); @@ -189,9 +190,6 @@ class Backend {              chrome.tabs.onZoomChange.addListener(onZoomChange);          } -        const onConnect = this._onWebExtensionEventWrapper(this._onConnect.bind(this)); -        chrome.runtime.onConnect.addListener(onConnect); -          const onMessage = this._onMessageWrapper.bind(this);          chrome.runtime.onMessage.addListener(onMessage); @@ -228,8 +226,8 @@ class Backend {                  log.error(e);              } -            const deinflectionReasions = await this._fetchAsset('/data/deinflect.json', true); -            this._translator.prepare(deinflectionReasions); +            const deinflectionReasons = await this._fetchAsset('/data/deinflect.json', true); +            this._translator.prepare(deinflectionReasons);              await this._optionsUtil.prepare();              this._defaultAnkiFieldTemplates = (await this._fetchAsset('/data/templates/default-anki-field-templates.handlebars')).trim(); @@ -331,58 +329,6 @@ class Backend {          return invokeMessageHandler(messageHandler, params, callback, sender);      } -    _onConnect(port) { -        try { -            let details; -            try { -                details = JSON.parse(port.name); -            } catch (e) { -                return; -            } -            if (details.name !== 'background-cross-frame-communication-port') { return; } - -            const senderTabId = (port.sender && port.sender.tab ? port.sender.tab.id : null); -            if (typeof senderTabId !== 'number') { -                throw new Error('Port does not have an associated tab ID'); -            } -            const senderFrameId = port.sender.frameId; -            if (typeof senderFrameId !== 'number') { -                throw new Error('Port does not have an associated frame ID'); -            } -            let {targetTabId, targetFrameId} = details; -            if (typeof targetTabId !== 'number') { -                targetTabId = senderTabId; -            } - -            const details2 = { -                name: 'cross-frame-communication-port', -                sourceTabId: senderTabId, -                sourceFrameId: senderFrameId -            }; -            let forwardPort = chrome.tabs.connect(targetTabId, {frameId: targetFrameId, name: JSON.stringify(details2)}); - -            const cleanup = () => { -                this._checkLastError(chrome.runtime.lastError); -                if (forwardPort !== null) { -                    forwardPort.disconnect(); -                    forwardPort = null; -                } -                if (port !== null) { -                    port.disconnect(); -                    port = null; -                } -            }; - -            port.onMessage.addListener((message) => { forwardPort.postMessage(message); }); -            forwardPort.onMessage.addListener((message) => { port.postMessage(message); }); -            port.onDisconnect.addListener(cleanup); -            forwardPort.onDisconnect.addListener(cleanup); -        } catch (e) { -            port.disconnect(); -            log.error(e); -        } -    } -      _onZoomChange({tabId, oldZoomFactor, newZoomFactor}) {          this._sendMessageTabIgnoreResponse(tabId, {action: 'Yomichan.zoomChanged', params: {oldZoomFactor, newZoomFactor}});      } @@ -2273,4 +2219,47 @@ class Backend {          }          return results;      } + +    _onApiOpenCrossFramePort({targetTabId, targetFrameId}, sender) { +        const sourceTabId = (sender && sender.tab ? sender.tab.id : null); +        if (typeof sourceTabId !== 'number') { +            throw new Error('Port does not have an associated tab ID'); +        } +        const sourceFrameId = sender.frameId; +        if (typeof sourceFrameId !== 'number') { +            throw new Error('Port does not have an associated frame ID'); +        } + +        const sourceDetails = { +            name: 'cross-frame-communication-port', +            otherTabId: targetTabId, +            otherFrameId: targetFrameId +        }; +        const targetDetails = { +            name: 'cross-frame-communication-port', +            otherTabId: sourceTabId, +            otherFrameId: sourceFrameId +        }; +        let sourcePort = chrome.tabs.connect(sourceTabId, {frameId: sourceFrameId, name: JSON.stringify(sourceDetails)}); +        let targetPort = chrome.tabs.connect(targetTabId, {frameId: targetFrameId, name: JSON.stringify(targetDetails)}); + +        const cleanup = () => { +            this._checkLastError(chrome.runtime.lastError); +            if (targetPort !== null) { +                targetPort.disconnect(); +                targetPort = null; +            } +            if (sourcePort !== null) { +                sourcePort.disconnect(); +                sourcePort = null; +            } +        }; + +        sourcePort.onMessage.addListener((message) => { targetPort.postMessage(message); }); +        targetPort.onMessage.addListener((message) => { sourcePort.postMessage(message); }); +        sourcePort.onDisconnect.addListener(cleanup); +        targetPort.onDisconnect.addListener(cleanup); + +        return {targetTabId, targetFrameId}; +    }  } diff --git a/ext/js/comm/api.js b/ext/js/comm/api.js index de12bb6c..72d2ba07 100644 --- a/ext/js/comm/api.js +++ b/ext/js/comm/api.js @@ -181,6 +181,10 @@ class API {          return this._invoke('loadExtensionScripts', {files});      } +    openCrossFramePort(targetTabId, targetFrameId) { +        return this._invoke('openCrossFramePort', {targetTabId, targetFrameId}); +    } +      // Utilities      _createActionPort(timeout=5000) { diff --git a/ext/js/comm/cross-frame-api.js b/ext/js/comm/cross-frame-api.js index 7892eb4c..fb2a1718 100644 --- a/ext/js/comm/cross-frame-api.js +++ b/ext/js/comm/cross-frame-api.js @@ -224,10 +224,13 @@ class CrossFrameAPI {          this._commPorts = new Map();          this._messageHandlers = new Map();          this._onDisconnectBind = this._onDisconnect.bind(this); +        this._tabId = null; +        this._frameId = null;      } -    prepare() { +    async prepare() {          chrome.runtime.onConnect.addListener(this._onConnect.bind(this)); +        ({tabId: this._tabId, frameId: this._frameId} = await yomichan.api.frameInformationGet());      }      invoke(targetFrameId, action, params={}) { @@ -235,8 +238,8 @@ class CrossFrameAPI {      }      async invokeTab(targetTabId, targetFrameId, action, params={}) { -        if (typeof targetTabId !== 'number') { targetTabId = null; } -        const commPort = this._getOrCreateCommPort(targetTabId, targetFrameId); +        if (typeof targetTabId !== 'number') { targetTabId = this._tabId; } +        const commPort = await this._getOrCreateCommPort(targetTabId, targetFrameId);          return await commPort.invoke(action, params, this._ackTimeout, this._responseTimeout);      } @@ -265,8 +268,8 @@ class CrossFrameAPI {              }              if (details.name !== 'cross-frame-communication-port') { return; } -            const otherTabId = details.sourceTabId; -            const otherFrameId = details.sourceFrameId; +            const otherTabId = details.otherTabId; +            const otherFrameId = details.otherFrameId;              this._setupCommPort(otherTabId, otherFrameId, port);          } catch (e) {              port.disconnect(); @@ -297,14 +300,16 @@ class CrossFrameAPI {          return this._createCommPort(otherTabId, otherFrameId);      } -    _createCommPort(otherTabId, otherFrameId) { -        const details = { -            name: 'background-cross-frame-communication-port', -            targetTabId: otherTabId, -            targetFrameId: otherFrameId -        }; -        const port = yomichan.connect(null, {name: JSON.stringify(details)}); -        return this._setupCommPort(otherTabId, otherFrameId, port); +    async _createCommPort(otherTabId, otherFrameId) { +        await yomichan.api.openCrossFramePort(otherTabId, otherFrameId); + +        const tabPorts = this._commPorts.get(otherTabId); +        if (typeof tabPorts !== 'undefined') { +            const commPort = tabPorts.get(otherFrameId); +            if (typeof commPort !== 'undefined') { +                return commPort; +            } +        }      }      _setupCommPort(otherTabId, otherFrameId, port) { diff --git a/ext/js/core.js b/ext/js/core.js index 5b064a36..1e749c7d 100644 --- a/ext/js/core.js +++ b/ext/js/core.js @@ -309,7 +309,7 @@ function promiseTimeout(delay, resolveValue) {   * Creates a promise that will resolve after the next animation frame, using `requestAnimationFrame`.   * @param {number} [timeout] A maximum duration (in milliseconds) to wait until the promise resolves. If null or omitted, no timeout is used.   * @returns {Promise<{time: number, timeout: number}>} A promise that is resolved with `{time, timeout}`, where `time` is the timestamp from `requestAnimationFrame`, - *  and `timeout` is a boolean indicating whether the cause was a timeout or not. + *   and `timeout` is a boolean indicating whether the cause was a timeout or not.   * @throws The promise throws an error if animation is not supported in this context, such as in a service worker.   */  function promiseAnimationFrame(timeout=null) { @@ -609,7 +609,7 @@ class DynamicProperty extends EventDispatcher {       * @param {*} value The override value to assign.       * @param {number} [priority] The priority value to use, as a number.       * @returns {string} A string token which can be passed to the clearOverride function -     *  to remove the override. +     *   to remove the override.       */      setOverride(value, priority=0) {          const overridesCount = this._overrides.length; diff --git a/ext/js/dom/dom-text-scanner.js b/ext/js/dom/dom-text-scanner.js index dc5bd96a..ec4c7bd6 100644 --- a/ext/js/dom/dom-text-scanner.js +++ b/ext/js/dom/dom-text-scanner.js @@ -405,8 +405,8 @@ class DOMTextScanner {       * @returns {{enterable: boolean, newlines: number}} The seek information.       *   The `enterable` value indicates whether the content of this node should be entered.       *   The `newlines` value corresponds to the number of newline characters that should be added. -     *     1 newline corresponds to a simple new line in the layout. -     *     2 newlines corresponds to a significant visual distinction since the previous content. +     *   - 1 newline corresponds to a simple new line in the layout. +     *   - 2 newlines corresponds to a significant visual distinction since the previous content.       */      static getElementSeekInfo(element) {          let enterable = true; diff --git a/ext/js/dom/sandbox/css-style-applier.js b/ext/js/dom/sandbox/css-style-applier.js index 01936d26..a47ef6ef 100644 --- a/ext/js/dom/sandbox/css-style-applier.js +++ b/ext/js/dom/sandbox/css-style-applier.js @@ -35,9 +35,10 @@ class CssStyleApplier {       * @property {string} value The property's value.       */ +    /* eslint-disable jsdoc/check-line-alignment */      /**       * Creates a new instance of the class. -     * @param {string} styleDataUrl The local URL to the JSON file continaing the style rules. +     * @param {string} styleDataUrl The local URL to the JSON file containing the style rules.       *   The style rules should be of the format:       *   ```       *   [ @@ -57,6 +58,7 @@ class CssStyleApplier {          this._patternHtmlWhitespace = /[\t\r\n\f ]+/g;          this._patternClassNameCharacter = /[0-9a-zA-Z-_]/;      } +    /* eslint-enable jsdoc/check-line-alignment */      /**       * Loads the data file for use. diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index edb38bfb..3b47cc51 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -93,6 +93,12 @@ class Translator {          }          if (mode === 'simple') { +            if (sortFrequencyDictionary !== null) { +                const sortDictionaryMap = [sortFrequencyDictionary] +                    .filter((key) => enabledDictionaryMap.has(key)) +                    .reduce((subMap, key) => subMap.set(key, enabledDictionaryMap.get(key)), new Map()); +                await this._addTermMeta(dictionaryEntries, sortDictionaryMap); +            }              this._clearTermTags(dictionaryEntries);          } else {              await this._addTermMeta(dictionaryEntries, enabledDictionaryMap); diff --git a/ext/js/yomichan.js b/ext/js/yomichan.js index 6eea952e..a4feaa23 100644 --- a/ext/js/yomichan.js +++ b/ext/js/yomichan.js @@ -129,12 +129,12 @@ class Yomichan extends EventDispatcher {          if (!isBackground) {              this._api = new API(this); -            this._crossFrame = new CrossFrameAPI(); -            this._crossFrame.prepare(); -              this.sendMessage({action: 'requestBackendReadySignal'});              await this._isBackendReadyPromise; +            this._crossFrame = new CrossFrameAPI(); +            await this._crossFrame.prepare(); +              log.on('log', this._onForwardLog.bind(this));          }      } @@ -172,24 +172,6 @@ class Yomichan extends EventDispatcher {          }      } -    /** -     * Runs `chrome.runtime.connect()` with additional exception handling events. -     * @param {...*} args The arguments to be passed to `chrome.runtime.connect()`. -     * @returns {Port} The resulting port. -     * @throws {Error} Errors thrown by `chrome.runtime.connect()` are re-thrown. -     */ -    connect(...args) { -        try { -            return chrome.runtime.connect(...args); -        } catch (e) { -            this.triggerExtensionUnloaded(); -            throw e; -        } -    } - -    /** -     * Runs chrome.runtime.connect() with additional exception handling events. -     */      triggerExtensionUnloaded() {          this._isExtensionUnloaded = true;          if (this._isTriggeringExtensionUnloaded) { return; } @@ -232,7 +214,9 @@ class Yomichan extends EventDispatcher {      }      _onMessageOptionsUpdated({source}) { -        this.trigger('optionsUpdated', {source}); +        if (source !== 'background') { +            this.trigger('optionsUpdated', {source}); +        }      }      _onMessageDatabaseUpdated({type, cause}) { |