From 8cdf4a12b80b1cfa922a41f25fbf260e3488a291 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Mon, 26 Jan 2026 23:59:53 +0100 Subject: [PATCH] fix comment on profiles lol --- public/s/js/user_comments.js | 186 +++++++++++++++++++++++++++++++++++ views/comments_user.html | 90 ++--------------- 2 files changed, 192 insertions(+), 84 deletions(-) create mode 100644 public/s/js/user_comments.js diff --git a/public/s/js/user_comments.js b/public/s/js/user_comments.js new file mode 100644 index 0000000..744af8d --- /dev/null +++ b/public/s/js/user_comments.js @@ -0,0 +1,186 @@ +class UserCommentSystem { + constructor() { + this.container = document.getElementById('user-comments-container'); + this.username = this.container ? this.container.dataset.user : null; + this.page = 1; + this.loading = false; + this.finished = false; + this.customEmojis = UserCommentSystem.emojiCache || {}; + + if (this.username) { + this.init(); + } + } + + async init() { + this.loadEmojis(); + this.loadMore(); + this.bindEvents(); + } + + async loadEmojis() { + if (UserCommentSystem.emojiCache) { + this.customEmojis = UserCommentSystem.emojiCache; + return; + } + try { + const res = await fetch('/api/v2/emojis'); + const data = await res.json(); + if (data.success) { + this.customEmojis = {}; + data.emojis.forEach(e => { + this.customEmojis[e.name] = e.url; + }); + UserCommentSystem.emojiCache = this.customEmojis; + } + } catch (e) { + console.error("Failed to load emojis", e); + } + } + + bindEvents() { + window.addEventListener('scroll', () => { + if (this.loading || this.finished) return; + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 500) { + this.loadMore(); + } + }); + } + + async loadMore() { + if (this.loading || this.finished) return; + this.loading = true; + + const loader = document.createElement('div'); + loader.className = 'loader-placeholder'; + loader.innerText = 'Loading...'; + loader.style.textAlign = 'center'; + loader.style.padding = '10px'; + this.container.appendChild(loader); + + try { + const res = await fetch('/user/' + encodeURIComponent(this.username) + '/comments?page=' + this.page + '&json=true'); + const json = await res.json(); + + loader.remove(); + + if (json.success && json.comments.length > 0) { + json.comments.forEach(c => { + console.log('Raw Comment Content (ID ' + c.id + '):', c.content); + const html = this.renderComment(c); + this.container.insertAdjacentHTML('beforeend', html); + }); + this.page++; + } else { + this.finished = true; + if (this.page === 1 && (!json.comments || json.comments.length === 0)) { + this.container.innerHTML = '
No comments found.
'; + } + } + } catch (e) { + console.error(e); + loader.remove(); + } finally { + this.loading = false; + } + } + + renderEmoji(match, name) { + if (this.customEmojis && this.customEmojis[name]) { + return `${name}`; + } + return match; + } + + renderCommentContent(content) { + if (typeof marked === 'undefined') { + console.error('UserCommentSystem: marked.js is undefined!'); + return this.escapeHtml(content).replace(/:([a-z0-9_]+):/g, (m, n) => this.renderEmoji(m, n)); + } + + try { + // 1. Pre-process server-escaped content + + // Fix Greentext: Server sends >lool -> convert to > lool for marked + let safe = content.replace(/^>/gm, '> '); + // Also handle raw > just in case + safe = safe.replace(/^>(?=[^ ])/gm, '> '); + + // Fix Images: Server sends -> convert to markdown ![]() + // This avoids them being escaped by our HTML escaping later + safe = safe.replace(/]*src="([^"]+)"[^>]*>/g, (match, src) => { + let altMatch = match.match(/alt="([^"]*)"/); + let alt = altMatch ? altMatch[1] : ''; + return `![${alt}](${src})`; + }); + + // 2. Escape HTML (standard safety) + safe = safe + .replace(/&/g, "&") + .replace(/|<\/p>|\n/g, ''); + return `> ${cleanQuote}
`; + }; + + // 3. Parse Markdown + let md = marked.parse(safe, { + breaks: true, + renderer: renderer + }); + + return md.replace(/:([a-z0-9_]+):/g, (m, n) => this.renderEmoji(m, n)); + } catch (e) { + console.error('UserCommentSystem Markdown Render Error:', e); + return this.escapeHtml(content); + } + } + + renderComment(c) { + const date = new Date(c.created_at).toLocaleString(); + const content = this.renderCommentContent(c.content); + + // Replicating the structure of comments.js but adapting for the list view + // We add a header indicating which item this comment belongs to + + return ` +
+
+ Comment on Item #${c.item_id} +
+ +
+
+ Item Thumbnail +
+
+
+ ${this.username} + ${date} + #${c.id} +
+
${content}
+
+
+
+ `; + } + + escapeHtml(unsafe) { + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + } +} + +window.addEventListener('DOMContentLoaded', () => { + new UserCommentSystem(); +}); diff --git a/views/comments_user.html b/views/comments_user.html index 8d60660..39a75fe 100644 --- a/views/comments_user.html +++ b/views/comments_user.html @@ -1,4 +1,5 @@ @include(snippets/header) +
@if(user.avatar) @@ -18,91 +19,12 @@
- @each(comments as c) -
-
- - - -
-
-
- On Item #{{ c.item_id }} - {{ c.created_at }} -
-
- {{ c.content }} -
-
-
- @endeach + +
+ @include(snippets/footer) - - \ No newline at end of file + + \ No newline at end of file