fix(js): preserve pending indicator state
Track pending class and indicator state with small reference counts so overlapping requests do not hide indicators early or strip a class that existed before the request. req: convention/007 req: convention/008
This commit is contained in:
+37
-2
@@ -8,6 +8,8 @@
|
||||
const pending = new WeakMap();
|
||||
const queues = new WeakMap();
|
||||
const timers = new WeakMap();
|
||||
const pendingClassStates = new WeakMap();
|
||||
const indicatorStates = new WeakMap();
|
||||
const disabledStates = new WeakMap();
|
||||
const sseSources = new WeakMap();
|
||||
const atomStores = new WeakMap();
|
||||
@@ -71,9 +73,9 @@
|
||||
|
||||
function showPending(el, on) {
|
||||
const klass = el.getAttribute("data-slhx-pending-class");
|
||||
if (klass) el.classList.toggle(klass, on);
|
||||
if (klass) togglePendingClass(el, klass, on);
|
||||
const root = rootOf(el) || document;
|
||||
forEachElement(root, (i) => { if (i.hasAttribute("data-slhx-indicator")) i.hidden = !on; });
|
||||
forEachElement(root, (i) => { if (i.hasAttribute("data-slhx-indicator")) toggleIndicator(i, on); });
|
||||
if (el.hasAttribute("data-slhx-disable-while-pending")) {
|
||||
const controls = [];
|
||||
if (isDisableControl(el)) controls.push(el);
|
||||
@@ -82,6 +84,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
function togglePendingClass(el, klass, on) {
|
||||
const state = pendingClassStates.get(el);
|
||||
if (on) {
|
||||
if (state) state.count += 1;
|
||||
else pendingClassStates.set(el, { count: 1, className: klass, hadClass: el.classList.contains(klass) });
|
||||
el.classList.add(klass);
|
||||
return;
|
||||
}
|
||||
if (!state) return;
|
||||
state.count -= 1;
|
||||
if (state.count <= 0) {
|
||||
if (state.hadClass) el.classList.add(state.className);
|
||||
else el.classList.remove(state.className);
|
||||
pendingClassStates.delete(el);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleIndicator(indicator, on) {
|
||||
const state = indicatorStates.get(indicator);
|
||||
if (on) {
|
||||
if (state) state.count += 1;
|
||||
else indicatorStates.set(indicator, { count: 1, hidden: indicator.hidden });
|
||||
indicator.hidden = false;
|
||||
return;
|
||||
}
|
||||
if (!state) return;
|
||||
state.count -= 1;
|
||||
if (state.count <= 0) {
|
||||
indicator.hidden = state.hidden;
|
||||
indicatorStates.delete(indicator);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDisabled(control, on) {
|
||||
const state = disabledStates.get(control);
|
||||
if (on) {
|
||||
|
||||
@@ -55,9 +55,14 @@ fn runtime_toggles_pending_conventions_around_requests() {
|
||||
|
||||
assert!(source.contains("function showPending(el, on)"));
|
||||
assert!(source.contains("el.getAttribute(\"data-slhx-pending-class\")"));
|
||||
assert!(source.contains("el.classList.toggle(klass, on)"));
|
||||
assert!(source.contains("forEachElement(root, (i) => { if (i.hasAttribute(\"data-slhx-indicator\")) i.hidden = !on; })"));
|
||||
assert!(source.contains("i.hidden = !on"));
|
||||
assert!(source.contains("const pendingClassStates = new WeakMap()"));
|
||||
assert!(source.contains("function togglePendingClass(el, klass, on)"));
|
||||
assert!(source.contains("hadClass: el.classList.contains(klass)"));
|
||||
assert!(source.contains("if (state.hadClass) el.classList.add(state.className)"));
|
||||
assert!(source.contains("const indicatorStates = new WeakMap()"));
|
||||
assert!(source.contains("function toggleIndicator(indicator, on)"));
|
||||
assert!(source.contains("toggleIndicator(i, on)"));
|
||||
assert!(source.contains("indicator.hidden = state.hidden"));
|
||||
assert!(source.contains("el.hasAttribute(\"data-slhx-disable-while-pending\")"));
|
||||
assert!(source.contains("if (isDisableControl(el)) controls.push(el)"));
|
||||
assert!(source.contains("forEachElement(el, (child) => { if (isDisableControl(child)) controls.push(child); })"));
|
||||
|
||||
Reference in New Issue
Block a user