Popup window (#773)
* Add option usePopupWindow * Add PopupWindow class * Add support for creating PopupWindow
This commit is contained in:
parent
55770934f8
commit
44f38c4dea
@ -53,6 +53,7 @@
|
||||
"fg/js/popup-factory.js",
|
||||
"fg/js/frame-offset-forwarder.js",
|
||||
"fg/js/popup-proxy.js",
|
||||
"fg/js/popup-window.js",
|
||||
"fg/js/frontend.js",
|
||||
"fg/js/content-script-main.js"
|
||||
],
|
||||
|
@ -111,7 +111,8 @@
|
||||
"showPitchAccentGraph",
|
||||
"showIframePopupsInRootFrame",
|
||||
"useSecurePopupFrameUrl",
|
||||
"usePopupShadowDom"
|
||||
"usePopupShadowDom",
|
||||
"usePopupWindow"
|
||||
],
|
||||
"properties": {
|
||||
"enable": {
|
||||
@ -257,6 +258,10 @@
|
||||
"usePopupShadowDom": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"usePopupWindow": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -467,6 +467,7 @@ class OptionsUtil {
|
||||
static _updateVersion4(options) {
|
||||
// Version 4 changes:
|
||||
// Options conditions converted to string representations.
|
||||
// Added usePopupWindow.
|
||||
for (const {conditionGroups} of options.profiles) {
|
||||
for (const {conditions} of conditionGroups) {
|
||||
for (const condition of conditions) {
|
||||
@ -479,6 +480,9 @@ class OptionsUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const {options: profileOptions} of options.profiles) {
|
||||
profileOptions.general.usePopupWindow = false;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
@ -180,6 +180,10 @@
|
||||
<label><input type="checkbox" id="show-iframe-popups-in-root-frame" data-setting="general.showIframePopupsInRootFrame"> Show iframe popups in root frame</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox options-advanced">
|
||||
<label><input type="checkbox" data-setting="general.usePopupWindow"> Use a native popup window when scanning text on web pages</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox options-advanced">
|
||||
<label><input type="checkbox" data-setting="general.useSecurePopupFrameUrl"> Use secure popup frame URL</label>
|
||||
</div>
|
||||
|
@ -307,11 +307,17 @@ class Frontend {
|
||||
}
|
||||
|
||||
async _updatePopup() {
|
||||
const showIframePopupsInRootFrame = this._options.general.showIframePopupsInRootFrame;
|
||||
const {usePopupWindow, showIframePopupsInRootFrame} = this._options.general;
|
||||
const isIframe = !this._useProxyPopup && (window !== window.parent);
|
||||
|
||||
let popupPromise;
|
||||
if (
|
||||
if (usePopupWindow) {
|
||||
popupPromise = this._popupCache.get('window');
|
||||
if (typeof popupPromise === 'undefined') {
|
||||
popupPromise = this._getPopupWindow();
|
||||
this._popupCache.set('window', popupPromise);
|
||||
}
|
||||
} else if (
|
||||
isIframe &&
|
||||
showIframePopupsInRootFrame &&
|
||||
DocumentUtil.getFullscreenElement() === null &&
|
||||
@ -404,6 +410,14 @@ class Frontend {
|
||||
return popup;
|
||||
}
|
||||
|
||||
async _getPopupWindow() {
|
||||
return await this._popupFactory.getOrCreatePopup({
|
||||
ownerFrameId: this._frameId,
|
||||
depth: this._depth,
|
||||
popupWindow: true
|
||||
});
|
||||
}
|
||||
|
||||
_ignoreElements() {
|
||||
if (this._popup !== null) {
|
||||
const container = this._popup.container;
|
||||
|
@ -19,6 +19,7 @@
|
||||
* FrameOffsetForwarder
|
||||
* Popup
|
||||
* PopupProxy
|
||||
* PopupWindow
|
||||
* api
|
||||
*/
|
||||
|
||||
@ -52,7 +53,7 @@ class PopupFactory {
|
||||
]);
|
||||
}
|
||||
|
||||
async getOrCreatePopup({frameId=null, ownerFrameId=null, id=null, parentPopupId=null, depth=null}) {
|
||||
async getOrCreatePopup({frameId=null, ownerFrameId=null, id=null, parentPopupId=null, depth=null, popupWindow=false}) {
|
||||
// Find by existing id
|
||||
if (id !== null) {
|
||||
const popup = this._popups.get(id);
|
||||
@ -85,7 +86,15 @@ class PopupFactory {
|
||||
depth = 0;
|
||||
}
|
||||
|
||||
if (frameId === this._frameId) {
|
||||
if (popupWindow) {
|
||||
// New unique id
|
||||
if (id === null) {
|
||||
id = generateId(16);
|
||||
}
|
||||
const popup = new PopupWindow(id, depth, this._frameId, ownerFrameId);
|
||||
this._popups.set(id, popup);
|
||||
return popup;
|
||||
} else if (frameId === this._frameId) {
|
||||
// New unique id
|
||||
if (id === null) {
|
||||
id = generateId(16);
|
||||
|
161
ext/fg/js/popup-window.js
Normal file
161
ext/fg/js/popup-window.js
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* global
|
||||
* api
|
||||
*/
|
||||
|
||||
class PopupWindow extends EventDispatcher {
|
||||
constructor(id, depth, frameId, ownerFrameId) {
|
||||
super();
|
||||
this._id = id;
|
||||
this._depth = depth;
|
||||
this._frameId = frameId;
|
||||
this._ownerFrameId = ownerFrameId;
|
||||
this._popupTabId = null;
|
||||
}
|
||||
|
||||
// Public properties
|
||||
|
||||
get id() {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
set parent(value) {
|
||||
throw new Error('Not supported on PopupProxy');
|
||||
}
|
||||
|
||||
get child() {
|
||||
return null;
|
||||
}
|
||||
|
||||
set child(value) {
|
||||
throw new Error('Not supported on PopupProxy');
|
||||
}
|
||||
|
||||
get depth() {
|
||||
return this._depth;
|
||||
}
|
||||
|
||||
get frameContentWindow() {
|
||||
return null;
|
||||
}
|
||||
|
||||
get container() {
|
||||
return null;
|
||||
}
|
||||
|
||||
get frameId() {
|
||||
return this._frameId;
|
||||
}
|
||||
|
||||
|
||||
// Public functions
|
||||
|
||||
setOptionsContext(optionsContext, source) {
|
||||
return this._invoke(false, 'setOptionsContext', {id: this._id, optionsContext, source});
|
||||
}
|
||||
|
||||
hide(_changeFocus) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
async isVisible() {
|
||||
return (this._popupTabId !== null && await api.isTabSearchPopup(this._popupTabId));
|
||||
}
|
||||
|
||||
setVisibleOverride(_value, _priority) {
|
||||
return null;
|
||||
}
|
||||
|
||||
clearVisibleOverride(_token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
async containsPoint(_x, _y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
showContent(_details, displayDetails) {
|
||||
return this._invoke(true, 'setContent', {id: this._id, details: displayDetails});
|
||||
}
|
||||
|
||||
setCustomCss(css) {
|
||||
return this._invoke(false, 'setCustomCss', {id: this._id, css});
|
||||
}
|
||||
|
||||
clearAutoPlayTimer() {
|
||||
return this._invoke(false, 'clearAutoPlayTimer', {id: this._id});
|
||||
}
|
||||
|
||||
setContentScale(_scale) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
isVisibleSync() {
|
||||
throw new Error('Not supported on PopupWindow');
|
||||
}
|
||||
|
||||
updateTheme() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
async setCustomOuterCss(_css, _useWebExtensionApi) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
async setChildrenSupported(_value) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
getFrameRect() {
|
||||
return new DOMRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
async _invoke(open, action, params={}, defaultReturnValue) {
|
||||
if (yomichan.isExtensionUnloaded) {
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
const frameId = 0;
|
||||
if (this._popupTabId !== null) {
|
||||
try {
|
||||
return await api.crossFrame.invokeTab(this._popupTabId, frameId, 'popupMessage', {action, params});
|
||||
} catch (e) {
|
||||
if (yomichan.isExtensionUnloaded) {
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
this._popupTabId = null;
|
||||
}
|
||||
|
||||
if (!open) {
|
||||
return defaultReturnValue;
|
||||
}
|
||||
|
||||
const {tabId} = await api.getOrCreateSearchPopup({focus: 'ifCreated'});
|
||||
this._popupTabId = tabId;
|
||||
|
||||
return await api.crossFrame.invokeTab(this._popupTabId, frameId, 'popupMessage', {action, params});
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@
|
||||
"fg/js/popup-factory.js",
|
||||
"fg/js/frame-offset-forwarder.js",
|
||||
"fg/js/popup-proxy.js",
|
||||
"fg/js/popup-window.js",
|
||||
"fg/js/frontend.js",
|
||||
"fg/js/content-script-main.js"
|
||||
],
|
||||
|
@ -363,6 +363,7 @@ class Display extends EventDispatcher {
|
||||
'/mixed/js/frame-client.js',
|
||||
'/fg/js/popup.js',
|
||||
'/fg/js/popup-proxy.js',
|
||||
'/fg/js/popup-window.js',
|
||||
'/fg/js/popup-factory.js',
|
||||
'/fg/js/frame-offset-forwarder.js',
|
||||
'/fg/js/frontend.js'
|
||||
|
Loading…
Reference in New Issue
Block a user