70 lines
2.0 KiB
JavaScript
70 lines
2.0 KiB
JavaScript
// Manages run-comparison selection on the runs list.
|
|
// HTMX re-renders #runs-slot every 3s, so we keep state in a Set outside
|
|
// the polled region and re-apply checked state on every afterSwap.
|
|
|
|
(function () {
|
|
const MIN = 2;
|
|
const MAX = 8;
|
|
const selected = new Set();
|
|
|
|
const btn = document.getElementById('compare-btn');
|
|
const clearBtn = document.getElementById('compare-clear');
|
|
const countEl = document.getElementById('compare-count');
|
|
const slot = document.getElementById('runs-slot');
|
|
if (!btn || !countEl || !slot) return;
|
|
|
|
function refreshButton() {
|
|
const n = selected.size;
|
|
countEl.textContent = `(${n}/${MAX})`;
|
|
btn.disabled = n < MIN || n > MAX;
|
|
if (clearBtn) clearBtn.hidden = n === 0;
|
|
}
|
|
|
|
function applyToDOM() {
|
|
// Selections persist across swaps — with server-side filtering, rows
|
|
// leave the DOM when they don't match the current filter, but the user
|
|
// still has them "in the cart".
|
|
const atCap = selected.size >= MAX;
|
|
slot.querySelectorAll('.compare-cb').forEach((cb) => {
|
|
const stem = cb.dataset.stem;
|
|
cb.checked = selected.has(stem);
|
|
cb.disabled = atCap && !cb.checked;
|
|
});
|
|
refreshButton();
|
|
}
|
|
|
|
slot.addEventListener('change', (e) => {
|
|
const cb = e.target;
|
|
if (!cb.matches || !cb.matches('.compare-cb')) return;
|
|
const stem = cb.dataset.stem;
|
|
if (cb.checked) {
|
|
if (selected.size >= MAX) {
|
|
cb.checked = false;
|
|
return;
|
|
}
|
|
selected.add(stem);
|
|
} else {
|
|
selected.delete(stem);
|
|
}
|
|
applyToDOM();
|
|
});
|
|
|
|
document.body.addEventListener('htmx:afterSwap', (e) => {
|
|
if (e.target && e.target.id === 'runs-slot') applyToDOM();
|
|
});
|
|
|
|
btn.addEventListener('click', () => {
|
|
const n = selected.size;
|
|
if (n < MIN || n > MAX) return;
|
|
const qs = [...selected].map((s) => `stem=${encodeURIComponent(s)}`).join('&');
|
|
window.open(`/compare?${qs}`, '_blank', 'noopener');
|
|
});
|
|
|
|
if (clearBtn) clearBtn.addEventListener('click', () => {
|
|
selected.clear();
|
|
applyToDOM();
|
|
});
|
|
|
|
applyToDOM();
|
|
})();
|