aboutsummaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/app/popup-factory.js1
-rw-r--r--ext/js/background/backend.js105
-rw-r--r--ext/js/comm/api.js4
-rw-r--r--ext/js/comm/cross-frame-api.js31
-rw-r--r--ext/js/core.js4
-rw-r--r--ext/js/dom/dom-text-scanner.js4
-rw-r--r--ext/js/dom/sandbox/css-style-applier.js4
-rw-r--r--ext/js/language/translator.js6
-rw-r--r--ext/js/yomichan.js28
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}) {