Improve wiki linking

This commit is contained in:
2026-06-09 18:36:40 +02:00
parent 5525a03179
commit 204e89dbce
3 changed files with 160 additions and 78 deletions
+67 -8
View File
@@ -172,17 +172,76 @@
movie: function () { M.run(movieCtx); },
};
// Wiki link button: drop an empty [[]] at the cursor and open the `[[`
// completion popup so the same autocomplete flow handles target selection.
// isValidWikiTarget mirrors the Go validator in wikilinks.go — absolute
// path, no empty/dot segments. Used to gate the modal's INSERT button.
function isValidWikiTarget(p) {
if (!p || p[0] !== '/') return false;
var trimmed = p.replace(/^\/+|\/+$/g, '');
if (trimmed === '') return true;
var segs = trimmed.split('/');
for (var i = 0; i < segs.length; i++) {
if (segs[i] === '' || segs[i] === '.' || segs[i] === '..') return false;
}
return true;
}
// Wiki link button (ALT+SHIFT+P): open a modal with a target field backed by
// full /_search typeahead plus an optional display-text field, then insert
// [[target]] or [[target::display]] at the cursor. (Inline `[[` typing uses
// the folder-scoped completion in wikicomplete.js instead.)
function insertWikilink() {
var sel = view.state.selection.main;
view.dispatch({
changes: { from: sel.from, to: sel.to, insert: '[[]]' },
selection: { anchor: sel.from + 2 },
scrollIntoView: true,
var selectedText = view.state.sliceDoc(sel.from, sel.to);
var container = document.createElement('div');
var targetWrap = document.createElement('div');
var targetInput = document.createElement('input');
targetInput.type = 'text';
targetInput.className = 'input';
targetInput.placeholder = 'Page path or search…';
targetWrap.appendChild(targetInput);
var displayInput = document.createElement('input');
displayInput.type = 'text';
displayInput.className = 'input';
displayInput.placeholder = 'Display text (optional)';
if (selectedText) displayInput.value = selectedText;
container.appendChild(targetWrap);
container.appendChild(displayInput);
var handle = openModal({
title: 'Insert link',
body: container,
confirm: {
label: 'INSERT',
initiallyDisabled: true,
onConfirm: function () {
var target = targetInput.value.trim();
if (!isValidWikiTarget(target)) return;
var display = displayInput.value.trim();
handle.close();
insertAtCursor(display ? '[[' + target + '::' + display + ']]' : '[[' + target + ']]');
}
}
});
function updateConfirm() {
handle.setConfirmDisabled(!isValidWikiTarget(targetInput.value.trim()));
}
targetInput.addEventListener('input', updateConfirm);
window.attachSuggestions(targetInput, {
showFooter: false,
container: targetWrap,
onPick: function (r) {
targetInput.value = '/' + r.path;
updateConfirm();
displayInput.focus();
displayInput.select();
}
});
view.focus();
CM.startCompletion(view);
}
// --- Keyboard shortcut registration ---