Serve delete, move and merge dialogs as htmx fragments

The server renders the dialogs (?dialog=delete|move) and answers a move
that needs confirmation with the merge dialog itself, so the client no
longer builds action URLs or interprets X-Merge-Available. Successful
mutations send HX-Redirect, which hx.js turns into a history replace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 16:37:46 +02:00
co-authored by Claude Opus 5.5
parent 465aed47b3
commit 3a3fb3b51f
11 changed files with 371 additions and 230 deletions
+16 -1
View File
@@ -301,6 +301,10 @@ func (h *handler) serveDir(w http.ResponseWriter, r *http.Request, urlPath, fsPa
h.handlePost(w, r, urlPath, fsPath)
return
}
if r.URL.Query().Has("dialog") {
h.serveDialog(w, r, urlPath)
return
}
for _, ph := range pageTypeHandlers {
if target, ok := ph.redirect(h.root, fsPath, urlPath, r); ok {
@@ -427,7 +431,18 @@ func (h *handler) handlePost(w http.ResponseWriter, r *http.Request, urlPath, fs
return
}
if _, ok := query["move"]; ok {
h.handleMove(w, r, urlPath, fsPath, query.Get("move"), query.Has("merge"))
// The destination comes either whole (?move=/dst, or the merge
// dialog's move field) or as the move dialog's parent + name.
// Body fields take precedence over the bare ?move query key.
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
dst := r.FormValue("move")
if name := strings.TrimSpace(r.FormValue("name")); dst == "" && name != "" {
dst = strings.TrimRight(r.FormValue("parent"), "/") + "/" + name
}
h.handleMove(w, r, urlPath, fsPath, dst, r.FormValue("merge") != "")
return
}
if query.Has("toggle") {