dr-sandbox/app/web/static/compare-select.js
Michael Pilosov 59a6bece2e runs: live counter + keep compare selections across filter swaps
- Counter shows 'N / cap' where cap flips 10→50 based on whether any
  chip is active. Updates immediately on chip click and after every
  htmx swap.
- compare-select.js no longer prunes selections that aren't in the
  current DOM slice — server-side filtering replaces the whole list, so
  absence from DOM means 'off-current-filter', not 'run deleted'.
2026-04-22 18:02:35 -06:00

63 lines
1.8 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 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;
}
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');
});
applyToDOM();
})();