From 892e4860b46072246945ddb85b4bc0554c22288c Mon Sep 17 00:00:00 2001 From: luxick Date: Thu, 7 May 2026 19:35:10 +0200 Subject: [PATCH] Make page rewrite optional --- assets/page-actions.js | 48 +++++++++++++++++++++++++------ assets/style.css | 6 ++++ main.go | 2 +- moves.go | 64 ++++++++++++++++++++++-------------------- 4 files changed, 80 insertions(+), 40 deletions(-) diff --git a/assets/page-actions.js b/assets/page-actions.js index 8de2034..f9edc9e 100644 --- a/assets/page-actions.js +++ b/assets/page-actions.js @@ -56,16 +56,46 @@ function movePage() { preselect: parent, hideFiles: true, confirmLabel: 'NEXT', - allowRoot: false, onSelect: function (newParent) { - promptPageName('Move — new name?', currentName, 'MOVE', function (name) { - var dest = (newParent === '/' ? '' : newParent) + '/' + name; - var form = document.createElement('form'); - form.method = 'POST'; - form.action = window.location.pathname + '?move=' + - encodeURIComponent(dest); - document.body.appendChild(form); - form.submit(); + var input = document.createElement('input'); + input.type = 'text'; + input.className = 'modal-input'; + input.placeholder = 'Page name'; + input.value = currentName; + + var linksCheckbox = document.createElement('input'); + linksCheckbox.type = 'checkbox'; + linksCheckbox.id = 'move-update-links'; + + var linksLabel = document.createElement('label'); + linksLabel.htmlFor = linksCheckbox.id; + linksLabel.className = 'modal-checkbox'; + linksLabel.appendChild(linksCheckbox); + linksLabel.appendChild(document.createTextNode('Update links')); + + var body = document.createDocumentFragment(); + body.appendChild(input); + body.appendChild(linksLabel); + + openModal({ + title: 'Move — new name?', + body: body, + confirm: { + label: 'MOVE', + onConfirm: function () { + var name = input.value.trim(); + if (!name) return; + var dest = (newParent === '/' ? '' : newParent) + '/' + name; + var action = window.location.pathname + '?move=' + + encodeURIComponent(dest); + if (linksCheckbox.checked) action += '&links=1'; + var form = document.createElement('form'); + form.method = 'POST'; + form.action = action; + document.body.appendChild(form); + form.submit(); + } + } }); } }); diff --git a/assets/style.css b/assets/style.css index 573c2de..9fa929e 100644 --- a/assets/style.css +++ b/assets/style.css @@ -626,6 +626,12 @@ hr { outline: none; } +.modal-checkbox { + display: flex; + align-items: center; + gap: 0.5rem; +} + /* === Tree picker === */ .tree-picker { max-height: 60vh; diff --git a/main.go b/main.go index abf9557..bcf2bb0 100644 --- a/main.go +++ b/main.go @@ -291,7 +291,7 @@ 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")) + h.handleMove(w, r, urlPath, fsPath, query.Get("move"), query.Has("links")) return } if query.Has("toggle") { diff --git a/moves.go b/moves.go index 58dcba6..4353346 100644 --- a/moves.go +++ b/moves.go @@ -10,10 +10,11 @@ import ( "strings" ) -// handleMove moves the folder at srcFsPath (wiki URL srcURL) to dstURL and -// rewrites every [[...]] wiki link across the tree that targets the old path -// or any descendant. All rewritten files are held in memory for rollback. -func (h *handler) handleMove(w http.ResponseWriter, r *http.Request, srcURL, srcFsPath, dstURL string) { +// handleMove moves the folder at srcFsPath (wiki URL srcURL) to dstURL. When +// updateLinks is true it also rewrites every [[...]] wiki link across the +// tree that targets the old path or any descendant; rewritten files are held +// in memory for rollback. +func (h *handler) handleMove(w http.ResponseWriter, r *http.Request, srcURL, srcFsPath, dstURL string, updateLinks bool) { oldPath := normalizeMovePath(srcURL) if oldPath == "/" { http.Error(w, "cannot move wiki root", http.StatusBadRequest) @@ -44,35 +45,38 @@ func (h *handler) handleMove(w http.ResponseWriter, r *http.Request, srcURL, src return } - // Phase 1: walk the tree and rewrite every index.md that references the - // moved path. Keep the pre-rewrite bytes in memory so we can revert on - // failure. The walker only reads directory listings and files literally - // named index.md; hidden directories are pruned. A cheap substring check - // skips parsing files that cannot contain a relevant link. + // Phase 1: optionally walk the tree and rewrite every index.md that + // references the moved path. Keep the pre-rewrite bytes in memory so we + // can revert on failure. The walker only reads directory listings and + // files literally named index.md; hidden directories are pruned. A cheap + // substring check skips parsing files that cannot contain a relevant + // link. rewritten := map[string][]byte{} - needle := []byte("[[" + oldPath) - walkErr := walkIndexFiles(h.root, func(fsPath string) error { - orig, err := os.ReadFile(fsPath) - if err != nil { - return err - } - if !bytes.Contains(orig, needle) { + if updateLinks { + needle := []byte("[[" + oldPath) + walkErr := walkIndexFiles(h.root, func(fsPath string) error { + orig, err := os.ReadFile(fsPath) + if err != nil { + return err + } + if !bytes.Contains(orig, needle) { + return nil + } + updated, changed := rewriteWikiLinks(orig, oldPath, newPath) + if !changed { + return nil + } + if err := writeFileAtomic(fsPath, updated, 0644); err != nil { + return fmt.Errorf("write %s: %w", fsPath, err) + } + rewritten[fsPath] = orig return nil + }) + if walkErr != nil { + rollbackRewrites(rewritten) + http.Error(w, "rewrite failed: "+walkErr.Error(), http.StatusInternalServerError) + return } - updated, changed := rewriteWikiLinks(orig, oldPath, newPath) - if !changed { - return nil - } - if err := writeFileAtomic(fsPath, updated, 0644); err != nil { - return fmt.Errorf("write %s: %w", fsPath, err) - } - rewritten[fsPath] = orig - return nil - }) - if walkErr != nil { - rollbackRewrites(rewritten) - http.Error(w, "rewrite failed: "+walkErr.Error(), http.StatusInternalServerError) - return } // Phase 2: create intermediate parent folders for the destination.