const id = getElement('metadata-post').innerText;
if (id) {
const host = getElement('metadata-instance').innerText;
const i18nreplies = getElement('i18n--is-replies').innerHTML;
const i18nreblogs = getElement('i18n--is-reblogs').innerHTML;
const i18nfavourites = getElement('i18n--is-favourites').innerHTML;
const style = document.createElement('style');
style.textContent = `
#comments > * {width: var(--golden-ratio)}
#comments noscript {margin: var(--medskip) 0}
#discussion-starter {margin-bottom: var(--medskip)}
#discussion-starter > footer {display: flex; align-items: center; justify-content: space-between}
.mastodon-comment {margin: 1rem 0 1rem calc(var(--mul) * var(--indent)); border: 1pt solid #fff4; border-left: 2pt solid var(--ac); background: #80808008; padding: 1rem 1rem 1ex; box-shadow: 0 .5pt 1pt 0 var(--g18s); overflow: auto}
.mastodon-comment .content {margin-left: 4rem; line-height: calc(var(--baselineStretch) * 1.272)}
.mastodon-comment .par a {max-width: 100%; vertical-align: bottom; white-space: break-spaces}
.mastodon-comment .attachments * {width: 100%; height: auto}
.mastodon-comment > footer {margin-top: 1rem; margin-left: 3.5rem}
.mastodon-comment > footer .stat {display: inline-flex; flex-shrink: 0; gap: 5pt}
.stat a {display: inline-flex; align-items: center; padding: 2pt; color: var(--mid); gap: 2pt}
.stat a::before {vertical-align: text-top}
a.replies.active, a.reblogs.active {color: var(--ac)}
a.favourites.active {color: var(--i3i)}
.mastodon-comment .date {margin-left: auto; padding-left: 1rem; color: var(--mid); font-size: calc(10pt * var(--fontScale))}
@media only screen and (max-width: 960px) {
.mastodon-comment .content, .mastodon-comment > footer {margin-left: 0}
}
`;
document.head.appendChild(style);
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
let commentsLoaded = false;
const toot_active = (toot, what) => {
const count = toot[`${what}_count`];
return count > 0 ? 'active' : '';
};
const toot_count = (toot, what) => {
const count = toot[`${what}_count`];
return count > 0 ? count : '';
};
const user_account = (account) => {
let result = `@${account.acct}`;
if (!account.acct.includes('@')) {
const domain = new URL(account.url);
result += `@${domain.hostname}`;
}
return result;
};
const render_toots = (toots, in_reply_to, depth) => {
const tootsToRender = toots
.filter(toot => toot.in_reply_to_id === in_reply_to)
.sort((a, b) => a.created_at.localeCompare(b.created_at));
tootsToRender.forEach(toot => render_toot(toots, toot, depth));
};
const render_toot = (toots, toot, depth) => {
toot.account.display_name = escapeHtml(toot.account.display_name);
toot.account.emojis.forEach(emoji => {
toot.account.display_name = toot.account.display_name.replace(
`:${emoji.shortcode}:`,
`
`
);
});
const renderAttachment = attachment => {
const attachmentTypes = {
image: () => `
`,
video: () => ``,
gifv: () => ``,
audio: () => ``,
default: () => `${attachment.type}`
};
return (attachmentTypes[attachment.type] || attachmentTypes.default)();
};
const mastodonComment = `
`;
getElement('mastodon-comments-list')
.appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
render_toots(toots, toot.id, depth + 1);
};
const toot_stats = toot => `
${toot_count(toot, 'replies')}
${toot_count(toot, 'reblogs')}
${toot_count(toot, 'favourites')}
`;
const loadComments = async () => {
if (commentsLoaded) return;
const commentsList = getElement('mastodon-comments-list');
commentsList.innerHTML = getElement('i18n--is-loading').innerHTML;
try {
const [tootResponse, contextResponse] = await Promise.all([
fetch(`https://${host}/api/v1/statuses/${id}`),
fetch(`https://${host}/api/v1/statuses/${id}/context`)
]);
const [toot, data] = await Promise.all([
tootResponse.json(),
contextResponse.json()
]);
getElement("mastodon-stats").innerHTML = toot_stats(toot);
if (data.descendants?.length > 0) {
commentsList.innerHTML = "";
render_toots(data.descendants, id, 0);
} else {
commentsList.innerHTML = getElement('i18n--no-comment').innerHTML;
}
commentsLoaded = true;
commentsList.setAttribute('aria-busy', 'false');
} catch (error) {
console.error('Error loading comments:', error);
commentsList.innerHTML = 'Error loading comments';
}
};
const respondToVisibility = (element, callback) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
callback();
}
});
}, { root: null });
observer.observe(element);
};
const comments = getElement("mastodon-comments-list");
respondToVisibility(comments, loadComments);
}