From 9ea2ce57cb9cca67c8cf28c2a98fe21c84d27511 Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 22 Oct 2023 00:03:33 +0300 Subject: [PATCH] combine style/editor settings + allow multiple #help-popup on screen --- edit.html | 103 ---------------------------------------- edit/base.js | 51 ++------------------ edit/drafts.js | 3 +- edit/edit.css | 60 ++++------------------- edit/edit.js | 28 ++++------- edit/linter-dialogs.js | 4 +- edit/regexp-tester.js | 4 +- edit/sections-editor.js | 2 + edit/settings.css | 56 ++++++++++++++++------ edit/settings.html | 93 ++++++++++++++++++++++++++++++++++-- edit/settings.js | 86 +++++++++++++++++++++++++++++---- edit/source-editor.js | 4 +- edit/util.js | 44 ++++++++--------- js/dom.js | 8 +++- js/prefs.js | 1 + 15 files changed, 268 insertions(+), 279 deletions(-) diff --git a/edit.html b/edit.html index e39d74906d..4e42152525 100644 --- a/edit.html +++ b/edit.html @@ -277,105 +277,6 @@

-
-

-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - - - -
-
- -
-
-
-
- - -
-
- -
- -
- - - -
-
- -
- -
-
-
- -
- -
-
-
- -
- -
- - - -
-
-
-

@@ -415,10 +316,6 @@

