diff --git a/public/s/css/f0ckm.css b/public/s/css/f0ckm.css index f9774d8..6f691d3 100644 --- a/public/s/css/f0ckm.css +++ b/public/s/css/f0ckm.css @@ -1925,6 +1925,32 @@ body.sidebar-right-hidden .global-sidebar-right { /* Hidden by default, shown via JS if overflow detected */ } + +.item-comment-truncated-notice { + display: block; + margin-top: 8px; + font-size: 0.85em; + color: #666; +} + +.load-full-comment-btn { + background: none; + border: none; + padding: 0; + color: var(--accent); + font-size: inherit; + font-family: inherit; + cursor: pointer; + opacity: 0.85; + text-decoration: underline; + text-underline-offset: 2px; + transition: opacity 0.15s; +} + +.load-full-comment-btn:hover { + opacity: 1; +} + /* Avatar in sidebar activity */ .sidebar-avatar-link { flex-shrink: 0; @@ -7886,6 +7912,7 @@ span.badge.badge-current { text-decoration: underline; } + .sidebar-comment-img.emoji { width: auto; display: inline-block; diff --git a/public/s/js/comments.js b/public/s/js/comments.js index e5ef61e..da08e43 100644 --- a/public/s/js/comments.js +++ b/public/s/js/comments.js @@ -461,7 +461,7 @@ class CommentSystem { const contentEl = el.querySelector('.comment-content'); if (contentEl) { - contentEl.innerHTML = this.renderCommentContent(data.content); + contentEl.innerHTML = this.renderCommentContent(data.content, data.comment_id); // Flash effect to draw attention el.classList.remove('new-item-fade'); @@ -1237,7 +1237,7 @@ class CommentSystem { const contentEl = el.querySelector('.comment-content'); if (contentEl && contentEl.dataset.raw !== incoming.content) { window.f0ckDebug(`[CommentSystem] Reconcile: Updating content for #c${id}`); - contentEl.innerHTML = this.renderCommentContent(incoming.content); + contentEl.innerHTML = this.renderCommentContent(incoming.content, incoming.id); contentEl.dataset.raw = incoming.content; } @@ -1366,14 +1366,17 @@ class CommentSystem { syncLevel(roots, list, false); } - renderCommentContent(content) { + // Maximum characters to fully render in the item view per comment + static get ITEM_VIEW_MAX_CHARS() { return 10000; } + + renderCommentContent(content, commentId = null, bypassTruncation = false) { if (!content) return ''; - - // Anti-recursion / Performance safeguard for extremely long comments - if (content.length > 50000) { - console.warn('Comment too long, skipping markdown for performance'); - // Use native escaping and
 to avoid all regex/marked overhead for huge strings
-            return `
${this.escapeHtml(content)}
`; + + // Truncate extremely long comments before any processing + let truncated = false; + if (!bypassTruncation && content.length > CommentSystem.ITEM_VIEW_MAX_CHARS) { + content = content.substring(0, CommentSystem.ITEM_VIEW_MAX_CHARS); + truncated = true; } if (typeof marked === 'undefined') { @@ -1633,10 +1636,19 @@ class CommentSystem { if (window.Sanitizer && typeof Sanitizer.clean === 'function') { md = Sanitizer.clean(md); } + + if (truncated) { + md += ``; + } + return md; } catch (e) { console.error('Markdown error:', e); - return this.escapeHtml(content); + let fallback = this.escapeHtml(content); + if (truncated) { + fallback += ` `; + } + return fallback; } } @@ -1722,7 +1734,7 @@ class CommentSystem { const isPinned = comment.is_pinned; // Add @mention prefix if this is a reply to a reply - const content = isDeleted ? '[deleted]' : this.renderCommentContent(comment.content); + const content = isDeleted ? '[deleted]' : this.renderCommentContent(comment.content, comment.id); const date = new Date(comment.created_at).toLocaleString(); // Admin buttons @@ -2009,6 +2021,19 @@ class CommentSystem { return; } + // Load full comment (expand truncated) + const loadFullBtn = target.closest('.load-full-comment-btn'); + if (loadFullBtn) { + const contentEl = loadFullBtn.closest('.comment-content'); + if (contentEl) { + const fullContent = contentEl.dataset.raw; + if (fullContent) { + contentEl.innerHTML = this.renderCommentContent(fullContent, null, true); + } + } + return; + } + // Comment Context Link (>>ID) const contextLink = target.closest('.comment-context-link'); if (contextLink) { diff --git a/public/s/js/sidebar-activity.js b/public/s/js/sidebar-activity.js index f7c6f72..a35ea8b 100644 --- a/public/s/js/sidebar-activity.js +++ b/public/s/js/sidebar-activity.js @@ -86,13 +86,16 @@ } }; + // Maximum characters to render in the sidebar per comment + const SIDEBAR_CONTENT_TRUNCATE = 200; + const renderCommentContent = (content, commentId = null, itemId = null) => { if (!content) return ''; - // Anti-recursion / Performance safeguard for extremely long comments - if (content.length > 50000) { - console.warn('Sidebar Activity: Comment too long, skipping markdown'); - return `
${escapeHtml(content)}
`; + // Truncate extremely long comments before any processing to keep the sidebar + // fast and the DOM lean, regardless of markdown / regex complexity. + if (content.length > SIDEBAR_CONTENT_TRUNCATE) { + content = content.substring(0, SIDEBAR_CONTENT_TRUNCATE) + '\u2026'; } if (typeof marked === 'undefined') {