/** * Initialisiert die Kommentarfunktion. * * Kommentare werden per AJAX gespeichert, * ohne dass die Seite neu geladen werden muss. */ document.addEventListener("DOMContentLoaded", function () { const form = document.getElementById("comment-form"); const commentsList = document.getElementById("comments-list"); const commentContent = document.getElementById("comment-content"); const parentCommentInput = document.getElementById("parent-comment-id"); const replyInfo = document.getElementById("reply-info"); /** * Fragt vor dem Löschen eines Kommentars nach einer Bestätigung. * * Der Listener funktioniert auch für Kommentare, * die später per AJAX eingefügt werden. */ document.addEventListener("submit", function (event) { if (!event.target.classList.contains("delete-comment-form")) { return; } const confirmed = confirm( "Möchtest du diesen Kommentar wirklich löschen?" ); if (!confirmed) { event.preventDefault(); } }); if (!form || !commentsList || !commentContent || !parentCommentInput) { return; } /** * Aktiviert einen einzelnen Antworten-Link. * * @param {HTMLAnchorElement} replyLink Antworten-Link */ function registerReplyButton(replyLink) { replyLink.addEventListener("click", function (event) { /* * Mit JavaScript wird die Seite nicht neu geladen. * Ohne JavaScript funktioniert der normale Link. */ event.preventDefault(); parentCommentInput.value = replyLink.dataset.commentId; if (replyInfo) { replyInfo.textContent = "Antwort auf " + replyLink.dataset.author; replyInfo.style.display = "block"; } commentContent.focus(); }); } /** * Registriert alle bereits vorhandenen Antwort-Buttons. */ document.querySelectorAll(".reply-button").forEach(function (button) { registerReplyButton(button); }); /** * Sendet Kommentare per AJAX an den Server. */ form.addEventListener("submit", function (event) { event.preventDefault(); const formData = new FormData(form); const parentCommentId = parentCommentInput.value; fetch(form.action, { method: "POST", body: formData, headers: { "X-Requested-With": "XMLHttpRequest" } }) .then(function (response) { if (!response.ok) { throw new Error("Fehlerhafte Serverantwort."); } return response.json(); }) .then(function (data) { if (!data.success) { alert(data.message); return; } const emptyMessage = commentsList.querySelector( ".no-comments-message" ); if (emptyMessage) { emptyMessage.remove(); } const commentElement = document.createElement("div"); commentElement.classList.add("comment-item"); commentElement.dataset.commentId = data.commentId; if (parentCommentId !== "") { commentElement.classList.add("comment-reply"); commentElement.innerHTML = `

${escapeHtml(data.author)} ${escapeHtml(data.created)}

${escapeHtml(data.content).replace(/\n/g, "
")}

Antwort bearbeiten
`; const parentReplies = commentsList.querySelector( `.comment-item[data-comment-id="${parentCommentId}"] .comment-replies` ); if (parentReplies) { parentReplies.appendChild(commentElement); } else { commentsList.prepend(commentElement); } } else { commentElement.innerHTML = `

${escapeHtml(data.author)} ${escapeHtml(data.created)}

${escapeHtml(data.content).replace(/\n/g, "
")}

Kommentar bearbeiten
Antworten
`; commentsList.prepend(commentElement); const newReplyButton = commentElement.querySelector(".reply-button"); if (newReplyButton) { registerReplyButton(newReplyButton); } } commentContent.value = ""; parentCommentInput.value = ""; if (replyInfo) { replyInfo.textContent = ""; replyInfo.style.display = "none"; } }) .catch(function (error) { console.error(error); alert("Kommentar konnte nicht gesendet werden."); }); }); /** * Entfernt HTML-Sonderzeichen aus Nutzereingaben. * * @param {*} text Zu bereinigender Text * @returns {string} Sicherer Text */ function escapeHtml(text) { const div = document.createElement("div"); div.textContent = String(text ?? ""); return div.innerHTML; } });