summaryrefslogtreecommitdiff
path: root/ext/fg/js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/fg/js')
-rw-r--r--ext/fg/js/float.js25
-rw-r--r--ext/fg/js/frontend.js76
-rw-r--r--ext/fg/js/popup-proxy.js14
-rw-r--r--ext/fg/js/popup.js32
4 files changed, 106 insertions, 41 deletions
diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js
index 61d42fb3..690d1b9e 100644
--- a/ext/fg/js/float.js
+++ b/ext/fg/js/float.js
@@ -31,7 +31,7 @@ class DisplayFloat extends Display {
this._nestedPopupsPrepared = false;
this._ownerFrameId = null;
this._frameEndpoint = new FrameEndpoint();
- this._windowMessageHandlers = new Map([
+ this._messageHandlers = new Map([
['configure', {async: true, handler: this._onMessageConfigure.bind(this)}],
['setOptionsContext', {async: false, handler: this._onMessageSetOptionsContext.bind(this)}],
['setContent', {async: false, handler: this._onMessageSetContent.bind(this)}],
@@ -39,6 +39,9 @@ class DisplayFloat extends Display {
['setCustomCss', {async: false, handler: this._onMessageSetCustomCss.bind(this)}],
['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}]
]);
+ this._windowMessageHandlers = new Map([
+ ['extensionUnloaded', {async: false, handler: this._onMessageExtensionUnloaded.bind(this)}]
+ ]);
this.registerActions([
['copy-host-selection', () => this._copySelection()]
@@ -54,6 +57,7 @@ class DisplayFloat extends Display {
api.crossFrame.registerHandlers([
['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}]
]);
+ window.addEventListener('message', this._onWindowMessage.bind(this), false);
this._frameEndpoint.signal();
}
@@ -107,7 +111,7 @@ class DisplayFloat extends Display {
}
const {action, params} = data.data;
- const handlerInfo = this._windowMessageHandlers.get(action);
+ const handlerInfo = this._messageHandlers.get(action);
if (typeof handlerInfo === 'undefined') {
throw new Error(`Invalid action: ${action}`);
}
@@ -117,6 +121,18 @@ class DisplayFloat extends Display {
return {async, result};
}
+ _onWindowMessage(e) {
+ const data = e.data;
+ if (!this._frameEndpoint.authenticate(data)) { return; }
+
+ const {action, params} = data.data;
+ const messageHandler = this._windowMessageHandlers.get(action);
+ if (typeof messageHandler === 'undefined') { return; }
+
+ const callback = () => {}; // NOP
+ yomichan.invokeMessageHandler(messageHandler, params, callback);
+ }
+
async _onMessageConfigure({frameId, ownerFrameId, popupId, optionsContext, childrenSupported, scale}) {
this._ownerFrameId = ownerFrameId;
this.setOptionsContext(optionsContext);
@@ -152,6 +168,11 @@ class DisplayFloat extends Display {
this._setContentScale(scale);
}
+ _onMessageExtensionUnloaded() {
+ if (yomichan.isExtensionUnloaded) { return; }
+ yomichan.triggerExtensionUnloaded();
+ }
+
// Private
_copySelection() {
diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js
index aa03d4b5..bd64f1ac 100644
--- a/ext/fg/js/frontend.js
+++ b/ext/fg/js/frontend.js
@@ -147,26 +147,13 @@ class Frontend {
}
async updateOptions() {
- const optionsContext = await this.getOptionsContext();
- this._options = await api.optionsGet(optionsContext);
-
- await this._updatePopup();
-
- this._textScanner.setOptions(this._options);
- this._updateTextScannerEnabled();
-
- const ignoreNodes = ['.scan-disable', '.scan-disable *'];
- if (!this._options.scanning.enableOnPopupExpressions) {
- ignoreNodes.push('.source-text', '.source-text *');
- }
- this._textScanner.ignoreNodes = ignoreNodes.join(',');
-
- this._updateContentScale();
-
- const textSourceCurrent = this._textScanner.getCurrentTextSource();
- const causeCurrent = this._textScanner.causeCurrent;
- if (textSourceCurrent !== null && causeCurrent !== null) {
- await this._search(textSourceCurrent, causeCurrent);
+ try {
+ await this._updateOptionsInternal();
+ } catch (e) {
+ if (!yomichan.isExtensionUnloaded) {
+ throw e;
+ }
+ this._showExtensionUnloaded(null);
}
}
@@ -243,6 +230,30 @@ class Frontend {
await this.updateOptions();
}
+ async _updateOptionsInternal() {
+ const optionsContext = await this.getOptionsContext();
+ this._options = await api.optionsGet(optionsContext);
+
+ await this._updatePopup();
+
+ this._textScanner.setOptions(this._options);
+ this._updateTextScannerEnabled();
+
+ const ignoreNodes = ['.scan-disable', '.scan-disable *'];
+ if (!this._options.scanning.enableOnPopupExpressions) {
+ ignoreNodes.push('.source-text', '.source-text *');
+ }
+ this._textScanner.ignoreNodes = ignoreNodes.join(',');
+
+ this._updateContentScale();
+
+ const textSourceCurrent = this._textScanner.getCurrentTextSource();
+ const causeCurrent = this._textScanner.causeCurrent;
+ if (textSourceCurrent !== null && causeCurrent !== null) {
+ await this._search(textSourceCurrent, causeCurrent);
+ }
+ }
+
async _updatePopup() {
const showIframePopupsInRootFrame = this._options.general.showIframePopupsInRootFrame;
const isIframe = !this._useProxyPopup && (window !== window.parent);
@@ -328,8 +339,15 @@ class Frontend {
return this._popup === null || this._popup.isProxy() ? [] : [this._popup.getContainer()];
}
- _ignorePoint(x, y) {
- return this._popup !== null && this._popup.containsPoint(x, y);
+ async _ignorePoint(x, y) {
+ try {
+ return this._popup !== null && await this._popup.containsPoint(x, y);
+ } catch (e) {
+ if (!yomichan.isExtensionUnloaded) {
+ throw e;
+ }
+ return false;
+ }
}
async _search(textSource, cause) {
@@ -352,7 +370,7 @@ class Frontend {
} catch (e) {
if (yomichan.isExtensionUnloaded) {
if (textSource !== null && this._options.scanning.modifier !== 'none') {
- this._showPopupContent(textSource, await this.getOptionsContext(), 'extensionUnloaded');
+ this._showExtensionUnloaded(textSource);
}
} else {
yomichan.logError(e);
@@ -392,6 +410,14 @@ class Frontend {
return {definitions, type: 'kanji'};
}
+ async _showExtensionUnloaded(textSource) {
+ if (textSource === null) {
+ textSource = this._textScanner.getCurrentTextSource();
+ if (textSource === null) { return; }
+ }
+ this._showPopupContent(textSource, await this.getOptionsContext());
+ }
+
_showContent(textSource, focus, definitions, type, optionsContext) {
const {url} = optionsContext;
const sentenceExtent = this._options.anki.sentenceExt;
@@ -414,6 +440,10 @@ class Frontend {
details,
context
);
+ this._lastShowPromise.catch((error) => {
+ if (yomichan.isExtensionUnloaded) { return; }
+ yomichan.logError(error);
+ });
return this._lastShowPromise;
}
diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js
index 352c5b34..09c184db 100644
--- a/ext/fg/js/popup-proxy.js
+++ b/ext/fg/js/popup-proxy.js
@@ -69,7 +69,11 @@ class PopupProxy extends EventDispatcher {
}
async isVisible() {
- return await this._invoke('isVisible', {id: this._id});
+ try {
+ return await this._invoke('isVisible', {id: this._id});
+ } catch (e) {
+ return false;
+ }
}
setVisibleOverride(visible) {
@@ -98,8 +102,12 @@ class PopupProxy extends EventDispatcher {
this._invoke('setCustomCss', {id: this._id, css});
}
- clearAutoPlayTimer() {
- this._invoke('clearAutoPlayTimer', {id: this._id});
+ async clearAutoPlayTimer() {
+ try {
+ await this._invoke('clearAutoPlayTimer', {id: this._id});
+ } catch (e) {
+ // NOP
+ }
}
setContentScale(scale) {
diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js
index 4f2de4f2..35e66044 100644
--- a/ext/fg/js/popup.js
+++ b/ext/fg/js/popup.js
@@ -83,6 +83,7 @@ class Popup {
this._frame.addEventListener('mousedown', (e) => e.stopPropagation());
this._frame.addEventListener('scroll', (e) => e.stopPropagation());
this._frame.addEventListener('load', this._onFrameLoad.bind(this));
+ yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this));
}
isProxy() {
@@ -149,8 +150,12 @@ class Popup {
this._invokeApi('setCustomCss', {css});
}
- clearAutoPlayTimer() {
- this._invokeApi('clearAutoPlayTimer');
+ async clearAutoPlayTimer() {
+ try {
+ await this._invokeApi('clearAutoPlayTimer');
+ } catch (e) {
+ // NOP
+ }
}
setContentScale(scale) {
@@ -447,6 +452,18 @@ class Popup {
return await api.crossFrame.invoke(this._frameClient.frameId, 'popupMessage', message);
}
+ _invokeWindowApi(action, params={}) {
+ const contentWindow = this._frame.contentWindow;
+ if (this._frameClient === null || !this._frameClient.isConnected() || contentWindow === null) { return; }
+
+ const message = this._frameClient.createMessage({action, params});
+ contentWindow.postMessage(message, this._targetOrigin);
+ }
+
+ _onExtensionUnloaded() {
+ this._invokeWindowApi('extensionUnloaded');
+ }
+
_getFrameParentElement() {
const defaultParent = document.body;
const fullscreenElement = DOM.getFullscreenElement();
@@ -636,15 +653,4 @@ class Popup {
bottom: window.innerHeight
};
}
-
- static isFrameAboutBlank(frame) {
- try {
- const contentDocument = frame.contentDocument;
- if (contentDocument === null) { return false; }
- const url = contentDocument.location.href;
- return /^about:blank(?:[#?]|$)/.test(url);
- } catch (e) {
- return false;
- }
- }
}