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._setTitleText(query);
window.parent.postMessage('popupClose', '*');
yomichan.trigger('closePopups');
} catch (e) {
this.onError(e);
}

View File

@ -30,6 +30,7 @@ class DisplayFloat extends Display {
this._secret = yomichan.generateId(16);
this._token = null;
this._nestedPopupsPrepared = false;
this._ownerFrameId = null;
this._windowMessageHandlers = new Map([
['initialize', {handler: this._onMessageInitialize.bind(this), authenticate: false}],
['configure', {handler: this._onMessageConfigure.bind(this)}],
@ -60,7 +61,7 @@ class DisplayFloat extends Display {
}
onEscape() {
window.parent.postMessage('popupClose', '*');
this._invoke('closePopup');
}
async setOptionsContext(optionsContext) {
@ -134,7 +135,8 @@ class DisplayFloat extends Display {
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);
await this.updateOptions();
@ -173,7 +175,7 @@ class DisplayFloat extends Display {
// Private
_copySelection() {
window.parent.postMessage('selectionCopy', '*');
this._invoke('copySelection');
}
_clearAutoPlayTimer() {
@ -266,4 +268,8 @@ class DisplayFloat extends Display {
);
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._contentScale = 1.0;
this._lastShowPromise = Promise.resolve();
this._enabledEventListeners = new EventListenerCollection();
this._activeModifiers = new Set();
this._optionsUpdatePending = false;
this._textScanner = new TextScanner({
@ -63,11 +62,6 @@ class Frontend {
this._popupCache = new Map();
this._updatePopupToken = null;
this._windowMessageHandlers = new Map([
['popupClose', this._onMessagePopupClose.bind(this)],
['selectionCopy', this._onMessageSelectionCopy.bind()]
]);
this._runtimeMessageHandlers = new Map([
['popupSetVisibleOverride', this._onMessagePopupSetVisibleOverride.bind(this)],
['rootPopupRequestInformationBroadcast', this._onMessageRootPopupRequestInformationBroadcast.bind(this)],
@ -111,13 +105,16 @@ class Frontend {
yomichan.on('optionsUpdated', this.updateOptions.bind(this));
yomichan.on('zoomChanged', this._onZoomChanged.bind(this));
yomichan.on('closePopups', this._onApiClosePopup.bind(this));
chrome.runtime.onMessage.addListener(this._onRuntimeMessage.bind(this));
this._textScanner.on('clearSelection', this._onClearSelection.bind(this));
this._textScanner.on('activeModifiersChanged', this._onActiveModifiersChanged.bind(this));
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();
@ -179,14 +176,6 @@ class Frontend {
// Message handlers
_onMessagePopupClose() {
this._textScanner.clearSelection(false);
}
_onMessageSelectionCopy() {
document.execCommand('copy');
}
_onMessagePopupSetVisibleOverride({visible}) {
this._popup.setVisibleOverride(visible);
}
@ -205,20 +194,20 @@ class Frontend {
return window.location.href;
}
_onApiClosePopup() {
this._textScanner.clearSelection(false);
}
_onApiCopySelection() {
document.execCommand('copy');
}
// Private
_onResize() {
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) {
const handler = this._runtimeMessageHandlers.get(action);
if (typeof handler !== 'function') { return false; }
@ -307,11 +296,11 @@ class Frontend {
}
async _getDefaultPopup() {
return this._popupFactory.getOrCreatePopup(null, null, this._depth);
return this._popupFactory.getOrCreatePopup({depth: this._depth, ownerFrameId: this._frameId});
}
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();
return popup;
}
@ -328,7 +317,7 @@ class Frontend {
api.broadcastTab('rootPopupRequestInformationBroadcast');
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', () => {
this._allowRootFramePopupProxy = false;
this._updatePopup();
@ -444,11 +433,7 @@ class Frontend {
this._depth <= this._options.scanning.popupNestingMaxDepth &&
!this._disabledOverride
);
this._enabledEventListeners.removeAllEventListeners();
this._textScanner.setEnabled(enabled);
if (enabled) {
this._enabledEventListeners.addEventListener(window, 'message', this._onWindowMessage.bind(this));
}
}
_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
if (id !== null) {
const popup = this._popups.get(id);
@ -80,7 +80,7 @@ class PopupFactory {
} else if (depth === null) {
depth = 0;
}
const popup = new Popup(id, depth, this._frameId);
const popup = new Popup(id, depth, this._frameId, ownerFrameId);
if (parent !== null) {
popup.setParent(parent);
}
@ -91,8 +91,8 @@ class PopupFactory {
// API message handlers
_onApiGetOrCreatePopup({id, parentId}) {
const popup = this.getOrCreatePopup(id, parentId);
_onApiGetOrCreatePopup({id, parentId, ownerFrameId}) {
const popup = this.getOrCreatePopup({id, parentId, ownerFrameId});
return {
id: popup.id
};

View File

@ -20,12 +20,13 @@
*/
class PopupProxy extends EventDispatcher {
constructor(id, depth, parentPopupId, parentFrameId, frameOffsetForwarder=null) {
constructor(id, depth, parentPopupId, parentFrameId, ownerFrameId, frameOffsetForwarder=null) {
super();
this._id = id;
this._depth = depth;
this._parentPopupId = parentPopupId;
this._parentFrameId = parentFrameId;
this._ownerFrameId = ownerFrameId;
this._frameOffsetForwarder = frameOffsetForwarder;
this._frameOffset = null;
@ -51,7 +52,7 @@ class PopupProxy extends EventDispatcher {
// Public functions
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;
}

View File

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