Context popup improvements (#1039)

* Refactor context-main.js

* Simplify tags

* Use flex layout

* Use image masks for icons, update styles

* Remove old classes

* Add profile button

* Add support for profile selection

* Add title

* Swap the options and search link order

* Fix title
This commit is contained in:
toasted-nutbread 2020-11-19 18:37:02 -05:00 committed by GitHub
parent b0a5650625
commit e5255a03e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 183 additions and 66 deletions

View File

@ -2,7 +2,8 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1" /> <meta name="viewport" content="width=device-width,initial-scale=1">
<title>Yomichan Action Popup</title>
<link rel="icon" type="image/png" href="/mixed/img/icon16.png" sizes="16x16"> <link rel="icon" type="image/png" href="/mixed/img/icon16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/mixed/img/icon19.png" sizes="19x19"> <link rel="icon" type="image/png" href="/mixed/img/icon19.png" sizes="19x19">
<link rel="icon" type="image/png" href="/mixed/img/icon32.png" sizes="32x32"> <link rel="icon" type="image/png" href="/mixed/img/icon32.png" sizes="32x32">
@ -19,13 +20,18 @@
<input type="checkbox" id="enable-search"> <input type="checkbox" id="enable-search">
<div class="toggle-group"> <div class="toggle-group">
<span class="toggle-on">On</span> <span class="toggle-on">On</span>
<span class="btnx btn-defaulxt toggle-off">Off</span> <span class="toggle-off">Off</span>
<span class="btnx xbtn-default toggle-handle"></span> <span class="toggle-handle"></span>
</div> </div>
</label> </label>
<div class="nav-button-container"> <div class="nav-button-container">
<a class="nav-button action-open-search" data-icon="magnifying-glass" title="Search (Alt + Insert)&#10;(Middle click to open in new tab)"></a> <button class="nav-button action-select-profile" data-icon="profile" title="Change primary profile">
<span class="profile-select-container"><select class="profile-select" id="profile-select">
<optgroup label="Primary Profile" id="profile-select-option-group"></optgroup>
</select></span>
</button>
<a class="nav-button action-open-options" data-icon="cog" title="Options&#10;(Middle click to open in new tab)"></a> <a class="nav-button action-open-options" data-icon="cog" title="Options&#10;(Middle click to open in new tab)"></a>
<a class="nav-button action-open-search" data-icon="magnifying-glass" title="Search (Alt + Insert)&#10;(Middle click to open in new tab)"></a>
<a class="nav-button action-open-help" data-icon="question-mark" title="Help"></a> <a class="nav-button action-open-help" data-icon="question-mark" title="Help"></a>
</div> </div>
</div> </div>
@ -33,7 +39,7 @@
<div id="full"> <div id="full">
<h3 id="extension-info">Yomichan</h3> <h3 id="extension-info">Yomichan</h3>
<label class="link-group"> <label class="link-group">
<span class="link-group-icon"><input type="checkbox" id="enable-search2" /></span><span class="link-group-label">Enable content scanning</span> <span class="link-group-icon"><input type="checkbox" id="enable-search2"></span><span class="link-group-label">Enable content scanning</span>
</label> </label>
<a class="link-group action-open-options"> <a class="link-group action-open-options">
<span class="link-group-icon" data-icon="chevron"></span><span class="link-group-label">Options</span> <span class="link-group-icon" data-icon="chevron"></span><span class="link-group-label">Options</span>

View File

@ -35,7 +35,9 @@ label {
} }
#mini { #mini {
text-align: center; display: flex;
flex-flow: column nowrap;
align-items: center;
} }
#full { #full {
display: none; display: none;
@ -243,10 +245,17 @@ body[data-loaded=true] .toggle-group {
display: block; display: block;
width: 16px; width: 16px;
height: 16px; height: 16px;
background-position: center center;
background-size: 16px 16px;
background-repeat: no-repeat;
box-sizing: content-box; box-sizing: content-box;
background-color: #333333;
mask-repeat: no-repeat;
mask-position: center center;
mask-mode: alpha;
mask-size: 16px 16px;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center center;
-webkit-mask-mode: alpha;
-webkit-mask-size: 16px 16px;
pointer-events: none;
} }
.nav-button:hover { .nav-button:hover {
z-index: 1; z-index: 1;
@ -264,19 +273,67 @@ body[data-loaded=true] .toggle-group {
outline: none; outline: none;
} }
.nav-button[data-icon=magnifying-glass]::after { .nav-button[data-icon=magnifying-glass]::after {
background-image: url(/mixed/img/magnifying-glass.svg); mask-image: url(/mixed/img/magnifying-glass.svg);
-webkit-mask-image: url(/mixed/img/magnifying-glass.svg);
} }
.nav-button[data-icon=cog]::after { .nav-button[data-icon=cog]::after {
background-image: url(/mixed/img/cog.svg); mask-image: url(/mixed/img/cog.svg);
-webkit-mask-image: url(/mixed/img/cog.svg);
} }
.nav-button[data-icon=question-mark]::after { .nav-button[data-icon=question-mark]::after {
background-image: url(/mixed/img/question-mark-circle.svg); mask-image: url(/mixed/img/question-mark-circle.svg);
-webkit-mask-image: url(/mixed/img/question-mark-circle.svg);
} }
.nav-button:first-of-type { .nav-button[data-icon=profile]::after {
mask-image: url(/mixed/img/profile.svg);
-webkit-mask-image: url(/mixed/img/profile.svg);
}
.nav-button:first-child {
border-top-left-radius: 3px; border-top-left-radius: 3px;
border-bottom-left-radius: 3px; border-bottom-left-radius: 3px;
} }
.nav-button:last-of-type { .nav-button:last-child {
border-top-right-radius: 3px; border-top-right-radius: 3px;
border-bottom-right-radius: 3px; border-bottom-right-radius: 3px;
} }
.action-select-profile {
position: relative;
}
.profile-select-container {
position: absolute;
left: -1px;
top: -1px;
right: -1px;
bottom: -1px;
}
select.profile-select {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
box-sizing: border-box;
border: 0;
margin: 0;
padding: 0.375em;
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
opacity: 0;
outline: none;
cursor: pointer;
font-size: 14px;
}
.profile-select optgroup {
color: #666666;
font-weight: normal;
font-style: normal;
background-color: #f2f2f2;
}
.profile-select option {
color: #333333;
font-weight: normal;
font-style: normal;
background-color: initial;
}

View File

@ -19,73 +19,127 @@
* api * api
*/ */
function showExtensionInfo(manifest) { class DisplayController {
const node = document.getElementById('extension-info'); constructor() {
if (node === null) { return; } this._optionsFull = null;
}
node.textContent = `${manifest.name} v${manifest.version}`; async prepare() {
} const manifest = chrome.runtime.getManifest();
function setupButtonEvents(selector, command, url) { this._showExtensionInfo(manifest);
const nodes = document.querySelectorAll(selector); this._setupEnvironment();
for (const node of nodes) { this._setupButtonEvents('.action-open-search', 'search', chrome.runtime.getURL('/bg/search.html'));
node.addEventListener('click', (e) => { this._setupButtonEvents('.action-open-options', 'options', chrome.runtime.getURL(manifest.options_ui.page));
if (e.button !== 0) { return; } this._setupButtonEvents('.action-open-help', 'help', 'https://foosoft.net/projects/yomichan/');
api.commandExec(command, {mode: e.ctrlKey ? 'newTab' : 'existingOrNewTab'});
e.preventDefault();
}, false);
node.addEventListener('auxclick', (e) => {
if (e.button !== 1) { return; }
api.commandExec(command, {mode: 'newTab'});
e.preventDefault();
}, false);
if (typeof url === 'string') { const optionsFull = await api.optionsGetFull();
node.href = url; this._optionsFull = optionsFull;
node.target = '_blank';
node.rel = 'noopener'; const {profiles, profileCurrent} = optionsFull;
const primaryProfile = (profileCurrent >= 0 && profileCurrent < profiles.length) ? profiles[profileCurrent] : null;
if (primaryProfile !== null) {
this._setupOptions(primaryProfile);
}
this._updateProfileSelect(profiles, profileCurrent);
setTimeout(() => {
document.body.dataset.loaded = 'true';
}, 10);
}
// Private
_showExtensionInfo(manifest) {
const node = document.getElementById('extension-info');
if (node === null) { return; }
node.textContent = `${manifest.name} v${manifest.version}`;
}
_setupButtonEvents(selector, command, url) {
const nodes = document.querySelectorAll(selector);
for (const node of nodes) {
node.addEventListener('click', (e) => {
if (e.button !== 0) { return; }
api.commandExec(command, {mode: e.ctrlKey ? 'newTab' : 'existingOrNewTab'});
e.preventDefault();
}, false);
node.addEventListener('auxclick', (e) => {
if (e.button !== 1) { return; }
api.commandExec(command, {mode: 'newTab'});
e.preventDefault();
}, false);
if (typeof url === 'string') {
node.href = url;
node.target = '_blank';
node.rel = 'noopener';
}
} }
} }
}
async function setupEnvironment() { async _setupEnvironment() {
// Firefox mobile opens this page as a full webpage. // Firefox mobile opens this page as a full webpage.
const {browser} = await api.getEnvironmentInfo(); const {browser} = await api.getEnvironmentInfo();
document.documentElement.dataset.mode = (browser === 'firefox-mobile' ? 'full' : 'mini'); document.documentElement.dataset.mode = (browser === 'firefox-mobile' ? 'full' : 'mini');
}
async function setupOptions() {
const optionsContext = {
depth: 0,
url: window.location.href
};
const options = await api.optionsGet(optionsContext);
const extensionEnabled = options.general.enable;
const onToggleChanged = () => api.commandExec('toggle');
for (const toggle of document.querySelectorAll('#enable-search,#enable-search2')) {
toggle.checked = extensionEnabled;
toggle.addEventListener('change', onToggleChanged, false);
} }
setTimeout(() => { _setupOptions({options}) {
document.body.dataset.loaded = 'true'; const extensionEnabled = options.general.enable;
}, 10); const onToggleChanged = () => api.commandExec('toggle');
for (const toggle of document.querySelectorAll('#enable-search,#enable-search2')) {
toggle.checked = extensionEnabled;
toggle.addEventListener('change', onToggleChanged, false);
}
}
_updateProfileSelect(profiles, profileCurrent) {
const select = document.querySelector('#profile-select');
const optionGroup = document.querySelector('#profile-select-option-group');
const fragment = document.createDocumentFragment();
for (let i = 0, ii = profiles.length; i < ii; ++i) {
const {name} = profiles[i];
const option = document.createElement('option');
option.textContent = name;
option.value = `${i}`;
fragment.appendChild(option);
}
optionGroup.textContent = '';
optionGroup.appendChild(fragment);
select.value = `${profileCurrent}`;
select.addEventListener('change', this._onProfileSelectChange.bind(this), false);
}
_onProfileSelectChange(e) {
const value = parseInt(e.currentTarget.value, 10);
if (typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= this._optionsFull.profiles.length) {
this._setPrimaryProfileIndex(value);
}
}
async _setPrimaryProfileIndex(value) {
return await api.modifySettings(
[{
action: 'set',
path: 'profileCurrent',
value,
scope: 'global'
}]
);
}
} }
(async () => { (async () => {
api.forwardLogsToBackend(); api.forwardLogsToBackend();
await yomichan.backendReady(); await yomichan.backendReady();
const manifest = chrome.runtime.getManifest();
api.logIndicatorClear(); api.logIndicatorClear();
showExtensionInfo(manifest);
setupEnvironment(); const displayController = new DisplayController();
setupOptions(); displayController.prepare();
setupButtonEvents('.action-open-search', 'search', chrome.runtime.getURL('/bg/search.html'));
setupButtonEvents('.action-open-options', 'options', chrome.runtime.getURL(manifest.options_ui.page));
setupButtonEvents('.action-open-help', 'help', 'https://foosoft.net/projects/yomichan/');
yomichan.ready(); yomichan.ready();
})(); })();