From e5255a03e68574afecced794f8092bf76ec241a3 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Thu, 19 Nov 2020 18:37:02 -0500 Subject: [PATCH] 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 --- ext/bg/context.html | 16 ++-- ext/bg/css/context.css | 75 +++++++++++++++--- ext/bg/js/context-main.js | 158 +++++++++++++++++++++++++------------- 3 files changed, 183 insertions(+), 66 deletions(-) diff --git a/ext/bg/context.html b/ext/bg/context.html index 2fa2f520..1eb9c058 100644 --- a/ext/bg/context.html +++ b/ext/bg/context.html @@ -2,7 +2,8 @@ - + + Yomichan Action Popup @@ -19,13 +20,18 @@
On - Off - + Off +
@@ -33,7 +39,7 @@

Yomichan

Options diff --git a/ext/bg/css/context.css b/ext/bg/css/context.css index 2d42dd16..c1e88ef5 100644 --- a/ext/bg/css/context.css +++ b/ext/bg/css/context.css @@ -35,7 +35,9 @@ label { } #mini { - text-align: center; + display: flex; + flex-flow: column nowrap; + align-items: center; } #full { display: none; @@ -243,10 +245,17 @@ body[data-loaded=true] .toggle-group { display: block; width: 16px; height: 16px; - background-position: center center; - background-size: 16px 16px; - background-repeat: no-repeat; 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 { z-index: 1; @@ -264,19 +273,67 @@ body[data-loaded=true] .toggle-group { outline: none; } .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 { - 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 { - 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-bottom-left-radius: 3px; } -.nav-button:last-of-type { +.nav-button:last-child { border-top-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; +} diff --git a/ext/bg/js/context-main.js b/ext/bg/js/context-main.js index 72abe554..e7cff04c 100644 --- a/ext/bg/js/context-main.js +++ b/ext/bg/js/context-main.js @@ -19,73 +19,127 @@ * api */ -function showExtensionInfo(manifest) { - const node = document.getElementById('extension-info'); - if (node === null) { return; } +class DisplayController { + constructor() { + this._optionsFull = null; + } - node.textContent = `${manifest.name} v${manifest.version}`; -} + async prepare() { + const manifest = chrome.runtime.getManifest(); -function 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); + this._showExtensionInfo(manifest); + this._setupEnvironment(); + this._setupButtonEvents('.action-open-search', 'search', chrome.runtime.getURL('/bg/search.html')); + this._setupButtonEvents('.action-open-options', 'options', chrome.runtime.getURL(manifest.options_ui.page)); + this._setupButtonEvents('.action-open-help', 'help', 'https://foosoft.net/projects/yomichan/'); - if (typeof url === 'string') { - node.href = url; - node.target = '_blank'; - node.rel = 'noopener'; + const optionsFull = await api.optionsGetFull(); + this._optionsFull = optionsFull; + + 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() { - // Firefox mobile opens this page as a full webpage. - const {browser} = await api.getEnvironmentInfo(); - 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); + async _setupEnvironment() { + // Firefox mobile opens this page as a full webpage. + const {browser} = await api.getEnvironmentInfo(); + document.documentElement.dataset.mode = (browser === 'firefox-mobile' ? 'full' : 'mini'); } - setTimeout(() => { - document.body.dataset.loaded = 'true'; - }, 10); + _setupOptions({options}) { + 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); + } + } + + _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 () => { api.forwardLogsToBackend(); await yomichan.backendReady(); - const manifest = chrome.runtime.getManifest(); - api.logIndicatorClear(); - showExtensionInfo(manifest); - setupEnvironment(); - setupOptions(); - 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/'); + + const displayController = new DisplayController(); + displayController.prepare(); yomichan.ready(); })();