From 166451b8f76224542b49c13cb27a258eb291f05e Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 9 Feb 2021 22:56:04 -0500 Subject: Improve popup window ownership (#1364) * Update frameInformationGet to also return the tab ID * Add tabId to Frontend * Pass tabId/frameId to Display * Pass ownership information using setContent * Remove ownerFrameId for Popup classes * Use frameId instead of ownerFrameId for screenshotting * Use contentOrigin instead of owner * Update _invokeContentOrigin implementation --- ext/mixed/js/display.js | 96 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 28 deletions(-) (limited to 'ext/mixed/js/display.js') diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 99ccfa85..69cc3d42 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -36,8 +36,10 @@ */ class Display extends EventDispatcher { - constructor(pageType, japaneseUtil, documentFocusController, hotkeyHandler) { + constructor(tabId, frameId, pageType, japaneseUtil, documentFocusController, hotkeyHandler) { super(); + this._tabId = tabId; + this._frameId = frameId; this._pageType = pageType; this._japaneseUtil = japaneseUtil; this._documentFocusController = documentFocusController; @@ -98,7 +100,8 @@ class Display extends EventDispatcher { this._depth = 0; this._parentPopupId = null; this._parentFrameId = null; - this._ownerFrameId = null; + this._contentOriginTabId = tabId; + this._contentOriginFrameId = frameId; this._childrenSupported = true; this._frameEndpoint = (pageType === 'popup' ? new FrameEndpoint() : null); this._browser = null; @@ -199,6 +202,14 @@ class Display extends EventDispatcher { return this._progressIndicatorVisible; } + get tabId() { + return this._tabId; + } + + get frameId() { + return this._frameId; + } + async prepare() { // State setup const {documentElement} = document; @@ -246,6 +257,13 @@ class Display extends EventDispatcher { } } + getContentOrigin() { + return { + tabId: this._contentOriginTabId, + frameId: this._contentOriginFrameId + }; + } + initializeState() { this._onStateChanged(); if (this._frameEndpoint !== null) { @@ -394,7 +412,7 @@ class Display extends EventDispatcher { close() { switch (this._pageType) { case 'popup': - this._invokeOwner('closePopup'); + this._invokeContentOrigin('closePopup'); break; case 'search': this._closeTab(); @@ -427,7 +445,8 @@ class Display extends EventDispatcher { params: this._createSearchParams(type, query, false), state, content: { - definitions: null + definitions: null, + contentOrigin: this.getContentOrigin() } }; this.setContent(details); @@ -494,14 +513,10 @@ class Display extends EventDispatcher { this._setContentScale(scale); } - async _onMessageConfigure({depth, parentPopupId, parentFrameId, ownerFrameId, childrenSupported, scale, optionsContext}) { + async _onMessageConfigure({depth, parentPopupId, parentFrameId, childrenSupported, scale, optionsContext}) { this._depth = depth; this._parentPopupId = parentPopupId; this._parentFrameId = parentFrameId; - this._ownerFrameId = ownerFrameId; - if (this._pageType === 'popup') { - this._hotkeyHandler.forwardFrameId = ownerFrameId; - } this._childrenSupported = childrenSupported; this._setContentScale(scale); await this.setOptionsContext(optionsContext); @@ -615,7 +630,8 @@ class Display extends EventDispatcher { cause: 'queryParser' }, content: { - definitions + definitions, + contentOrigin: this.getContentOrigin() } }; this.setContent(details); @@ -629,7 +645,12 @@ class Display extends EventDispatcher { history: false, params: {type}, state: {}, - content: {} + content: { + contentOrigin: { + tabId: this._tabId, + frameId: this._frameId + } + } }; this.setContent(details); } @@ -691,7 +712,8 @@ class Display extends EventDispatcher { documentTitle }, content: { - definitions + definitions, + contentOrigin: this.getContentOrigin() } }; this.setContent(details); @@ -886,6 +908,24 @@ class Display extends EventDispatcher { changeHistory = true; } + let contentOriginValid = false; + const {contentOrigin} = content; + if (typeof contentOrigin === 'object' && contentOrigin !== null) { + const {tabId, frameId} = contentOrigin; + if (typeof tabId === 'number' && typeof frameId === 'number') { + this._contentOriginTabId = tabId; + this._contentOriginFrameId = frameId; + if (this._pageType === 'popup') { + this._hotkeyHandler.forwardFrameId = (tabId === this._tabId ? frameId : null); + } + contentOriginValid = true; + } + } + if (!contentOriginValid) { + content.contentOrigin = this.getContentOrigin(); + changeHistory = true; + } + await this._setOptionsContextIfDifferent(optionsContext); if (this._setContentToken !== token) { return; } @@ -1499,10 +1539,10 @@ class Display extends EventDispatcher { } = options; const timestamp = Date.now(); - const ownerFrameId = this._ownerFrameId; + const screenshotFrameId = this._contentOriginFrameId; const definitionDetails = this._getDefinitionDetailsForNote(definition); const audioDetails = (mode !== 'kanji' && this._ankiNoteBuilder.containsMarker(fields, 'audio') ? {sources, customSourceUrl, customSourceType} : null); - const screenshotDetails = (this._ankiNoteBuilder.containsMarker(fields, 'screenshot') ? {ownerFrameId, format, quality} : null); + const screenshotDetails = (this._ankiNoteBuilder.containsMarker(fields, 'screenshot') ? {frameId: screenshotFrameId, format, quality} : null); const clipboardDetails = { image: this._ankiNoteBuilder.containsMarker(fields, 'clipboard-image'), text: this._ankiNoteBuilder.containsMarker(fields, 'clipboard-text') @@ -1583,8 +1623,6 @@ class Display extends EventDispatcher { parentFrameId: this._parentFrameId }; - const {frameId} = await api.frameInformationGet(); - await dynamicLoader.loadScripts([ '/mixed/js/text-scanner.js', '/mixed/js/frame-client.js', @@ -1597,12 +1635,13 @@ class Display extends EventDispatcher { '/fg/js/frontend.js' ]); - const popupFactory = new PopupFactory(frameId); + const popupFactory = new PopupFactory(this._frameId); popupFactory.prepare(); Object.assign(setupNestedPopupsOptions, { depth: this._depth + 1, - frameId, + tabId: this._tabId, + frameId: this._frameId, popupFactory, pageType: this._pageType, allowRootFramePopupProxy: true, @@ -1615,15 +1654,15 @@ class Display extends EventDispatcher { await frontend.prepare(); } - async _invokeOwner(action, params={}) { - if (this._ownerFrameId === null) { - throw new Error('No owner frame'); + async _invokeContentOrigin(action, params={}) { + if (this._contentOriginTabId === this._tabId && this._contentOriginFrameId === this._frameId) { + throw new Error('Content origin is same page'); } - return await api.crossFrame.invoke(this._ownerFrameId, action, params); + return await api.crossFrame.invokeTab(this._contentOriginTabId, this._contentOriginFrameId, action, params); } _copyHostSelection() { - if (this._ownerFrameId === null || window.getSelection().toString()) { return false; } + if (this._contentOriginFrameId === null || window.getSelection().toString()) { return false; } this._copyHostSelectionInner(); return true; } @@ -1635,7 +1674,7 @@ class Display extends EventDispatcher { { let text; try { - text = await this._invokeOwner('getSelectionText'); + text = await this._invokeContentOrigin('getSelectionText'); } catch (e) { break; } @@ -1643,7 +1682,7 @@ class Display extends EventDispatcher { } break; default: - await this._invokeOwner('copySelection'); + await this._invokeContentOrigin('copySelection'); break; } } @@ -1760,7 +1799,8 @@ class Display extends EventDispatcher { documentTitle }, content: { - definitions + definitions, + contentOrigin: this.getContentOrigin() } }; this._definitionTextScanner.clearSelection(true); @@ -1816,7 +1856,7 @@ class Display extends EventDispatcher { } async _initializeFrameResize(token) { - const size = await this._invokeOwner('getFrameSize'); + const size = await this._invokeContentOrigin('getFrameSize'); if (this._frameResizeToken !== token) { return; } this._frameResizeStartSize = size; } @@ -1842,7 +1882,7 @@ class Display extends EventDispatcher { height += y - this._frameResizeStartOffset.y; width = Math.max(Math.max(0, handleSize.width), width); height = Math.max(Math.max(0, handleSize.height), height); - await this._invokeOwner('setFrameSize', {width, height}); + await this._invokeContentOrigin('setFrameSize', {width, height}); } _updateHotkeys(options) { -- cgit v1.2.3