// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later // Copyright (C) 2026 Florian Fischer // Get the id to this course's glossary activity const activityAutoLinkDiv = document.getElementById("glossary-autolink"); const activityLinkNode = activityAutoLinkDiv.querySelector("a.autolink"); const glossaryUrl = activityLinkNode.href; const glossaryId = (/id=(\d+)/).exec(glossaryUrl)[1]; // Remove the dummy autolink activityLinkNode.remove(); class GlossaryPost { constructor(eid, concept) { this.eid = eid; this.concept = concept; } } function autoLinkHTML(post) { const a = document.createElement("a"); a.classList.add("glossary", "autolink", "concept", `glossaryid${post.eid}`); a.dataset.entryid=post.eid; a.href = `/mod/glossary/showentry.php?eid=${post.eid}&displayformat=dictionary`; a.innerHTML = post.concept; return a.outerHTML; } function replaceAllText(node, pattern, newHTML) { var walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT); const found = []; while (walker.nextNode()) { const node = walker.currentNode; if (node.nodeValue.trim() && !(["SCRIPT", "STYLE"]).includes(node.parentNode.nodeName) ) { if (node.nodeValue.includes(pattern)) found.push(node.parentNode); } } for (const node of found) { node.innerHTML = node.innerHTML.replace(pattern, newHTML); } } const termsAlreadyAdded = new Map(); async function autoLink() { const glRes = await fetch(glossaryUrl + "&hook=ALL"); const glDoc = new DOMParser().parseFromString(await glRes.text(), "text/html"); glDoc.querySelectorAll(".glossarypost.dictionary").forEach((post) => { const concept = post.querySelector(".entry > .concept").innerText; const editurl = post.querySelector('.commands > a.icon[title*="Bearbeiten"]').href; const eid = (/&id=(\d+)/).exec(editurl)[1]; termsAlreadyAdded.set(concept, new GlossaryPost(eid, concept)); }); const page = document.querySelector('div[role="main"]'); for (const post of termsAlreadyAdded.values()) { replaceAllText(page, post.concept, autoLinkHTML(post)); } } async function addGlossaryItems() { const itemsToAdd = document.querySelectorAll(".glossary-item-toadd"); for (const item of itemsToAdd) { if (termsAlreadyAdded.has(item.dataset.term)) { item.classList.remove("glossary-item-toadd"); continue; } item.addEventListener("click", async function() { const editFormData = new FormData(); editFormData.set("cmid", glossaryId); editFormData.set("sesskey", M.cfg.sesskey); const editRes = await fetch("/mod/glossary/edit.php", { method: "POST", body: editFormData, }); const editDoc = new DOMParser().parseFromString(await editRes.text(), "text/html"); const form = editDoc.querySelector('div[role="main"] > form'); const formData = new FormData(form); formData.set("concept", item.dataset.term ? item.dataset.term: item.textContent); formData.set("definition_editor[text]", item.dataset.def); formData.set("usedynalink", "1"); formData.set("submitbutton", "Änderung speichern"); const addRes = await fetch("/mod/glossary/edit.php", { method: "POST", body: formData, }); const showAddedPostUrl = addRes.url; item.classList.remove("glossary-item-toadd"); const eid = (/hook=(\d+)/).exec(showAddedPostUrl)[1]; const post = new GlossaryPost(eid, item.dataset.term) item.innerHTML = autoLinkHTML(post); // Link to all occurrences of the added term const page = document.querySelector('div[role="main"]'); replaceAllText(page, post.concept, autoLinkHTML(post)); }, { once: true }); } } autoLink().then( addGlossaryItems ); // @license-end