Merge pull request 'master' (#35) from master into 98

Reviewed-on: #35
This commit is contained in:
Kibi Kelburton
2026-07-28 20:02:13 +00:00
4 changed files with 75 additions and 50 deletions

View File

@@ -1160,17 +1160,13 @@ class CommentSystem {
const author = openerEl.dataset.display || openerEl.dataset.username || 'System'; const author = openerEl.dataset.display || openerEl.dataset.username || 'System';
const contentEl = body.querySelector('.comment-content'); const contentEl = body.querySelector('.comment-content');
if (contentEl) { if (contentEl) {
const LINE_MAX = 200;
let rawText = (contentEl.dataset.raw || '').trim(); let rawText = (contentEl.dataset.raw || '').trim();
if (rawText.includes('>') || rawText.includes('<') || rawText.includes('&')) { if (rawText.includes('>') || rawText.includes('<') || rawText.includes('&')) {
const txt = document.createElement('textarea'); const txt = document.createElement('textarea');
txt.innerHTML = rawText; txt.innerHTML = rawText;
rawText = txt.value; rawText = txt.value;
} }
// Preserve all lines but cap any single line exceeding LINE_MAX chars const lines = rawText.split('\n');
const lines = rawText.split('\n').map(line =>
line.length > LINE_MAX ? line.substring(0, LINE_MAX) + '\u2026' : line
);
const quote = `>>${id} \n>${author}\n${lines.map(line => `>${line}`).join('\n')}\n`; const quote = `>>${id} \n>${author}\n${lines.map(line => `>${line}`).join('\n')}\n`;
if (isNew) { if (isNew) {
@@ -1634,7 +1630,7 @@ class CommentSystem {
// Truncate extremely long comments before any processing // Truncate extremely long comments before any processing
let truncated = false; let truncated = false;
if (!bypassTruncation && content.length > CommentSystem.ITEM_VIEW_MAX_CHARS) { if (!bypassTruncation && content.length > CommentSystem.ITEM_VIEW_MAX_CHARS) {
content = content.substring(0, CommentSystem.ITEM_VIEW_MAX_CHARS) + '\u2026'; content = content.substring(0, CommentSystem.ITEM_VIEW_MAX_CHARS);
truncated = true; truncated = true;
} }

View File

@@ -7567,29 +7567,48 @@ class NotificationSystem {
// Helper: apply a display name change to all relevant DOM nodes // Helper: apply a display name change to all relevant DOM nodes
this.applyDisplayNameUpdate = (display_name, user) => { this.applyDisplayNameUpdate = (display_name, user) => {
const isSelf = !user || (window.f0ckSession?.user && user.toLowerCase() === window.f0ckSession.user.toLowerCase());
// Capture old value before overwriting — needed for thumb matching below // Capture old value before overwriting — needed for thumb matching below
const oldDisplayName = window.f0ckSession?.display_name || null; const oldDisplayName = isSelf ? (window.f0ckSession?.display_name || null) : null;
if (window.f0ckSession) window.f0ckSession.display_name = display_name || null; if (isSelf && window.f0ckSession) {
window.f0ckSession.display_name = display_name || null;
}
const userName = user || window.f0ckSession?.user; const userName = user || window.f0ckSession?.user;
// Update ALL nav-display-name instances (handles the profile page having a duplicate ID) // Update navbar display name only if this update is for the logged-in user
document.querySelectorAll('#nav-display-name').forEach(nameSpan => { if (isSelf) {
// preserve the badges (Admin, Mod) document.querySelectorAll('#nav-display-name').forEach(nameSpan => {
for (let i = nameSpan.childNodes.length - 1; i >= 0; i--) { for (let i = nameSpan.childNodes.length - 1; i >= 0; i--) {
let node = nameSpan.childNodes[i]; let node = nameSpan.childNodes[i];
if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim().length > 0) { if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim().length > 0) {
// Match and preserve any non-breaking spaces at the start (from admin/mod badges) const match = node.nodeValue.match(new RegExp('^(\\s*)(.*)'));
const match = node.nodeValue.match(new RegExp('^(\\s*)(.*)')); node.nodeValue = (match ? match[1] : '') + (display_name || userName || '');
node.nodeValue = (match ? match[1] : '') + (display_name || userName || ''); break;
break; }
}
});
}
// Update profile header display name if currently viewing this user's profile
const profileBox = document.getElementById('live-profile-preview-box');
if (profileBox && profileBox.dataset.bannerUser && userName && profileBox.dataset.bannerUser.toLowerCase() === userName.toLowerCase()) {
const profileNameSpan = document.getElementById('profile-display-name');
if (profileNameSpan) {
for (let i = profileNameSpan.childNodes.length - 1; i >= 0; i--) {
let node = profileNameSpan.childNodes[i];
if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim().length > 0) {
const match = node.nodeValue.match(new RegExp('^(\\s*)(.*)'));
node.nodeValue = (match ? match[1] : '') + (display_name || userName || '');
break;
}
} }
} }
}); const bracket = document.getElementById('username-bracket');
if (bracket) {
const bracket = document.getElementById('username-bracket');
if (bracket) {
bracket.style.display = display_name ? 'inline' : 'none'; bracket.style.display = display_name ? 'inline' : 'none';
}
} }
if (userName) { if (userName) {
@@ -7616,6 +7635,7 @@ class NotificationSystem {
// Helper: apply a username color change to relevant DOM nodes // Helper: apply a username color change to relevant DOM nodes
this.applyUsernameColorUpdate = (username_color, user) => { this.applyUsernameColorUpdate = (username_color, user) => {
const isSelf = !user || (window.f0ckSession?.user && user.toLowerCase() === window.f0ckSession.user.toLowerCase());
const userName = user || window.f0ckSession?.user; const userName = user || window.f0ckSession?.user;
if (!userName) return; if (!userName) return;
@@ -7662,22 +7682,21 @@ class NotificationSystem {
} }
}); });
// Special case for settings page preview block // Profile header display name color (if currently viewing this user's profile)
if (window.f0ckSession && userName === window.f0ckSession.user) { const profileBox = document.getElementById('live-profile-preview-box');
const previewBlock = document.getElementById('live-profile-preview-box'); if (profileBox && profileBox.dataset.bannerUser && profileBox.dataset.bannerUser.toLowerCase() === userName.toLowerCase()) {
if (previewBlock) { const profileNameSpan = document.getElementById('profile-display-name');
if (profileNameSpan) {
if (username_color) { if (username_color) {
previewBlock.style.setProperty('--author-accent', username_color); profileNameSpan.style.color = username_color;
previewBlock.style.setProperty('--author-border', username_color);
} else { } else {
previewBlock.style.setProperty('--author-accent', 'var(--accent)'); profileNameSpan.style.removeProperty('color');
previewBlock.style.setProperty('--author-border', 'var(--accent)');
} }
} }
} }
// Handle the nav-display-name span elements (profile header and top navbar) // Navbar display name color (only for current user)
if (window.f0ckSession && userName === window.f0ckSession.user) { if (isSelf) {
document.querySelectorAll('#nav-display-name').forEach(el => { document.querySelectorAll('#nav-display-name').forEach(el => {
if (username_color) { if (username_color) {
el.style.color = username_color; el.style.color = username_color;
@@ -7690,14 +7709,21 @@ class NotificationSystem {
// Helper: apply an avatar update to relevant DOM nodes // Helper: apply an avatar update to relevant DOM nodes
this.applyAvatarUpdate = (avatar_file, user) => { this.applyAvatarUpdate = (avatar_file, user) => {
const isSelf = !user || (window.f0ckSession?.user && user.toLowerCase() === window.f0ckSession.user.toLowerCase());
const userName = user || window.f0ckSession?.user; const userName = user || window.f0ckSession?.user;
if (!userName) return; if (!userName) return;
const newSrc = avatar_file ? `/a/${avatar_file}?t=${Date.now()}` : '/a/default.png'; const newSrc = avatar_file ? `/a/${avatar_file}?t=${Date.now()}` : '/a/default.png';
// Update Nav Avatar & profile header Avatar (only for current user) // Update Nav Avatar only for current user
if (window.f0ckSession && userName === window.f0ckSession.user) { if (isSelf) {
document.querySelectorAll('.nav-avatar-img, .profile_head_avatar img').forEach(img => img.src = newSrc); document.querySelectorAll('.nav-avatar-img').forEach(img => img.src = newSrc);
}
// Update profile header avatar if currently viewing this user's profile
const profileBox = document.getElementById('live-profile-preview-box');
if (profileBox && profileBox.dataset.bannerUser && profileBox.dataset.bannerUser.toLowerCase() === userName.toLowerCase()) {
document.querySelectorAll('.profile_head_avatar img').forEach(img => img.src = newSrc);
} }
// Update globally (comments, sidebar, polls, rank, infoboxes, favs) // Update globally (comments, sidebar, polls, rank, infoboxes, favs)

View File

@@ -153,12 +153,6 @@
const renderCommentContent = (content, commentId = null, itemId = null) => { const renderCommentContent = (content, commentId = null, itemId = null) => {
if (!content) return ''; if (!content) return '';
// 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') { if (typeof marked === 'undefined') {
return escapeHtml(content) return escapeHtml(content)
.replace(/:([a-z0-9_]+):/g, (m, n) => renderEmoji(m, n)); .replace(/:([a-z0-9_]+):/g, (m, n) => renderEmoji(m, n));

View File

@@ -48,7 +48,7 @@
<div class="profile_head_username"> <div class="profile_head_username">
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;"> <div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;">
<div style="flex: 1; min-width: 0; word-break: break-word; line-height: 1.2; align-self: flex-start; margin-top: 0; display: flex; align-items: center; gap: 5px;" id="profile-name-container"> <div style="flex: 1; min-width: 0; word-break: break-word; line-height: 1.2; align-self: flex-start; margin-top: 0; display: flex; align-items: center; gap: 5px;" id="profile-name-container">
<span id="nav-display-name" @if(user.username_color) style="color: {{ user.username_color }}" @endif>@if(user.admin)&#9889;&nbsp;@elseif(user.is_moderator)&#128737;&nbsp;@endif{!! user.display_name || user.user !!}@if(user.is_ghost) <span class="badge badge-secondary" style="font-size: 0.5em; vertical-align: middle; background-color: #5bc0de; color: #fff; padding: 2px 5px; border-radius: 3px; margin-left: 5px;">LEGACY</span>@endif @if(user.banned) <span class="badge badge-danger" tooltip="{{ user.ban_duration }}" style="font-size: 0.5em; vertical-align: middle; background-color: #d9534f; color: #fff; padding: 2px 5px; border-radius: 3px; margin-left: 5px;">BANNED</span>@endif</span>@if(user.display_name) <span style="font-size: 0.65em; color: #666; font-weight: 400; margin-left: 5px; letter-spacing: 0.5px;" id="username-bracket">({!! user.user !!})</span>@endif <span id="profile-display-name" @if(user.username_color) style="color: {{ user.username_color }}" @endif>@if(user.admin)&#9889;&nbsp;@elseif(user.is_moderator)&#128737;&nbsp;@endif{!! user.display_name || user.user !!}@if(user.is_ghost) <span class="badge badge-secondary" style="font-size: 0.5em; vertical-align: middle; background-color: #5bc0de; color: #fff; padding: 2px 5px; border-radius: 3px; margin-left: 5px;">LEGACY</span>@endif @if(user.banned) <span class="badge badge-danger" tooltip="{{ user.ban_duration }}" style="font-size: 0.5em; vertical-align: middle; background-color: #d9534f; color: #fff; padding: 2px 5px; border-radius: 3px; margin-left: 5px;">BANNED</span>@endif</span>@if(user.display_name) <span style="font-size: 0.65em; color: #666; font-weight: 400; margin-left: 5px; letter-spacing: 0.5px;" id="username-bracket">({!! user.user !!})</span>@endif
@if(session && session.id === user.user_id) @if(session && session.id === user.user_id)
<button id="inline-name-edit-btn" style="background: transparent; border:none; color: var(--text-muted); cursor: pointer; font-size: 0.7em; padding: 0;" title="Edit Name & Color"> <button id="inline-name-edit-btn" style="background: transparent; border:none; color: var(--text-muted); cursor: pointer; font-size: 0.7em; padding: 0;" title="Edit Name & Color">
<i class="fa-solid fa-pen"></i> <i class="fa-solid fa-pen"></i>
@@ -509,18 +509,27 @@
nameContainer.style.display = 'flex'; nameContainer.style.display = 'flex';
nameEditContainer.style.display = 'none'; nameEditContainer.style.display = 'none';
const nameSpan = document.getElementById('nav-display-name'); const updateNameNode = (el, text) => {
if (nameSpan) { if (!el) return;
nameSpan.style.color = color; for (let i = el.childNodes.length - 1; i >= 0; i--) {
for (let i = nameSpan.childNodes.length - 1; i >= 0; i--) { let node = el.childNodes[i];
let node = nameSpan.childNodes[i];
if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim().length > 0) { if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim().length > 0) {
// Match and preserve any non-breaking spaces at the start (from admin/mod badges) const match = node.nodeValue.match(new RegExp('^(\\s*)(.*)'));
const match = node.nodeValue.match(new RegExp('^(\\\\s*)(.*)')); node.nodeValue = (match ? match[1] : '') + text;
node.nodeValue = (match ? match[1] : '') + (displayName ? displayName : '{{ user.user }}');
break; break;
} }
} }
};
const targetName = displayName ? displayName : '{{ user.user }}';
const profileSpan = document.getElementById('profile-display-name');
if (profileSpan) {
profileSpan.style.color = color;
updateNameNode(profileSpan, targetName);
}
const navSpan = document.getElementById('nav-display-name');
if (navSpan) {
navSpan.style.color = color;
updateNameNode(navSpan, targetName);
} }
const bracket = document.getElementById('username-bracket'); const bracket = document.getElementById('username-bracket');
if (bracket) { if (bracket) {