speed up setupLivePrefs

This commit is contained in:
tophf 2022-02-16 22:32:38 +03:00
parent b7cfbe6e66
commit adef93c3ed

View File

@ -304,28 +304,17 @@ function scrollElementIntoView(element, {invalidMarginRatio = 0} = {}) {
* Accepts an array of pref names (values are fetched via prefs.get) * Accepts an array of pref names (values are fetched via prefs.get)
* and establishes a two-way connection between the document elements and the actual prefs * and establishes a two-way connection between the document elements and the actual prefs
*/ */
function setupLivePrefs(ids = prefs.knownKeys.filter(id => $(`#${CSS.escape(id)}, [name=${CSS.escape(id)}]`))) { function setupLivePrefs(ids) {
let forceUpdate = true; let forceUpdate = 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('*'));
prefs.subscribe(ids, updateElement, {runNow: true}); prefs.subscribe(ids, updateElement, {runNow: true});
forceUpdate = false; forceUpdate = false;
for (const id of ids) {
const elements = $$(`#${CSS.escape(id)}, [name=${CSS.escape(id)}]`);
for (const element of elements) {
element.addEventListener('change', onChange);
}
}
function onChange() { function onChange() {
if (!this.checkValidity()) { if (this.checkValidity() && (this.type !== 'radio' || this.checked)) {
return; prefs.set(this.id || this.name, getValue(this));
} }
if (this.type === 'radio' && !this.checked) {
return;
}
prefs.set(this.id || this.name, getValue(this));
} }
function getValue(el) { function getValue(el) {
const type = el.dataset.valueType || el.type; const type = el.dataset.valueType || el.type;
return type === 'checkbox' ? el.checked : return type === 'checkbox' ? el.checked :
@ -334,20 +323,16 @@ function setupLivePrefs(ids = prefs.knownKeys.filter(id => $(`#${CSS.escape(id)}
type === 'number' ? Number(el.value) : type === 'number' ? Number(el.value) :
el.value; el.value;
} }
function isSame(el, oldValue, value) { function isSame(el, oldValue, value) {
return oldValue === value || return el.type === 'radio' ? el.checked === (oldValue === value) :
typeof value === 'boolean' && el.localName === 'select' && typeof value === 'boolean' && oldValue === `${value}` ||
el.tagName === 'SELECT' && oldValue === value;
oldValue === `${value}` ||
el.type === 'radio' && (oldValue === value) === el.checked;
} }
function updateElement(id, value) { function updateElement(id, value) {
const els = $$(`#${CSS.escape(id)}, [name=${CSS.escape(id)}]`); const byId = document.getElementById(id);
const els = byId ? [byId] : document.getElementsByName(id);
if (!els.length) { if (!els.length) {
// FIXME: why do we unsub all ids when a single id is missing from the page prefs.unsubscribe(id, updateElement);
prefs.unsubscribe(ids, updateElement);
return; return;
} }
for (const el of els) { for (const el of els) {
@ -361,6 +346,7 @@ function setupLivePrefs(ids = prefs.knownKeys.filter(id => $(`#${CSS.escape(id)}
el.value = value; el.value = value;
} }
el.dispatchEvent(new Event('change', {bubbles: true})); el.dispatchEvent(new Event('change', {bubbles: true}));
if (forceUpdate) el.on('change', onChange);
} }
} }
} }