-
-
-
-
diff --git a/edit/base.js b/edit/base.js index 8096e36869..e64ed28fd9 100644 --- a/edit/base.js +++ b/edit/base.js @@ -1,4 +1,4 @@ -/* global $$ $ $create messageBoxProxy setInputValue setupLivePrefs */// dom.js +/* global $$ $ messageBoxProxy setInputValue setupLivePrefs */// dom.js /* global API */// msg.js /* global CODEMIRROR_THEMES */ /* global CodeMirror */ @@ -109,11 +109,10 @@ const editor = { /* exported EditorHeader */ function EditorHeader() { initBeautifyButton($('#beautify')); - initKeymapElement(); initNameArea(); - initThemeElement(); setupLivePrefs(); - + // move the theme after built-in CSS so that its same-specificity selectors win + document.head.appendChild($('#cm-theme')); window.on('load', () => { prefs.subscribe('editor.keyMap', showHotkeyInTooltip, true); window.on('showHotkeyInTooltip', showHotkeyInTooltip); @@ -155,50 +154,6 @@ function EditorHeader() { enabledEl.onchange = () => editor.updateEnabledness(enabledEl.checked); } - function initThemeElement() { - $('#editor.theme').append(...[ - $create('option', {value: 'default'}, t('defaultTheme')), - ...Object.keys(CODEMIRROR_THEMES).map(s => $create('option', s)), - ]); - // move the theme after built-in CSS so that its same-specificity selectors win - document.head.appendChild($('#cm-theme')); - } - - function initKeymapElement() { - // move 'pc' or 'mac' prefix to the end of the displayed label - const maps = Object.keys(CodeMirror.keyMap) - .map(name => ({ - value: name, - name: name.replace(/^(pc|mac)(.+)/, (s, arch, baseName) => - baseName.toLowerCase() + '-' + (arch === 'mac' ? 'Mac' : 'PC')), - })) - .sort((a, b) => a.name < b.name && -1 || a.name > b.name && 1); - - const fragment = document.createDocumentFragment(); - let bin = fragment; - let groupName; - // group suffixed maps in - maps.forEach(({value, name}, i) => { - groupName = !name.includes('-') ? name : groupName; - const groupWithNext = maps[i + 1] && maps[i + 1].name.startsWith(groupName); - if (groupWithNext) { - if (bin === fragment) { - bin = fragment.appendChild($create('optgroup', {label: name.split('-')[0]})); - } - } - const el = bin.appendChild($create('option', {value}, name)); - if (value === prefs.defaults['editor.keyMap']) { - el.dataset.default = ''; - el.title = t('defaultTheme'); - } - if (!groupWithNext) bin = fragment; - }); - const selector = $('#editor.keyMap'); - selector.textContent = ''; - selector.appendChild(fragment); - selector.value = prefs.get('editor.keyMap'); - } - function showHotkeyInTooltip(_, mapName = prefs.get('editor.keyMap')) { const extraKeys = CodeMirror.defaults.extraKeys; for (const el of $$('[data-hotkey-tooltip]')) { diff --git a/edit/drafts.js b/edit/drafts.js index 89459731aa..cd69c5d8f4 100644 --- a/edit/drafts.js +++ b/edit/drafts.js @@ -39,7 +39,7 @@ const info = t('draftTitle', makeRelativeDate(draft.date)); const popup = showCodeMirrorPopup(info, '', {value, readOnly: true}); popup.className += ' danger'; - window.on('closeHelp', onNo, {once: true}); + helpPopup.div.onClose.add(onNo); helpPopup.contents.append( $create('p', t('draftAction')), $create('.buttons', [t('confirmYes'), t('confirmNo')].map((btn, i) => @@ -51,7 +51,6 @@ } else { API.drafts.delete(makeId()).catch(() => {}); } - window.off('closeHelp', onNo); helpPopup.close(); } diff --git a/edit/edit.css b/edit/edit.css index a5173792b1..28294dae79 100644 --- a/edit/edit.css +++ b/edit/edit.css @@ -67,14 +67,6 @@ html:not(.is-new-style) #heading::before { .usercss:not(.compact-layout) #popup-button { right: 24px; } -/************ checkbox & select************/ -.options-column > .option { - margin-bottom: .25rem; -} - -.options-column > .usercss-only { - margin-bottom: .75rem; -} /************ header ************/ #header { @@ -115,14 +107,6 @@ html:not(.is-new-style) #heading::before { margin-top: 1rem; margin-left: 1.7rem; } -.aligned { - display: table-row; -} -.aligned > *:not(.icon) { - display: table-cell; - margin-top: 0.1rem; - min-height: 1.4rem; -} /* basic info */ #basic-info { @@ -178,9 +162,6 @@ a.icon { position: absolute; margin-top: -1px; } -#sections-help { - margin-left: -1px; -} .i-info { width: 14px; height: 16px; @@ -195,9 +176,6 @@ i, .i-config:hover { color: var(--fg); } -#options span i { - margin-top: -3px; /* inline info and config icons */ -} /* collapsibles */ #header details { margin-right: var(--header-resizer-width); @@ -338,16 +316,6 @@ i, transform: scale(0.125); transform-origin: 0 10px; } -/* options */ -#options [type="number"] { - width: 3.5em; - text-align: left; - padding-left: .25em; -} -#options .option.aligned > label { - padding: .1rem .25rem 0 0; - vertical-align: middle; -} /* footer */ .usercss #footer { display: block; @@ -723,15 +691,14 @@ i, #help-popup { --pad-x: 1.5rem; --pad-y: 1rem; - --pad-y2: calc(var(--pad-y) / 1.5); + --pad-y2: calc(var( + --pad-y) / 1.5); top: 3rem; right: 3rem; - max-width: 50vw; + max-width: calc(100% - var(--header-width) - 6rem); position: fixed; - display: none; background-color: var(--bg); box-shadow: 3px 3px 30px rgba(0, 0, 0, 0.5); - padding: var(--pad-y) var(--pad-x) 0; z-index: 99; } #help-popup.big, @@ -749,7 +716,6 @@ i, #help-popup .title { font-weight: bold; background-color: rgba(128, 128, 128, .15); - margin: calc(-1 * var(--pad-y)) calc(-1 * var(--pad-x)) 0; padding: var(--pad-y2) var(--pad-x); } #help-popup.danger .title { @@ -762,13 +728,14 @@ i, #help-popup .contents { max-height: calc(100vh - 8rem); overflow-y: auto; - padding: var(--pad-y) 0; + padding: var(--pad-y) var(--pad-x); } #help-popup .dismiss { position: absolute; right: 0; top: 0; padding: var(--pad-y2) .5em; + font-size: 14px; } #help-popup input[type="search"], #help-popup .CodeMirror { @@ -953,14 +920,6 @@ i, display: none !important; /* hide during page init */ } -#options:not([open]) + #lint { - margin-top: 0; -} - -#options-wrapper .options-column:nth-child(2) { - margin-top: .75rem; -} - .single-editor { position: relative; height: 100%; @@ -1148,7 +1107,6 @@ i, max-width: 50vw; right: 0; } - #options[open], #publish[open], #lint:not([open]) { flex: 0 0 auto; @@ -1169,20 +1127,20 @@ i, overflow: hidden; flex: 1; } - #help-popup.big[style="display: block;"], - #help-popup[style="display: block;"] { + #help-popup.big, + #help-popup { width: max-content; height: min-content; - max-width: 90%; + max-width: 100vw; max-height: 90vh; top: 7rem; + right: 0; margin: auto; } #help-popup[style*="left:"] { left: 1rem !important; margin-top: -2.35rem; } - #help-popup:not([style*="display: block;"]), #help-popup .CodeMirror-lint-markers, #help-popup .CodeMirror-guttermarker-subtle { display: none !important; diff --git a/edit/edit.js b/edit/edit.js index ca92a69db3..7d660c361b 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -3,7 +3,7 @@ /* global CodeMirror */ /* global SectionsEditor */ /* global SourceEditor */ -/* global clipString createHotkeyInput helpPopup */// util.js +/* global clipString */// util.js /* global closeCurrentTab deepEqual mapObj sessionStore tryJSONparse */// toolbox.js /* global cmFactory */ /* global editor EditorHeader */// base.js @@ -39,16 +39,15 @@ editor.styleReady.then(async () => { $('#toc').onclick = e => editor.jumpToEditor([...$('#toc').children].indexOf(e.target)); - $('#keyMap-help').onclick = () => - require(['/edit/show-keymap-help'], () => showKeymapHelp()); /* global showKeymapHelp */ - $('#linter-settings').onclick = () => - require(['/edit/linter-dialogs'], () => linterMan.showLintConfig()); $('#lint-help').onclick = () => require(['/edit/linter-dialogs'], () => linterMan.showLintHelp()); - $('#style-settings-btn').onclick = () => require([ - '/edit/settings.css', - '/edit/settings', /* global StyleSettings */ - ], () => StyleSettings()); + $('#style-settings-btn').onclick = function () { + this.disabled = true; + require([ + '/edit/settings.css', + '/edit/settings', /* global StyleSettings */ + ], () => StyleSettings(this)); + }; require([ '/edit/autocomplete', @@ -374,17 +373,6 @@ function EditorMethods() { cmFactory.globalSetOption('colorpicker', defaults.colorpicker); }, true); - $('#colorpicker-settings').onclick = function (event) { - event.preventDefault(); - const input = createHotkeyInput('editor.colorpicker.hotkey', {onDone: () => helpPopup.close()}); - const popup = helpPopup.show(t('helpKeyMapHotkey'), input); - const bounds = this.getBoundingClientRect(); - popup.style.left = bounds.right + 10 + 'px'; - popup.style.top = bounds.top - popup.clientHeight / 2 + 'px'; - popup.style.right = 'auto'; - $('input', popup).focus(); - }; - function invokeColorpicker(cm) { cm.state.colorpicker.openPopup(prefs.get('editor.colorpicker.color')); } diff --git a/edit/linter-dialogs.js b/edit/linter-dialogs.js index eee99eda86..723fe348d4 100644 --- a/edit/linter-dialogs.js +++ b/edit/linter-dialogs.js @@ -74,7 +74,7 @@ }); cm.on('changes', updateConfigButtons); updateConfigButtons(); - window.on('closeHelp', onConfigClose, {once: true}); + helpPopup.div.onClose.add(onConfigClose); }; linterMan.showLintHelp = async () => { @@ -124,7 +124,7 @@ } async function getLinter() { - const val = $('#editor.linter').value; + const val = editor.getCurrentLinter(); if (val && !RULES[val]) { RULES[val] = await linterMan.worker.getRules(val); } diff --git a/edit/regexp-tester.js b/edit/regexp-tester.js index 9d41b9a371..59904cee51 100644 --- a/edit/regexp-tester.js +++ b/edit/regexp-tester.js @@ -22,8 +22,8 @@ const regexpTester = (() => { chrome.tabs.onRemoved.addListener(onTabRemoved); chrome.tabs.onUpdated.addListener(onTabUpdated); } - helpPopup.show('', $create('.regexp-report')); - window.on('closeHelp', () => regexpTester.toggle(false), {once: true}); + helpPopup.show('', $create('.regexp-report')) + .onClose.add(() => regexpTester.toggle(false)); isShown = true; } else if (!state && isShown) { unwatch(); diff --git a/edit/sections-editor.js b/edit/sections-editor.js index 1b92f9ec3f..e1205bd921 100644 --- a/edit/sections-editor.js +++ b/edit/sections-editor.js @@ -46,6 +46,8 @@ function SectionsEditor() { updateLivePreview, updateMeta, + getCurrentLinter: () => prefs.get('editor.linter'), + getEditors() { return sections.filter(s => !s.removed).map(s => s.cm); }, diff --git a/edit/settings.css b/edit/settings.css index 93542beab8..8bcd828740 100644 --- a/edit/settings.css +++ b/edit/settings.css @@ -1,49 +1,77 @@ -#help-popup.style-settings-popup.dirty .title::after { +#help-popup[data-type="settings"].dirty .title[data-style]::after { content: ' *'; } -.compact-layout #help-popup.style-settings-popup { - width: 90%; +@media (max-height: 800px) { + #help-popup[data-type="settings"] { + column-count: 2; + column-gap: 0; + } + #help-popup .contents { + break-before: avoid; + break-inside: avoid; + } } -#help-popup.style-settings-popup { - max-width: calc(100vw - 12rem); -} -.style-settings { +.settings { padding: 0 1px; /* for focus outline */ border: 0; margin: 0; max-width: 100%; box-sizing: border-box; } -.style-settings > * { +.settings > * { display: block; margin: 1rem 0; padding: 0; } -.style-settings > :first-child { +.settings > :first-child { margin-top: 0; } -.style-settings > :last-child { +.settings > :last-child { margin-bottom: 0; } -.style-settings input:disabled ~ label { +.settings input:disabled ~ label { opacity: .5; } -.style-settings .w100 { +.settings .w100 { display: block; width: 100%; margin-top: .25em; box-sizing: border-box; } -.style-settings textarea { +.settings textarea { resize: vertical; min-height: 2.5em; max-height: 50vh; white-space: pre; } -.style-settings .radio-wrapper { +.settings .radio-wrapper { display: inline-flex; padding: 0 .8em 0 0; } a[data-cmd=note] { vertical-align: text-bottom; } + +/* editor settings */ +.settings[data-editor] > :not(.aligned) > * { + display: block; + margin: 0; + padding: .15em 0; +} +.settings[data-editor] .aligned > * { + display: table-row; +} +.settings[data-editor] .aligned > * > :not(.icon) { + display: table-cell; + margin-top: 0.1rem; + min-height: 1.4rem; +} +.settings[data-editor] .aligned label { + padding: .1rem .25rem 0 0; + vertical-align: middle; +} +.settings[data-editor] .aligned [type="number"] { + width: 3.5em; + text-align: left; + padding-left: .25em; +} diff --git a/edit/settings.html b/edit/settings.html index 7125609645..6903c62409 100644 --- a/edit/settings.html +++ b/edit/settings.html @@ -1,5 +1,6 @@ -
-
+
+
+
@@ -30,12 +31,98 @@ -
+
+
+ + +
+
+
+
+ + + + + + + +
+ + + + +
+ +
+
+
+ + +
+
+ +
+ +
+ + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ + + +
+
+
+
diff --git a/edit/settings.js b/edit/settings.js index 36ab123a9a..575d06adc8 100644 --- a/edit/settings.js +++ b/edit/settings.js @@ -1,21 +1,24 @@ -/* global $ moveFocus setupLivePrefs */// dom.js +/* global $ $create moveFocus setupLivePrefs */// dom.js /* global API */// msg.js +/* global CodeMirror */ +/* global CODEMIRROR_THEMES */ /* global editor */ -/* global helpPopup */// util.js +/* global helpPopup createHotkeyInput */// util.js +/* global linterMan */ /* global prefs */ /* global t */// localization.js /* global debounce tryURL */// toolbox.js 'use strict'; /* exported StyleSettings */ -async function StyleSettings() { +async function StyleSettings(btnOpen) { const AUTOSAVE_DELAY = 500; // same as config-dialog.js const SS_ID = 'styleSettings'; const PASS = val => val; await t.fetchTemplate('/edit/settings.html', SS_ID); + let ui = t.template[SS_ID].cloneNode(true); const {style} = editor; - const ui = t.template[SS_ID].cloneNode(true); - const elForm = $('.style-settings', ui); + const elForm = $('.settings', ui); const elAuto = $('#config\\.autosave', ui); const elSave = $('#ss-save', ui); const elUpd = $('#ss-updatable', ui); @@ -38,13 +41,16 @@ async function StyleSettings() { $('#ss-scheme-off', ui).hidden = val !== 'never'; }, true); window.on(SS_ID, update); - window.on('closeHelp', () => window.off(SS_ID, update), {once: true}); - helpPopup.show(t(SS_ID), ui, { - className: 'style-settings-popup', + ui = helpPopup.show(true, ui); + ui.dataset.type = 'settings'; + ui.onClose.add(() => { + btnOpen.disabled = false; + window.off(SS_ID, update); }); elSave.onclick = save; $('#ss-close', ui).onclick = helpPopup.close; - setupLivePrefs([elAuto.id]); + setupLivePrefs(ui); + EditorSettings(ui); moveFocus(ui, 0); function autosave(el, setter) { @@ -130,3 +136,65 @@ async function StyleSettings() { updaters.forEach(fn => fn()); } } + +function EditorSettings() { + prefs.subscribe('editor.linter', editor.updateLinterSwitch, true); + + //#region Keymap + // move 'pc' or 'mac' prefix to the end of the displayed label + const maps = Object.keys(CodeMirror.keyMap) + .map(name => ({ + value: name, + name: name.replace(/^(pc|mac)(.+)/, (s, arch, baseName) => + baseName.toLowerCase() + '-' + (arch === 'mac' ? 'Mac' : 'PC')), + })) + .sort((a, b) => a.name < b.name && -1 || a.name > b.name && 1); + const fragment = document.createDocumentFragment(); + let bin = fragment; + let groupName; + // group suffixed maps in + maps.forEach(({value, name}, i) => { + groupName = !name.includes('-') ? name : groupName; + const groupWithNext = maps[i + 1] && maps[i + 1].name.startsWith(groupName); + if (groupWithNext) { + if (bin === fragment) { + bin = fragment.appendChild($create('optgroup', {label: name.split('-')[0]})); + } + } + const el = bin.appendChild($create('option', {value}, name)); + if (value === prefs.defaults['editor.keyMap']) { + el.dataset.default = ''; + el.title = t('defaultTheme'); + } + if (!groupWithNext) bin = fragment; + }); + const selector = $('#editor.keyMap'); + selector.textContent = ''; + selector.appendChild(fragment); + selector.value = prefs.get('editor.keyMap'); + //#endregion + + //#region Theme + $('#editor.theme').append(...[ + $create('option', {value: 'default'}, t('defaultTheme')), + ...Object.keys(CODEMIRROR_THEMES).map(s => $create('option', s)), + ]); + //#endregion + + //#region Buttons + $('#colorpicker-settings').onclick = function (event) { + event.preventDefault(); + const bounds = this.getBoundingClientRect(); + const input = createHotkeyInput('editor.colorpicker.hotkey', {onDone: () => helpPopup.close()}); + const popup = helpPopup.show(t('helpKeyMapHotkey'), input); + popup.style.top = bounds.bottom + 'px'; + $('input', popup).focus(); + }; + $('#keyMap-help').onclick = () => { + require(['/edit/show-keymap-help'], () => showKeymapHelp()); /* global showKeymapHelp */ + }; + $('#linter-settings').onclick = () => { + require(['/edit/linter-dialogs'], () => linterMan.showLintConfig()); + }; + //#endregion +} diff --git a/edit/source-editor.js b/edit/source-editor.js index cda8524331..19f785b62b 100644 --- a/edit/source-editor.js +++ b/edit/source-editor.js @@ -61,9 +61,11 @@ async function SourceEditor() { Object.assign(editor, { sections: sectionFinder.sections, replaceStyle, + updateLinterSwitch, updateLivePreview, updateMeta, closestVisible: () => cm, + getCurrentLinter, getEditors: () => [cm], getEditorTitle: () => '', getValue: asObject => asObject @@ -105,7 +107,6 @@ async function SourceEditor() { scrollToEditor: () => {}, }); - prefs.subscribe('editor.linter', updateLinterSwitch, true); prefs.subscribe('editor.appliesToLineWidget', (k, val) => sectionWidget.toggle(val), true); prefs.subscribe('editor.toc.expanded', (k, val) => sectionFinder.onOff(editor.updateToc, val), true); @@ -156,6 +157,7 @@ async function SourceEditor() { function updateLinterSwitch() { const el = $('#editor.linter'); + if (!el) return; el.value = getCurrentLinter(); const cssLintOption = $('[value="csslint"]', el); const mode = getModeName(); diff --git a/edit/util.js b/edit/util.js index 4837f79252..358b0c4593 100644 --- a/edit/util.js +++ b/edit/util.js @@ -1,4 +1,4 @@ -/* global $ $create getEventKeyName messageBoxProxy moveFocus */// dom.js +/* global $$ $ $create getEventKeyName messageBoxProxy moveFocus */// dom.js /* global CodeMirror */ /* global editor */ /* global prefs */ @@ -7,27 +7,24 @@ 'use strict'; const helpPopup = { + SEL: '#help-popup', /** - * @param {string} title - plain text + * @param {string|true} title - plain text or `true` to use `body` instead of .title and .contents * @param {string|Node} body - Node, html or plain text * @param {Node} [props] - DOM props for the popup element - * @returns {Element} the popup + * @returns {Element & {onClose: Set}} the popup */ show(title = '', body, props) { - const div = $('#help-popup'); - const contents = helpPopup.contents = $('.contents', div); - div.style = ''; - div.className = ''; - contents.textContent = ''; - Object.assign(div, props); - if (body) { - contents.appendChild(typeof body === 'string' ? t.HTML(body) : body); - } - $('.title', div).textContent = title; - $('.dismiss', div).onclick = helpPopup.close; + const div = $create(helpPopup.SEL, props, [ + $create('i.i-close.dismiss', {onclick: helpPopup.close}), + ].concat(title === true ? body : [ + $create('.title', title), + helpPopup.contents = $create('.contents', body && t.HTML(body)), + ])); + document.body.append(div); + div.onClose = new Set(); window.on('keydown', helpPopup.close, true); - div.style.display = 'block'; helpPopup.originalFocus = document.activeElement; helpPopup.div = div; moveFocus(div, 0); @@ -43,7 +40,7 @@ const helpPopup = { !(el = document.activeElement) || !el.closest('#search-replace-dialog') ); - const {div} = helpPopup; + let div = event && event.target.closest(helpPopup.SEL) || helpPopup.div; if (!canClose || !div) { return; } @@ -57,11 +54,12 @@ const helpPopup = { if (div.contains(document.activeElement) && (el = helpPopup.originalFocus)) { el.focus(); } - const {contents} = helpPopup; - div.style.display = ''; - contents.textContent = ''; - window.off('keydown', helpPopup.close, true); - window.dispatchEvent(new Event('closeHelp')); + div.remove(); + for (const fn of div.onClose) fn(); + div = helpPopup.div = $$(helpPopup.SEL).pop(); + if (div) helpPopup.contents = $('.contents', div); + else window.off('keydown', helpPopup.close, true); + return true; }, }; @@ -202,11 +200,11 @@ function showCodeMirrorPopup(title, html, options) { }; window.on('keydown', onKeyDown, true); - window.on('closeHelp', () => { + helpPopup.div.onClose.add(() => { window.off('keydown', onKeyDown, true); $.root.style.removeProperty('pointer-events'); cm = popup.codebox = null; - }, {once: true}); + }); return popup; } diff --git a/js/dom.js b/js/dom.js index cd66f407e0..c30a16e819 100644 --- a/js/dom.js +++ b/js/dom.js @@ -294,12 +294,18 @@ function setInputValue(input, value) { /** * Accepts an array of pref names (values are fetched via prefs.get) + * or an element inside which to look for elements with known pref ids * and establishes a two-way connection between the document elements and the actual prefs */ function setupLivePrefs(ids) { let init = true; // getElementsByTagName is cached so it's much faster than calling querySelector for each id - ids = ids ? [...ids] : prefs.knownKeys.filter(id => id in document.getElementsByTagName('*')); + if (Array.isArray(ids)) { + ids = [...ids]; + } else { + ids = (ids instanceof Element ? ids : document).getElementsByTagName('*'); + ids = prefs.knownKeys.filter(id => id in ids); + } prefs.subscribe(ids, updateElement, true); init = false; function onChange() { diff --git a/js/prefs.js b/js/prefs.js index d1edd689c1..ecab41d860 100644 --- a/js/prefs.js +++ b/js/prefs.js @@ -219,6 +219,7 @@ * 2) if `keys` is falsy, no key/value will be provided */ subscribe(keys, fn, runNow) { + if (!fn) return; let toRun; for (const key of Array.isArray(keys) ? new Set(keys) : [keys]) { if (!(key in defaults)) { warnUnknown(key); continue; }