diff --git a/public/s/js/comments.js b/public/s/js/comments.js
index cd99de1..b7b3882 100644
--- a/public/s/js/comments.js
+++ b/public/s/js/comments.js
@@ -2223,14 +2223,29 @@ class CommentSystem {
}
const bannerEnabled = window.f0ckCommentBannerEnabled !== false && window.f0ckSession?.comment_banner_enabled !== false;
- const bannerStyle = (bannerEnabled && comment.banner_file && comment.banner_file !== 'null')
+ let bannerStyle = (bannerEnabled && comment.banner_file && comment.banner_file !== 'null')
? `style="--author-banner: url('/a/${comment.banner_file}'); --author-banner-position: ${comment.banner_position === 'center' ? 'center top' : (comment.banner_position || 'center top')}; --author-banner-size: ${(comment.banner_size && comment.banner_size !== 'cover') ? comment.banner_size : '100% auto'}; --author-banner-repeat: no-repeat;"`
: '';
const authorUserId = comment.user_id ?? (comment.username && window.f0ckSession && comment.username.toLowerCase() === (window.f0ckSession.user || '').toLowerCase() ? (window.f0ckSession.id || window.f0ckSession.user_id) : null);
const authorUsernameColor = comment.username_color || (comment.username && window.f0ckSession && comment.username.toLowerCase() === (window.f0ckSession.user || '').toLowerCase() ? window.f0ckSession.username_color : null);
- return `
${repliesHtml}`;
+ const isAnonGuest = window.f0ckSession?.guest_anonymize && !window.f0ckSession?.logged_in;
+ if (isAnonGuest) bannerStyle = '';
+
+ const avatarHtml = isAnonGuest
+ ? ``
+ : ``;
+
+ const authorHtml = isAnonGuest
+ ? ``
+ : (comment.username
+ ? ``
+ : '');
+
+ const anonDataAttrs = isAnonGuest ? '' : `data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}"`;
+
+ return `${repliesHtml}`;
}
timeAgo(date) {
diff --git a/public/s/js/f0ckm.js b/public/s/js/f0ckm.js
index 866044a..2bc703a 100644
--- a/public/s/js/f0ckm.js
+++ b/public/s/js/f0ckm.js
@@ -6526,7 +6526,7 @@ window.cancelAnimFrame = (function () {
}
};
const initExcludedTagsModal = () => {
- if (window.f0ckSession && !window.f0ckSession.logged_in) return;
+ const isLoggedIn = !!(window.f0ckSession && window.f0ckSession.logged_in);
const overlay = document.getElementById('excluded-tags-overlay');
if (!overlay) return;
@@ -6544,9 +6544,9 @@ window.cancelAnimFrame = (function () {
overlay.offsetHeight;
overlay.classList.add('visible');
document.body.style.overflow = 'hidden';
- renderTags();
+ if (isLoggedIn) renderTags();
if (window.syncRatingButtonUI) window.syncRatingButtonUI();
- if (window.innerWidth > 768) input.focus();
+ if (isLoggedIn && window.innerWidth > 768) input.focus();
} else {
overlay.classList.remove('visible');
document.body.style.overflow = '';
@@ -6611,149 +6611,105 @@ window.cancelAnimFrame = (function () {
if (e.target === overlay) toggleModal(false);
});
- const addTag = async () => {
- const tagname = input.value.trim();
- if (!tagname) return;
- suggestions.style.display = 'none';
- try {
- const res = await fetch('/api/v2/settings/excluded_tags', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- tagname
- })
- });
- const data = await res.json();
- if (data.success) {
- renderTags();
- input.value = '';
- } else {
- window.flashMessage(data.msg || 'Error adding tag', 3000, 'error');
- }
- } catch (e) {
- console.error(e);
- } finally {
- if (window.innerWidth > 768) input.focus();
- }
- };
- input.addEventListener('keydown', e => {
- if (e.key === 'Enter') {
- e.preventDefault();
- // If a suggestion is highlighted, use it
- if (highlightIdx >= 0) {
- const items = suggestions.querySelectorAll('.tag-suggestion-item');
- if (items[highlightIdx]) {
- input.value = items[highlightIdx].querySelector('.tag-suggestion-name').textContent;
- }
- }
+ if (isLoggedIn) {
+ const addTag = async () => {
+ const tagname = input.value.trim();
+ if (!tagname) return;
suggestions.style.display = 'none';
- addTag();
- }
- });
-
- list.addEventListener('click', async e => {
- if (e.target.classList.contains('remove-excluded-tag')) {
- e.preventDefault();
- const tag = e.target.getAttribute('data-tag');
try {
- const res = await fetch(`/api/v2/settings/excluded_tags/${encodeURIComponent(tag)}`, {
- method: 'DELETE'
+ const res = await fetch('/api/v2/settings/excluded_tags', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ tagname })
});
const data = await res.json();
- if (data.success) renderTags();
+ if (data.success) { renderTags(); input.value = ''; }
+ else window.flashMessage(data.msg || 'Error adding tag', 3000, 'error');
} catch (e) {
console.error(e);
+ } finally {
+ if (window.innerWidth > 768) input.focus();
}
- }
- });
-
- // Autocomplete with dropdown suggestions
- let debounceTimer = null;
- let highlightIdx = -1;
-
- const renderSuggestions = (items) => {
- suggestions.innerHTML = '';
- highlightIdx = -1;
- if (!items.length) {
- suggestions.style.display = 'none';
- return;
- }
- items.forEach(s => {
- const div = document.createElement('div');
- div.className = 'tag-suggestion-item';
-
- const name = document.createElement('span');
- name.className = 'tag-suggestion-name';
- name.textContent = s.tag;
-
- const meta = document.createElement('span');
- meta.className = 'tag-suggestion-meta';
- meta.textContent = `${s.tagged}× · ${s.score.toFixed(2)}`;
-
- div.appendChild(name);
- div.appendChild(meta);
-
- div.addEventListener('mousedown', (e) => {
+ };
+ input.addEventListener('keydown', e => {
+ if (e.key === 'Enter') {
e.preventDefault();
- input.value = s.tag;
+ if (highlightIdx >= 0) {
+ const items = suggestions.querySelectorAll('.tag-suggestion-item');
+ if (items[highlightIdx]) input.value = items[highlightIdx].querySelector('.tag-suggestion-name').textContent;
+ }
suggestions.style.display = 'none';
addTag();
- });
- suggestions.appendChild(div);
- });
- suggestions.style.display = 'block';
- };
-
- input.addEventListener('input', () => {
- const q = input.value.trim();
- highlightIdx = -1;
- if (q.length < 1) {
- suggestions.style.display = 'none';
- return;
- }
- if (debounceTimer) clearTimeout(debounceTimer);
- debounceTimer = setTimeout(async () => {
- try {
- const res = await fetch(`/api/v2/tags/suggest?q=${encodeURIComponent(q)}`);
- const json = await res.json();
- if (json.success && json.suggestions) {
- renderSuggestions(json.suggestions.slice(0, 8));
- } else {
- suggestions.style.display = 'none';
- }
- } catch (e) {
- suggestions.style.display = 'none';
}
- }, 300);
- });
+ });
- input.addEventListener('keydown', e => {
- const items = suggestions.querySelectorAll('.tag-suggestion-item');
- if (!items.length || suggestions.style.display === 'none') return;
+ list.addEventListener('click', async e => {
+ if (e.target.classList.contains('remove-excluded-tag')) {
+ e.preventDefault();
+ const tag = e.target.getAttribute('data-tag');
+ try {
+ const res = await fetch(`/api/v2/settings/excluded_tags/${encodeURIComponent(tag)}`, { method: 'DELETE' });
+ const data = await res.json();
+ if (data.success) renderTags();
+ } catch (e) { console.error(e); }
+ }
+ });
- if (e.key === 'ArrowDown') {
- e.preventDefault();
- if (highlightIdx >= 0 && highlightIdx < items.length) items[highlightIdx].classList.remove('active');
- highlightIdx = highlightIdx < items.length - 1 ? highlightIdx + 1 : 0;
- items[highlightIdx].classList.add('active');
- items[highlightIdx].scrollIntoView({ block: 'nearest' });
- } else if (e.key === 'ArrowUp') {
- e.preventDefault();
- if (highlightIdx >= 0 && highlightIdx < items.length) items[highlightIdx].classList.remove('active');
- highlightIdx = highlightIdx > 0 ? highlightIdx - 1 : items.length - 1;
- items[highlightIdx].classList.add('active');
- items[highlightIdx].scrollIntoView({ block: 'nearest' });
- } else if (e.key === 'Escape') {
- suggestions.style.display = 'none';
+ // Autocomplete with dropdown suggestions
+ let debounceTimer = null;
+ let highlightIdx = -1;
+
+ const renderSuggestions = (items) => {
+ suggestions.innerHTML = '';
highlightIdx = -1;
- }
- });
+ if (!items.length) { suggestions.style.display = 'none'; return; }
+ items.forEach(s => {
+ const div = document.createElement('div');
+ div.className = 'tag-suggestion-item';
+ const name = document.createElement('span'); name.className = 'tag-suggestion-name'; name.textContent = s.tag;
+ const meta = document.createElement('span'); meta.className = 'tag-suggestion-meta'; meta.textContent = `${s.tagged}× · ${s.score.toFixed(2)}`;
+ div.appendChild(name); div.appendChild(meta);
+ div.addEventListener('mousedown', (e) => { e.preventDefault(); input.value = s.tag; suggestions.style.display = 'none'; addTag(); });
+ suggestions.appendChild(div);
+ });
+ suggestions.style.display = 'block';
+ };
- input.addEventListener('blur', () => {
- setTimeout(() => { suggestions.style.display = 'none'; }, 150);
- });
+ input.addEventListener('input', () => {
+ const q = input.value.trim();
+ highlightIdx = -1;
+ if (q.length < 1) { suggestions.style.display = 'none'; return; }
+ if (debounceTimer) clearTimeout(debounceTimer);
+ debounceTimer = setTimeout(async () => {
+ try {
+ const res = await fetch(`/api/v2/tags/suggest?q=${encodeURIComponent(q)}`);
+ const json = await res.json();
+ if (json.success && json.suggestions) renderSuggestions(json.suggestions.slice(0, 8));
+ else suggestions.style.display = 'none';
+ } catch (e) { suggestions.style.display = 'none'; }
+ }, 300);
+ });
+
+ input.addEventListener('keydown', e => {
+ const items = suggestions.querySelectorAll('.tag-suggestion-item');
+ if (!items.length || suggestions.style.display === 'none') return;
+ if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ if (highlightIdx >= 0 && highlightIdx < items.length) items[highlightIdx].classList.remove('active');
+ highlightIdx = highlightIdx < items.length - 1 ? highlightIdx + 1 : 0;
+ items[highlightIdx].classList.add('active'); items[highlightIdx].scrollIntoView({ block: 'nearest' });
+ } else if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ if (highlightIdx >= 0 && highlightIdx < items.length) items[highlightIdx].classList.remove('active');
+ highlightIdx = highlightIdx > 0 ? highlightIdx - 1 : items.length - 1;
+ items[highlightIdx].classList.add('active'); items[highlightIdx].scrollIntoView({ block: 'nearest' });
+ } else if (e.key === 'Escape') {
+ suggestions.style.display = 'none'; highlightIdx = -1;
+ }
+ });
+
+ input.addEventListener('blur', () => { setTimeout(() => { suggestions.style.display = 'none'; }, 150); });
+ } // end isLoggedIn tag block
// ESC to close, "e" to open
document.addEventListener('keydown', (e) => {
@@ -6922,30 +6878,39 @@ window.cancelAnimFrame = (function () {
const THUMB_SIZES = ['s', 'm', 'l', 'xl'];
const gridSizeBtns = overlay.querySelectorAll('.nav-grid-size-btn');
- const applyNavThumbSize = (size) => {
- if (!THUMB_SIZES.includes(size)) size = 'm';
+ const applyNavThumbSize = (size, persist = true) => {
+ if (!THUMB_SIZES.includes(size)) size = window.f0ckDefaultThumbSize || 'm';
document.documentElement.dataset.thumbSize = size;
- localStorage.setItem(THUMB_SIZE_KEY, size);
+ if (persist) localStorage.setItem(THUMB_SIZE_KEY, size);
gridSizeBtns.forEach(b => b.classList.toggle('active', b.dataset.thumbSize === size));
};
// Sync active state each time the modal opens
if (filterBtn) {
filterBtn.addEventListener('click', () => {
- const cur = localStorage.getItem(THUMB_SIZE_KEY) || 'm';
+ const cur = localStorage.getItem(THUMB_SIZE_KEY) || window.f0ckDefaultThumbSize || 'm';
gridSizeBtns.forEach(b => b.classList.toggle('active', b.dataset.thumbSize === cur));
});
}
gridSizeBtns.forEach(btn => {
- btn.addEventListener('click', () => applyNavThumbSize(btn.dataset.thumbSize));
+ btn.addEventListener('click', () => applyNavThumbSize(btn.dataset.thumbSize, true));
});
- // Apply persisted size immediately on init (every page load)
- applyNavThumbSize(localStorage.getItem(THUMB_SIZE_KEY) || 'm');
+ // Apply on init — do NOT persist so config default stays effective until user chooses
+ applyNavThumbSize(localStorage.getItem(THUMB_SIZE_KEY) || window.f0ckDefaultThumbSize || 'm', false);
+ };
+
+ // ── Thumb size init (runs on every page, independently of the filter modal) ──
+ const initThumbSize = () => {
+ const THUMB_SIZE_KEY = 'scroller_thumb_size';
+ const THUMB_SIZES = ['s', 'm', 'l', 'xl'];
+ const size = localStorage.getItem(THUMB_SIZE_KEY) || window.f0ckDefaultThumbSize || 'm';
+ document.documentElement.dataset.thumbSize = THUMB_SIZES.includes(size) ? size : (window.f0ckDefaultThumbSize || 'm');
};
document.addEventListener('DOMContentLoaded', () => {
+ initThumbSize(); // always runs — applies data-thumb-size to
initSearch();
initExcludedTagsModal();
if (window.updateFilterBadge) window.updateFilterBadge();
diff --git a/public/s/js/scroller.js b/public/s/js/scroller.js
index 56bb7f1..a89e8d6 100644
--- a/public/s/js/scroller.js
+++ b/public/s/js/scroller.js
@@ -100,27 +100,27 @@
// ── Grid / Thumbnail size ─────────────────────────────────────────────────
const THUMB_SIZES = ['s', 'm', 'l', 'xl'];
- let thumbSize = localStorage.getItem(THUMB_SIZE_KEY) || 'm';
- if (!THUMB_SIZES.includes(thumbSize)) thumbSize = 'm';
+ let thumbSize = localStorage.getItem(THUMB_SIZE_KEY) || window.f0ckDefaultThumbSize || 'm';
+ if (!THUMB_SIZES.includes(thumbSize)) thumbSize = window.f0ckDefaultThumbSize || 'm';
- function applyThumbSize(size) {
+ function applyThumbSize(size, persist = true) {
thumbSize = size;
document.documentElement.dataset.thumbSize = size;
- localStorage.setItem(THUMB_SIZE_KEY, size);
+ if (persist) localStorage.setItem(THUMB_SIZE_KEY, size);
// Sync pill active state whenever called outside the click handler
document.querySelectorAll('#thumb-size-pills .filter-pill').forEach(p =>
p.classList.toggle('active', p.dataset.thumbSize === size)
);
}
- // Apply persisted size on load
- applyThumbSize(thumbSize);
+ // Apply on init — do NOT persist so config default stays effective until user chooses
+ applyThumbSize(thumbSize, false);
// Wire pill click events
const thumbSizePillsEl = document.getElementById('thumb-size-pills');
if (thumbSizePillsEl) {
thumbSizePillsEl.querySelectorAll('.filter-pill').forEach(pill => {
pill.addEventListener('click', () => {
- applyThumbSize(pill.dataset.thumbSize);
+ applyThumbSize(pill.dataset.thumbSize, true);
});
});
}
@@ -1373,7 +1373,8 @@
const meta = document.createElement('div'); meta.className = 'scroll-meta';
// esc() the color value: a raw '"' in username_color would break out of the
// style attribute and allow arbitrary HTML injection (XSS).
- const colorStyle = item.username_color ? `color:${esc(item.username_color)}` : '';
+ const isAnonGuest = window.f0ckSession?.guest_anonymize && !window.f0ckSession?.logged_in;
+ const colorStyle = (!isAnonGuest && item.username_color) ? `color:${esc(item.username_color)}` : '';
const ratingHtml = `${esc(item.rating_label)}`;
const ocHtml = item.is_oc ? ` OC` : '';
const badgesHtml = `${ratingHtml}${ocHtml}
`;
@@ -1383,10 +1384,15 @@
item.tags.split(', ').map(t => `${esc(t.trim())}`).join('')
}`
: '';
- meta.innerHTML = `
- `;
+ meta.innerHTML = `
+