Display profile panel (#1178)
* Expose Display.displayGenerator * Update search when assigning options context * Don't clear selection unless the popup changes * Merge search styles * Create panel for changing the profile
This commit is contained in:
parent
ae36cccc36
commit
ad90bad057
@ -54,6 +54,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-footer-container1"><div class="content-footer-container2"><div class="content-footer" id="content-footer"></div><div class="scrollbar-spacer scrollbar"></div></div></div>
|
<div class="content-footer-container1"><div class="content-footer-container2"><div class="content-footer" id="content-footer"></div><div class="scrollbar-spacer scrollbar"></div></div></div>
|
||||||
|
<div class="overlay-panel-container">
|
||||||
|
<div class="overlay-panel scrollbar" id="profile-panel" hidden>
|
||||||
|
<div class="overlay-panel-inner">
|
||||||
|
<h3>Default Profile</h3>
|
||||||
|
<div class="profile-list" id="profile-list"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-sidebar scrollbar" id="content-sidebar" hidden>
|
<div class="content-sidebar scrollbar" id="content-sidebar" hidden>
|
||||||
<div class="content-sidebar-inner">
|
<div class="content-sidebar-inner">
|
||||||
@ -65,7 +73,7 @@
|
|||||||
<button class="sidebar-button" disabled id="navigate-next-button" title="Next definition (Alt + F)"><span class="sidebar-button-icon" data-icon="right-chevron"></span></button>
|
<button class="sidebar-button" disabled id="navigate-next-button" title="Next definition (Alt + F)"><span class="sidebar-button-icon" data-icon="right-chevron"></span></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-sidebar-bottom">
|
<div class="content-sidebar-bottom">
|
||||||
<!--<button class="sidebar-button" id="profile-button"><span class="sidebar-button-icon" data-icon="profile"></span></button>-->
|
<button class="sidebar-button" id="profile-button"><span class="sidebar-button-icon" data-icon="profile"></span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -96,10 +104,12 @@
|
|||||||
<script src="/mixed/js/display-generator.js"></script>
|
<script src="/mixed/js/display-generator.js"></script>
|
||||||
<script src="/mixed/js/display-history.js"></script>
|
<script src="/mixed/js/display-history.js"></script>
|
||||||
<script src="/mixed/js/display-notification.js"></script>
|
<script src="/mixed/js/display-notification.js"></script>
|
||||||
|
<script src="/mixed/js/display-profile-selection.js"></script>
|
||||||
<script src="/mixed/js/document-focus-controller.js"></script>
|
<script src="/mixed/js/document-focus-controller.js"></script>
|
||||||
<script src="/mixed/js/dynamic-loader.js"></script>
|
<script src="/mixed/js/dynamic-loader.js"></script>
|
||||||
<script src="/mixed/js/frame-endpoint.js"></script>
|
<script src="/mixed/js/frame-endpoint.js"></script>
|
||||||
<script src="/mixed/js/media-loader.js"></script>
|
<script src="/mixed/js/media-loader.js"></script>
|
||||||
|
<script src="/mixed/js/panel-element.js"></script>
|
||||||
<script src="/mixed/js/scroll.js"></script>
|
<script src="/mixed/js/scroll.js"></script>
|
||||||
<script src="/mixed/js/text-scanner.js"></script>
|
<script src="/mixed/js/text-scanner.js"></script>
|
||||||
<script src="/mixed/js/html-template-collection.js"></script>
|
<script src="/mixed/js/html-template-collection.js"></script>
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
/* global
|
/* global
|
||||||
* Display
|
* Display
|
||||||
|
* DisplayProfileSelection
|
||||||
* DocumentFocusController
|
* DocumentFocusController
|
||||||
* JapaneseUtil
|
* JapaneseUtil
|
||||||
* api
|
* api
|
||||||
@ -33,6 +34,8 @@
|
|||||||
const japaneseUtil = new JapaneseUtil(null);
|
const japaneseUtil = new JapaneseUtil(null);
|
||||||
const display = new Display('popup', japaneseUtil, documentFocusController);
|
const display = new Display('popup', japaneseUtil, documentFocusController);
|
||||||
await display.prepare();
|
await display.prepare();
|
||||||
|
const displayProfileSelection = new DisplayProfileSelection(display);
|
||||||
|
displayProfileSelection.prepare();
|
||||||
display.initializeState();
|
display.initializeState();
|
||||||
|
|
||||||
yomichan.ready();
|
yomichan.ready();
|
||||||
|
@ -349,6 +349,8 @@ class Frontend {
|
|||||||
const {usePopupWindow, showIframePopupsInRootFrame} = this._options.general;
|
const {usePopupWindow, showIframePopupsInRootFrame} = this._options.general;
|
||||||
const isIframe = !this._useProxyPopup && (window !== window.parent);
|
const isIframe = !this._useProxyPopup && (window !== window.parent);
|
||||||
|
|
||||||
|
const currentPopup = this._popup;
|
||||||
|
|
||||||
let popupPromise;
|
let popupPromise;
|
||||||
if (usePopupWindow) {
|
if (usePopupWindow) {
|
||||||
popupPromise = this._popupCache.get('window');
|
popupPromise = this._popupCache.get('window');
|
||||||
@ -393,7 +395,10 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
if (this._updatePopupToken !== token) { return; }
|
if (this._updatePopupToken !== token) { return; }
|
||||||
|
|
||||||
|
if (popup !== currentPopup) {
|
||||||
this._clearSelection(true);
|
this._clearSelection(true);
|
||||||
|
}
|
||||||
|
|
||||||
this._popupEventListeners.removeAllEventListeners();
|
this._popupEventListeners.removeAllEventListeners();
|
||||||
this._popup = popup;
|
this._popup = popup;
|
||||||
if (popup !== null) {
|
if (popup !== null) {
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
--action-button-padding: 0.3em;
|
--action-button-padding: 0.3em;
|
||||||
|
|
||||||
--list-margin: 0.72em;
|
--list-margin: 0.72em;
|
||||||
|
--main-content-size: 100%;
|
||||||
--main-content-vertical-padding: 0em;
|
--main-content-vertical-padding: 0em;
|
||||||
--main-content-horizontal-padding: 0em;
|
--main-content-horizontal-padding: 0em;
|
||||||
--entry-horizontal-padding: 0.72em;
|
--entry-horizontal-padding: 0.72em;
|
||||||
@ -77,6 +78,7 @@
|
|||||||
--entry-current-indicator-triangle-size: calc(1em * (var(--entry-current-indicator-triangle-size-no-units) / var(--font-size-no-units)));
|
--entry-current-indicator-triangle-size: calc(1em * (var(--entry-current-indicator-triangle-size-no-units) / var(--font-size-no-units)));
|
||||||
|
|
||||||
--animation-duration: 0.125s;
|
--animation-duration: 0.125s;
|
||||||
|
--animation-duration2: calc(2 * var(--animation-duration));
|
||||||
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
--background-color: #ffffff;
|
--background-color: #ffffff;
|
||||||
@ -239,6 +241,12 @@ h2 {
|
|||||||
margin: 0.25em 0 0;
|
margin: 0.25em 0 0;
|
||||||
border-bottom: calc(1em / (var(--font-size-no-units) * var(--h2-font-size-no-units))) solid var(--light-border-color);
|
border-bottom: calc(1em / (var(--font-size-no-units) * var(--h2-font-size-no-units))) solid var(--light-border-color);
|
||||||
}
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0.25em 0 0.375em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
color: var(--link-color);
|
color: var(--link-color);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -323,7 +331,10 @@ a {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.content-body-inner {
|
.content-body-inner {
|
||||||
width: 100%;
|
width: var(--main-content-size);
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0 auto;
|
||||||
padding: var(--main-content-vertical-padding) var(--main-content-horizontal-padding);
|
padding: var(--main-content-vertical-padding) var(--main-content-horizontal-padding);
|
||||||
}
|
}
|
||||||
.content-footer-container1 {
|
.content-footer-container1 {
|
||||||
@ -344,8 +355,8 @@ a {
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
.content-footer {
|
.content-footer {
|
||||||
max-width: var(--main-content-size);
|
width: var(--main-content-size);
|
||||||
width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -365,7 +376,7 @@ a {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background-color: var(--sidebar-background-color);
|
background-color: var(--sidebar-background-color);
|
||||||
z-index: 1;
|
z-index: 10;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -502,6 +513,9 @@ button.sidebar-button.danger:hover .sidebar-button-icon,
|
|||||||
button.sidebar-button.danger:focus .sidebar-button-icon {
|
button.sidebar-button.danger:focus .sidebar-button-icon {
|
||||||
background-color: var(--sidebar-button-danger-icon-color);
|
background-color: var(--sidebar-button-danger-icon-color);
|
||||||
}
|
}
|
||||||
|
button.sidebar-button.sidebar-button-highlight>.sidebar-button-icon {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
.sidebar-button-icon[data-icon=cross] {
|
.sidebar-button-icon[data-icon=cross] {
|
||||||
mask-image: url(/mixed/img/cross.svg);
|
mask-image: url(/mixed/img/cross.svg);
|
||||||
-webkit-mask-image: url(/mixed/img/cross.svg);
|
-webkit-mask-image: url(/mixed/img/cross.svg);
|
||||||
@ -1459,6 +1473,78 @@ button.action-button[data-icon=source-term]::before {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.overlay-panel-container {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 6;
|
||||||
|
}
|
||||||
|
.overlay-panel {
|
||||||
|
pointer-events: auto;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: var(--main-content-size);
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: var(--main-content-vertical-padding) var(--main-content-horizontal-padding);
|
||||||
|
overflow-y: scroll;
|
||||||
|
transform: none;
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
transition:
|
||||||
|
opacity var(--animation-duration2) ease-out,
|
||||||
|
visibility 0s linear,
|
||||||
|
transform var(--animation-duration2) ease-out;
|
||||||
|
}
|
||||||
|
.overlay-panel[hidden] {
|
||||||
|
transform: translate(4em, 0);
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition:
|
||||||
|
opacity var(--animation-duration2) ease-in,
|
||||||
|
visibility 0s linear var(--animation-duration2),
|
||||||
|
transform var(--animation-duration2) ease-in;
|
||||||
|
}
|
||||||
|
.overlay-panel[hidden]:not(.hidden-animating) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.overlay-panel-inner {
|
||||||
|
padding: var(--entry-vertical-padding) var(--entry-horizontal-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Profile panel */
|
||||||
|
.profile-list {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.profile-list-item {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.profile-list-item-selection {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.25em 0.5em 0.25em 0;
|
||||||
|
}
|
||||||
|
.profile-list-item-name {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: 0.25em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Conditional styles */
|
/* Conditional styles */
|
||||||
:root:not([data-enable-search-tags=true]) .tag[data-category=search] {
|
:root:not([data-enable-search-tags=true]) .tag[data-category=search] {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -57,14 +57,6 @@ h1 {
|
|||||||
border-bottom: calc(1em / (var(--font-size-no-units) * 2)) solid var(--separator-color1);
|
border-bottom: calc(1em / (var(--font-size-no-units) * 2)) solid var(--separator-color1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Content layout */
|
|
||||||
.content-body-inner {
|
|
||||||
width: var(--main-content-size);
|
|
||||||
max-width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search bar */
|
/* Search bar */
|
||||||
.search-textbox-container {
|
.search-textbox-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -129,5 +129,9 @@
|
|||||||
<div class="footer-notification-body"></div>
|
<div class="footer-notification-body"></div>
|
||||||
<button class="footer-notification-close-button"><span class="footer-notification-close-button-icon"></span></button>
|
<button class="footer-notification-close-button"><span class="footer-notification-close-button-icon"></span></button>
|
||||||
</div></template>
|
</div></template>
|
||||||
|
<template id="profile-list-item-template"><label class="profile-list-item">
|
||||||
|
<div class="profile-list-item-selection"><label class="radio"><input type="radio" class="profile-entry-is-default-radio" name="profile-entry-default-radio"><span class="radio-body"><span class="radio-border"></span><span class="radio-dot"></span></span></label></div>
|
||||||
|
<div class="profile-list-item-name"></div>
|
||||||
|
</label></template>
|
||||||
|
|
||||||
</body></html>
|
</body></html>
|
||||||
|
@ -121,6 +121,10 @@ class DisplayGenerator {
|
|||||||
return this._templates.instantiate('footer-notification');
|
return this._templates.instantiate('footer-notification');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createProfileListItem() {
|
||||||
|
return this._templates.instantiate('profile-list-item');
|
||||||
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
_createTermExpression(details) {
|
_createTermExpression(details) {
|
||||||
|
105
ext/mixed/js/display-profile-selection.js
Normal file
105
ext/mixed/js/display-profile-selection.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* PanelElement
|
||||||
|
* api
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DisplayProfileSelection {
|
||||||
|
constructor(display) {
|
||||||
|
this._display = display;
|
||||||
|
this._profielList = document.querySelector('#profile-list');
|
||||||
|
this._profileButton = document.querySelector('#profile-button');
|
||||||
|
this._profilePanel = new PanelElement({
|
||||||
|
node: document.querySelector('#profile-panel'),
|
||||||
|
closingAnimationDuration: 375 // Milliseconds; includes buffer
|
||||||
|
});
|
||||||
|
this._profileListNeedsUpdate = false;
|
||||||
|
this._eventListeners = new EventListenerCollection();
|
||||||
|
this._source = generateId(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
async prepare() {
|
||||||
|
yomichan.on('optionsUpdated', this._onOptionsUpdated.bind(this));
|
||||||
|
this._profileButton.addEventListener('click', this._onProfileButtonClick.bind(this), false);
|
||||||
|
this._profileListNeedsUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
|
|
||||||
|
_onOptionsUpdated({source}) {
|
||||||
|
if (source === this._source) { return; }
|
||||||
|
this._profileListNeedsUpdate = true;
|
||||||
|
if (this._profilePanel.isVisible()) {
|
||||||
|
this._updateProfileList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onProfileButtonClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this._setProfilePanelVisible(!this._profilePanel.isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
_setProfilePanelVisible(visible) {
|
||||||
|
this._profilePanel.setVisible(visible);
|
||||||
|
this._profileButton.classList.toggle('sidebar-button-highlight', visible);
|
||||||
|
if (visible && this._profileListNeedsUpdate) {
|
||||||
|
this._updateProfileList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _updateProfileList() {
|
||||||
|
this._profileListNeedsUpdate = false;
|
||||||
|
const options = await api.optionsGetFull();
|
||||||
|
|
||||||
|
this._eventListeners.removeAllEventListeners();
|
||||||
|
const displayGenerator = this._display.displayGenerator;
|
||||||
|
|
||||||
|
const {profileCurrent, profiles} = options;
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
for (let i = 0, ii = profiles.length; i < ii; ++i) {
|
||||||
|
const {name} = profiles[i];
|
||||||
|
const entry = displayGenerator.createProfileListItem();
|
||||||
|
const radio = entry.querySelector('.profile-entry-is-default-radio');
|
||||||
|
radio.checked = (i === profileCurrent);
|
||||||
|
const nameNode = entry.querySelector('.profile-list-item-name');
|
||||||
|
nameNode.textContent = name;
|
||||||
|
fragment.appendChild(entry);
|
||||||
|
this._eventListeners.addEventListener(radio, 'change', this._onProfileRadioChange.bind(this, i), false);
|
||||||
|
}
|
||||||
|
this._profielList.textContent = '';
|
||||||
|
this._profielList.appendChild(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onProfileRadioChange(index, e) {
|
||||||
|
if (e.currentTarget.checked) {
|
||||||
|
this._setProfileCurrent(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _setProfileCurrent(index) {
|
||||||
|
await api.modifySettings([{
|
||||||
|
action: 'set',
|
||||||
|
path: 'profileCurrent',
|
||||||
|
value: index,
|
||||||
|
scope: 'global'
|
||||||
|
}], this._source);
|
||||||
|
this._setProfilePanelVisible(false);
|
||||||
|
}
|
||||||
|
}
|
@ -170,6 +170,10 @@ class Display extends EventDispatcher {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get displayGenerator() {
|
||||||
|
return this._displayGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
get autoPlayAudioDelay() {
|
get autoPlayAudioDelay() {
|
||||||
return this._autoPlayAudioDelay;
|
return this._autoPlayAudioDelay;
|
||||||
}
|
}
|
||||||
@ -523,6 +527,7 @@ class Display extends EventDispatcher {
|
|||||||
|
|
||||||
_onMessageSetOptionsContext({optionsContext}) {
|
_onMessageSetOptionsContext({optionsContext}) {
|
||||||
this.setOptionsContext(optionsContext);
|
this.setOptionsContext(optionsContext);
|
||||||
|
this.searchLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMessageSetContent({details}) {
|
_onMessageSetContent({details}) {
|
||||||
|
Loading…
Reference in New Issue
Block a user