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/popup-factory.js",
|
||||||
"fg/js/frame-offset-forwarder.js",
|
"fg/js/frame-offset-forwarder.js",
|
||||||
"fg/js/popup-proxy.js",
|
"fg/js/popup-proxy.js",
|
||||||
|
"fg/js/popup-window.js",
|
||||||
"fg/js/frontend.js",
|
"fg/js/frontend.js",
|
||||||
"fg/js/content-script-main.js"
|
"fg/js/content-script-main.js"
|
||||||
],
|
],
|
||||||
|
@ -111,7 +111,8 @@
|
|||||||
"showPitchAccentGraph",
|
"showPitchAccentGraph",
|
||||||
"showIframePopupsInRootFrame",
|
"showIframePopupsInRootFrame",
|
||||||
"useSecurePopupFrameUrl",
|
"useSecurePopupFrameUrl",
|
||||||
"usePopupShadowDom"
|
"usePopupShadowDom",
|
||||||
|
"usePopupWindow"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"enable": {
|
"enable": {
|
||||||
@ -257,6 +258,10 @@
|
|||||||
"usePopupShadowDom": {
|
"usePopupShadowDom": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true
|
"default": true
|
||||||
|
},
|
||||||
|
"usePopupWindow": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -467,6 +467,7 @@ class OptionsUtil {
|
|||||||
static _updateVersion4(options) {
|
static _updateVersion4(options) {
|
||||||
// Version 4 changes:
|
// Version 4 changes:
|
||||||
// Options conditions converted to string representations.
|
// Options conditions converted to string representations.
|
||||||
|
// Added usePopupWindow.
|
||||||
for (const {conditionGroups} of options.profiles) {
|
for (const {conditionGroups} of options.profiles) {
|
||||||
for (const {conditions} of conditionGroups) {
|
for (const {conditions} of conditionGroups) {
|
||||||
for (const condition of conditions) {
|
for (const condition of conditions) {
|
||||||
@ -479,6 +480,9 @@ class OptionsUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const {options: profileOptions} of options.profiles) {
|
||||||
|
profileOptions.general.usePopupWindow = false;
|
||||||
|
}
|
||||||
return options;
|
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>
|
<label><input type="checkbox" id="show-iframe-popups-in-root-frame" data-setting="general.showIframePopupsInRootFrame"> Show iframe popups in root frame</label>
|
||||||
</div>
|
</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">
|
<div class="checkbox options-advanced">
|
||||||
<label><input type="checkbox" data-setting="general.useSecurePopupFrameUrl"> Use secure popup frame URL</label>
|
<label><input type="checkbox" data-setting="general.useSecurePopupFrameUrl"> Use secure popup frame URL</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -307,11 +307,17 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _updatePopup() {
|
async _updatePopup() {
|
||||||
const showIframePopupsInRootFrame = this._options.general.showIframePopupsInRootFrame;
|
const {usePopupWindow, showIframePopupsInRootFrame} = this._options.general;
|
||||||
const isIframe = !this._useProxyPopup && (window !== window.parent);
|
const isIframe = !this._useProxyPopup && (window !== window.parent);
|
||||||
|
|
||||||
let popupPromise;
|
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 &&
|
isIframe &&
|
||||||
showIframePopupsInRootFrame &&
|
showIframePopupsInRootFrame &&
|
||||||
DocumentUtil.getFullscreenElement() === null &&
|
DocumentUtil.getFullscreenElement() === null &&
|
||||||
@ -404,6 +410,14 @@ class Frontend {
|
|||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _getPopupWindow() {
|
||||||
|
return await this._popupFactory.getOrCreatePopup({
|
||||||
|
ownerFrameId: this._frameId,
|
||||||
|
depth: this._depth,
|
||||||
|
popupWindow: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_ignoreElements() {
|
_ignoreElements() {
|
||||||
if (this._popup !== null) {
|
if (this._popup !== null) {
|
||||||
const container = this._popup.container;
|
const container = this._popup.container;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
* FrameOffsetForwarder
|
* FrameOffsetForwarder
|
||||||
* Popup
|
* Popup
|
||||||
* PopupProxy
|
* PopupProxy
|
||||||
|
* PopupWindow
|
||||||
* api
|
* 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
|
// Find by existing id
|
||||||
if (id !== null) {
|
if (id !== null) {
|
||||||
const popup = this._popups.get(id);
|
const popup = this._popups.get(id);
|
||||||
@ -85,7 +86,15 @@ class PopupFactory {
|
|||||||
depth = 0;
|
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
|
// New unique id
|
||||||
if (id === null) {
|
if (id === null) {
|
||||||
id = generateId(16);
|
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/popup-factory.js",
|
||||||
"fg/js/frame-offset-forwarder.js",
|
"fg/js/frame-offset-forwarder.js",
|
||||||
"fg/js/popup-proxy.js",
|
"fg/js/popup-proxy.js",
|
||||||
|
"fg/js/popup-window.js",
|
||||||
"fg/js/frontend.js",
|
"fg/js/frontend.js",
|
||||||
"fg/js/content-script-main.js"
|
"fg/js/content-script-main.js"
|
||||||
],
|
],
|
||||||
|
@ -363,6 +363,7 @@ class Display extends EventDispatcher {
|
|||||||
'/mixed/js/frame-client.js',
|
'/mixed/js/frame-client.js',
|
||||||
'/fg/js/popup.js',
|
'/fg/js/popup.js',
|
||||||
'/fg/js/popup-proxy.js',
|
'/fg/js/popup-proxy.js',
|
||||||
|
'/fg/js/popup-window.js',
|
||||||
'/fg/js/popup-factory.js',
|
'/fg/js/popup-factory.js',
|
||||||
'/fg/js/frame-offset-forwarder.js',
|
'/fg/js/frame-offset-forwarder.js',
|
||||||
'/fg/js/frontend.js'
|
'/fg/js/frontend.js'
|
||||||
|
Loading…
Reference in New Issue
Block a user