summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2019-08-18 20:51:19 -0400
committertoasted-nutbread <toasted-nutbread@users.noreply.github.com>2019-09-02 19:33:28 -0400
commit53aad0bef68bf6930b684fda4a25e1a045cd800e (patch)
tree4e91dd4f3e6bac8ceefd7ecb321d15c024459f3f
parent42ec3e2a43dfd9ac0748ca7c364cef2b44f625a2 (diff)
Fix messaging issues when iframes are present in the document
-rw-r--r--ext/bg/js/api.js5
-rw-r--r--ext/bg/js/backend.js4
-rw-r--r--ext/bg/js/search-frontend.js2
-rw-r--r--ext/fg/js/api.js4
-rw-r--r--ext/fg/js/frontend-api-receiver.js16
-rw-r--r--ext/fg/js/frontend-api-sender.js8
-rw-r--r--ext/fg/js/frontend.js10
-rw-r--r--ext/fg/js/popup-proxy-host.js21
-rw-r--r--ext/fg/js/popup-proxy.js9
-rw-r--r--ext/fg/js/popup.js55
-rw-r--r--ext/manifest.json2
11 files changed, 97 insertions, 39 deletions
diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js
index 4b2bacd7..b8ef4362 100644
--- a/ext/bg/js/api.js
+++ b/ext/bg/js/api.js
@@ -205,3 +205,8 @@ function apiForward(action, params, sender) {
chrome.tabs.sendMessage(tabId, {action, params}, (response) => resolve(response));
});
}
+
+function apiFrameInformationGet(sender) {
+ const frameId = sender.frameId;
+ return Promise.resolve({frameId});
+}
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js
index 8f99c13a..39fd4288 100644
--- a/ext/bg/js/backend.js
+++ b/ext/bg/js/backend.js
@@ -127,6 +127,10 @@ class Backend {
forward: ({action, params}) => {
forward(apiForward(action, params, sender), callback);
+ },
+
+ frameInformationGet: () => {
+ forward(apiFrameInformationGet(sender), callback);
}
};
diff --git a/ext/bg/js/search-frontend.js b/ext/bg/js/search-frontend.js
index 77aa4052..840a1ea8 100644
--- a/ext/bg/js/search-frontend.js
+++ b/ext/bg/js/search-frontend.js
@@ -25,8 +25,8 @@ async function searchFrontendSetup() {
'/fg/js/api.js',
'/fg/js/frontend-api-receiver.js',
'/fg/js/popup.js',
- '/fg/js/popup-proxy-host.js',
'/fg/js/util.js',
+ '/fg/js/popup-proxy-host.js',
'/fg/js/frontend.js'
];
for (const src of scriptSrcs) {
diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js
index 99ad307c..6bcb0dbb 100644
--- a/ext/fg/js/api.js
+++ b/ext/fg/js/api.js
@@ -64,3 +64,7 @@ function apiScreenshotGet(options) {
function apiForward(action, params) {
return utilInvoke('forward', {action, params});
}
+
+function apiFrameInformationGet() {
+ return utilInvoke('frameInformationGet');
+}
diff --git a/ext/fg/js/frontend-api-receiver.js b/ext/fg/js/frontend-api-receiver.js
index f5d29f67..687e5c3c 100644
--- a/ext/fg/js/frontend-api-receiver.js
+++ b/ext/fg/js/frontend-api-receiver.js
@@ -31,7 +31,7 @@ class FrontendApiReceiver {
port.onMessage.addListener(this.onMessage.bind(this, port));
}
- onMessage(port, {id, action, params, target}) {
+ onMessage(port, {id, action, params, target, senderId}) {
if (
target !== this.source ||
!this.handlers.hasOwnProperty(action)
@@ -39,24 +39,24 @@ class FrontendApiReceiver {
return;
}
- this.sendAck(port, id);
+ this.sendAck(port, id, senderId);
const handler = this.handlers[action];
handler(params).then(
result => {
- this.sendResult(port, id, {result});
+ this.sendResult(port, id, senderId, {result});
},
e => {
const error = typeof e.toString === 'function' ? e.toString() : e;
- this.sendResult(port, id, {error});
+ this.sendResult(port, id, senderId, {error});
});
}
- sendAck(port, id) {
- port.postMessage({type: 'ack', id});
+ sendAck(port, id, senderId) {
+ port.postMessage({type: 'ack', id, senderId});
}
- sendResult(port, id, data) {
- port.postMessage({type: 'result', id, data});
+ sendResult(port, id, senderId, data) {
+ port.postMessage({type: 'result', id, senderId, data});
}
}
diff --git a/ext/fg/js/frontend-api-sender.js b/ext/fg/js/frontend-api-sender.js
index e2becb90..a1cb02c4 100644
--- a/ext/fg/js/frontend-api-sender.js
+++ b/ext/fg/js/frontend-api-sender.js
@@ -19,6 +19,7 @@
class FrontendApiSender {
constructor() {
+ this.senderId = FrontendApiSender.generateId(16);
this.ackTimeout = 3000; // 3 seconds
this.responseTimeout = 10000; // 10 seconds
this.callbacks = {};
@@ -43,11 +44,12 @@ class FrontendApiSender {
this.callbacks[id] = info;
info.timer = setTimeout(() => this.onError(id, 'Timeout (ack)'), this.ackTimeout);
- this.port.postMessage({id, action, params, target});
+ this.port.postMessage({id, action, params, target, senderId: this.senderId});
});
}
- onMessage({type, id, data}) {
+ onMessage({type, id, data, senderId}) {
+ if (senderId !== this.senderId) { return; }
switch (type) {
case 'ack':
this.onAck(id);
@@ -69,7 +71,7 @@ class FrontendApiSender {
onAck(id) {
if (!this.callbacks.hasOwnProperty(id)) {
- console.warn(`ID ${id} not found`);
+ console.warn(`ID ${id} not found for ack`);
return;
}
diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js
index d378dd61..9c511d8a 100644
--- a/ext/fg/js/frontend.js
+++ b/ext/fg/js/frontend.js
@@ -42,14 +42,20 @@ class Frontend {
const isNested = (currentUrl === floatUrl);
let id = null;
+ let parentFrameId = null;
if (isNested) {
- const match = /[&?]id=([^&]*?)(?:&|$)/.exec(location.href);
+ let match = /[&?]id=([^&]*?)(?:&|$)/.exec(location.href);
if (match !== null) {
id = match[1];
}
+
+ match = /[&?]parent=(\d+)(?:&|$)/.exec(location.href);
+ if (match !== null) {
+ parentFrameId = parseInt(match[1], 10);
+ }
}
- const popup = isNested ? new PopupProxy(id) : PopupProxyHost.instance.createPopup();
+ const popup = isNested ? new PopupProxy(id, parentFrameId) : PopupProxyHost.instance.createPopup(null);
const frontend = new Frontend(popup);
frontend.prepare();
return frontend;
diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js
index ba3db832..cdd1d02c 100644
--- a/ext/fg/js/popup-proxy-host.js
+++ b/ext/fg/js/popup-proxy-host.js
@@ -21,7 +21,22 @@ class PopupProxyHost {
constructor() {
this.popups = {};
this.nextId = 0;
- this.apiReceiver = new FrontendApiReceiver('popup-proxy-host', {
+ this.apiReceiver = null;
+ this.frameIdPromise = null;
+ }
+
+ static create() {
+ const popupProxyHost = new PopupProxyHost();
+ popupProxyHost.prepare();
+ return popupProxyHost;
+ }
+
+ async prepare() {
+ this.frameIdPromise = apiFrameInformationGet();
+ const {frameId} = await this.frameIdPromise;
+ if (typeof frameId !== 'number') { return; }
+
+ this.apiReceiver = new FrontendApiReceiver(`popup-proxy-host#${frameId}`, {
createNestedPopup: ({parentId}) => this.createNestedPopup(parentId),
show: ({id, elementRect, options}) => this.show(id, elementRect, options),
showOrphaned: ({id, elementRect, options}) => this.show(id, elementRect, options),
@@ -39,7 +54,7 @@ class PopupProxyHost {
const depth = (parent !== null ? parent.depth + 1 : 0);
const id = `${this.nextId}`;
++this.nextId;
- const popup = new Popup(id, depth);
+ const popup = new Popup(id, depth, this.frameIdPromise);
if (parent !== null) {
popup.parent = parent;
parent.children.push(popup);
@@ -116,4 +131,4 @@ class PopupProxyHost {
}
}
-PopupProxyHost.instance = new PopupProxyHost();
+PopupProxyHost.instance = PopupProxyHost.create();
diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js
index 3a15be7d..bbf6a2cf 100644
--- a/ext/fg/js/popup-proxy.js
+++ b/ext/fg/js/popup-proxy.js
@@ -18,12 +18,14 @@
class PopupProxy {
- constructor(parentId) {
+ constructor(parentId, parentFrameId) {
this.parentId = parentId;
+ this.parentFrameId = parentFrameId;
this.id = null;
this.idPromise = null;
this.parent = null;
this.children = [];
+ this.depth = 0;
this.container = null;
@@ -102,7 +104,10 @@ class PopupProxy {
}
invokeHostApi(action, params={}) {
- return this.apiSender.invoke(action, params, 'popup-proxy-host');
+ if (typeof this.parentFrameId !== 'number') {
+ return Promise.reject('Invalid frame');
+ }
+ return this.apiSender.invoke(action, params, `popup-proxy-host#${this.parentFrameId}`);
}
static DOMRectToJson(domRect) {
diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js
index 00dfeb89..24b5684d 100644
--- a/ext/fg/js/popup.js
+++ b/ext/fg/js/popup.js
@@ -18,38 +18,55 @@
class Popup {
- constructor(id, depth) {
+ constructor(id, depth, frameIdPromise) {
this.id = id;
this.depth = depth;
+ this.frameIdPromise = frameIdPromise;
+ this.frameId = null;
this.parent = null;
this.children = [];
this.container = document.createElement('iframe');
this.container.id = 'yomichan-float';
this.container.addEventListener('mousedown', e => e.stopPropagation());
this.container.addEventListener('scroll', e => e.stopPropagation());
- this.container.setAttribute('src', chrome.extension.getURL(`/fg/float.html?id=${id}&depth=${depth}`));
this.container.style.width = '0px';
this.container.style.height = '0px';
- this.injected = null;
+ this.injectPromise = null;
+ this.isInjected = false;
}
inject(options) {
- if (!this.injected) {
- this.injected = new Promise((resolve, reject) => {
- this.container.addEventListener('load', () => {
- this.invokeApi('setOptions', {
- general: {
- customPopupCss: options.general.customPopupCss
- }
- });
- resolve();
- });
- this.observeFullscreen();
- this.onFullscreenChanged();
- });
+ if (this.injectPromise === null) {
+ this.injectPromise = this.createInjectPromise(options);
+ }
+ return this.injectPromise;
+ }
+
+ async createInjectPromise(options) {
+ try {
+ const {frameId} = await this.frameIdPromise;
+ if (typeof frameId === 'number') {
+ this.frameId = frameId;
+ }
+ } catch (e) {
+ // NOP
}
- return this.injected;
+ return new Promise((resolve) => {
+ const parent = (typeof this.frameId === 'number' ? this.frameId : '');
+ this.container.setAttribute('src', chrome.extension.getURL(`/fg/float.html?id=${this.id}&depth=${this.depth}&parent=${parent}`));
+ this.container.addEventListener('load', () => {
+ this.invokeApi('setOptions', {
+ general: {
+ customPopupCss: options.general.customPopupCss
+ }
+ });
+ resolve();
+ });
+ this.observeFullscreen();
+ this.onFullscreenChanged();
+ this.isInjected = true;
+ });
}
async show(elementRect, writingMode, options) {
@@ -215,7 +232,7 @@ class Popup {
}
isVisible() {
- return this.injected && this.container.style.visibility !== 'hidden';
+ return this.isInjected && this.container.style.visibility !== 'hidden';
}
setVisible(visible) {
@@ -260,7 +277,7 @@ class Popup {
}
clearAutoPlayTimer() {
- if (this.injected) {
+ if (this.isInjected) {
this.invokeApi('clearAutoPlayTimer');
}
}
diff --git a/ext/manifest.json b/ext/manifest.json
index eed6e40a..06d13dd1 100644
--- a/ext/manifest.json
+++ b/ext/manifest.json
@@ -23,9 +23,9 @@
"fg/js/document.js",
"fg/js/frontend-api-receiver.js",
"fg/js/popup.js",
- "fg/js/popup-proxy-host.js",
"fg/js/source.js",
"fg/js/util.js",
+ "fg/js/popup-proxy-host.js",
"fg/js/frontend.js"
],
"css": ["fg/css/client.css"],