text editor link autocomplete

This commit is contained in:
2026-06-12 13:57:14 -04:00
parent 0adb980cf7
commit 4655008154
3 changed files with 146 additions and 42 deletions

File diff suppressed because one or more lines are too long

View File

@@ -18,6 +18,7 @@
var codeMirrorContainer = document.querySelector("[data-codemirror-mount]"); var codeMirrorContainer = document.querySelector("[data-codemirror-mount]");
var codeMirrorReadyPromise = null; var codeMirrorReadyPromise = null;
var codeMirrorModules = null; var codeMirrorModules = null;
var documentCompletionOptionsPromise = null;
if (!form || !textarea || statusNodes.length === 0) { if (!form || !textarea || statusNodes.length === 0) {
return; return;
@@ -507,6 +508,105 @@
])); ]));
} }
function normalizeCompletionPath(doc) {
var docPath = doc && doc.path ? String(doc.path) : "";
return docPath.replace(/\.md$/, "");
}
function buildDocumentCompletionOptions(documents) {
var seen = new Set();
return (documents || [])
.map(function (doc) {
var label = normalizeCompletionPath(doc);
if (!label || seen.has(label) || label === path.replace(/\.md$/, "")) {
return null;
}
seen.add(label);
return {
label: label,
detail: doc.title && doc.title !== label ? doc.title : doc.path,
type: "file",
apply: function (view, completion, from, to) {
var insert = completion.label;
var after = view.state.doc.sliceString(to, Math.min(view.state.doc.length, to + 2));
if (after !== "]]") {
insert += "]]";
}
view.dispatch({
changes: { from: from, to: to, insert: insert },
selection: { anchor: from + insert.length },
});
},
};
})
.filter(Boolean)
.sort(function (a, b) {
return a.label.localeCompare(b.label);
});
}
function fetchDocumentCompletionOptions() {
return fetch("/api/documents", { credentials: "same-origin" })
.then(function (response) {
if (!response.ok) {
throw new Error("Could not load documents");
}
return response.json();
})
.then(function (data) {
var documents = data.documents || [];
if (window.MDHubCache && window.MDHubCache.cacheDocuments) {
window.MDHubCache.cacheDocuments(documents).catch(function () {});
}
return buildDocumentCompletionOptions(documents);
});
}
function loadDocumentCompletionOptions() {
if (documentCompletionOptionsPromise) {
return documentCompletionOptionsPromise;
}
documentCompletionOptionsPromise = Promise.resolve()
.then(function () {
if (window.MDHubCache && window.MDHubCache.getCachedDocuments) {
return window.MDHubCache.getCachedDocuments().then(function (documents) {
if (documents && documents.length > 0) {
return buildDocumentCompletionOptions(documents);
}
return fetchDocumentCompletionOptions();
});
}
return fetchDocumentCompletionOptions();
})
.catch(function () {
return [];
});
return documentCompletionOptionsPromise;
}
function wikiLinkCompletions(context) {
var before = context.matchBefore(/\[\[([^\]\n]*)$/);
if (!before) {
return null;
}
return loadDocumentCompletionOptions().then(function (options) {
if (!options.length) {
return null;
}
return {
from: before.from + 2,
to: before.to,
options: options,
validFor: /^[^\]\n]*$/,
};
});
}
function createCodeMirrorEditor(mount, initialValue, options) { function createCodeMirrorEditor(mount, initialValue, options) {
var cm = codeMirrorModules.cm; var cm = codeMirrorModules.cm;
var markdownModule = codeMirrorModules.markdown; var markdownModule = codeMirrorModules.markdown;
@@ -521,6 +621,10 @@
cm.EditorView.lineWrapping, cm.EditorView.lineWrapping,
codeMirrorTheme(), codeMirrorTheme(),
codeMirrorHighlighting(), codeMirrorHighlighting(),
cm.autocompletion({
override: [wikiLinkCompletions],
activateOnTyping: true,
}),
cm.EditorView.updateListener.of(function (update) { cm.EditorView.updateListener.of(function (update) {
if (update.docChanged) { if (update.docChanged) {
onChange(update.state.doc.toString()); onChange(update.state.doc.toString());

View File

@@ -1,4 +1,4 @@
const STATIC_CACHE = "md-hub-static-v6"; const STATIC_CACHE = "md-hub-static-v7";
const DB_NAME = "md-hub-cache"; const DB_NAME = "md-hub-cache";
const DB_VERSION = 3; const DB_VERSION = 3;
const STORE_PAGES = "pages"; const STORE_PAGES = "pages";