package main import ( "html/template" "log" "net/http" "path" "strings" ) var dialogTmpl = template.Must(template.New("dialogs").ParseFS(assets, "assets/page/dialogs.html")) // isHX reports whether r was issued by htmx. func isHX(r *http.Request) bool { return r.Header.Get("HX-Request") == "true" } // layoutTemplate names the template that renders a layout page for r: the // whole document, or for boosted navigation and htmx history restores only // the "partial" that hx.js swaps into the open page. The editor is never // boosted. func layoutTemplate(w http.ResponseWriter, r *http.Request, editMode bool) string { w.Header().Set("Vary", "HX-Boosted, HX-History-Restore-Request") if !editMode && (r.Header.Get("HX-Boosted") == "true" || r.Header.Get("HX-History-Restore-Request") == "true") { return "partial" } return "layout" } // redirectAfter sends the client to target once a mutation succeeded. htmx // requests get HX-Redirect (assets/hx.js turns it into a history replace, so // Back skips the pre-mutation page); plain form posts get a 303. func redirectAfter(w http.ResponseWriter, r *http.Request, target string) { if isHX(r) { w.Header().Set("HX-Redirect", target) w.WriteHeader(http.StatusNoContent) return } http.Redirect(w, r, target, http.StatusSeeOther) } // pageURL returns the escaped, slash-terminated browser URL of the page at // the wiki path p ("/" or "/a/b", trailing slash optional). func pageURL(p string) string { p = strings.Trim(p, "/") if p == "" { return "/" } return fileURL(p) + "/" } // renderDialog writes the named dialog from dialogs.html. func renderDialog(w http.ResponseWriter, name string, data any) { w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := dialogTmpl.ExecuteTemplate(w, name, data); err != nil { log.Printf("dialog template error: %v", err) } } // serveDialog handles GET ?dialog= for the page at urlPath. func (h *handler) serveDialog(w http.ResponseWriter, r *http.Request, urlPath, fsPath string) { page := normalizeMovePath(urlPath) name := r.URL.Query().Get("dialog") if page == "/" && (name == "delete" || name == "move") { http.Error(w, "not available for the wiki root", http.StatusBadRequest) return } switch name { case "view": view, sortKey, order := readPageSettings(fsPath).viewSettings() renderDialog(w, "view", struct{ View, Sort, Order string }{view, sortKey, order}) case "canvas": renderDialog(w, "canvas", nil) case "delete": renderDialog(w, "delete", struct{ Path string }{urlPath}) case "move": // parent comes from the folder picker; default to the current one. parent := r.URL.Query().Get("parent") if parent == "" { parent = path.Dir(page) } renderDialog(w, "move", struct{ Parent, Name string }{parent, path.Base(page)}) default: http.NotFound(w, r) } }