shadowfacts.net/site/static/js/comments.js

75 lines
2.1 KiB
JavaScript

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 `<ul class="comments-list">` + rendered + `</ul>`;
}
function renderComment(comment) {
const formattedDate = new Date(comment.published).toLocaleString("en-us", {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric"
});
return `
<div class="comment">
<img class="comment-user-avatar" src="${comment.author.icon}">
<div class="comment-main">
<p class="comment-info">
<a class="comment-user-name" href="${comment.author.id}">${comment.author.name}</a>
on
<a class="comment-date" href="${comment.id}">${formattedDate}</a>
</p>
<div class="comment-body">
${comment.content}
</div>
<div class="comment-children">
${renderCommentList(comment.children)}
</div>
</div>
</div>
`;
}