Make page rewrite optional

This commit is contained in:
2026-05-07 19:35:10 +02:00
parent 73743ced78
commit 892e4860b4
4 changed files with 80 additions and 40 deletions
+34 -4
View File
@@ -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 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 = window.location.pathname + '?move=' +
encodeURIComponent(dest);
form.action = action;
document.body.appendChild(form);
form.submit();
}
}
});
}
});
+6
View File
@@ -626,6 +626,12 @@ hr {
outline: none;
}
.modal-checkbox {
display: flex;
align-items: center;
gap: 0.5rem;
}
/* === Tree picker === */
.tree-picker {
max-height: 60vh;
+1 -1
View File
@@ -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") {
+13 -9
View File
@@ -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,12 +45,14 @@ 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{}
if updateLinks {
needle := []byte("[[" + oldPath)
walkErr := walkIndexFiles(h.root, func(fsPath string) error {
orig, err := os.ReadFile(fsPath)
@@ -74,6 +77,7 @@ func (h *handler) handleMove(w http.ResponseWriter, r *http.Request, srcURL, src
http.Error(w, "rewrite failed: "+walkErr.Error(), http.StatusInternalServerError)
return
}
}
// Phase 2: create intermediate parent folders for the destination.
if parent := filepath.Dir(dstFsPath); parent != "" {