From bbd2d8336422e6965b1f93739e64125053d2071d Mon Sep 17 00:00:00 2001 From: Mix Date: Sun, 11 Oct 2026 00:31:36 +0300 Subject: [PATCH] panel: show/hide rules reach a form that arrives in an htmx swap initShowWhen bound a change listener to each control it found at DOMContentLoaded, so a form swapped in later would have been neither synced nor wired. The rules now listen once on the document and are applied again on htmx:load. No form arrives by a swap today; the roadmap row that recorded the gap is struck. Checked in a browser on the application form: the rate-limit select toggles the manual and auto fields as before, and a copy of the form put into the page with htmx.swap is synced on arrival and follows its select. go vet and go test ./internal/web/... pass. Co-Authored-By: Claude Opus 5.5 --- docs/roadmap.md | 2 +- internal/web/view/static/panel.js | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index 39d5f46..c193ee2 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -279,7 +279,7 @@ is in the table below; the rest of it shipped in | Edge case | [dnscheck/resolver.go](../internal/dnscheck/resolver.go) fans out four parallel queries where a fallback chain would do — change it or write down why not | | UI | ~~`.pair` (DMARC templates) and `.split` (every other page) are two names for one layout~~ — struck: retired by [panel-redesign](#panel-redesign); both stylesheets are gone and every page is laid out by the component kit | | UI | ~~Two `back_link` elements in a row in `dmarc_domain.html`~~ — struck: retired by [panel-redesign](#panel-redesign); the page is rebuilt on the kit with one breadcrumb in its head | -| UI | `initShowWhen` is not re-run after an htmx swap — safe today (no form arrives that way), fragile if one ever does | +| UI | ~~`initShowWhen` is not re-run after an htmx swap~~ — struck: the show/hide rules listen on the document and are applied again on `htmx:load` | **Boundary:** no feature work and no behaviour change an operator would notice, apart from the backup re-auth prompt. Anything here that grows past an hour diff --git a/internal/web/view/static/panel.js b/internal/web/view/static/panel.js index 955d5d3..680a0c8 100644 --- a/internal/web/view/static/panel.js +++ b/internal/web/view/static/panel.js @@ -153,19 +153,28 @@ function initShowWhen(root) { showWhenRules.forEach(function (rule) { - root.querySelectorAll(rule.match).forEach(function (control) { - syncShowWhen(control); - control.addEventListener("change", function () { - syncShowWhen(control); - }); - }); + root.querySelectorAll(rule.match).forEach(syncShowWhen); }); } + // One listener for the document rather than one per control: a form that + // arrives in an htmx swap is covered without being wired up again. + document.addEventListener("change", function (ev) { + if (ev.target && ev.target.matches) { + syncShowWhen(ev.target); + } + }); + document.addEventListener("DOMContentLoaded", function () { initShowWhen(document); }); + // htmx:load fires for every element htmx puts into the page, so swapped-in + // markup starts with its blocks shown or hidden the way a full page does. + document.addEventListener("htmx:load", function (ev) { + initShowWhen(ev.detail.elt); + }); + // --- Adaptive monitoring polling --------------------------------------- // The four monitoring fragments carry data-poll and hx-trigger="load" for // the first fetch only. panel.js schedules the rest: 5 s while the operator