summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/fg/float.html12
-rw-r--r--ext/fg/js/float-main.js3
-rw-r--r--ext/fg/js/frontend.js7
-rw-r--r--ext/mixed/css/display.css94
-rw-r--r--ext/mixed/css/search.css8
-rw-r--r--ext/mixed/display-templates.html4
-rw-r--r--ext/mixed/js/display-generator.js4
-rw-r--r--ext/mixed/js/display-profile-selection.js105
-rw-r--r--ext/mixed/js/display.js5
9 files changed, 228 insertions, 14 deletions
diff --git a/ext/fg/float.html b/ext/fg/float.html
index d3c9ba27..e4f30d83 100644
--- a/ext/fg/float.html
+++ b/ext/fg/float.html
@@ -54,6 +54,14 @@
</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 class="content-sidebar scrollbar" id="content-sidebar" hidden>
<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>
</div>
<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>
@@ -96,10 +104,12 @@
<script src="/mixed/js/display-generator.js"></script>
<script src="/mixed/js/display-history.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/dynamic-loader.js"></script>
<script src="/mixed/js/frame-endpoint.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/text-scanner.js"></script>
<script src="/mixed/js/html-template-collection.js"></script>
diff --git a/ext/fg/js/float-main.js b/ext/fg/js/float-main.js
index aee736a2..a8b3d1b0 100644
--- a/ext/fg/js/float-main.js
+++ b/ext/fg/js/float-main.js
@@ -17,6 +17,7 @@
/* global
* Display
+ * DisplayProfileSelection
* DocumentFocusController
* JapaneseUtil
* api
@@ -33,6 +34,8 @@
const japaneseUtil = new JapaneseUtil(null);
const display = new Display('popup', japaneseUtil, documentFocusController);
await display.prepare();
+ const displayProfileSelection = new DisplayProfileSelection(display);
+ displayProfileSelection.prepare();
display.initializeState();
yomichan.ready();
diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js
index cb105341..c9b30d8b 100644
--- a/ext/fg/js/frontend.js
+++ b/ext/fg/js/frontend.js
@@ -349,6 +349,8 @@ class Frontend {
const {usePopupWindow, showIframePopupsInRootFrame} = this._options.general;
const isIframe = !this._useProxyPopup && (window !== window.parent);
+ const currentPopup = this._popup;
+
let popupPromise;
if (usePopupWindow) {
popupPromise = this._popupCache.get('window');
@@ -393,7 +395,10 @@ class Frontend {
}
if (this._updatePopupToken !== token) { return; }
- this._clearSelection(true);
+ if (popup !== currentPopup) {
+ this._clearSelection(true);
+ }
+
this._popupEventListeners.removeAllEventListeners();
this._popup = popup;
if (popup !== null) {
diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css
index 63eb6cb3..8ebdf756 100644
--- a/ext/mixed/css/display.css
+++ b/ext/mixed/css/display.css
@@ -38,6 +38,7 @@
--action-button-padding: 0.3em;
--list-margin: 0.72em;
+ --main-content-size: 100%;
--main-content-vertical-padding: 0em;
--main-content-horizontal-padding: 0em;
--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)));
--animation-duration: 0.125s;
+ --animation-duration2: calc(2 * var(--animation-duration));
/* Colors */
--background-color: #ffffff;
@@ -239,6 +241,12 @@ h2 {
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);
}
+h3 {
+ font-size: 1em;
+ font-weight: bold;
+ margin: 0.25em 0 0.375em;
+ padding: 0;
+}
a {
color: var(--link-color);
text-decoration: underline;
@@ -323,7 +331,10 @@ a {
position: relative;
}
.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);
}
.content-footer-container1 {
@@ -344,8 +355,8 @@ a {
flex: 1 1 auto;
}
.content-footer {
- max-width: var(--main-content-size);
- width: 100%;
+ width: var(--main-content-size);
+ max-width: 100%;
}
@@ -365,7 +376,7 @@ a {
overflow-x: hidden;
overflow-y: auto;
background-color: var(--sidebar-background-color);
- z-index: 1;
+ z-index: 10;
position: relative;
display: block;
}
@@ -502,6 +513,9 @@ button.sidebar-button.danger:hover .sidebar-button-icon,
button.sidebar-button.danger:focus .sidebar-button-icon {
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] {
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 */
:root:not([data-enable-search-tags=true]) .tag[data-category=search] {
display: none;
diff --git a/ext/mixed/css/search.css b/ext/mixed/css/search.css
index 5d4a8f78..6527f920 100644
--- a/ext/mixed/css/search.css
+++ b/ext/mixed/css/search.css
@@ -57,14 +57,6 @@ h1 {
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-textbox-container {
display: flex;
diff --git a/ext/mixed/display-templates.html b/ext/mixed/display-templates.html
index 26252634..b24ab09f 100644
--- a/ext/mixed/display-templates.html
+++ b/ext/mixed/display-templates.html
@@ -129,5 +129,9 @@
<div class="footer-notification-body"></div>
<button class="footer-notification-close-button"><span class="footer-notification-close-button-icon"></span></button>
</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>
diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js
index 1ccd5941..d25b7def 100644
--- a/ext/mixed/js/display-generator.js
+++ b/ext/mixed/js/display-generator.js
@@ -121,6 +121,10 @@ class DisplayGenerator {
return this._templates.instantiate('footer-notification');
}
+ createProfileListItem() {
+ return this._templates.instantiate('profile-list-item');
+ }
+
// Private
_createTermExpression(details) {
diff --git a/ext/mixed/js/display-profile-selection.js b/ext/mixed/js/display-profile-selection.js
new file mode 100644
index 00000000..b66099ff
--- /dev/null
+++ b/ext/mixed/js/display-profile-selection.js
@@ -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);
+ }
+}
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index b9ea3802..c0d84dce 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -170,6 +170,10 @@ class Display extends EventDispatcher {
]);
}
+ get displayGenerator() {
+ return this._displayGenerator;
+ }
+
get autoPlayAudioDelay() {
return this._autoPlayAudioDelay;
}
@@ -523,6 +527,7 @@ class Display extends EventDispatcher {
_onMessageSetOptionsContext({optionsContext}) {
this.setOptionsContext(optionsContext);
+ this.searchLast();
}
_onMessageSetContent({details}) {