Disable #cc-sync in panel-grid when there's only one stem (nothing to sync; aspect is fixed by the dialog) and hide any .compare-controls label whose select is disabled via :has.
70 lines
2.5 KiB
JavaScript
70 lines
2.5 KiB
JavaScript
// run-modal.js — homepage click-hijack for embedding links. Opens a
|
|
// <dialog id="run-modal"> that renders the run's embedding via panel-grid.js.
|
|
|
|
import { mountPanels } from './panel-grid.js?v=6';
|
|
|
|
const dialog = document.getElementById('run-modal');
|
|
const host = document.getElementById('modal-panel-host');
|
|
const controls = document.getElementById('modal-compare-controls');
|
|
const closeBtn = document.getElementById('run-modal-close');
|
|
const runsSlot = document.getElementById('runs-slot');
|
|
|
|
let active = null; // { destroy } returned by mountPanels
|
|
|
|
function openFor(stem) {
|
|
if (!dialog || !host || !controls) return;
|
|
if (active) { try { active.destroy(); } catch (_) {} active = null; }
|
|
active = mountPanels({ host, controls, stems: [stem] });
|
|
if (typeof dialog.showModal === 'function') dialog.showModal();
|
|
else dialog.setAttribute('open', '');
|
|
}
|
|
|
|
function closeModal() {
|
|
if (!dialog) return;
|
|
if (dialog.open) dialog.close();
|
|
if (active) { try { active.destroy(); } catch (_) {} active = null; }
|
|
}
|
|
|
|
function onRunsClick(ev) {
|
|
if (ev.defaultPrevented) return;
|
|
if (ev.button !== undefined && ev.button !== 0) return;
|
|
if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
|
|
const a = ev.target.closest('a[data-role="embedding-link"]');
|
|
if (!a) return;
|
|
if (!runsSlot || !runsSlot.contains(a)) return;
|
|
const stem = a.dataset.stem;
|
|
if (!stem) return;
|
|
ev.preventDefault();
|
|
openFor(stem);
|
|
}
|
|
|
|
function wire() {
|
|
if (!dialog) return;
|
|
if (runsSlot) runsSlot.addEventListener('click', onRunsClick);
|
|
if (closeBtn) closeBtn.addEventListener('click', closeModal);
|
|
dialog.addEventListener('close', () => {
|
|
if (active) { try { active.destroy(); } catch (_) {} active = null; }
|
|
});
|
|
// Clicking the backdrop (native behavior fires a click on the dialog
|
|
// itself, with target === dialog) closes the modal.
|
|
dialog.addEventListener('click', (ev) => {
|
|
if (ev.target === dialog) closeModal();
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', wire);
|
|
} else {
|
|
wire();
|
|
}
|
|
|
|
// htmx re-renders #runs-slot every 3s. Delegation on #runs-slot survives the
|
|
// swap (the slot element itself is stable), so we don't need to re-bind —
|
|
// but we keep the hook in case a consumer ever replaces the slot wholesale.
|
|
document.body.addEventListener('htmx:afterSwap', (ev) => {
|
|
if (ev.detail?.target?.id === 'runs-slot' && runsSlot && !runsSlot._runModalWired) {
|
|
runsSlot.addEventListener('click', onRunsClick);
|
|
runsSlot._runModalWired = true;
|
|
}
|
|
});
|