Refactor DisplayFloat=>Frontend message passing (#652)

* Change getOrCreatePopup arguments to be an object

* Add ownerFrameId to popup and DisplayFloat

* Refactor DisplayFloat host action invocation

* Use CrossFrameAPI instead of window.postMessage

* Update popup closing functionality on the search page
This commit is contained in:
toasted-nutbread 2020-07-08 19:50:13 -04:00 committed by GitHub
parent 128588bb92
commit 295ffa6e54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 41 deletions

View File

@ -255,7 +255,7 @@ class DisplaySearch extends Display {
this.clearContent(); this.clearContent();
} }
this._setTitleText(query); this._setTitleText(query);
window.parent.postMessage('popupClose', '*'); yomichan.trigger('closePopups');
} catch (e) { } catch (e) {
this.onError(e); this.onError(e);
} }

View File

@ -30,6 +30,7 @@ class DisplayFloat extends Display {
this._secret = yomichan.generateId(16); this._secret = yomichan.generateId(16);
this._token = null; this._token = null;
this._nestedPopupsPrepared = false; this._nestedPopupsPrepared = false;
this._ownerFrameId = null;
this._windowMessageHandlers = new Map([ this._windowMessageHandlers = new Map([
['initialize', {handler: this._onMessageInitialize.bind(this), authenticate: false}], ['initialize', {handler: this._onMessageInitialize.bind(this), authenticate: false}],
['configure', {handler: this._onMessageConfigure.bind(this)}], ['configure', {handler: this._onMessageConfigure.bind(this)}],
@ -60,7 +61,7 @@ class DisplayFloat extends Display {
} }
onEscape() { onEscape() {
window.parent.postMessage('popupClose', '*'); this._invoke('closePopup');
} }
async setOptionsContext(optionsContext) { async setOptionsContext(optionsContext) {
@ -134,7 +135,8 @@ class DisplayFloat extends Display {
this._initialize(params); this._initialize(params);
} }
async _onMessageConfigure({messageId, frameId, popupId, optionsContext, childrenSupported, scale}) { async _onMessageConfigure({messageId, frameId, ownerFrameId, popupId, optionsContext, childrenSupported, scale}) {
this._ownerFrameId = ownerFrameId;
this.setOptionsContext(optionsContext); this.setOptionsContext(optionsContext);
await this.updateOptions(); await this.updateOptions();
@ -173,7 +175,7 @@ class DisplayFloat extends Display {
// Private // Private
_copySelection() { _copySelection() {
window.parent.postMessage('selectionCopy', '*'); this._invoke('copySelection');
} }
_clearAutoPlayTimer() { _clearAutoPlayTimer() {
@ -266,4 +268,8 @@ class DisplayFloat extends Display {
); );
await frontend.prepare(); await frontend.prepare();
} }
_invoke(action, params={}) {
return api.crossFrame.invoke(this._ownerFrameId, action, params);
}
} }

View File

@ -33,7 +33,6 @@ class Frontend {
this._pageZoomFactor = 1.0; this._pageZoomFactor = 1.0;
this._contentScale = 1.0; this._contentScale = 1.0;
this._lastShowPromise = Promise.resolve(); this._lastShowPromise = Promise.resolve();
this._enabledEventListeners = new EventListenerCollection();
this._activeModifiers = new Set(); this._activeModifiers = new Set();
this._optionsUpdatePending = false; this._optionsUpdatePending = false;
this._textScanner = new TextScanner({ this._textScanner = new TextScanner({
@ -63,11 +62,6 @@ class Frontend {
this._popupCache = new Map(); this._popupCache = new Map();
this._updatePopupToken = null; this._updatePopupToken = null;
this._windowMessageHandlers = new Map([
['popupClose', this._onMessagePopupClose.bind(this)],
['selectionCopy', this._onMessageSelectionCopy.bind()]
]);
this._runtimeMessageHandlers = new Map([ this._runtimeMessageHandlers = new Map([
['popupSetVisibleOverride', this._onMessagePopupSetVisibleOverride.bind(this)], ['popupSetVisibleOverride', this._onMessagePopupSetVisibleOverride.bind(this)],
['rootPopupRequestInformationBroadcast', this._onMessageRootPopupRequestInformationBroadcast.bind(this)], ['rootPopupRequestInformationBroadcast', this._onMessageRootPopupRequestInformationBroadcast.bind(this)],
@ -111,13 +105,16 @@ class Frontend {
yomichan.on('optionsUpdated', this.updateOptions.bind(this)); yomichan.on('optionsUpdated', this.updateOptions.bind(this));
yomichan.on('zoomChanged', this._onZoomChanged.bind(this)); yomichan.on('zoomChanged', this._onZoomChanged.bind(this));
yomichan.on('closePopups', this._onApiClosePopup.bind(this));
chrome.runtime.onMessage.addListener(this._onRuntimeMessage.bind(this)); chrome.runtime.onMessage.addListener(this._onRuntimeMessage.bind(this));
this._textScanner.on('clearSelection', this._onClearSelection.bind(this)); this._textScanner.on('clearSelection', this._onClearSelection.bind(this));
this._textScanner.on('activeModifiersChanged', this._onActiveModifiersChanged.bind(this)); this._textScanner.on('activeModifiersChanged', this._onActiveModifiersChanged.bind(this));
api.crossFrame.registerHandlers([ api.crossFrame.registerHandlers([
['getUrl', {async: false, handler: this._onApiGetUrl.bind(this)}] ['getUrl', {async: false, handler: this._onApiGetUrl.bind(this)}],
['closePopup', {async: false, handler: this._onApiClosePopup.bind(this)}],
['copySelection', {async: false, handler: this._onApiCopySelection.bind(this)}]
]); ]);
this._updateContentScale(); this._updateContentScale();
@ -179,14 +176,6 @@ class Frontend {
// Message handlers // Message handlers
_onMessagePopupClose() {
this._textScanner.clearSelection(false);
}
_onMessageSelectionCopy() {
document.execCommand('copy');
}
_onMessagePopupSetVisibleOverride({visible}) { _onMessagePopupSetVisibleOverride({visible}) {
this._popup.setVisibleOverride(visible); this._popup.setVisibleOverride(visible);
} }
@ -205,20 +194,20 @@ class Frontend {
return window.location.href; return window.location.href;
} }
_onApiClosePopup() {
this._textScanner.clearSelection(false);
}
_onApiCopySelection() {
document.execCommand('copy');
}
// Private // Private
_onResize() { _onResize() {
this._updatePopupPosition(); this._updatePopupPosition();
} }
_onWindowMessage(e) {
const action = e.data;
const handler = this._windowMessageHandlers.get(action);
if (typeof handler !== 'function') { return false; }
handler();
}
_onRuntimeMessage({action, params}, sender, callback) { _onRuntimeMessage({action, params}, sender, callback) {
const handler = this._runtimeMessageHandlers.get(action); const handler = this._runtimeMessageHandlers.get(action);
if (typeof handler !== 'function') { return false; } if (typeof handler !== 'function') { return false; }
@ -307,11 +296,11 @@ class Frontend {
} }
async _getDefaultPopup() { async _getDefaultPopup() {
return this._popupFactory.getOrCreatePopup(null, null, this._depth); return this._popupFactory.getOrCreatePopup({depth: this._depth, ownerFrameId: this._frameId});
} }
async _getProxyPopup() { async _getProxyPopup() {
const popup = new PopupProxy(null, this._depth + 1, this._proxyPopupId, this._parentFrameId); const popup = new PopupProxy(null, this._depth + 1, this._proxyPopupId, this._parentFrameId, this._frameId);
await popup.prepare(); await popup.prepare();
return popup; return popup;
} }
@ -328,7 +317,7 @@ class Frontend {
api.broadcastTab('rootPopupRequestInformationBroadcast'); api.broadcastTab('rootPopupRequestInformationBroadcast');
const {popupId, frameId: parentFrameId} = await rootPopupInformationPromise; const {popupId, frameId: parentFrameId} = await rootPopupInformationPromise;
const popup = new PopupProxy(popupId, 0, null, parentFrameId, this._frameOffsetForwarder); const popup = new PopupProxy(popupId, 0, null, parentFrameId, this._frameId, this._frameOffsetForwarder);
popup.on('offsetNotFound', () => { popup.on('offsetNotFound', () => {
this._allowRootFramePopupProxy = false; this._allowRootFramePopupProxy = false;
this._updatePopup(); this._updatePopup();
@ -444,11 +433,7 @@ class Frontend {
this._depth <= this._options.scanning.popupNestingMaxDepth && this._depth <= this._options.scanning.popupNestingMaxDepth &&
!this._disabledOverride !this._disabledOverride
); );
this._enabledEventListeners.removeAllEventListeners();
this._textScanner.setEnabled(enabled); this._textScanner.setEnabled(enabled);
if (enabled) {
this._enabledEventListeners.addEventListener(window, 'message', this._onWindowMessage.bind(this));
}
} }
_updateContentScale() { _updateContentScale() {

View File

@ -43,7 +43,7 @@ class PopupFactory {
]); ]);
} }
getOrCreatePopup(id=null, parentId=null, depth=null) { getOrCreatePopup({id=null, parentId=null, ownerFrameId=null, depth=null}) {
// Find by existing id // Find by existing id
if (id !== null) { if (id !== null) {
const popup = this._popups.get(id); const popup = this._popups.get(id);
@ -80,7 +80,7 @@ class PopupFactory {
} else if (depth === null) { } else if (depth === null) {
depth = 0; depth = 0;
} }
const popup = new Popup(id, depth, this._frameId); const popup = new Popup(id, depth, this._frameId, ownerFrameId);
if (parent !== null) { if (parent !== null) {
popup.setParent(parent); popup.setParent(parent);
} }
@ -91,8 +91,8 @@ class PopupFactory {
// API message handlers // API message handlers
_onApiGetOrCreatePopup({id, parentId}) { _onApiGetOrCreatePopup({id, parentId, ownerFrameId}) {
const popup = this.getOrCreatePopup(id, parentId); const popup = this.getOrCreatePopup({id, parentId, ownerFrameId});
return { return {
id: popup.id id: popup.id
}; };

View File

@ -20,12 +20,13 @@
*/ */
class PopupProxy extends EventDispatcher { class PopupProxy extends EventDispatcher {
constructor(id, depth, parentPopupId, parentFrameId, frameOffsetForwarder=null) { constructor(id, depth, parentPopupId, parentFrameId, ownerFrameId, frameOffsetForwarder=null) {
super(); super();
this._id = id; this._id = id;
this._depth = depth; this._depth = depth;
this._parentPopupId = parentPopupId; this._parentPopupId = parentPopupId;
this._parentFrameId = parentFrameId; this._parentFrameId = parentFrameId;
this._ownerFrameId = ownerFrameId;
this._frameOffsetForwarder = frameOffsetForwarder; this._frameOffsetForwarder = frameOffsetForwarder;
this._frameOffset = null; this._frameOffset = null;
@ -51,7 +52,7 @@ class PopupProxy extends EventDispatcher {
// Public functions // Public functions
async prepare() { async prepare() {
const {id} = await this._invoke('getOrCreatePopup', {id: this._id, parentId: this._parentPopupId}); const {id} = await this._invoke('getOrCreatePopup', {id: this._id, parentId: this._parentPopupId, ownerFrameId: this._ownerFrameId});
this._id = id; this._id = id;
} }

View File

@ -22,10 +22,11 @@
*/ */
class Popup { class Popup {
constructor(id, depth, frameId) { constructor(id, depth, frameId, ownerFrameId) {
this._id = id; this._id = id;
this._depth = depth; this._depth = depth;
this._frameId = frameId; this._frameId = frameId;
this._ownerFrameId = ownerFrameId;
this._parent = null; this._parent = null;
this._child = null; this._child = null;
this._childrenSupported = true; this._childrenSupported = true;
@ -382,6 +383,7 @@ class Popup {
this._invokeApi('configure', { this._invokeApi('configure', {
messageId, messageId,
frameId: this._frameId, frameId: this._frameId,
ownerFrameId: this._ownerFrameId,
popupId: this._id, popupId: this._id,
optionsContext: this._optionsContext, optionsContext: this._optionsContext,
childrenSupported: this._childrenSupported, childrenSupported: this._childrenSupported,