Fix screenshot popup hide (#753)
* Refactor Popup.setVisibleOverride * Use event to observe visibility changes * Add setAllVisibleOverride/clearAllVisibleOverride * Add setAllVisibleOverride/clearAllVisibleOverride cross frame handlers * Update how visibility is changed * Wait for next frame to ensure visibility has been updated
This commit is contained in:
parent
934355dd09
commit
773e28aa3c
@ -62,7 +62,6 @@ class Frontend {
|
|||||||
this._updatePopupToken = null;
|
this._updatePopupToken = null;
|
||||||
|
|
||||||
this._runtimeMessageHandlers = new Map([
|
this._runtimeMessageHandlers = new Map([
|
||||||
['popupSetVisibleOverride', {async: false, handler: this._onMessagePopupSetVisibleOverride.bind(this)}],
|
|
||||||
['requestFrontendReadyBroadcast', {async: false, handler: this._onMessageRequestFrontendReadyBroadcast.bind(this)}]
|
['requestFrontendReadyBroadcast', {async: false, handler: this._onMessageRequestFrontendReadyBroadcast.bind(this)}]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -108,11 +107,13 @@ class Frontend {
|
|||||||
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)}],
|
['closePopup', {async: false, handler: this._onApiClosePopup.bind(this)}],
|
||||||
['copySelection', {async: false, handler: this._onApiCopySelection.bind(this)}],
|
['copySelection', {async: false, handler: this._onApiCopySelection.bind(this)}],
|
||||||
['getPopupInfo', {async: false, handler: this._onApiGetPopupInfo.bind(this)}],
|
['getPopupInfo', {async: false, handler: this._onApiGetPopupInfo.bind(this)}],
|
||||||
['getDocumentInformation', {async: false, handler: this._onApiGetDocumentInformation.bind(this)}]
|
['getDocumentInformation', {async: false, handler: this._onApiGetDocumentInformation.bind(this)}],
|
||||||
|
['setAllVisibleOverride', {async: true, handler: this._onApiSetAllVisibleOverride.bind(this)}],
|
||||||
|
['clearAllVisibleOverride', {async: true, handler: this._onApiClearAllVisibleOverride.bind(this)}]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this._updateContentScale();
|
this._updateContentScale();
|
||||||
@ -161,11 +162,6 @@ class Frontend {
|
|||||||
|
|
||||||
// Message handlers
|
// Message handlers
|
||||||
|
|
||||||
_onMessagePopupSetVisibleOverride({visible}) {
|
|
||||||
if (this._popup === null) { return; }
|
|
||||||
this._popup.setVisibleOverride(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onMessageRequestFrontendReadyBroadcast({frameId}) {
|
_onMessageRequestFrontendReadyBroadcast({frameId}) {
|
||||||
this._signalFrontendReady(frameId);
|
this._signalFrontendReady(frameId);
|
||||||
}
|
}
|
||||||
@ -196,6 +192,18 @@ class Frontend {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _onApiSetAllVisibleOverride({value, priority, awaitFrame}) {
|
||||||
|
const result = await this._popupFactory.setAllVisibleOverride(value, priority);
|
||||||
|
if (awaitFrame) {
|
||||||
|
await promiseAnimationFrame(100);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onApiClearAllVisibleOverride({token}) {
|
||||||
|
return await this._popupFactory.clearAllVisibleOverride(token);
|
||||||
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
_onResize() {
|
_onResize() {
|
||||||
|
@ -27,6 +27,7 @@ class PopupFactory {
|
|||||||
this._frameId = frameId;
|
this._frameId = frameId;
|
||||||
this._frameOffsetForwarder = new FrameOffsetForwarder(frameId);
|
this._frameOffsetForwarder = new FrameOffsetForwarder(frameId);
|
||||||
this._popups = new Map();
|
this._popups = new Map();
|
||||||
|
this._allPopupVisibilityTokenMap = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public functions
|
// Public functions
|
||||||
@ -39,6 +40,7 @@ class PopupFactory {
|
|||||||
['hide', {async: false, handler: this._onApiHide.bind(this)}],
|
['hide', {async: false, handler: this._onApiHide.bind(this)}],
|
||||||
['isVisible', {async: true, handler: this._onApiIsVisibleAsync.bind(this)}],
|
['isVisible', {async: true, handler: this._onApiIsVisibleAsync.bind(this)}],
|
||||||
['setVisibleOverride', {async: true, handler: this._onApiSetVisibleOverride.bind(this)}],
|
['setVisibleOverride', {async: true, handler: this._onApiSetVisibleOverride.bind(this)}],
|
||||||
|
['clearVisibleOverride', {async: true, handler: this._onApiClearVisibleOverride.bind(this)}],
|
||||||
['containsPoint', {async: true, handler: this._onApiContainsPoint.bind(this)}],
|
['containsPoint', {async: true, handler: this._onApiContainsPoint.bind(this)}],
|
||||||
['showContent', {async: true, handler: this._onApiShowContent.bind(this)}],
|
['showContent', {async: true, handler: this._onApiShowContent.bind(this)}],
|
||||||
['setCustomCss', {async: false, handler: this._onApiSetCustomCss.bind(this)}],
|
['setCustomCss', {async: false, handler: this._onApiSetCustomCss.bind(this)}],
|
||||||
@ -108,6 +110,40 @@ class PopupFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setAllVisibleOverride(value, priority) {
|
||||||
|
const promises = [];
|
||||||
|
const errors = [];
|
||||||
|
for (const popup of this._popups.values()) {
|
||||||
|
const promise = popup.setVisibleOverride(value, priority)
|
||||||
|
.then(
|
||||||
|
(token) => ({popup, token}),
|
||||||
|
(error) => { errors.push(error); return null; }
|
||||||
|
);
|
||||||
|
promises.push(promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
|
||||||
|
if (errors.length === 0) {
|
||||||
|
const token = generateId(16);
|
||||||
|
this._allPopupVisibilityTokenMap.set(token, results);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert on error
|
||||||
|
await this._revertPopupVisibilityOverrides(results);
|
||||||
|
throw errors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
async clearAllVisibleOverride(token) {
|
||||||
|
const results = this._allPopupVisibilityTokenMap.get(token);
|
||||||
|
if (typeof results === 'undefined') { return false; }
|
||||||
|
|
||||||
|
this._allPopupVisibilityTokenMap.delete(token);
|
||||||
|
await this._revertPopupVisibilityOverrides(results);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// API message handlers
|
// API message handlers
|
||||||
|
|
||||||
async _onApiGetOrCreatePopup({id, parentPopupId, frameId, ownerFrameId}) {
|
async _onApiGetOrCreatePopup({id, parentPopupId, frameId, ownerFrameId}) {
|
||||||
@ -134,9 +170,14 @@ class PopupFactory {
|
|||||||
return await popup.isVisible();
|
return await popup.isVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onApiSetVisibleOverride({id, visible}) {
|
async _onApiSetVisibleOverride({id, value, priority}) {
|
||||||
const popup = this._getPopup(id);
|
const popup = this._getPopup(id);
|
||||||
return await popup.setVisibleOverride(visible);
|
return await popup.setVisibleOverride(value, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onApiClearVisibleOverride({id, token}) {
|
||||||
|
const popup = this._getPopup(id);
|
||||||
|
return await popup.clearVisibleOverride(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onApiContainsPoint({id, x, y}) {
|
async _onApiContainsPoint({id, x, y}) {
|
||||||
@ -216,4 +257,19 @@ class PopupFactory {
|
|||||||
const parent = popup.parent;
|
const parent = popup.parent;
|
||||||
return parent === null || parent.isVisibleSync();
|
return parent === null || parent.isVisibleSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _revertPopupVisibilityOverrides(overrides) {
|
||||||
|
const promises = [];
|
||||||
|
for (const value of overrides) {
|
||||||
|
if (value === null) { continue; }
|
||||||
|
const {popup, token} = value;
|
||||||
|
const promise = popup.clearVisibleOverride(token)
|
||||||
|
.then(
|
||||||
|
(v) => v,
|
||||||
|
() => false
|
||||||
|
);
|
||||||
|
promises.push(promise);
|
||||||
|
}
|
||||||
|
return await Promise.all(promises);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,8 +86,12 @@ class PopupProxy extends EventDispatcher {
|
|||||||
return this._invokeSafe('isVisible', {id: this._id}, false);
|
return this._invokeSafe('isVisible', {id: this._id}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisibleOverride(visible) {
|
async setVisibleOverride(value, priority) {
|
||||||
return this._invokeSafe('setVisibleOverride', {id: this._id, visible});
|
return this._invokeSafe('setVisibleOverride', {id: this._id, value, priority});
|
||||||
|
}
|
||||||
|
|
||||||
|
async clearVisibleOverride(token) {
|
||||||
|
return this._invokeSafe('clearVisibleOverride', {id: this._id, token});
|
||||||
}
|
}
|
||||||
|
|
||||||
async containsPoint(x, y) {
|
async containsPoint(x, y) {
|
||||||
|
@ -34,8 +34,7 @@ class Popup extends EventDispatcher {
|
|||||||
this._childrenSupported = true;
|
this._childrenSupported = true;
|
||||||
this._injectPromise = null;
|
this._injectPromise = null;
|
||||||
this._injectPromiseComplete = false;
|
this._injectPromiseComplete = false;
|
||||||
this._visible = false;
|
this._visible = new DynamicProperty(false);
|
||||||
this._visibleOverride = null;
|
|
||||||
this._options = null;
|
this._options = null;
|
||||||
this._optionsContext = null;
|
this._optionsContext = null;
|
||||||
this._contentScale = 1.0;
|
this._contentScale = 1.0;
|
||||||
@ -96,11 +95,12 @@ class Popup extends EventDispatcher {
|
|||||||
// Public functions
|
// Public functions
|
||||||
|
|
||||||
prepare() {
|
prepare() {
|
||||||
this._updateVisibility();
|
|
||||||
this._frame.addEventListener('mousedown', (e) => e.stopPropagation());
|
this._frame.addEventListener('mousedown', (e) => e.stopPropagation());
|
||||||
this._frame.addEventListener('scroll', (e) => e.stopPropagation());
|
this._frame.addEventListener('scroll', (e) => e.stopPropagation());
|
||||||
this._frame.addEventListener('load', this._onFrameLoad.bind(this));
|
this._frame.addEventListener('load', this._onFrameLoad.bind(this));
|
||||||
|
this._visible.on('change', this._onVisibleChange.bind(this));
|
||||||
yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this));
|
yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this));
|
||||||
|
this._onVisibleChange({value: this.isVisibleSync()});
|
||||||
}
|
}
|
||||||
|
|
||||||
async setOptionsContext(optionsContext, source) {
|
async setOptionsContext(optionsContext, source) {
|
||||||
@ -131,9 +131,12 @@ class Popup extends EventDispatcher {
|
|||||||
return this.isVisibleSync();
|
return this.isVisibleSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisibleOverride(visible) {
|
async setVisibleOverride(value, priority) {
|
||||||
this._visibleOverride = visible;
|
return this._visible.setOverride(value, priority);
|
||||||
this._updateVisibility();
|
}
|
||||||
|
|
||||||
|
async clearVisibleOverride(token) {
|
||||||
|
return this._visible.clearOverride(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
async containsPoint(x, y) {
|
async containsPoint(x, y) {
|
||||||
@ -177,7 +180,7 @@ class Popup extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isVisibleSync() {
|
isVisibleSync() {
|
||||||
return (this._visibleOverride !== null ? this._visibleOverride : this._visible);
|
return this._visible.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTheme() {
|
updateTheme() {
|
||||||
@ -392,12 +395,11 @@ class Popup extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_setVisible(visible) {
|
_setVisible(visible) {
|
||||||
this._visible = visible;
|
this._visible.defaultValue = visible;
|
||||||
this._updateVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateVisibility() {
|
_onVisibleChange({value}) {
|
||||||
this._frame.style.setProperty('visibility', this.isVisibleSync() ? 'visible' : 'hidden', 'important');
|
this._frame.style.setProperty('visibility', value ? 'visible' : 'hidden', 'important');
|
||||||
}
|
}
|
||||||
|
|
||||||
_focusParent() {
|
_focusParent() {
|
||||||
|
@ -1145,9 +1145,12 @@ class Display extends EventDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _getScreenshot() {
|
async _getScreenshot() {
|
||||||
|
const ownerFrameId = this._ownerFrameId;
|
||||||
|
let token = null;
|
||||||
try {
|
try {
|
||||||
await this._setPopupVisibleOverride(false);
|
if (ownerFrameId !== null) {
|
||||||
await promiseTimeout(1); // Wait for popup to be hidden.
|
token = await api.crossFrame.invoke(ownerFrameId, 'setAllVisibleOverride', {value: false, priority: 0, awaitFrame: true});
|
||||||
|
}
|
||||||
|
|
||||||
const {format, quality} = this._options.anki.screenshot;
|
const {format, quality} = this._options.anki.screenshot;
|
||||||
const dataUrl = await api.screenshotGet({format, quality});
|
const dataUrl = await api.screenshotGet({format, quality});
|
||||||
@ -1155,7 +1158,9 @@ class Display extends EventDispatcher {
|
|||||||
|
|
||||||
return {dataUrl, format};
|
return {dataUrl, format};
|
||||||
} finally {
|
} finally {
|
||||||
await this._setPopupVisibleOverride(null);
|
if (token !== null) {
|
||||||
|
await api.crossFrame.invoke(ownerFrameId, 'clearAllVisibleOverride', {token});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1163,10 +1168,6 @@ class Display extends EventDispatcher {
|
|||||||
return this._options.general.resultOutputMode === 'merge' ? 0 : -1;
|
return this._options.general.resultOutputMode === 'merge' ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setPopupVisibleOverride(visible) {
|
|
||||||
return api.broadcastTab('popupSetVisibleOverride', {visible});
|
|
||||||
}
|
|
||||||
|
|
||||||
_getEntry(index) {
|
_getEntry(index) {
|
||||||
const entries = this._container.querySelectorAll('.entry');
|
const entries = this._container.querySelectorAll('.entry');
|
||||||
return index >= 0 && index < entries.length ? entries[index] : null;
|
return index >= 0 && index < entries.length ? entries[index] : null;
|
||||||
|
Loading…
Reference in New Issue
Block a user