// 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 MAX = 2; 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 !== MAX; } function applyToDOM() { const checkboxes = slot.querySelectorAll('.compare-cb'); // Drop any selected stems that are no longer in the DOM (run aged out of list) const present = new Set(); checkboxes.forEach((cb) => present.add(cb.dataset.stem)); for (const s of [...selected]) if (!present.has(s)) selected.delete(s); const atCap = selected.size >= MAX; checkboxes.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', () => { if (selected.size !== MAX) return; const [a, b] = [...selected]; const url = `/compare?a=${encodeURIComponent(a)}&b=${encodeURIComponent(b)}`; window.open(url, '_blank', 'noopener'); }); applyToDOM(); })();