From 22af2a85daac1456effa770bfb65c08c3b1b211b Mon Sep 17 00:00:00 2001 From: narcolepticinsomniac Date: Tue, 14 Nov 2017 21:48:48 -0500 Subject: [PATCH] Only apply to Chrome --- options.css | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++++ options.js | 97 +++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 options.css create mode 100644 options.js diff --git a/options.css b/options.css new file mode 100644 index 00000000..4b8d811a --- /dev/null +++ b/options.css @@ -0,0 +1,292 @@ +html.opera { + display: flex; + align-items: center; + justify-content: center; + height: 100%; +} + +html.opera body { + width: auto; +} + +html.firefox .block { + padding-left: 6px; +} + +html.firefox #notes { + padding-left: calc(6px + 2ex); +} + +body { + background: #fff; + margin: 0; + font-family: "Helvetica Neue", Helvetica, sans-serif; + font-size: 12px; + width: 480px; + min-width: 400px; + max-width: 800px; +} + +@media (min-width: 401px) { + .firefox body { + width: calc(100% - 6px); /* TODO: rework to avoid compensating padding of 'html.firefox .block' */ + } +} + +.firefox .chromium-only { + display: none; +} + +.block { + display: flex; + align-items: center; + margin: 1em 0; + border-bottom: 1px dotted #ccc; + padding: 0 16px .75em; + position: relative; +} + +.block:last-child { + border-bottom: none; + padding-bottom: 0; +} + +.collapsed, .collapsible h1 { + cursor: pointer; +} + +.collapsed .items { + display: none; +} + +h1 { + width: 30%; + margin: 0; + font-size: 120%; + font-weight: bold; + padding-right: 8px; + box-sizing: border-box; + overflow-wrap: break-word; +} + +.items { + width: 70%; +} + +label { + display: flex; + margin: .25ex 0; + align-items: center; +} + +label > :first-child { + margin-right: 8px; + flex-grow: 1; +} + +label:not([disabled]) > :first-child { + cursor: default; +} + +label:not([disabled]):hover > :first-child { + text-shadow: 0 0 0.01px rgba(0, 0, 0, .25); + cursor: pointer; +} + +button, +input[type=number], +input[type="color"], +select, +.onoffswitch { + width: 60px; + box-sizing: border-box; + flex-shrink: 0; +} + +a { + text-decoration-skip: ink; +} + +button { + text-align: center; +} + +input[type=number] { + text-align: right; +} + +input[type=number]:invalid { + background-color: rgba(255, 0, 0, 0.1); + color: darkred; +} + +input[type="color"] { + box-sizing: border-box; + height: 2em; +} + +.iconset { + display: flex; +} + +.iconset input { + display: block; +} + +#actions { + justify-content: space-around; + align-items: stretch; + padding-right: 8px; +} + +#actions button { + width: auto; + margin-right: 8px; +} + +[data-cmd="check-updates"] button { + position: relative; +} + +.update-in-progress [data-cmd="check-updates"] { + opacity: .5; + pointer-events: none; +} + +.update-in-progress #update-progress { + position: absolute; + top: 0; + left: 0; + bottom: 0; + background-color: currentColor; + content: ""; + opacity: .35; +} + +#updates-installed { + position: absolute; + font-size: 85%; + margin-top: 1px; +} + +#updates-installed::after { + content: attr(data-value); + margin-left: .5ex; + font-weight: bold; +} + +#updates-installed:not([data-value]), +#updates-installed[data-value=""] { + display: none; +} + +#advanced.collapsible.collapsed { + height: 40px; + padding: 0; + margin: 0; + justify-content: center; +} + +html:not(.firefox):not(.opera) #options > .block:nth-last-of-type(3) { + margin-bottom: 0; +} + +#advanced.collapsible:not(.collapsed) .collapsible-resizer { + padding-right: 8px; + box-sizing: border-box; + width: 30%; +} + +#advanced.collapsible h1 { + width: unset; + padding: 0; + color: #333; + transition: color .5s; + display: inline-flex; + align-items: center; +} + +#advanced.collapsible:not(.collapsed) h1:hover { + color: #666; +} + +#advanced.collapsible.collapsed h1 { + padding: 0; + color: #666; +} + +#advanced.collapsible.collapsed:hover h1 { + color: #333; +} + +#advanced.collapsible .svg-icon { + fill: #333; + transition: fill .5s; + height: 16px; + width: 16px; +} + +#advanced.collapsible.collapsed .svg-icon, +#advanced.collapsible:not(.collapsed) h1:hover .svg-icon { + fill: #666; +} + +#advanced.collapsible.collapsed:hover .svg-icon { + fill: #333; +} + +#advanced.collapsible h1 .svg-icon { + margin-left: 2px; +} + +#advanced.collapsible.collapsed .is-expanded, +#advanced:not(.collapsible) .svg-icon { + display: none; +} + +#advanced.collapsible:not(.collapsed) .is-collapsed { + display: none; +} + +#notes { + background-color: #f4f4f4; + padding: 1.5ex 16px 1ex calc(16px + 2ex); + font-size: 90%; + color: #777; +} + +#notes ol { + margin: 0; + padding: 0; +} + +#notes li:not(last-child) { + margin-bottom: 1ex; +} + +#notes a { + color: inherit; +} + +#notes a:hover { + color: black; +} + +#notes p { + line-height: 1.25; + margin-top: 1ex; + margin-bottom: 1ex; +} + +sup { + vertical-align: baseline; + position: relative; + top: -0.4em; +} + +@keyframes fadeinout { + 0% { opacity: 0 } + 10% { opacity: 1 } + 25% { opacity: 1 } + 100% { opacity: 0 } +} diff --git a/options.js b/options.js new file mode 100644 index 00000000..aec49a12 --- /dev/null +++ b/options.js @@ -0,0 +1,97 @@ +'use strict'; + +setupLivePrefs(); +setupRadioButtons(); +enforceInputRange($('#popupWidth')); + +if (!FIREFOX && !OPERA) { + const block = $('#advanced'); + block.classList.add('collapsible', 'collapsed'); + block.onclick = event => { + if (block.classList.contains('collapsed') || event.target.closest('h1')) { + block.classList.toggle('collapsed'); + } + }; +} + +// actions +document.onclick = e => { + const target = e.target.closest('[data-cmd]'); + if (!target) { + return; + } + // prevent double-triggering in case a sub-element was clicked + e.stopPropagation(); + + switch (target.dataset.cmd) { + case 'open-manage': + openURL({url: 'manage.html'}); + break; + + case 'check-updates': + checkUpdates(); + break; + + case 'open-keyboard': + openURL({url: URLS.configureCommands}); + e.preventDefault(); + break; + + case 'reset': + $$('input') + .filter(input => input.id in prefs.readOnlyValues) + .forEach(input => prefs.reset(input.id)); + break; + } +}; + +function checkUpdates() { + let total = 0; + let checked = 0; + let updated = 0; + const maxWidth = $('#update-progress').parentElement.clientWidth; + BG.updater.checkAllStyles({observer}); + + function observer(state, value) { + switch (state) { + case BG.updater.COUNT: + total = value; + document.body.classList.add('update-in-progress'); + break; + case BG.updater.UPDATED: + updated++; + // fallthrough + case BG.updater.SKIPPED: + checked++; + break; + case BG.updater.DONE: + document.body.classList.remove('update-in-progress'); + return; + } + $('#update-progress').style.width = Math.round(checked / total * maxWidth) + 'px'; + $('#updates-installed').dataset.value = updated || ''; + } +} + +function setupRadioButtons() { + const sets = {}; + const onChange = function () { + const newValue = sets[this.name].indexOf(this); + if (newValue >= 0 && prefs.get(this.name) !== newValue) { + prefs.set(this.name, newValue); + } + }; + // group all radio-inputs by name="prefName" attribute + for (const el of $$('input[type="radio"][name]')) { + (sets[el.name] = sets[el.name] || []).push(el); + el.addEventListener('change', onChange); + } + // select the input corresponding to the actual pref value + for (const name in sets) { + sets[name][prefs.get(name)].checked = true; + } + // listen to pref changes and update the values + prefs.subscribe(Object.keys(sets), (key, value) => { + sets[key][value].checked = true; + }); +}