text editor link autocomplete
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
var codeMirrorContainer = document.querySelector("[data-codemirror-mount]");
|
||||
var codeMirrorReadyPromise = null;
|
||||
var codeMirrorModules = null;
|
||||
var documentCompletionOptionsPromise = null;
|
||||
|
||||
if (!form || !textarea || statusNodes.length === 0) {
|
||||
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) {
|
||||
var cm = codeMirrorModules.cm;
|
||||
var markdownModule = codeMirrorModules.markdown;
|
||||
@@ -521,6 +621,10 @@
|
||||
cm.EditorView.lineWrapping,
|
||||
codeMirrorTheme(),
|
||||
codeMirrorHighlighting(),
|
||||
cm.autocompletion({
|
||||
override: [wikiLinkCompletions],
|
||||
activateOnTyping: true,
|
||||
}),
|
||||
cm.EditorView.updateListener.of(function (update) {
|
||||
if (update.docChanged) {
|
||||
onChange(update.state.doc.toString());
|
||||
|
||||
Reference in New Issue
Block a user