This commit is contained in:
2026-09-28 22:12:38 +02:00
parent b96f188a59
commit 2cc768f1fd
24 changed files with 962 additions and 78 deletions
+27 -25
View File
@@ -2530,7 +2530,7 @@ window.cancelAnimFrame = (function () {
document.title = returnTitle;
}
const returnPath = new URL(returnUrl, window.location.origin).pathname;
const isStaticReturn = returnPath.match(/^\/(about|rules|terms|upload|subscriptions|stats|docs|settings|admin|mod|ranking|messages|meme|memes)/);
const isStaticReturn = returnPath.match(/^\/(about|rules|terms|privacy|upload|subscriptions|stats|docs|settings|admin|mod|ranking|messages|meme|memes)/);
if (isStaticReturn && typeof window.loadPageAjax === 'function') {
window.loadPageAjax(returnUrl, true, { skipPush: true });
}
@@ -2826,7 +2826,7 @@ window.cancelAnimFrame = (function () {
e.preventDefault();
const email = document.getElementById('forgot-email').value;
const status = document.getElementById('forgot-status');
const btn = forgotForm.querySelector('button');
const btn = forgotForm.querySelector('button[type="submit"]');
btn.disabled = true;
btn.textContent = i18n.sending || 'Sending...';
@@ -2868,7 +2868,7 @@ window.cancelAnimFrame = (function () {
const password = document.getElementById('reset-password').value;
const password_confirm = document.getElementById('reset-password-confirm').value;
const status = document.getElementById('reset-status');
const btn = resetForm.querySelector('button');
const btn = resetForm.querySelector('button[type="submit"]');
if (password !== password_confirm) {
status.className = 'flash-error';
@@ -2917,7 +2917,7 @@ window.cancelAnimFrame = (function () {
e.preventDefault();
switchModalView('login');
resetToLogin.style.display = 'none';
resetForm.querySelector('button').style.display = 'inline-block';
resetForm.querySelector('button[type="submit"]').style.display = 'inline-block';
});
}
}
@@ -2945,7 +2945,8 @@ window.cancelAnimFrame = (function () {
const formData = new FormData(registerForm);
const params = new URLSearchParams(formData);
const status = document.getElementById('register-status');
const btn = registerForm.querySelector('button');
const btn = registerForm.querySelector('button[type="submit"]');
const btnLabel = btn.textContent;
const password = formData.get('password');
const password_confirm = formData.get('password_confirm');
@@ -3014,7 +3015,7 @@ window.cancelAnimFrame = (function () {
}
} finally {
btn.disabled = false;
btn.textContent = 'Create Account';
btn.textContent = btnLabel;
}
});
}
@@ -3022,14 +3023,16 @@ window.cancelAnimFrame = (function () {
// Switch to register from login
// Switch to register from login
const loginToRegister = document.getElementById('login-to-register');
if (loginToRegister) {
loginToRegister.addEventListener('click', (e) => {
// "Register now" link and the Register button under "Login as Anonymous"
['login-to-register', 'modal-login-register-btn'].forEach(id => {
const el = document.getElementById(id);
if (!el) return;
el.addEventListener('click', (e) => {
e.preventDefault();
closeModal(loginModal);
openModal(registerModal);
});
}
});
// Switch to login from register
const registerToLogin = document.getElementById('register-to-login');
@@ -11339,7 +11342,7 @@ window.cancelAnimFrame = (function () {
const isAdmin = !!pathname.match(/^\/admin/);
const isMod = !!pathname.match(/^\/mod/);
const isSettings = pathname.match(/\/settings\/?(?:$|\?)/);
const isStatic = pathname.match(/\/(about|rules|terms|upload|subscriptions|stats|docs|discord|ranking|meme|memes)($|\/|\?)/);
const isStatic = pathname.match(/\/(about|rules|terms|privacy|upload|subscriptions|stats|docs|discord|ranking|meme|memes|pending)($|\/|\?)/);
const isUpload = pathname.match(/\/upload\/?(?:$|\?)/);
const isItem = typeof isItemPath === 'function' ? isItemPath(pathname) : (!pathname.startsWith('/4/') && /^\/\d+(?:[?#]|$)/.test(pathname));
const isMessages = !!pathname.match(/^\/messages(\/|$)/);
@@ -13583,7 +13586,7 @@ window.cancelAnimFrame = (function () {
pathname.match(/\/p\/\d+/) ||
pathname.match(/^\/\d+(?:[?#]|$)/) ||
pathname.match(/^\/[a-zA-Z0-9_-]{11}(?:[?#]|$)/) ||
pathname.match(/^\/(about|rules|terms|upload|subscriptions|stats|docs|settings|admin|mod|ranking|messages|meme|memes)/) ||
pathname.match(/^\/(about|rules|terms|privacy|upload|subscriptions|stats|docs|settings|admin|mod|ranking|messages|meme|memes)/) ||
pathname.startsWith('/abyss')
)) ||
(pathname.startsWith('/4/') && isItemPath(pathname))
@@ -17144,8 +17147,8 @@ window.cancelAnimFrame = (function () {
window.addEventListener('resize', syncEdgeZone, { passive: true });
// Returns true if (clientX, clientY) is within the pill's hit area.
// The pill is #sidebar-drag-zone::after — 4×40px, centered on pointer:fine,
// right-aligned with padding-right:6px on pointer:coarse.
// The pill is #sidebar-drag-zone::after — 5×40px, right-aligned at the zone's edge
// (padding-right:3px on pointer:coarse, peeking out on hover for pointer:fine).
const isWithinPillArea = (clientX, clientY) => {
const rect = edgeZone.getBoundingClientRect();
const pillH = 40;
@@ -17153,10 +17156,9 @@ window.cancelAnimFrame = (function () {
// Vertical: pill is always centered in the drag zone
const pillCenterY = rect.top + rect.height / 2;
if (clientY < pillCenterY - pillH / 2 - hitPad || clientY > pillCenterY + pillH / 2 + hitPad) return false;
// Horizontal: right-aligned on touch, centered on mouse
const isCoarse = window.matchMedia('(pointer: coarse)').matches;
const pillCenterX = isCoarse ? rect.right - 6 - 2 : rect.left + rect.width / 2;
return clientX >= pillCenterX - 2 - hitPad && clientX <= pillCenterX + 2 + hitPad;
// Horizontal: right-aligned against the zone's edge
const pillCenterX = rect.right - 3 - 2.5;
return clientX >= pillCenterX - 2.5 - hitPad && clientX <= pillCenterX + 2.5 + hitPad;
};
// Touchend: tap on the pill toggles sidebar; rest of drag zone only responds to swipe
@@ -19050,7 +19052,7 @@ class NotificationSystem {
else msg = (window.f0ckI18n && window.f0ckI18n.notif_commented) || 'commented';
}
// For admin_pending the thumbnail lives in /mod/pending/t/ until approved
// Pending thumbnails live in /pending/t/ until approved (served to the uploader and to staff only)
let thumbSrc, thumbOnerror;
if (n.type === 'warning') {
return `
@@ -19064,11 +19066,11 @@ class NotificationSystem {
</div>
`;
} else if (n.type === 'admin_pending') {
thumbSrc = `/mod/pending/t/${n.item_id}.webp`;
thumbSrc = `/pending/t/${n.item_id}.webp`;
thumbOnerror = `this.onerror=null;this.src='/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';}`;
} else {
thumbSrc = `/t/${n.item_id}.webp`;
thumbOnerror = `this.onerror=null;this.src='/mod/pending/t/${n.item_id}.webp';this.onerror=function(){this.onerror=null;this.src='/mod/deleted/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';};}`;
thumbOnerror = `this.onerror=null;this.src='/pending/t/${n.item_id}.webp';this.onerror=function(){this.onerror=null;this.src='/mod/deleted/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';};}`;
}
const thumb = n.item_id ? `<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="${thumbSrc}" alt="thumb" onerror="${thumbOnerror}"></div>` : '';
return `
@@ -19089,7 +19091,7 @@ class NotificationSystem {
const link = `/${itemKey}`;
return `
<a href="${link}" class="notif-item ${n.is_read ? '' : 'unread'} notif-with-thumb" data-id="${n.id}" data-item-id="${n.item_id || ''}" data-item-slug="${n.item_slug || n.slug || ''}">
<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="/t/${n.item_id}.webp" alt="thumb" onerror="this.onerror=null;this.src='/mod/pending/t/${n.item_id}.webp';this.onerror=function(){this.onerror=null;this.src='/mod/deleted/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';};}"></div>
<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="/t/${n.item_id}.webp" alt="thumb" onerror="this.onerror=null;this.src='/pending/t/${n.item_id}.webp';this.onerror=function(){this.onerror=null;this.src='/mod/deleted/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';};}"></div>
<div class="notif-content">
<div>
<strong>${(window.f0ckI18n && window.f0ckI18n.notif_upload_approved) || 'Your Upload has been approved'}</strong>
@@ -19157,7 +19159,7 @@ class NotificationSystem {
const link = '/mod/approve';
return `
<a href="${link}" class="notif-item ${n.is_read ? '' : 'unread'} notif-with-thumb" data-id="${n.id}" data-item-id="${n.item_id || ''}" data-item-slug="${n.item_slug || n.slug || ''}">
<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="/mod/pending/t/${n.item_id}.webp" alt="thumb" onerror="this.onerror=null;this.src='/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';}"></div>
<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="/pending/t/${n.item_id}.webp" alt="thumb" onerror="this.onerror=null;this.src='/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';}"></div>
<div class="notif-content">
<div>
<strong>${(window.f0ckI18n && window.f0ckI18n.notif_upload_pending) || 'A new upload needs approval'}</strong>
@@ -19172,7 +19174,7 @@ class NotificationSystem {
const link = '/mod/reports';
return `
<a href="${link}" class="notif-item ${n.is_read ? '' : 'unread'} notif-with-thumb" data-id="${n.id}" data-item-id="${n.item_id || ''}" data-item-slug="${n.item_slug || n.slug || ''}">
<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="/t/${n.item_id}.webp" alt="thumb" onerror="this.onerror=null;this.src='/mod/pending/t/${n.item_id}.webp';this.onerror=function(){this.onerror=null;this.src='/mod/deleted/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';};}"></div>
<div class="notif-thumb"${n.item_mode ? ` data-mode="${n.item_mode}"` : ''}><img src="/t/${n.item_id}.webp" alt="thumb" onerror="this.onerror=null;this.src='/pending/t/${n.item_id}.webp';this.onerror=function(){this.onerror=null;this.src='/mod/deleted/t/${n.item_id}.webp';this.onerror=function(){this.style.display='none';};}"></div>
<div class="notif-content">
<div>
<strong>${(window.f0ckI18n && window.f0ckI18n.notif_new_report) || 'A new user report has been submitted'}</strong>
@@ -22001,7 +22003,7 @@ document.addEventListener('DOMContentLoaded', () => {
const new_password = document.getElementById('force_new_password').value;
const new_password_confirm = document.getElementById('force_new_password_confirm').value;
const status = document.getElementById('force-password-status');
const btn = forcePasswordForm.querySelector('button');
const btn = forcePasswordForm.querySelector('button[type="submit"]');
if (new_password !== new_password_confirm) {
status.textContent = 'Passwords do not match.';
+3 -2
View File
@@ -3832,8 +3832,9 @@
if (n.type === 'warning') {
thumb = `<div class="notif-thumb" style="display:flex;align-items:center;justify-content:center;background:var(--bg-lighter);color:var(--danger);font-size:1.5em;"><i class="fa-solid fa-triangle-exclamation"></i></div>`;
} else {
const thumbSrc = n.type === 'admin_pending' ? `/mod/pending/t/${n.item_id}.webp` : `/t/${n.item_id}.webp`;
thumb = n.item_id ? `<div class="notif-thumb"><img src="${thumbSrc}" alt="" onerror="this.style.display='none'"></div>` : '';
// Pending items aren't in /t/ yet: fall back to /pending/t/ (uploader + staff only)
const thumbSrc = n.type === 'admin_pending' ? `/pending/t/${n.item_id}.webp` : `/t/${n.item_id}.webp`;
thumb = n.item_id ? `<div class="notif-thumb"><img src="${thumbSrc}" alt="" onerror="this.onerror=function(){this.style.display='none'};this.src='/pending/t/${n.item_id}.webp'"></div>` : '';
}
return `<a href="${link}" target="_blank" class="notif-item ${n.is_read ? '' : 'unread'} notif-with-thumb" data-id="${n.id}">
${thumb}
+17 -1
View File
@@ -7,6 +7,16 @@ window.escapeHtmlUpload = window.escapeHtmlUpload || ((unsafe) => {
.replace(/'/g, "&#039;");
});
// Manual approval: after an upload, send the uploader to their status page focused on the new item
window.f0ckGoToPending = window.f0ckGoToPending || ((id) => {
const target = '/pending' + (id ? '#i' + id : '');
if (typeof window.loadPageAjax === 'function') {
window.loadPageAjax(target, false, { bypassCache: true, skipCache: true, skipInherit: true });
} else {
window.location.href = target;
}
});
// ============================================================
// URL Upload Tracker — single panel, active jobs only
// ============================================================
@@ -3002,6 +3012,8 @@ window.initUploadForm = (selector) => {
}
}
if (lastData?.manual_approval && lastData?.itemid) window.f0ckGoToPending(lastData.itemid);
// URL uploads: redirect or stay based on user preference (pending/async jobs skip redirect)
if (!lastData?.pending && !lastData?.manual_approval) {
if (lastData?.itemid && window.NotificationSystemInstance && typeof window.NotificationSystemInstance.handleNewItem === 'function') {
@@ -3416,7 +3428,11 @@ window.initUploadForm = (selector) => {
window.location.href = targetUrl;
}
}
// else: stay on current page (including manual_approval pending)
if (lastData?.manual_approval) {
const pendingItem = lastData || (uploadedResults && uploadedResults[0]);
window.f0ckGoToPending(pendingItem && pendingItem.itemid);
}
// else (redirect disabled): stay on current page
}
} else {
restoreBtn();