96 lines
3.6 KiB
JavaScript
96 lines
3.6 KiB
JavaScript
// „Gibt es schon?" — zeigt beim Anlegen eines Eintrags vorhandene Einträge mit
|
|
// ähnlichem Titel an (AUSBAUSTUFEN.md 5.7).
|
|
//
|
|
// Agenten bekommen bei "remember" eine Rückfrage, wenn es schon einen
|
|
// ähnlichen Eintrag gibt. Menschen im Formular bekommen denselben Hinweis,
|
|
// nur ohne Sperre: Die Liste erscheint unter dem Titel, speichern lässt sich
|
|
// trotzdem. Geprüft wird auf dem Server mit derselben Logik wie bei MCP
|
|
// (internal/duplicates), damit beide Wege gleich urteilen.
|
|
//
|
|
// Gefragt wird erst, wenn eine Weile nicht getippt wurde (delay), nicht
|
|
// bei jedem Buchstaben. Antworten, die zu spät für den aktuellen Titel
|
|
// kommen, werden verworfen.
|
|
(function () {
|
|
"use strict";
|
|
|
|
var titleInput = document.querySelector("input[data-similar-url]");
|
|
var box = document.querySelector("[data-similar-list]");
|
|
if (!titleInput || !box) {
|
|
return;
|
|
}
|
|
var list = box.querySelector("ul");
|
|
var slugField = document.querySelector("input[name=slug]");
|
|
var url = titleInput.getAttribute("data-similar-url");
|
|
// Die Adresse eines Eintrags: aus der Such-URL ".../entries/similar" wird
|
|
// ".../e/<slug>".
|
|
var entryBase = url.replace(/entries\/similar$/, "e/");
|
|
|
|
var delay = 400; // Millisekunden ohne Tippen, bevor gefragt wird
|
|
var timeoutId = null;
|
|
var lastQuery = "";
|
|
|
|
function show(candidates) {
|
|
list.textContent = "";
|
|
candidates.forEach(function (k) {
|
|
var li = document.createElement("li");
|
|
var a = document.createElement("a");
|
|
a.href = entryBase + encodeURIComponent(k.slug);
|
|
a.target = "_blank";
|
|
a.rel = "noopener";
|
|
a.textContent = k.title;
|
|
li.appendChild(a);
|
|
|
|
// Die gemeinsamen Wörter zeigen, warum der Eintrag hier steht.
|
|
// Ist es nur ein allgemeines Wort, sieht man sofort: anderes Thema.
|
|
if (k.shared && k.shared.length) {
|
|
var reason = document.createElement("span");
|
|
reason.className = "help";
|
|
reason.textContent = " — gemeinsam: " + k.shared.join(", ");
|
|
li.appendChild(reason);
|
|
}
|
|
list.appendChild(li);
|
|
});
|
|
box.hidden = candidates.length === 0;
|
|
}
|
|
|
|
function ask() {
|
|
var t = titleInput.value.trim();
|
|
var s = slugField ? slugField.value.trim() : "";
|
|
var cacheKey = t + "\u0000" + s;
|
|
if (cacheKey === lastQuery) {
|
|
return;
|
|
}
|
|
lastQuery = cacheKey;
|
|
|
|
if (t.length < 3) {
|
|
show([]);
|
|
return;
|
|
}
|
|
|
|
var address = url + "?title=" + encodeURIComponent(t) + "&slug=" + encodeURIComponent(s);
|
|
fetch(address, { credentials: "same-origin", headers: { "Accept": "application/json" } })
|
|
.then(function (answer) { return answer.ok ? answer.json() : []; })
|
|
.then(function (candidates) {
|
|
// Inzwischen weitergetippt? Dann gehört die Antwort zu einem
|
|
// alten Titel.
|
|
if (cacheKey === lastQuery) {
|
|
show(candidates || []);
|
|
}
|
|
})
|
|
.catch(function () { /* nur ein Hinweis — ohne ihn geht es auch */ });
|
|
}
|
|
|
|
function askLater() {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = setTimeout(ask, delay);
|
|
}
|
|
|
|
titleInput.addEventListener("input", askLater);
|
|
if (slugField) {
|
|
slugField.addEventListener("input", askLater);
|
|
}
|
|
// Vorbelegter Titel (z.B. nach einem Fehler zurück im Formular).
|
|
if (titleInput.value.trim() !== "") {
|
|
ask();
|
|
}
|
|
})();
|