Popup window options (#1245)

* Add popupWindow options

* Add toBoolean converter

* Add settings

* Use new options

* Add test link

* Fix window state not working

* Make the window section advanced only
This commit is contained in:
toasted-nutbread 2021-01-16 10:22:24 -05:00 committed by GitHub
parent dc4d659184
commit 8766744aa4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 295 additions and 23 deletions

View File

@ -230,7 +230,7 @@ h3 {
font-size: calc(1em / 1.125); font-size: calc(1em / 1.125);
color: var(--text-color-light); color: var(--text-color-light);
} }
.heading-link-light { a.heading-link-light {
color: var(--text-color-light); color: var(--text-color-light);
} }
.heading-description, .heading-description,

View File

@ -63,6 +63,7 @@
"type": "object", "type": "object",
"required": [ "required": [
"general", "general",
"popupWindow",
"audio", "audio",
"scanning", "scanning",
"translation", "translation",
@ -288,6 +289,57 @@
} }
} }
}, },
"popupWindow": {
"type": "object",
"required": [
"width",
"height",
"left",
"top",
"useLeft",
"useTop",
"windowType",
"windowState"
],
"properties": {
"width": {
"type": "integer",
"minimum": 0,
"default": 400
},
"height": {
"type": "integer",
"minimum": 0,
"default": 250
},
"left": {
"type": "integer",
"default": 0
},
"top": {
"type": "integer",
"default": 0
},
"useLeft": {
"type": "boolean",
"default": false
},
"useTop": {
"type": "boolean",
"default": false
},
"windowType": {
"type": "string",
"enum": ["normal", "popup"],
"default": "popup"
},
"windowState": {
"type": "string",
"enum": ["normal", "maximized", "fullscreen"],
"default": "normal"
}
}
},
"audio": { "audio": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@ -818,25 +818,12 @@ class Backend {
// Create a new window // Create a new window
const options = this.getOptions({current: true}); const options = this.getOptions({current: true});
const {popupWidth, popupHeight} = options.general; const createData = this._getSearchPopupWindowCreateData(baseUrl, options);
const popupWindow = await new Promise((resolve, reject) => { const {popupWindow: {windowState}} = options;
chrome.windows.create( const popupWindow = await this._createWindow(createData);
{ if (windowState !== 'normal') {
url: baseUrl, await this._updateWindow(popupWindow.id, {state: windowState});
width: popupWidth,
height: popupHeight,
type: 'popup'
},
(result) => {
const error = chrome.runtime.lastError;
if (error) {
reject(new Error(error.message));
} else {
resolve(result);
} }
}
);
});
const {tabs} = popupWindow; const {tabs} = popupWindow;
if (tabs.length === 0) { if (tabs.length === 0) {
@ -856,6 +843,52 @@ class Backend {
return {tab, created: true}; return {tab, created: true};
} }
_getSearchPopupWindowCreateData(url, options) {
const {popupWindow: {width, height, left, top, useLeft, useTop, windowType}} = options;
return {
url,
width,
height,
left: useLeft ? left : void 0,
top: useTop ? top : void 0,
type: windowType,
state: 'normal'
};
}
_createWindow(createData) {
return new Promise((resolve, reject) => {
chrome.windows.create(
createData,
(result) => {
const error = chrome.runtime.lastError;
if (error) {
reject(new Error(error.message));
} else {
resolve(result);
}
}
);
});
}
_updateWindow(windowId, updateInfo) {
return new Promise((resolve, reject) => {
chrome.windows.update(
windowId,
updateInfo,
(result) => {
const error = chrome.runtime.lastError;
if (error) {
reject(new Error(error.message));
} else {
resolve(result);
}
}
);
});
}
_updateSearchQuery(tabId, text, animate) { _updateSearchQuery(tabId, text, animate) {
return this._sendMessageTabPromise( return this._sendMessageTabPromise(
tabId, tabId,

View File

@ -689,6 +689,7 @@ class OptionsUtil {
// Changed general.popupActionBarLocation. // Changed general.popupActionBarLocation.
// Added inputs.hotkeys. // Added inputs.hotkeys.
// Added anki.suspendNewCards. // Added anki.suspendNewCards.
// Added popupWindow.
for (const profile of options.profiles) { for (const profile of options.profiles) {
profile.options.translation.textReplacements = { profile.options.translation.textReplacements = {
searchOriginal: true, searchOriginal: true,
@ -735,6 +736,16 @@ class OptionsUtil {
] ]
}; };
profile.options.anki.suspendNewCards = false; profile.options.anki.suspendNewCards = false;
profile.options.popupWindow = {
width: profile.options.general.popupWidth,
height: profile.options.general.popupHeight,
left: 0,
top: 0,
useLeft: false,
useTop: false,
windowType: 'popup',
windowState: 'normal'
};
} }
return options; return options;
} }

View File

@ -36,6 +36,7 @@ class GenericSettingController {
['splitTags', this._splitTags.bind(this)], ['splitTags', this._splitTags.bind(this)],
['joinTags', this._joinTags.bind(this)], ['joinTags', this._joinTags.bind(this)],
['toNumber', this._toNumber.bind(this)], ['toNumber', this._toNumber.bind(this)],
['toBoolean', this._toBoolean.bind(this)],
['toString', this._toString.bind(this)], ['toString', this._toString.bind(this)],
['conditionalConvert', this._conditionalConvert.bind(this)] ['conditionalConvert', this._conditionalConvert.bind(this)]
]); ]);
@ -206,6 +207,10 @@ class GenericSettingController {
return DOMDataBinder.convertToNumber(value, constraints); return DOMDataBinder.convertToNumber(value, constraints);
} }
_toBoolean(value) {
return (value === 'true');
}
_toString(value) { _toString(value) {
return `${value}`; return `${value}`;
} }

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2021 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 PopupWindowController {
prepare() {
const testLink = document.querySelector('#test-window-open-link');
testLink.addEventListener('click', this._onTestWindowOpenLinkClick.bind(this), false);
}
// Private
_onTestWindowOpenLinkClick(e) {
e.preventDefault();
this._testWindowOpen();
}
async _testWindowOpen() {
await api.getOrCreateSearchPopup({focus: true});
}
}

View File

@ -29,6 +29,7 @@
* ModalController * ModalController
* NestedPopupsController * NestedPopupsController
* PopupPreviewController * PopupPreviewController
* PopupWindowController
* ProfileController * ProfileController
* ScanInputsController * ScanInputsController
* ScanInputsSimpleController * ScanInputsSimpleController
@ -132,6 +133,9 @@ async function setupGenericSettingsController(genericSettingController) {
const keyboardShortcutController = new KeyboardShortcutController(settingsController); const keyboardShortcutController = new KeyboardShortcutController(settingsController);
keyboardShortcutController.prepare(); keyboardShortcutController.prepare();
const popupWindowController = new PopupWindowController();
popupWindowController.prepare();
await Promise.all(preparePromises); await Promise.all(preparePromises);
document.documentElement.dataset.loaded = 'true'; document.documentElement.dataset.loaded = 'true';

View File

@ -28,7 +28,7 @@
<a href="#!popup" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="popup"></span></span><span class="outline-item-label">Popup</span></a> <a href="#!popup" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="popup"></span></span><span class="outline-item-label">Popup</span></a>
<a href="#!popup-appearance" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="palette"></span></span><span class="outline-item-label">Appearance</span></a> <a href="#!popup-appearance" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="palette"></span></span><span class="outline-item-label">Appearance</span></a>
<a href="#!popup-size" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="popup-size"></span></span><span class="outline-item-label">Position &amp; Size</span></a> <a href="#!popup-size" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="popup-size"></span></span><span class="outline-item-label">Position &amp; Size</span></a>
<a href="#!window" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="window"></span></span><span class="outline-item-label">Window</span></a> <a href="#!window" class="outline-item advanced-only"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="window"></span></span><span class="outline-item-label">Window</span></a>
<a href="#!audio" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="speaker"></span></span><span class="outline-item-label">Audio</span></a> <a href="#!audio" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="speaker"></span></span><span class="outline-item-label">Audio</span></a>
<a href="#!text-parsing" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="text-parsing"></span></span><span class="outline-item-label">Text Parsing</span></a> <a href="#!text-parsing" class="outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="text-parsing"></span></span><span class="outline-item-label">Text Parsing</span></a>
<a href="#!sentence-parsing" class="outline-item advanced-only"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="sentence-parsing"></span></span><span class="outline-item-label">Sentence Parsing</span></a> <a href="#!sentence-parsing" class="outline-item advanced-only"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="sentence-parsing"></span></span><span class="outline-item-label">Sentence Parsing</span></a>
@ -921,11 +921,12 @@
</div> </div>
<!-- Window --> <!-- Window -->
<div class="heading-container"> <div class="heading-container advanced-only">
<div class="heading-container-icon"><span class="icon" data-icon="window"></span></div> <div class="heading-container-icon"><span class="icon" data-icon="window"></span></div>
<div class="heading-container-left"><h2 id="window"><a href="#!window">Window</a></h2></div> <div class="heading-container-left"><h2 id="window"><a href="#!window">Window</a></h2></div>
<div class="heading-container-right"><a class="heading-link-light" id="test-window-open-link">Open&hellip;</a></div>
</div> </div>
<div class="settings-group"> <div class="settings-group advanced-only">
<div class="settings-item"> <div class="settings-item">
<div class="settings-item-inner"> <div class="settings-item-inner">
<div class="settings-item-left"> <div class="settings-item-left">
@ -989,6 +990,123 @@
<input type="number" min="0" step="1" data-setting="general.maximumClipboardSearchLength"> <input type="number" min="0" step="1" data-setting="general.maximumClipboardSearchLength">
</div> </div>
</div></div> </div></div>
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left">
<div class="settings-item-label">Size</div>
<div class="settings-item-description">Control the size of the window, in pixels.</div>
</div>
<div class="settings-item-right">
<div class="settings-item-group">
<div class="settings-item-group-item">
<div class="settings-item-group-item-label">Width</div>
<input type="number" class="short-width short-height" min="0" step="1" data-setting="popupWindow.width">
</div>
<div class="settings-item-group-item">
<div class="settings-item-group-item-label">Height</div>
<input type="number" class="short-width short-height" min="0" step="1" data-setting="popupWindow.height">
</div>
</div>
</div>
</div></div>
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left">
<div class="settings-item-label">Left position</div>
<div class="settings-item-description">Control the left position of the window, in pixels.</div>
</div>
<div class="settings-item-right">
<div class="settings-item-group">
<div class="settings-item-group-item" id="popup-window-left-container" hidden>
<div class="settings-item-group-item-label">x</div>
<input type="number" class="short-width short-height" step="1" data-setting="popupWindow.left">
</div>
<div class="settings-item-group-item">
<div class="settings-item-group-item-label">Mode</div>
<select class="short-width short-height" data-setting="popupWindow.useLeft"
data-transform='[
{
"step": "pre",
"type": "toBoolean"
},
{
"type": "setVisibility",
"selector": "#popup-window-left-container",
"condition": {"op": "===", "value": true}
},
{
"step": "post",
"type": "toString"
}
]'
>
<option value="false">Auto</option>
<option value="true">Manual</option>
</select>
</div>
</div>
</div>
</div></div>
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left">
<div class="settings-item-label">Top position</div>
<div class="settings-item-description">Control the top position of the window, in pixels.</div>
</div>
<div class="settings-item-right">
<div class="settings-item-group">
<div class="settings-item-group-item" id="popup-window-top-container" hidden>
<div class="settings-item-group-item-label">y</div>
<input type="number" class="short-width short-height" step="1" data-setting="popupWindow.top">
</div>
<div class="settings-item-group-item">
<div class="settings-item-group-item-label">Mode</div>
<select class="short-width short-height" data-setting="popupWindow.useTop"
data-transform='[
{
"step": "pre",
"type": "toBoolean"
},
{
"type": "setVisibility",
"selector": "#popup-window-top-container",
"condition": {"op": "===", "value": true}
},
{
"step": "post",
"type": "toString"
}
]'
>
<option value="false">Auto</option>
<option value="true">Manual</option>
</select>
</div>
</div>
</div>
</div></div>
<div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable">
<div class="settings-item-left">
<div class="settings-item-label">Window style</div>
<div class="settings-item-description">Change the appearance of the window.</div>
</div>
<div class="settings-item-right">
<div class="settings-item-group">
<div class="settings-item-group-item">
<div class="settings-item-group-item-label">Type</div>
<select class="short-width short-height" data-setting="popupWindow.windowType">
<option value="normal">Normal</option>
<option value="popup">Popup</option>
</select>
</div>
<div class="settings-item-group-item">
<div class="settings-item-group-item-label">State</div>
<select class="short-width short-height" data-setting="popupWindow.windowState">
<option value="normal">Normal</option>
<option value="maximized">Maximized</option>
<option value="fullscreen">Fullscreen</option>
</select>
</div>
</div>
</div>
</div></div>
</div> </div>
<!-- Audio --> <!-- Audio -->
@ -2971,6 +3089,7 @@
<script src="/bg/js/settings2/keyboard-shortcuts-controller.js"></script> <script src="/bg/js/settings2/keyboard-shortcuts-controller.js"></script>
<script src="/bg/js/settings2/nested-popups-controller.js"></script> <script src="/bg/js/settings2/nested-popups-controller.js"></script>
<script src="/bg/js/settings2/popup-window-controller.js"></script>
<script src="/bg/js/settings2/secondary-search-dictionary-controller.js"></script> <script src="/bg/js/settings2/secondary-search-dictionary-controller.js"></script>
<script src="/bg/js/settings2/sentence-termination-characters-controller.js"></script> <script src="/bg/js/settings2/sentence-termination-characters-controller.js"></script>
<script src="/bg/js/settings2/settings-display-controller.js"></script> <script src="/bg/js/settings2/settings-display-controller.js"></script>

View File

@ -457,6 +457,16 @@ function createProfileOptionsUpdatedTestData1() {
{action: 'viewNote', key: 'KeyV', modifiers: ['alt'], scopes: ['popup', 'search'], enabled: true}, {action: 'viewNote', key: 'KeyV', modifiers: ['alt'], scopes: ['popup', 'search'], enabled: true},
{action: 'copyHostSelection', key: 'KeyC', modifiers: ['ctrl'], scopes: ['popup', 'search'], enabled: true} {action: 'copyHostSelection', key: 'KeyC', modifiers: ['ctrl'], scopes: ['popup', 'search'], enabled: true}
] ]
},
popupWindow: {
width: 400,
height: 250,
left: 0,
top: 0,
useLeft: false,
useTop: false,
windowType: 'popup',
windowState: 'normal'
} }
}; };
} }