let commentsLoaded = false; const details = document.getElementById("comments-container"); details.addEventListener("toggle", (even) => { if (details.open && !commentsLoaded) { fetchComments().then(() => { commentsLoaded = true; }); } }); async function fetchComments() { const res = await fetch(`/comments?id=${permalink}`); const comments = await res.json(); const rootId = new URL(permalink, document.location); const tree = buildCommentsTree(comments, rootId)[0]; const html = renderCommentList(tree); document.getElementById("comments-container").innerHTML += html; } function buildCommentsTree(comments, parent) { console.log(`Building tree for ${parent}`); let [children, rem] = partition(comments, it => { const inReplyTo = new URL(it.inReplyTo); return inReplyTo.hostname === parent.hostname && inReplyTo.pathname === parent.pathname; }); for (const child of children) { const [subChildren, subRem] = buildCommentsTree(rem, new URL(child.id)); rem = subRem; child.children = subChildren; } return [children, rem] } function partition(array, fn) { const trueArr = []; const falseArr = []; for (const el of array) { (fn(el) ? trueArr : falseArr).push(el); } return [trueArr, falseArr]; } function renderCommentList(comments) { const rendered = comments.map(renderComment).join("\n"); return ``; } function renderComment(comment) { const formattedDate = new Date(comment.published).toLocaleString("en-us", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "numeric" }); return `

${comment.author.name} on ${formattedDate}

${comment.content}
${renderCommentList(comment.children)}
`; }