ghost rider

This commit is contained in:
2026-09-12 03:11:29 +02:00
parent 155395237b
commit b55a17dc85
25 changed files with 1012 additions and 204 deletions
+112 -19
View File
@@ -794,7 +794,9 @@ html[theme='paper'] a#prev {
}
html[theme='light'] .item_title,
html[theme='paper'] .item_title {
html[theme='light'] .item-title,
html[theme='paper'] .item_title,
html[theme='paper'] .item-title {
color: #0f172a;
}
@@ -2866,7 +2868,8 @@ body.sidebar-right-hidden #sidebar-drag-zone {
max-width: 100%;
}
body.layout-legacy .item-layout-container .item-main-content .item_title {
body.layout-legacy .item-layout-container .item-main-content .item_title,
body.layout-legacy .item-layout-container .item-main-content .item-title {
align-self: center;
width: 800px;
max-width: 100%;
@@ -3217,6 +3220,7 @@ body.sidebar-right-hidden #sidebar-drag-zone {
.item-layout-container .item-main-content>._204863,
.item-layout-container .item-main-content>.item_title,
.item-layout-container .item-main-content>.item-title,
.item-layout-container .item-main-content>.content,
.item-layout-container .item-main-content>.metadata,
.item-layout-container .item-main-content #comments-container {
@@ -3231,11 +3235,13 @@ body.sidebar-right-hidden #sidebar-drag-zone {
/* Reset z-index in fullscreen to prevent sibling stacking contexts from showing metadata/comments over the player */
#main:fullscreen .item-layout-container .item-main-content>._204863,
#main:fullscreen .item-layout-container .item-main-content>.item_title,
#main:fullscreen .item-layout-container .item-main-content>.item-title,
#main:fullscreen .item-layout-container .item-main-content>.content,
#main:fullscreen .item-layout-container .item-main-content>.metadata,
#main:fullscreen .item-layout-container .item-main-content #comments-container,
#onara-modal:fullscreen .item-layout-container .item-main-content>._204863,
#onara-modal:fullscreen .item-layout-container .item-main-content>.item_title,
#onara-modal:fullscreen .item-layout-container .item-main-content>.item-title,
#onara-modal:fullscreen .item-layout-container .item-main-content>.content,
#onara-modal:fullscreen .item-layout-container .item-main-content>.metadata,
#onara-modal:fullscreen .item-layout-container .item-main-content #comments-container {
@@ -4850,7 +4856,8 @@ html[theme='f0ck95d'] {
--comment-bg: #0b0a0a;
}
html[theme="f0ck95d"] .item_title {
html[theme="f0ck95d"] .item_title,
html[theme="f0ck95d"] .item-title {
background: black;
border-left: 2px solid gray;
border-right: 2px solid gray;
@@ -5753,7 +5760,8 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content,
._204863,
.item_title {
.item_title,
.item-title {
animation: contentSlideIn 0.55s cubic-bezier(0.16, 1, 0.3, 1) both;
will-change: transform, opacity;
}
@@ -5769,9 +5777,11 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content.slide-next,
._204863.slide-next,
.item_title.slide-next,
.item-title.slide-next,
#onara-modal .content.slide-next,
#onara-modal ._204863.slide-next,
#onara-modal .item_title.slide-next {
#onara-modal .item_title.slide-next,
#onara-modal .item-title.slide-next {
animation: contentSlideInRight 0.45s cubic-bezier(0.16, 1, 0.3, 1) both !important;
will-change: transform, opacity;
}
@@ -5779,9 +5789,11 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content.slide-prev,
._204863.slide-prev,
.item_title.slide-prev,
.item-title.slide-prev,
#onara-modal .content.slide-prev,
#onara-modal ._204863.slide-prev,
#onara-modal .item_title.slide-prev {
#onara-modal .item_title.slide-prev,
#onara-modal .item-title.slide-prev {
animation: contentSlideInLeft 0.45s cubic-bezier(0.16, 1, 0.3, 1) both !important;
will-change: transform, opacity;
}
@@ -5789,9 +5801,11 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content.slide-out-left,
._204863.slide-out-left,
.item_title.slide-out-left,
.item-title.slide-out-left,
#onara-modal .content.slide-out-left,
#onara-modal ._204863.slide-out-left,
#onara-modal .item_title.slide-out-left {
#onara-modal .item_title.slide-out-left,
#onara-modal .item-title.slide-out-left {
animation: contentSlideOutLeft 0.22s cubic-bezier(0.3, 0, 0.8, 1) forwards !important;
pointer-events: none;
will-change: transform, opacity;
@@ -5800,9 +5814,11 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content.slide-out-right,
._204863.slide-out-right,
.item_title.slide-out-right,
.item-title.slide-out-right,
#onara-modal .content.slide-out-right,
#onara-modal ._204863.slide-out-right,
#onara-modal .item_title.slide-out-right {
#onara-modal .item_title.slide-out-right,
#onara-modal .item-title.slide-out-right {
animation: contentSlideOutRight 0.22s cubic-bezier(0.3, 0, 0.8, 1) forwards !important;
pointer-events: none;
will-change: transform, opacity;
@@ -5811,9 +5827,11 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content.fade-in-zoom,
._204863.fade-in-zoom,
.item_title.fade-in-zoom,
.item-title.fade-in-zoom,
#onara-modal .content.fade-in-zoom,
#onara-modal ._204863.fade-in-zoom,
#onara-modal .item_title.fade-in-zoom {
#onara-modal .item_title.fade-in-zoom,
#onara-modal .item-title.fade-in-zoom {
animation: contentFadeInZoom 0.35s cubic-bezier(0.16, 1, 0.3, 1) both !important;
will-change: transform, opacity;
}
@@ -5821,9 +5839,11 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
.content.fade-out-zoom,
._204863.fade-out-zoom,
.item_title.fade-out-zoom,
.item-title.fade-out-zoom,
#onara-modal .content.fade-out-zoom,
#onara-modal ._204863.fade-out-zoom,
#onara-modal .item_title.fade-out-zoom {
#onara-modal .item_title.fade-out-zoom,
#onara-modal .item-title.fade-out-zoom {
animation: contentFadeOutZoom 0.18s cubic-bezier(0.3, 0, 0.8, 1) forwards !important;
pointer-events: none;
will-change: transform, opacity;
@@ -5990,11 +6010,13 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
position: relative;
}
.item_title {
.item_title,
.item-title,
.item-itle {
width: 100%;
max-width: 1100px;
padding: 4px 10px;
border-top: none;
padding: 0px 0px 5px 0px;
color: rgba(255, 255, 255, 0.72);
font-size: 0.82em;
font-family: inherit;
@@ -6004,12 +6026,26 @@ body.layout-modern.sidebar-right-hidden .pagination-container-fluid {
text-overflow: ellipsis;
line-height: 1.6;
box-sizing: border-box;
min-height: calc(1.6em + 5px) !important;
z-index: 1;
position: relative;
}
.item_title:empty::before {
.item_title_text:empty::before,
.item_title:empty::before,
.item-title:empty::before,
.item-itle:empty::before {
content: '\00a0';
visibility: hidden;
user-select: none;
pointer-events: none;
}
.item_title:has(.info-title-edit-wrap),
.item-title:has(.info-title-edit-wrap),
.item-itle:has(.info-title-edit-wrap) {
white-space: normal;
overflow: visible;
}
/* .location {
@@ -12034,7 +12070,15 @@ textarea.mod-reason {
color: #fff;
border: 1px solid #444;
resize: vertical;
padding: 5px;
padding: 8px;
border-radius: 4px;
box-sizing: border-box;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
textarea.mod-reason:focus {
outline: none;
border-color: #666;
}
.error-msg {
@@ -12044,6 +12088,47 @@ textarea.mod-reason {
display: none;
}
.error-msg:not(:empty) {
display: block;
}
#report-error {
color: #ff6b6b;
font-size: 0.88em;
margin: 10px 0 5px 0;
padding: 8px 12px;
background: rgba(255, 107, 107, 0.12);
border: 1px solid rgba(255, 107, 107, 0.35);
border-radius: 4px;
text-align: left;
line-height: 1.4;
word-break: break-word;
animation: fadeIn 0.2s ease-in-out;
}
#report-error:empty {
display: none !important;
}
.field-error {
border-color: #ff6b6b !important;
box-shadow: 0 0 0 2px rgba(255, 107, 107, 0.4) !important;
animation: fieldShake 0.4s ease-in-out;
}
#modal-report-recaptcha.field-error {
border: 1px solid #ff6b6b !important;
border-radius: 4px;
box-shadow: 0 0 0 2px rgba(255, 107, 107, 0.4) !important;
padding: 4px;
}
@keyframes fieldShake {
0%, 100% { transform: translateX(0); }
20%, 60% { transform: translateX(-6px); }
40%, 80% { transform: translateX(6px); }
}
/* ---------- notifications.html styles ---------- */
.notif-history-container {
max-width: 760px !important;
@@ -17748,7 +17833,6 @@ body.scroller-active #gchat-reopen-bubble {
.info-title-edit-wrap {
display: flex;
align-items: center;
gap: 6px;
margin-top: 2px;
}
@@ -17756,9 +17840,8 @@ body.scroller-active #gchat-reopen-bubble {
flex: 1;
background: rgba(0, 0, 0, 0.35);
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 6px;
color: #fff;
padding: 6px 10px;
padding: 7px 10px;
font-size: 0.88rem;
outline: none;
transition: all 0.18s ease;
@@ -17774,7 +17857,6 @@ body.scroller-active #gchat-reopen-bubble {
background: var(--accent, #9f0);
color: #111;
border: none;
border-radius: 6px;
width: 32px;
height: 32px;
display: flex;
@@ -19019,6 +19101,16 @@ body.onara-modal-open #sidebar-drag-zone {
z-index: 10061 !important;
}
body.onara-modal-open .admin-bar {
z-index: 100080 !important;
filter: none !important;
}
body.onara-modal-open .admin-bar.open {
opacity: 1 !important;
pointer-events: auto !important;
visibility: visible !important;
}
/* Modal wrapper covers main content area with subtle dark glassmorphism, respecting sidebar */
.onara-modal-wrapper {
position: fixed !important;
@@ -19204,7 +19296,8 @@ body.layout-modern #onara-modal .item-layout-container .item-main-content {
#onara-modal .content:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom),
#onara-modal ._204863:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom),
#onara-modal .item_title:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom) {
#onara-modal .item_title:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom),
#onara-modal .item-title:not(.slide-next):not(.slide-prev):not(.slide-out-left):not(.slide-out-right):not(.fade-in-zoom):not(.fade-out-zoom) {
animation: contentSlideIn 0.55s cubic-bezier(0.16, 1, 0.3, 1) both !important;
will-change: transform, opacity;
}
+59
View File
@@ -391,11 +391,70 @@
deleteEvent(e);
} else if (target.closest("#a_pin")) {
pinButtonEvent(e);
} else if (target.closest("#a_unavailable")) {
unavailableButtonEvent(e);
} else if (target.closest("#a_favo")) {
toggleFavEvent(e);
}
});
const unavailableButtonEvent = async e => {
if (e) e.preventDefault();
const ctx = getContext();
if (!ctx) return;
const { postid } = ctx;
const unavBtn = document.querySelector('#a_unavailable');
if (!unavBtn) return;
const currentVis = parseInt(unavBtn.getAttribute('data-visibility') || '0', 10);
const willBeUnavailable = currentVis !== 3;
const targetVis = willBeUnavailable ? 3 : 0;
const actionText = willBeUnavailable ? 'Make Unavailable (serves HTTP 451 to non-logged in visitors)' : 'Make Available (Public)';
const proceed = async () => {
try {
const res = await (await fetch('/api/v2/item/visibility', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRF-Token': window.f0ckSession?.csrf_token
},
body: new URLSearchParams({ postid, id: postid, visibility: targetVis })
})).json();
if (res.success) {
const isNowUnav = res.visibility === 3;
unavBtn.setAttribute('data-visibility', res.visibility);
unavBtn.classList.toggle('active', isNowUnav);
unavBtn.style.color = isNowUnav ? 'var(--danger, #ff4444)' : '';
unavBtn.setAttribute('title', isNowUnav ? 'Make Available (Public)' : 'Make Unavailable (451)');
const infoVisLabel = document.getElementById('info-visibility-label');
if (infoVisLabel) {
infoVisLabel.innerHTML = isNowUnav
? '<i class="fa-solid fa-ban" style="color: var(--color-danger, #ff4444);"></i> Unavailable (451)'
: '<i class="fa-solid fa-globe" style="color: var(--color-success, #00C851);"></i> Public';
}
const infoVisBtn = document.getElementById('info-visibility-edit-btn');
if (infoVisBtn) infoVisBtn.dataset.visibility = res.visibility;
window.flashMessage(isNowUnav ? 'ITEM MARKED UNAVAILABLE (451)' : 'ITEM RESTORED TO PUBLIC');
} else {
alert('Error: ' + (res.msg || 'Failed to update visibility'));
}
} catch (err) {
console.error('Unavailable error:', err);
}
};
if (typeof ModAction !== 'undefined' && ModAction.confirm) {
ModAction.confirm('Item Visibility', `${actionText} for post <strong>#${postid}</strong>?`, proceed);
} else if (confirm(`${actionText} for post #${postid}?`)) {
proceed();
}
};
const pinButtonEvent = async e => {
if (e) e.preventDefault();
const ctx = getContext();
+1 -1
View File
@@ -2245,7 +2245,7 @@ class CommentSystem {
const anonDataAttrs = isAnonGuest ? '' : `data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}"`;
return `<div class="${commentClass} ${isDeleted ? 'deleted' : ''} ${isPinned ? 'pinned' : ''}" id="c${comment.id}" ${bannerStyle}>${avatarHtml}<div class="comment-body"><div class="comment-header"><div class="comment-header-left">${pinnedBadge}${authorHtml}${contextMarker}${backlinkHtml}</div><a href="#c${comment.id}" class="comment-time timeago" tooltip="${fullDate}" data-iso="${isoDate}" data-id="${comment.id}" ${anonDataAttrs}>${timeAgo}</a></div><div class="comment-content" data-raw="${this.escapeHtml(comment.content)}">${content}</div>${this.renderCommentAttachments(comment.files, comment.content)}${this.renderCommentPoll(comment.poll, comment.id, isAnonGuest ? null : comment.username)}<div class="comment-footer"><div class="comment-footer-right"><div class="comment-actions">${!isDeleted && currentUserId ? `<button class="reply-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Reply"><i class="fa-solid fa-reply"></i></button><button class="quote-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Quote with Text"><i class="fa-solid fa-quote-left"></i></button><button class="report-comment-btn" data-id="${comment.id}" title="Report Comment" style="background:none;border:none;color:inherit;cursor:pointer;opacity:0.75;padding:0;"><i class="fa-solid fa-triangle-exclamation"></i></button>` : ''}${adminButtons}${userDeleteButton}</div></div></div></div><a href="#c${comment.id}" class="comment-permalink" title="Permalink" data-id="${comment.id}" ${anonDataAttrs}>#${comment.id}</a></div>${repliesHtml}`;
return `<div class="${commentClass} ${isDeleted ? 'deleted' : ''} ${isPinned ? 'pinned' : ''}" id="c${comment.id}" ${bannerStyle}>${avatarHtml}<div class="comment-body"><div class="comment-header"><div class="comment-header-left">${pinnedBadge}${authorHtml}${contextMarker}${backlinkHtml}</div><a href="#c${comment.id}" class="comment-time timeago" tooltip="${fullDate}" data-iso="${isoDate}" data-id="${comment.id}" ${anonDataAttrs}>${timeAgo}</a></div><div class="comment-content" data-raw="${this.escapeHtml(comment.content)}">${content}</div>${this.renderCommentAttachments(comment.files, comment.content)}${this.renderCommentPoll(comment.poll, comment.id, isAnonGuest ? null : comment.username)}<div class="comment-footer"><div class="comment-footer-right"><div class="comment-actions">${!isDeleted ? `${currentUserId ? `<button class="reply-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Reply"><i class="fa-solid fa-reply"></i></button><button class="quote-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Quote with Text"><i class="fa-solid fa-quote-left"></i></button>` : ''}<button class="report-comment-btn" data-id="${comment.id}" title="Report Comment" style="background:none;border:none;color:inherit;cursor:pointer;opacity:0.75;padding:0;"><i class="fa-solid fa-triangle-exclamation"></i></button>` : ''}${adminButtons}${userDeleteButton}</div></div></div></div><a href="#c${comment.id}" class="comment-permalink" title="Permalink" data-id="${comment.id}" ${anonDataAttrs}>#${comment.id}</a></div>${repliesHtml}`;
}
timeAgo(date) {
+224 -61
View File
@@ -972,12 +972,53 @@ window.cancelAnimFrame = (function () {
}
});
// Prevent left-click navigation on timestamp links
const fallbackCopy = (text, msg) => {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.left = "-9999px";
textarea.style.top = "0";
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
document.execCommand("copy");
if (typeof window.flashMessage === 'function') {
window.flashMessage(msg);
}
} catch (err) {
console.error("Fallback copy failed:", err);
}
document.body.removeChild(textarea);
};
const copyCurrentUrl = () => {
const url = window.location.href;
const msg = (window.f0ckI18n && window.f0ckI18n.copied) || 'URL copied to clipboard';
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(url).then(() => {
if (typeof window.flashMessage === 'function') {
window.flashMessage(msg);
}
}).catch(() => {
fallbackCopy(url, msg);
});
} else {
fallbackCopy(url, msg);
}
};
window.copyCurrentUrl = copyCurrentUrl;
// Left-click on timestamp copies the current URL to clipboard and shows toast (same as pressing "y")
document.addEventListener('click', (e) => {
if (e.target.closest('.timestamp-link')) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
const tsTarget = e.target.closest('.timestamp-link, time.timeago');
if (tsTarget) {
if (e.button === 0) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
copyCurrentUrl();
}
}
}, true);
@@ -5492,26 +5533,7 @@ window.cancelAnimFrame = (function () {
"i": clickOnElementBinding("a#a_addtag"),
"l": () => window.toggleBackground(),
"y": () => {
const url = window.location.href;
if (navigator.clipboard) {
navigator.clipboard.writeText(url).then(() => window.flashMessage('URL copied to clipboard'));
} else {
const textarea = document.createElement("textarea");
textarea.value = url;
textarea.style.position = "fixed";
textarea.style.left = "-9999px";
textarea.style.top = "0";
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
document.execCommand("copy");
window.flashMessage((window.f0ckI18n && window.f0ckI18n.copied) || 'URL copied to clipboard');
} catch (err) {
console.error("Fallback copy failed:", err);
}
document.body.removeChild(textarea);
}
copyCurrentUrl();
},
" ": () => {
if (video && typeof video.play === 'function') { // Check if video wrapper exists/is valid
@@ -7683,8 +7705,8 @@ window.cancelAnimFrame = (function () {
document.querySelector('.messages-convo-page')
);
const sel = hasDedicatedWrapper
? '.index-layout-wrapper, .meme-layout-wrapper, .messages-convo-page, .pagination-container-fluid'
: '.pagination-container-fluid, .pagewrapper';
? '.index-layout-wrapper, .meme-layout-wrapper, .messages-convo-page, .pagination-container-fluid, .admin-bar'
: '.pagination-container-fluid, .pagewrapper, .admin-bar';
return document.querySelectorAll(sel);
};
@@ -7705,10 +7727,10 @@ window.cancelAnimFrame = (function () {
const wrappers = getSidebarWrappers();
if (animateWrappers) {
wrappers.forEach(w => {
const isPagination = w.classList.contains('pagination-container-fluid');
const isRightEdge = w.classList.contains('pagination-container-fluid') || w.classList.contains('admin-bar');
const isMessages = w.classList.contains('messages-convo-page');
const prop = (isPagination || isMessages) ? 'right' : 'padding-right';
const prop = (isRightEdge || isMessages) ? 'right' : 'padding-right';
const targetVal = isHidden ? sidebarWidth + 'px' : '0px';
w.style.setProperty('transition', `${prop} 0.3s ease-in-out`, 'important');
@@ -11166,6 +11188,82 @@ document.addEventListener('DOMContentLoaded', () => {
const reportUserInput = document.getElementById('report-user-id');
const reportReason = document.getElementById('report-reason');
const reportError = document.getElementById('report-error');
let _reportRcWidgetId = null;
const showReportError = (msg, targetEl) => {
if (!reportError) return;
reportError.innerHTML = '';
const icon = document.createElement('i');
icon.className = 'fa fa-circle-exclamation';
icon.style.marginRight = '6px';
reportError.appendChild(icon);
reportError.appendChild(document.createTextNode(' ' + msg));
reportError.style.display = 'block';
if (targetEl) {
targetEl.classList.remove('field-error');
void targetEl.offsetWidth; // Force reflow to re-trigger CSS shake animation
targetEl.classList.add('field-error');
if (typeof targetEl.focus === 'function') {
try { targetEl.focus(); } catch (e) {}
}
}
};
const clearReportError = () => {
if (reportError) {
reportError.innerHTML = '';
reportError.style.display = 'none';
}
if (reportReason) reportReason.classList.remove('field-error');
const rcEl = document.getElementById('modal-report-recaptcha');
if (rcEl) rcEl.classList.remove('field-error');
};
if (reportReason) {
reportReason.addEventListener('input', () => {
if (reportReason.value.trim()) {
reportReason.classList.remove('field-error');
const rcEl = document.getElementById('modal-report-recaptcha');
if (!rcEl || !rcEl.classList.contains('field-error')) {
clearReportError();
}
}
});
reportReason.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
e.preventDefault();
const submitBtn = document.getElementById('report-submit');
if (submitBtn && !submitBtn.disabled) submitBtn.click();
}
});
}
window.renderReportRecaptcha = function() {
const rcEl = document.getElementById('modal-report-recaptcha');
if (!rcEl || !window.grecaptcha || typeof grecaptcha.render !== 'function') return;
if (_reportRcWidgetId !== null) {
try { grecaptcha.reset(_reportRcWidgetId); } catch(e) {}
} else {
const sitekey = rcEl.dataset.sitekey || (window.f0ckConfig && window.f0ckConfig.recaptcha_site_key);
if (sitekey) {
try {
_reportRcWidgetId = grecaptcha.render(rcEl, {
sitekey: sitekey,
theme: 'dark',
callback: function() {
rcEl.classList.remove('field-error');
if (!reportReason || !reportReason.classList.contains('field-error')) {
clearReportError();
}
}
});
} catch(e) {
console.warn('[REPORT] Failed to render recaptcha:', e);
}
}
}
};
// Open item report
document.addEventListener('click', (e) => {
@@ -11176,9 +11274,11 @@ document.addEventListener('DOMContentLoaded', () => {
reportCommentInput.value = '';
reportUserInput.value = '';
reportReason.value = '';
reportError.textContent = '';
clearReportError();
reportModal.style.display = 'flex';
document.body.classList.add('modal-open');
setTimeout(() => { try { reportReason.focus(); } catch(err){} }, 50);
if (window.renderReportRecaptcha) window.renderReportRecaptcha();
}
const commentBtn = e.target.closest('.report-comment-btn');
@@ -11188,9 +11288,11 @@ document.addEventListener('DOMContentLoaded', () => {
reportCommentInput.value = commentBtn.dataset.id;
reportUserInput.value = '';
reportReason.value = '';
reportError.textContent = '';
clearReportError();
reportModal.style.display = 'flex';
document.body.classList.add('modal-open');
setTimeout(() => { try { reportReason.focus(); } catch(err){} }, 50);
if (window.renderReportRecaptcha) window.renderReportRecaptcha();
}
const userBtn = e.target.closest('.report-user-btn'); // for future
@@ -11200,32 +11302,58 @@ document.addEventListener('DOMContentLoaded', () => {
reportCommentInput.value = '';
reportUserInput.value = userBtn.dataset.userId;
reportReason.value = '';
reportError.textContent = '';
clearReportError();
reportModal.style.display = 'flex';
document.body.classList.add('modal-open');
setTimeout(() => { try { reportReason.focus(); } catch(err){} }, 50);
if (window.renderReportRecaptcha) window.renderReportRecaptcha();
}
// Close logic
if (e.target.matches('#report-cancel') || e.target.id === 'report-modal') {
reportModal.style.display = 'none';
document.body.classList.remove('modal-open');
clearReportError();
if (_reportRcWidgetId !== null && window.grecaptcha) {
try { grecaptcha.reset(_reportRcWidgetId); } catch(e) {}
}
}
// Submit logic
if (e.target.matches('#report-submit')) {
clearReportError();
const reason = reportReason.value.trim();
if (!reason) {
reportError.textContent = (window.f0ckI18n && window.f0ckI18n.reason_required) || 'Please provide a reason.';
showReportError((window.f0ckI18n && window.f0ckI18n.reason_required) || 'Please provide a reason.', reportReason);
return;
}
const rcEl = document.getElementById('modal-report-recaptcha');
let rcToken = '';
if (rcEl) {
if (_reportRcWidgetId === null || !window.grecaptcha) {
showReportError((window.f0ckI18n && window.f0ckI18n.captcha_loading) || 'CAPTCHA is still loading. Please wait a moment.', rcEl);
return;
}
rcToken = grecaptcha.getResponse(_reportRcWidgetId);
if (!rcToken) {
showReportError((window.f0ckI18n && window.f0ckI18n.captcha_required) || 'Please complete the CAPTCHA.', rcEl);
return;
}
}
const payload = new URLSearchParams();
if (reportItemInput.value) payload.append('item_id', reportItemInput.value);
if (reportCommentInput.value) payload.append('comment_id', reportCommentInput.value);
if (reportUserInput.value) payload.append('reported_user_id', reportUserInput.value);
payload.append('reason', reason);
if (rcToken) payload.append('g-recaptcha-response', rcToken);
const submitBtn = e.target;
const originalBtnText = submitBtn.innerHTML;
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fa fa-spinner fa-spin" style="margin-right: 5px;"></i>' + ((window.f0ckI18n && window.f0ckI18n.processing) || 'Processing...');
e.target.disabled = true;
fetch('/api/v2/report', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
@@ -11235,20 +11363,28 @@ document.addEventListener('DOMContentLoaded', () => {
.then(data => {
if (data.success) {
reportModal.style.display = 'none';
document.body.classList.remove('modal-open');
clearReportError();
if (window.showFlash) window.showFlash((window.f0ckI18n && window.f0ckI18n.report_success) || 'Report submitted successfully.', 'success');
// Reset fields for future reports
reportReason.value = '';
} else {
reportError.textContent = data.msg || (window.f0ckI18n && window.f0ckI18n.report_error) || 'An error occurred.';
if (window.showFlash) window.showFlash(data.msg || (window.f0ckI18n && window.f0ckI18n.report_error) || 'An error occurred.', 'error');
const errMsg = data.msg || (window.f0ckI18n && window.f0ckI18n.report_error) || 'An error occurred.';
showReportError(errMsg);
if (window.showFlash) window.showFlash(errMsg, 'error');
}
})
.catch(err => {
reportError.textContent = (window.f0ckI18n && window.f0ckI18n.network_error) || 'Network error.';
if (window.showFlash) window.showFlash((window.f0ckI18n && window.f0ckI18n.network_error) || 'Network error.', 'error');
const errMsg = (window.f0ckI18n && window.f0ckI18n.network_error) || 'Network error.';
showReportError(errMsg);
if (window.showFlash) window.showFlash(errMsg, 'error');
})
.finally(() => {
e.target.disabled = false;
submitBtn.disabled = false;
submitBtn.innerHTML = originalBtnText;
if (_reportRcWidgetId !== null && window.grecaptcha) {
try { grecaptcha.reset(_reportRcWidgetId); } catch(e) {}
}
});
}
});
@@ -12585,9 +12721,9 @@ document.addEventListener('click', (e) => {
visSaveBtn.textContent = origText;
if (data.success) {
const visVal = parseInt(data.visibility, 10);
const titles = ['Public', 'Unlisted', 'Private'];
const icons = ['fa-globe', 'fa-link', 'fa-lock'];
const colors = ['var(--color-success, #00C851)', 'var(--color-warning, #ffbb33)', 'var(--color-danger, #ff4444)'];
const titles = ['Public', 'Unlisted', 'Private', 'Unavailable'];
const icons = ['fa-globe', 'fa-link', 'fa-lock', 'fa-ban'];
const colors = ['var(--color-success, #00C851)', 'var(--color-warning, #ffbb33)', 'var(--color-danger, #ff4444)', 'var(--color-danger, #ff4444)'];
const visBtn = document.getElementById('a_visibility');
if (visBtn) {
@@ -12595,6 +12731,14 @@ document.addEventListener('click', (e) => {
visBtn.setAttribute('title', `Visibility: ${titles[visVal]} (Click to change)`);
}
const unavBtn = document.getElementById('a_unavailable');
if (unavBtn) {
unavBtn.dataset.visibility = visVal;
unavBtn.classList.toggle('active', visVal === 3);
unavBtn.style.color = visVal === 3 ? 'var(--danger, #ff4444)' : '';
unavBtn.setAttribute('title', visVal === 3 ? 'Make Available (Public)' : 'Make Unavailable (451)');
}
const infoVisBtn = document.getElementById('info-visibility-edit-btn');
if (infoVisBtn) {
infoVisBtn.dataset.visibility = visVal;
@@ -12627,8 +12771,9 @@ document.addEventListener('click', (e) => {
const saveBtn = e.target.closest('#info-title-save');
if (saveBtn) {
e.preventDefault();
const input = document.getElementById('info-title-input');
const status = document.getElementById('info-title-status');
const container = saveBtn.closest('.item_title') || document;
const input = container.querySelector('#info-title-input') || document.getElementById('info-title-input');
const status = container.querySelector('#info-title-status') || document.getElementById('info-title-status');
if (!input) return;
const itemId = input.dataset.itemId;
@@ -12652,25 +12797,27 @@ document.addEventListener('click', (e) => {
saveBtn.disabled = false;
saveBtn.innerHTML = origIcon;
if (data.success) {
// Update the live .item_title bar below the ID bar
const titleBar = document.querySelector('.item_title');
if (titleBar) {
titleBar.textContent = data.title || '';
} else if (data.title) {
// Fallback: create it if somehow missing (e.g. enable_item_title was toggled)
const idBar = document.querySelector('.item-main-content > ._204863');
if (idBar) {
const newBar = document.createElement('div');
newBar.className = 'item_title';
newBar.textContent = data.title;
idBar.insertAdjacentElement('afterend', newBar);
}
// Keep input form intact and update its value
input.value = data.title || '';
// Update any plain-text title display element
const textEl = container.querySelector('.item_title_text') || document.querySelector('.item_title_text');
if (textEl) {
textEl.textContent = data.title || '';
}
// Invalidate cache so navigating next/prev fetches fresh HTML from server
if (window.invalidateItemCache) {
window.invalidateItemCache(itemId);
}
if (status) {
status.textContent = '✓ Saved';
status.style.color = 'var(--accent, #5cb85c)';
status.style.display = 'inline';
setTimeout(() => { status.style.display = 'none'; }, 2000);
status.style.display = 'none';
status.textContent = '';
}
if (window.flashMessage) {
window.flashMessage('Title saved', 2000, 'success');
}
} else {
if (status) {
@@ -12678,6 +12825,9 @@ document.addEventListener('click', (e) => {
status.style.color = '#e84040';
status.style.display = 'inline';
}
if (window.flashMessage) {
window.flashMessage('Error while saving Title', 3000, 'error');
}
}
})
.catch(() => {
@@ -12688,6 +12838,9 @@ document.addEventListener('click', (e) => {
status.style.color = '#e84040';
status.style.display = 'inline';
}
if (window.flashMessage) {
window.flashMessage('Error while saving Title', 3000, 'error');
}
});
return;
}
@@ -12823,6 +12976,16 @@ document.addEventListener('click', (e) => {
}
});
// Handle Enter key on title input
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && e.target && e.target.id === 'info-title-input') {
e.preventDefault();
const container = e.target.closest('.item_title') || document;
const saveBtn = container.querySelector('#info-title-save') || document.getElementById('info-title-save');
if (saveBtn) saveBtn.click();
}
});
// Ensure any navigation event restores the scroll state
window.addEventListener('pjax:start', () => {
if (window.resetGlobalScrollState) window.resetGlobalScrollState();
+1 -1
View File
@@ -419,7 +419,7 @@ if (!window.UserCommentSystem) {
? `style="--author-banner: url('/a/${c.banner_file}'); --author-banner-position: ${c.banner_position === 'center' ? 'center top' : (c.banner_position || 'center top')}; --author-banner-size: ${(c.banner_size && c.banner_size !== 'cover') ? c.banner_size : '100% auto'}; --author-banner-repeat: no-repeat;"`
: '';
return `<div class="comment" id="c${c.id}" ${bannerStyle}><div class="comment-avatar"><a href="/${itemKey}"><img src="/t/${c.item_id}.webp" alt=""></a></div><div class="comment-body"><div class="comment-header"><div class="comment-header-left"><span class="comment-author" tooltip="ID: ${c.user_id}" ${this.userColor ? `style="color: ${this.userColor}"` : ''}>${this.username}</span></div><span class="comment-time timeago" title="${fullDate}">${timeAgo}</span></div><div class="comment-content" data-raw="${this.escapeHtml(c.content)}">${content}</div>${this.renderCommentAttachments(c.files, c.content)}${this.renderCommentPoll(c.poll, c.id)}<div class="comment-footer"><div class="comment-footer-right"><div class="comment-actions">${window.f0ckSession && window.f0ckSession.logged_in ? `<button class="report-comment-btn" data-id="${c.id}" title="Report Comment" style="background:none;border:none;color:inherit;cursor:pointer;opacity:0.75;padding:0;"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 512 512" fill="currentColor"><path d="M506.3 417l-213.3-364c-16.3-28-57.5-28-73.8 0l-213.2 364C-10.6 445.1 9.7 480 42.7 480h426.6C502.5 480 522.6 445.1 506.3 417zM256 384c-14.1 0-25.6-11.5-25.6-25.6 0-14.1 11.5-25.6 25.6-25.6 14.1 0 25.6 11.5 25.6 25.6C281.6 372.5 270.1 384 256 384zM281.6 264.4c0 14.1-11.5 25.6-25.6 25.6-14.1 0-25.6-11.5-25.6-25.6v-96c0-14.1 11.5-25.6 25.6-25.6 14.1 0 25.6 11.5 25.6 25.6V264.4z"/></svg></button>` : ''}</div></div></div></div><a href="/${itemKey}#c${c.id}" class="comment-permalink" title="Permalink">#${c.id}</a></div>`;
return `<div class="comment" id="c${c.id}" ${bannerStyle}><div class="comment-avatar"><a href="/${itemKey}"><img src="/t/${c.item_id}.webp" alt=""></a></div><div class="comment-body"><div class="comment-header"><div class="comment-header-left"><span class="comment-author" tooltip="ID: ${c.user_id}" ${this.userColor ? `style="color: ${this.userColor}"` : ''}>${this.username}</span></div><span class="comment-time timeago" title="${fullDate}">${timeAgo}</span></div><div class="comment-content" data-raw="${this.escapeHtml(c.content)}">${content}</div>${this.renderCommentAttachments(c.files, c.content)}${this.renderCommentPoll(c.poll, c.id)}<div class="comment-footer"><div class="comment-footer-right"><div class="comment-actions"><button class="report-comment-btn" data-id="${c.id}" title="Report Comment" style="background:none;border:none;color:inherit;cursor:pointer;opacity:0.75;padding:0;"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 512 512" fill="currentColor"><path d="M506.3 417l-213.3-364c-16.3-28-57.5-28-73.8 0l-213.2 364C-10.6 445.1 9.7 480 42.7 480h426.6C502.5 480 522.6 445.1 506.3 417zM256 384c-14.1 0-25.6-11.5-25.6-25.6 0-14.1 11.5-25.6 25.6-25.6 14.1 0 25.6 11.5 25.6 25.6C281.6 372.5 270.1 384 256 384zM281.6 264.4c0 14.1-11.5 25.6-25.6 25.6-14.1 0-25.6-11.5-25.6-25.6v-96c0-14.1 11.5-25.6 25.6-25.6 14.1 0 25.6 11.5 25.6 25.6V264.4z"/></svg></button></div></div></div></div><a href="/${itemKey}#c${c.id}" class="comment-permalink" title="Permalink">#${c.id}</a></div>`;
}
startLiveTimestamps() {