This commit is contained in:
2026-09-10 00:07:22 +02:00
parent 43ff87ed62
commit 73ffe02bbb
12 changed files with 1327 additions and 275 deletions
+300 -22
View File
@@ -9111,7 +9111,7 @@ input#s_avatar {
height: 100%;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(5px);
z-index: 10001;
z-index: 100100;
display: flex;
align-items: center;
justify-content: center;
@@ -11765,7 +11765,7 @@ input:checked+.slider:before {
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
z-index: 100100;
}
body.modal-open {
@@ -12941,7 +12941,7 @@ body.layout-modern>.pagewrapper:not(:has(.index-layout-wrapper)):not(:has(.item-
left: 0;
width: 100vw;
height: 100vh;
z-index: 10000;
z-index: 100100;
overflow: auto;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
@@ -14866,29 +14866,16 @@ span.gchat-post-card--loading {
}
}
body.layout-modern .gapRight {
justify-content: center;
}
body.layout-modern .gapRight>svg.iconset,
body.layout-modern .gapRight>i.iconset {
height: 30px;
width: 30px;
margin: 5px;
padding: 5px;
right: 0px;
background: var(--badge-tag);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 18px;
box-sizing: border-box;
}
.gapRight,
body.layout-modern .gapRight,
body.layout-legacy .gapRight {
justify-content: center;
}
.gapRight>svg.iconset,
.gapRight>i.iconset,
body.layout-modern .gapRight>svg.iconset,
body.layout-modern .gapRight>i.iconset,
body.layout-legacy .gapRight>svg.iconset,
body.layout-legacy .gapRight>i.iconset {
height: 30px;
@@ -14904,6 +14891,7 @@ body.layout-legacy .gapRight>i.iconset {
box-sizing: border-box;
}
.gapRight>.iconset#a_favo,
body.layout-legacy .gapRight>.iconset#a_favo {
fill: #ff009b;
}
@@ -18613,4 +18601,294 @@ a.lazy-thumb.filtered-upload-ghost:hover::after {
.item-main-content {
padding-left: 15px;
padding-right: 15px;
}
/* ==========================================================================
ONARA ALTERNATIVE FLAVOR: Fullscreen See-Through Modal Wrapper
========================================================================== */
/* Prevent scrolling on background document when Onara modal is active */
body.onara-modal-open {
overflow: hidden !important;
}
/* Background main page elements (outside posts) are dimmed and softly blurred */
body.onara-modal-open .pagewrapper {
pointer-events: none !important;
user-select: none !important;
}
body.onara-modal-open .pagewrapper > *:not(.index-layout-wrapper):not(#main),
body.onara-modal-open .index-container > *:not(.posts),
body.onara-modal-open #footbar,
body.onara-modal-open .pagination-container-fluid {
opacity: 0.25 !important;
filter: blur(1.5px) !important;
transition: opacity 0.25s cubic-bezier(0.16, 1, 0.3, 1),
filter 0.25s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
/* All non-active background thumbnails are strictly dimmed, blurred, with no outlines or badges */
body.onara-modal-open .posts > a.thumb:not(.onara-active) {
opacity: 0.25 !important;
filter: blur(1.5px) !important;
box-shadow: none !important;
outline: none !important;
transition: opacity 0.25s cubic-bezier(0.16, 1, 0.3, 1),
filter 0.25s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
body.onara-modal-open .posts > a.thumb:not(.onara-active)::after {
visibility: hidden !important;
opacity: 0 !important;
}
/* ONLY the single currently active thumbnail in the background shines through with TAB highlight */
body.onara-modal-open .posts > a.thumb.onara-active {
opacity: 1 !important;
filter: none !important;
box-shadow: 0 0 0 2px var(--white, #fff), 0 0 16px rgba(255, 255, 255, 0.6) !important;
z-index: 25 !important;
}
body.onara-modal-open .posts > a.thumb.onara-active::after {
visibility: visible !important;
opacity: 1 !important;
}
/* Navbar and right sidebar stay fully visible, sharp, and interactive */
body.onara-modal-open nav.navbar {
opacity: 1 !important;
filter: none !important;
pointer-events: auto !important;
z-index: 10060 !important;
}
body.onara-modal-open .global-sidebar-right {
opacity: 1 !important;
filter: none !important;
pointer-events: auto !important;
z-index: 10060 !important;
}
body.onara-modal-open #sidebar-drag-zone {
opacity: 1 !important;
pointer-events: auto !important;
z-index: 10061 !important;
}
/* Modal wrapper covers main content area with subtle dark glassmorphism, respecting sidebar */
.onara-modal-wrapper {
position: fixed !important;
top: var(--navbar-h, 50px) !important;
bottom: 0 !important;
left: 0 !important;
right: 300px !important;
width: auto !important;
height: calc(100vh - var(--navbar-h, 50px)) !important;
z-index: 10050 !important;
display: none;
flex-direction: column !important;
background: rgba(10, 12, 16, 0.72) !important;
backdrop-filter: blur(5px) saturate(130%) !important;
-webkit-backdrop-filter: blur(5px) saturate(130%) !important;
overflow-y: auto !important;
overflow-x: hidden !important;
box-sizing: border-box !important;
animation: onaraFadeIn 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;
transition: right 0.3s ease-in-out !important;
cursor: pointer;
}
body.onara-modal-open .onara-modal-wrapper {
display: flex !important;
}
/* Sidebar hidden: modal expands to right edge */
body.sidebar-right-hidden .onara-modal-wrapper {
right: 0 !important;
}
/* Tablet (600px - 999px): sidebar is min(280px, 80vw) */
@media (min-width: 600px) and (max-width: 999px) {
.onara-modal-wrapper {
right: min(280px, 80vw) !important;
}
body.sidebar-right-hidden .onara-modal-wrapper {
right: 0 !important;
}
}
/* Mobile (<= 599px): sidebar is pure overlay, modal uses full width */
@media (max-width: 599px) {
.onara-modal-wrapper {
right: 0 !important;
}
}
@keyframes onaraFadeIn {
from {
opacity: 0;
transform: scale(0.99);
}
to {
opacity: 1;
transform: scale(1);
}
}
.onara-backdrop {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
min-height: 100% !important;
z-index: 1 !important;
cursor: pointer;
}
.onara-modal-content {
position: relative !important;
z-index: 2 !important;
width: 100% !important;
min-height: 100% !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: flex-start !important;
flex: 1 0 auto !important;
padding: 20px 0 80px 0 !important;
box-sizing: border-box !important;
cursor: pointer;
}
#onara-item-mount {
width: 100% !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: flex-start !important;
cursor: pointer;
}
/* Center the item layout inside modal and make it 100% scrollable */
#onara-modal .item-layout-container,
body.layout-legacy #onara-modal .item-layout-container,
body.layout-modern #onara-modal .item-layout-container {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: flex-start !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
margin: 0 auto !important;
padding: 0 15px !important;
box-sizing: border-box !important;
grid-template-columns: none !important;
grid-template-rows: none !important;
cursor: pointer;
}
#onara-modal .item-main-content,
body.layout-legacy #onara-modal .item-layout-container .item-main-content,
body.layout-modern #onara-modal .item-layout-container .item-main-content {
cursor: default !important;
}
#onara-modal .item-main-content,
body.layout-legacy #onara-modal .item-layout-container .item-main-content,
body.layout-modern #onara-modal .item-layout-container .item-main-content {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
width: 100% !important;
max-width: 850px !important;
height: auto !important;
min-height: auto !important;
max-height: none !important;
overflow: visible !important;
margin: 0 auto !important;
padding: 0 !important;
box-sizing: border-box !important;
grid-column: auto !important;
}
#onara-modal .item-main-content::before,
#onara-modal .item-main-content::after {
display: none !important;
}
#onara-modal .item-main-content > * {
width: 100% !important;
max-width: 800px !important;
margin-left: auto !important;
margin-right: auto !important;
}
#onara-modal .item-main-content .metadata {
width: 100% !important;
max-width: 600px !important;
margin-left: auto !important;
margin-right: auto !important;
}
#onara-modal #comments-container {
display: flex !important;
flex-direction: column !important;
flex: 0 0 auto !important;
height: auto !important;
max-height: none !important;
overflow: visible !important;
width: 100% !important;
max-width: 600px !important;
}
/* Modern layout: left sidebar flows below media inside modal */
body.layout-modern #onara-modal .item-sidebar-left {
display: flex !important;
flex-direction: column !important;
width: 100% !important;
max-width: 600px !important;
height: auto !important;
max-height: none !important;
position: static !important;
order: 2 !important;
margin: 20px auto 0 auto !important;
border-right: none !important;
box-shadow: none !important;
overflow: visible !important;
}
body.layout-modern #onara-modal .item-main-content {
order: 1 !important;
}
/* Auxiliary modals, overlays, and dialogs MUST open in front of Onara modal and fixed bars */
body.onara-modal-open .modal-overlay,
body.onara-modal-open .image-modal-overlay,
body.onara-modal-open .dm-modal-overlay,
body.onara-modal-open .swal2-container,
body.onara-modal-open .modal-backdrop,
body.onara-modal-open .modal,
body.onara-modal-open #image-modal,
body.onara-modal-open #report-modal,
body.onara-modal-open #info-modal,
body.onara-modal-open #visibility-modal,
body.onara-modal-open #halls-modal,
body.onara-modal-open #mod-action-modal,
body.onara-modal-open #warning-modal,
body.onara-modal-open #content-warning-modal,
body.onara-modal-open #login-modal,
body.onara-modal-open #register-modal,
body.onara-modal-open #shortcuts-modal,
body.onara-modal-open #excluded-tags-overlay,
body.onara-modal-open #upload-drag-modal,
body.onara-modal-open #rethumb-capture-modal,
body.onara-modal-open #gchat-img-modal {
z-index: 100100 !important;
}
+487 -117
View File
@@ -117,6 +117,17 @@ window.cancelAnimFrame = (function () {
} catch(e) { console.error('Visit tracking error:', e); }
};
const ensureLayoutClass = () => {
if (window.f0ckSession && window.f0ckSession.use_new_layout === false) {
document.body.classList.remove('layout-modern');
document.body.classList.add('layout-legacy');
} else if (!document.body.classList.contains('layout-legacy')) {
document.body.classList.add('layout-modern');
}
};
window.ensureLayoutClass = ensureLayoutClass;
ensureLayoutClass();
window.applyThumbCacheBust = (bgUrlStr) => {
if (!bgUrlStr) return bgUrlStr;
try {
@@ -178,8 +189,24 @@ window.cancelAnimFrame = (function () {
} catch(e) {}
});
const currentId = typeof window.getCurrentItemId === 'function' ? window.getCurrentItemId() : null;
// Update audio cover in player if viewing this audio item
const audioCover = document.getElementById('f0ck-audio-cover');
if (audioCover && currentId === idStr) {
const coverUrl = `/ca/${idStr}.webp?t=${timestamp}`;
audioCover.src = coverUrl;
const parent = audioCover.parentElement;
if (parent) {
parent.style.background = `url('${coverUrl}') no-repeat center / contain black`;
}
const audioEl = document.querySelector('audio#my-video');
if (audioEl) {
audioEl.setAttribute('poster', coverUrl);
}
}
// Refresh background canvas if it matches the current item
const currentId = window.getCurrentItemId();
if (currentId === idStr && window.initBackground) {
window.initBackground();
}
@@ -732,10 +759,16 @@ window.cancelAnimFrame = (function () {
if (data.success) {
window.flashMessage('ALL MODE ACTIVATED');
gridCacheMap.clear();
const isOnaraOpen = document.body.classList.contains('onara-modal-open');
const isGridView = document.querySelector('.posts, .tags-grid');
const isItemView = document.getElementById('prev') || document.getElementById('next') || /^\/\d+/.test(window.location.pathname);
let reloadPromise = null;
if (isGridView) {
if (isOnaraOpen) {
const bgUrl = window._onaraReturnUrl || getOnaraBaseUrl();
const urlObj = new URL(bgUrl, window.location.origin);
urlObj.searchParams.delete('mode');
reloadPromise = window.loadPageAjax ? window.loadPageAjax(urlObj.toString(), true, { skipCache: true, skipPush: true }) : null;
} else if (isGridView) {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete('mode');
reloadPromise = window.loadPageAjax ? window.loadPageAjax(currentUrl.toString(), true, { skipCache: true }) : null;
@@ -790,10 +823,16 @@ window.cancelAnimFrame = (function () {
: 'ALL MODE ACTIVATED';
window.flashMessage(label);
gridCacheMap.clear();
const isOnaraOpen = document.body.classList.contains('onara-modal-open');
const isGridView = document.querySelector('.posts, .tags-grid');
const isItemView = document.getElementById('prev') || document.getElementById('next') || /^\/\d+/.test(window.location.pathname);
let reloadPromise = null;
if (isGridView) {
if (isOnaraOpen) {
const bgUrl = window._onaraReturnUrl || getOnaraBaseUrl();
const urlObj = new URL(bgUrl, window.location.origin);
urlObj.searchParams.delete('mode');
reloadPromise = window.loadPageAjax ? window.loadPageAjax(urlObj.toString(), true, { skipCache: true, skipPush: true }) : null;
} else if (isGridView) {
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete('mode');
reloadPromise = window.loadPageAjax ? window.loadPageAjax(currentUrl.toString(), true, { skipCache: true }) : null;
@@ -1014,6 +1053,159 @@ window.cancelAnimFrame = (function () {
});
};
// ── Onara Alternative Flavor: Fullscreen Modal Wrapper ─────────────────────
const isOnaraActive = () => !!(window.f0ckSession?.onara || window.onara);
const getOrCreateOnaraModal = () => {
let modal = document.getElementById('onara-modal');
if (!modal) {
modal = document.createElement('div');
modal.id = 'onara-modal';
modal.className = 'onara-modal-wrapper';
modal.style.display = 'none';
modal.setAttribute('aria-hidden', 'true');
modal.innerHTML = `
<div class="onara-backdrop" id="onara-backdrop"></div>
<div class="onara-modal-content" id="onara-modal-content">
<div id="onara-item-mount" class="item-view"></div>
</div>
`;
document.body.appendChild(modal);
}
return modal;
};
const updateOnaraActiveItem = (itemid, url) => {
if (!isOnaraActive()) return;
// Clear onara-active from any and all elements to guarantee only 1 item is selected
document.querySelectorAll('.onara-active').forEach(el => el.classList.remove('onara-active'));
let targetThumb = null;
if (url) {
try {
const parsedPath = new URL(url, window.location.origin).pathname;
targetThumb = document.querySelector(`.posts > a.thumb[href="${parsedPath}"], .posts > a.thumb[href="${url}"]`);
} catch {}
}
if (!targetThumb && itemid) {
targetThumb = document.querySelector(`.posts > a.thumb[href$="/${itemid}"], .posts > a.thumb[data-bg*="/${itemid}."]`);
}
// Blur any other active element so browser native focus cannot highlight a second thumbnail
if (document.activeElement && document.activeElement !== targetThumb && typeof document.activeElement.blur === 'function') {
document.activeElement.blur();
}
if (targetThumb) {
targetThumb.classList.add('onara-active');
targetThumb.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'instant' });
}
};
window.updateOnaraActiveItem = updateOnaraActiveItem;
const getOnaraBaseUrl = (itemUrl = window.location.href) => {
try {
const urlObj = new URL(itemUrl, window.location.origin);
let path = urlObj.pathname.replace(/\/+$/, '');
path = path.replace(/\/(?:\d+|[a-zA-Z0-9_-]{11})$/, '');
const postsEl = document.querySelector('.posts[data-current-page]');
const currentPage = postsEl ? parseInt(postsEl.dataset.currentPage, 10) : 1;
if (currentPage > 1 && !path.includes('/p/')) {
path = (path ? path : '') + '/p/' + currentPage;
}
if (!path) path = '/';
return path + (urlObj.search || '') + (urlObj.hash || '');
} catch {
return '/';
}
};
window.getOnaraBaseUrl = getOnaraBaseUrl;
const promoteOnaraModals = () => {
const mount = document.getElementById('onara-item-mount');
if (!mount) return;
const modals = mount.querySelectorAll('#info-modal, #visibility-modal, .modal-overlay');
modals.forEach(m => {
const existing = document.body.querySelector(`:scope > #${m.id}`);
if (existing && existing !== m) {
existing.remove();
}
document.body.appendChild(m);
});
};
window.promoteOnaraModals = promoteOnaraModals;
const closeOnaraModal = (options = {}) => {
const modal = document.getElementById('onara-modal');
if (!modal || modal.style.display === 'none') return;
// Close any auxiliary modals that may be open
const infoModal = document.getElementById('info-modal');
if (infoModal) infoModal.style.display = 'none';
const visModal = document.getElementById('visibility-modal');
if (visModal) visModal.style.display = 'none';
const reportModal = document.getElementById('report-modal');
if (reportModal) reportModal.style.display = 'none';
const hallsModal = document.getElementById('halls-modal');
if (hallsModal) hallsModal.style.display = 'none';
if (typeof window.closeImageModal === 'function') window.closeImageModal();
document.body.classList.remove('modal-open');
stopMedia();
const mount = document.getElementById('onara-item-mount');
if (mount) mount.innerHTML = '';
modal.style.display = 'none';
modal.setAttribute('aria-hidden', 'true');
document.body.classList.remove('onara-modal-open');
// Restore background canvas if needed
const canvas = document.getElementById('bg');
if (canvas) {
canvas.classList.remove('fader-out', 'fast-fade');
if (window.initBackground) window.initBackground();
}
if (!options.skipHistory) {
const returnUrl = window._onaraReturnUrl || getOnaraBaseUrl();
history.pushState({}, '', returnUrl);
if (window._onaraReturnTitle) {
document.title = window._onaraReturnTitle;
} else if (window.f0ckDomain) {
document.title = window.f0ckDomain;
}
}
window._onaraReturnUrl = null;
window._onaraReturnTitle = null;
// Maintain focus on active item so user TAB navigation seamlessly resumes from current progress
const activeThumb = document.querySelector('.posts > a.thumb.onara-active');
document.querySelectorAll('.onara-active').forEach(el => el.classList.remove('onara-active'));
if (activeThumb) {
try {
activeThumb.focus({ preventScroll: true });
} catch {}
}
};
window.closeOnaraModal = closeOnaraModal;
window.isOnaraActive = isOnaraActive;
// Onara modal close click delegation: clicking outside .item-main-content closes modal
document.addEventListener('click', (e) => {
if (!document.body.classList.contains('onara-modal-open')) return;
// Do not close if clicking inside the item content
if (e.target.closest('.item-main-content')) return;
// Do not close if clicking auxiliary modals, dropdowns, or notifications
if (e.target.closest('.modal-overlay:not(#onara-modal), .modal-content, .swal2-container, .tippy-box, #comments-container .emoji-picker')) return;
// Do not close if clicking the global sidebar right or navbar (as modal respects them)
if (e.target.closest('.global-sidebar-right, nav.navbar, #sidebar-drag-zone')) return;
// Any click outside .item-main-content (e.g. left side, right side, backdrop, modal background) closes
if (e.target.closest('#onara-modal') || e.target.id === 'onara-backdrop') {
e.preventDefault();
closeOnaraModal();
}
});
if (loginModal) {
if (loginBtn) {
loginBtn.addEventListener('click', (e) => {
@@ -1372,8 +1564,49 @@ window.cancelAnimFrame = (function () {
closeModal(loginModal);
closeModal(registerModal);
closeModal(shortcutsModal);
const imageModal = document.getElementById('image-modal');
if (imageModal && (imageModal.classList.contains('visible') || imageModal.style.display === 'flex' || imageModal.style.display === 'block')) {
if (typeof window.closeImageModal === 'function') window.closeImageModal();
else {
imageModal.classList.remove('visible');
imageModal.style.display = 'none';
document.body.classList.remove('modal-open');
}
return;
}
const infoModal = document.getElementById('info-modal');
if (infoModal) closeModal(infoModal);
if (infoModal && infoModal.style.display !== 'none') {
infoModal.style.display = 'none';
document.body.classList.remove('modal-open');
return;
}
const visModal = document.getElementById('visibility-modal');
if (visModal && visModal.style.display !== 'none') {
visModal.style.display = 'none';
document.body.classList.remove('modal-open');
return;
}
const reportModal = document.getElementById('report-modal');
if (reportModal && reportModal.style.display !== 'none') {
reportModal.style.display = 'none';
document.body.classList.remove('modal-open');
return;
}
const hallsModal = document.getElementById('halls-modal');
if (hallsModal && hallsModal.style.display !== 'none') {
hallsModal.style.display = 'none';
document.body.classList.remove('modal-open');
return;
}
const anyOtherModal = document.querySelector('.modal-overlay:not(#onara-modal):not([style*="display: none"]), .modal.show, .swal2-container');
if (anyOtherModal && window.getComputedStyle(anyOtherModal).display !== 'none') {
anyOtherModal.style.display = 'none';
document.body.classList.remove('modal-open');
return;
}
if (document.body.classList.contains('onara-modal-open')) {
closeOnaraModal();
}
}
});
@@ -1519,15 +1752,42 @@ window.cancelAnimFrame = (function () {
}
};
const initOnaraInitialState = () => {
if (!isOnaraActive()) return;
promoteOnaraModals();
if (document.body.classList.contains('onara-modal-open')) {
const modal = document.getElementById('onara-modal');
if (modal) {
modal.style.display = 'flex';
modal.setAttribute('aria-hidden', 'false');
}
if (!window._onaraReturnUrl) {
window._onaraReturnUrl = getOnaraBaseUrl();
window._onaraReturnTitle = window.f0ckDomain || 'f0ck';
}
const pathSegments = window.location.pathname.split('/');
const keySegments = pathSegments.filter(s => /^\d+$/.test(s) || /^[a-zA-Z0-9_-]{11}$/.test(s));
const activeKey = keySegments.length ? keySegments[keySegments.length - 1] : null;
if (activeKey) {
updateOnaraActiveItem(activeKey, window.location.href);
if (typeof window.trackVisit === 'function') {
window.trackVisit(activeKey);
}
}
}
};
// Initial Load
document.addEventListener('DOMContentLoaded', () => {
setupMedia();
initOnaraInitialState();
if (typeof requestIdleCallback === 'function') {
requestIdleCallback(() => prefetchNextPrevItems());
} else {
setTimeout(prefetchNextPrevItems, 500);
}
});
initOnaraInitialState();
// Export init function for dynamic calls
window.initBackground = () => {
@@ -2380,6 +2640,7 @@ window.cancelAnimFrame = (function () {
// Immediately restore scrollability and hide modals
if (window.resetGlobalScrollState) window.resetGlobalScrollState();
if (window.hideAllModals) window.hideAllModals();
if (window.closeOnaraModal) window.closeOnaraModal({ skipHistory: true });
isNavigating = true;
@@ -2493,7 +2754,7 @@ window.cancelAnimFrame = (function () {
// Keep cache alive — cleared on mode/filter changes via gridCacheMap.clear()
if (navbar) navbar.classList.add('pbwork');
stopMedia();
if (!document.body.classList.contains('onara-modal-open')) stopMedia();
// Fade out background canvas (item view blur)
const canvas = document.getElementById('bg');
@@ -2514,9 +2775,12 @@ window.cancelAnimFrame = (function () {
cache.node.style.display = '';
cache.node.classList.remove('cached-grid');
main.className = '';
document.body.classList.remove('legacy-view', 'layout-modern', 'layout-legacy');
document.body.style.overflow = '';
document.body.style.height = '';
document.body.classList.remove('legacy-view');
ensureLayoutClass();
if (!document.body.classList.contains('onara-modal-open')) {
document.body.style.overflow = '';
document.body.style.height = '';
}
const paginationWrapper = document.querySelector('.pagination-wrapper');
if (paginationWrapper && cache.pagination) paginationWrapper.innerHTML = cache.pagination;
const restoredPosts = cache.node.querySelector('.posts');
@@ -2527,7 +2791,7 @@ window.cancelAnimFrame = (function () {
}
// Update URL bar (only for explicit clicks, not browser back/forward which already did it)
if (!options.skipPush) history.pushState({}, '', url);
if (!options.skipPush && !document.body.classList.contains('onara-modal-open')) history.pushState({}, '', url);
// Restore scroll position
requestAnimationFrame(() => window.scrollTo(0, cache.scroll));
@@ -2576,11 +2840,13 @@ window.cancelAnimFrame = (function () {
main.className = ''; // Reset class
// Clear legacy-view state (layout-lock) now that we are swapping to a list view
document.body.classList.remove('legacy-view', 'layout-modern', 'layout-legacy');
document.body.style.overflow = '';
document.body.style.height = '';
// Toggle button lives permanently in body via header.html — no removal needed
stopMedia(); // Ensure media stops when leaving item view
document.body.classList.remove('legacy-view');
ensureLayoutClass();
if (!document.body.classList.contains('onara-modal-open')) {
document.body.style.overflow = '';
document.body.style.height = '';
stopMedia(); // Ensure media stops when leaving item view
}
// Fade out background canvas for smooth transition to black
const canvas = document.getElementById('bg');
@@ -2737,6 +3003,7 @@ window.cancelAnimFrame = (function () {
// Ensure we keep a layout class but reset others
document.body.classList.remove('item-layout-active', 'meme-layout-active'); // Kill known breakers
ensureLayoutClass();
}
// Reset navbar to clean state
@@ -2745,9 +3012,11 @@ window.cancelAnimFrame = (function () {
navbar.classList.remove('scrolled', 'pbwork');
}
document.body.style.overflow = '';
document.body.style.height = '';
document.body.style.minHeight = '';
if (!document.body.classList.contains('onara-modal-open')) {
document.body.style.overflow = '';
document.body.style.height = '';
document.body.style.minHeight = '';
}
window.f0ckDebug("[loadPageAjax] State synced for " + (isFullPage ? "full page" : "partial"));
if (window.updateMimeLabel) window.updateMimeLabel();
@@ -2949,7 +3218,7 @@ window.cancelAnimFrame = (function () {
}
// UPDATE HISTORY BEFORE INITIALIZING SCRIPTS
if (!options.skipPush) {
if (!options.skipPush && !document.body.classList.contains('onara-modal-open')) {
history.pushState({}, '', url);
}
@@ -3319,6 +3588,15 @@ window.cancelAnimFrame = (function () {
isNavigating = true;
const isGridPage = !!document.querySelector('.index-layout-wrapper, .index-container, .posts');
const isModalOpen = document.body.classList.contains('onara-modal-open');
const useOnara = isOnaraActive() && (isGridPage || isModalOpen);
if (useOnara && !isModalOpen) {
window._onaraReturnUrl = window.location.href;
window._onaraReturnTitle = document.title;
}
// ── Scroller-active cleanup (same as loadPageAjax) ───────────────────
if (document.body.classList.contains('scroller-active')) {
document.head.querySelectorAll('[data-pjax-abyss]').forEach(el => el.remove());
@@ -3349,7 +3627,7 @@ window.cancelAnimFrame = (function () {
const currentScroll = window.scrollY;
// Save scroll position for current page (only for new navigations)
if (!options.skipPush && !options.keepMedia) {
if (!options.skipPush && !options.keepMedia && !useOnara) {
const currentState = history.state || {};
history.replaceState({ ...currentState, scroll: currentScroll }, document.title, window.location.href);
}
@@ -3521,39 +3799,54 @@ window.cancelAnimFrame = (function () {
// ── Render cached HTML (same DOM setup as the normal path below) ──
const _html = _cachedItem.html;
let _container = document.querySelector('#main .container') || (document.getElementById('main')?.classList.contains('item-view') ? document.getElementById('main') : null);
const _isStructuralPage = !!document.querySelector('.pagewrapper');
const _isModeratorPage = !!document.querySelector('.approval-grid, .audit-log-container, .mod-reports-page');
const _isNotificationsPage = !!document.querySelector('.notifications-page, .notif-history-container');
const _isIndexPage = !!document.querySelector('.index-container, .posts');
const _isStaticPage = !!document.querySelector('.static-page, .about-container, .upload-container');
let _container;
if (!options.keepMedia && (!_container || _isModeratorPage || _isNotificationsPage || _isIndexPage || _isStaticPage || _isStructuralPage)) {
if (main) {
const _iw = main.querySelector('.index-layout-wrapper');
const _ic = main.querySelector('.index-container');
const _ntc = _iw || _ic;
if (_ntc && _isIndexPage) {
const _ck = window.location.pathname + window.location.search;
const _pw = document.querySelector('.pagination-wrapper');
gridCacheMap.set(_ck, { node: _ntc, scroll: currentScroll, pagination: _pw ? _pw.innerHTML : '' });
_ntc.remove();
if (useOnara) {
const onaraModal = getOrCreateOnaraModal();
const onaraMount = document.getElementById('onara-item-mount');
document.body.classList.add('onara-modal-open');
onaraModal.style.display = 'flex';
onaraModal.setAttribute('aria-hidden', 'false');
if (!options.keepMedia) {
onaraMount.innerHTML = '';
}
_container = onaraMount;
updateOnaraActiveItem(itemid, url);
} else {
_container = document.querySelector('#main .container') || (document.getElementById('main')?.classList.contains('item-view') ? document.getElementById('main') : null);
const _isStructuralPage = !!document.querySelector('.pagewrapper');
const _isModeratorPage = !!document.querySelector('.approval-grid, .audit-log-container, .mod-reports-page');
const _isNotificationsPage = !!document.querySelector('.notifications-page, .notif-history-container');
const _isIndexPage = !!document.querySelector('.index-container, .posts');
const _isStaticPage = !!document.querySelector('.static-page, .about-container, .upload-container');
if (!options.keepMedia && (!_container || _isModeratorPage || _isNotificationsPage || _isIndexPage || _isStaticPage || _isStructuralPage)) {
if (main) {
const _iw = main.querySelector('.index-layout-wrapper');
const _ic = main.querySelector('.index-container');
const _ntc = _iw || _ic;
if (_ntc && _isIndexPage) {
const _ck = window.location.pathname + window.location.search;
const _pw = document.querySelector('.pagination-wrapper');
gridCacheMap.set(_ck, { node: _ntc, scroll: currentScroll, pagination: _pw ? _pw.innerHTML : '' });
_ntc.remove();
}
main.className = 'item-view';
document.body.classList.remove('legacy-view', 'layout-modern', 'layout-legacy');
if (window.f0ckSession && !window.f0ckSession.use_new_layout) {
document.body.classList.add('layout-legacy');
} else {
document.body.classList.add('layout-modern');
}
if (window.syncNavbarHeight) window.syncNavbarHeight();
main.innerHTML = '';
_container = main;
}
main.className = 'item-view';
document.body.classList.remove('legacy-view', 'layout-modern', 'layout-legacy');
if (window.f0ckSession && !window.f0ckSession.use_new_layout) {
document.body.classList.add('layout-legacy');
} else {
document.body.classList.add('layout-modern');
}
if (window.syncNavbarHeight) window.syncNavbarHeight();
main.innerHTML = '';
_container = main;
} else if (_container && !options.keepMedia) {
_container.innerHTML = '';
_container.removeAttribute('style');
if (main) main.className = 'item-view';
}
} else if (_container && !options.keepMedia) {
_container.innerHTML = '';
_container.removeAttribute('style');
if (main) main.className = 'item-view';
}
if (options.keepMedia) {
@@ -3568,14 +3861,18 @@ window.cancelAnimFrame = (function () {
_container.insertAdjacentHTML('beforeend', _html);
}
if (options.skipPush && history.state?.scroll !== undefined) {
if (useOnara) {
promoteOnaraModals();
const onaraModal = document.getElementById('onara-modal');
if (onaraModal) onaraModal.scrollTo(0, 0);
} else if (options.skipPush && history.state?.scroll !== undefined) {
requestAnimationFrame(() => window.scrollTo(0, history.state.scroll));
} else if (!options.keepMedia) {
window.scrollTo(0, 0);
}
const _hash = new URL(url, window.location.origin).hash;
const itemKey = _cachedItem.slug || itemid;
const itemKey = (window.f0ckSession?.enable_item_slugs !== false && _cachedItem.slug) ? _cachedItem.slug : (_cachedItem.slug || itemid);
let _pushUrl = `/${itemKey}`;
if (userHall && userHallOwner) _pushUrl = `/user/${encodeURIComponent(userHallOwner)}/hall/${encodeURIComponent(userHall)}/${itemKey}`;
else if (user) { _pushUrl = `/user/${encodeURIComponent(user)}/${itemKey}`; if (isFavs) _pushUrl = `/user/${encodeURIComponent(user)}/favs/${itemKey}`; }
@@ -3585,7 +3882,7 @@ window.cancelAnimFrame = (function () {
if (mime) _pushUrl = _pushUrl.replace(new RegExp(`/${itemKey}$`), `/${mime}/${itemKey}`);
if (_hash) _pushUrl += _hash;
if (!options.keepMedia && !options.skipPush) history.pushState({}, '', _pushUrl);
if (!options.keepMedia && !options.skipPush) history.pushState({ onara: useOnara }, '', _pushUrl);
document.title = `${window.f0ckDomain} - ${itemKey}`;
if (navbar) navbar.classList.remove('pbwork');
@@ -3678,55 +3975,69 @@ window.cancelAnimFrame = (function () {
// Track visit for guests
window.trackVisit(itemid);
let container = document.querySelector('#main .container') || (document.getElementById('main') && document.getElementById('main').classList.contains('item-view') ? document.getElementById('main') : null);
const isStructuralPage = !!document.querySelector('.pagewrapper');
const isModeratorPage = !!document.querySelector('.approval-grid, .audit-log-container, .mod-reports-page');
const isNotificationsPage = !!document.querySelector('.notifications-page, .notif-history-container');
const isIndexPage = !!document.querySelector('.index-container, .posts');
const isStaticPage = !!document.querySelector('.static-page, .about-container, .upload-container');
let container;
if (useOnara) {
const onaraModal = getOrCreateOnaraModal();
const onaraMount = document.getElementById('onara-item-mount');
document.body.classList.add('onara-modal-open');
onaraModal.style.display = 'flex';
onaraModal.setAttribute('aria-hidden', 'false');
if (!options.keepMedia) {
onaraMount.innerHTML = '';
}
container = onaraMount;
updateOnaraActiveItem(itemid, url);
} else {
container = document.querySelector('#main .container') || (document.getElementById('main') && document.getElementById('main').classList.contains('item-view') ? document.getElementById('main') : null);
const isStructuralPage = !!document.querySelector('.pagewrapper');
const isModeratorPage = !!document.querySelector('.approval-grid, .audit-log-container, .mod-reports-page');
const isNotificationsPage = !!document.querySelector('.notifications-page, .notif-history-container');
const isIndexPage = !!document.querySelector('.index-container, .posts');
const isStaticPage = !!document.querySelector('.static-page, .about-container, .upload-container');
if (!options.keepMedia && (!container || isModeratorPage || isNotificationsPage || isIndexPage || isStaticPage || isStructuralPage)) {
// Transition to Item View
if (main) {
// Check if we can cache the existing grid (Index Page only)
const indexWrapper = main.querySelector('.index-layout-wrapper');
const indexContainer = main.querySelector('.index-container');
const nodeToCache = indexWrapper || indexContainer;
if (!options.keepMedia && (!container || isModeratorPage || isNotificationsPage || isIndexPage || isStaticPage || isStructuralPage)) {
// Transition to Item View
if (main) {
// Check if we can cache the existing grid (Index Page only)
const indexWrapper = main.querySelector('.index-layout-wrapper');
const indexContainer = main.querySelector('.index-container');
const nodeToCache = indexWrapper || indexContainer;
if (nodeToCache && isIndexPage) {
const cacheKey = window.location.pathname + window.location.search;
const paginationWrapper = document.querySelector('.pagination-wrapper');
gridCacheMap.set(cacheKey, {
node: nodeToCache,
scroll: currentScroll,
pagination: paginationWrapper ? paginationWrapper.innerHTML : ''
});
nodeToCache.remove();
}
main.className = 'item-view';
if (nodeToCache && isIndexPage) {
const cacheKey = window.location.pathname + window.location.search;
const paginationWrapper = document.querySelector('.pagination-wrapper');
gridCacheMap.set(cacheKey, {
node: nodeToCache,
scroll: currentScroll,
pagination: paginationWrapper ? paginationWrapper.innerHTML : ''
});
nodeToCache.remove();
}
main.className = 'item-view';
// Correctly handle body classes for the current layout mode
document.body.classList.remove('legacy-view', 'layout-modern', 'layout-legacy');
if (window.f0ckSession && !window.f0ckSession.use_new_layout) {
document.body.classList.add('layout-legacy');
} else {
document.body.classList.add('layout-modern');
}
if (window.syncNavbarHeight) window.syncNavbarHeight();
// Correctly handle body classes for the current layout mode
document.body.classList.remove('legacy-view', 'layout-modern', 'layout-legacy');
if (window.f0ckSession && !window.f0ckSession.use_new_layout) {
document.body.classList.add('layout-legacy');
} else {
document.body.classList.add('layout-modern');
}
if (window.syncNavbarHeight) window.syncNavbarHeight();
// Toggle button lives permanently in body via header.html — no creation needed
// Toggle button lives permanently in body via header.html — no creation needed
// HTML goes directly into #main without outdated .container wrapper for New Layout
main.innerHTML = '';
container = main; // HTML goes directly into #main
// HTML goes directly into #main without outdated .container wrapper for New Layout
main.innerHTML = '';
container = main; // HTML goes directly into #main
}
} else if (container && !options.keepMedia) {
// Already in some kind of item view or compatible layout, just clear it
container.innerHTML = '';
container.removeAttribute('style'); // Ensure no carry-over styles
if (main) main.className = 'item-view';
}
} else if (container && !options.keepMedia) {
// Already in some kind of item view or compatible layout, just clear it
container.innerHTML = '';
container.removeAttribute('style'); // Ensure no carry-over styles
if (main) main.className = 'item-view';
}
if (options.keepMedia) {
@@ -3763,7 +4074,11 @@ window.cancelAnimFrame = (function () {
// Handle Scroll Position (Restore or Reset)
if (options.skipPush && history.state && history.state.scroll !== undefined) {
if (useOnara) {
promoteOnaraModals();
const onaraModal = document.getElementById('onara-modal');
if (onaraModal) onaraModal.scrollTo(0, 0);
} else if (options.skipPush && history.state && history.state.scroll !== undefined) {
requestAnimationFrame(() => window.scrollTo(0, history.state.scroll));
} else if (!options.keepMedia) {
window.scrollTo(0, 0);
@@ -3775,7 +4090,7 @@ window.cancelAnimFrame = (function () {
// Construct proper History URL (Context Aware)
// If we inherited context, we should reflect it in the URL
const hash = new URL(url, window.location.origin).hash;
const itemKey = responseSlug || itemid;
const itemKey = (window.f0ckSession?.enable_item_slugs !== false && responseSlug) ? responseSlug : (responseSlug || itemid);
let pushUrl = `/${itemKey}`;
// Logic from ajax.mjs context reconstruction:
if (userHall && userHallOwner) {
@@ -3799,7 +4114,7 @@ window.cancelAnimFrame = (function () {
if (!options.keepMedia && !options.skipPush) {
// We overwrite proper URL even if the link clicked was "naked"
history.pushState({}, '', pushUrl);
history.pushState({ onara: useOnara }, '', pushUrl);
}
if (!options.keepMedia) {
@@ -3900,11 +4215,17 @@ window.cancelAnimFrame = (function () {
gridCacheMap.clear();
// Refresh content
const isOnaraOpen = document.body.classList.contains('onara-modal-open');
const isGridView = document.querySelector('.posts, .tags-grid');
const isItemView = document.getElementById('prev') || document.getElementById('next');
let reloadPromise = null;
if (isGridView) {
if (isOnaraOpen) {
const bgUrl = window._onaraReturnUrl || getOnaraBaseUrl();
const urlObj = new URL(bgUrl, window.location.origin);
urlObj.searchParams.delete('mode');
reloadPromise = loadPageAjax(urlObj.toString(), true, { skipCache: true, skipPush: true });
} else if (isGridView) {
// Reload current page without ?mode= in the URL — server picks up mode from session/cookie
const currentUrl = new URL(window.location.href);
currentUrl.searchParams.delete('mode');
@@ -3935,6 +4256,13 @@ window.cancelAnimFrame = (function () {
const thumbnail = target.closest('.posts > a:not(.notif-item)');
if (thumbnail && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
e.preventDefault();
if (isOnaraActive()) {
document.querySelectorAll('.onara-active').forEach(el => el.classList.remove('onara-active'));
thumbnail.classList.add('onara-active');
if (document.activeElement && document.activeElement !== thumbnail && typeof document.activeElement.blur === 'function') {
document.activeElement.blur();
}
}
// Thumbnails inherit context (e.g. from Tag Index)
loadItemAjax(thumbnail.href, true);
return;
@@ -3945,6 +4273,25 @@ window.cancelAnimFrame = (function () {
// Special check for random
if (link.id === 'random' || link.id === 'nav-random') {
e.preventDefault();
// In Onara mode with a background grid, pick a random item from the grid so it reflects on the main page
if (isOnaraActive()) {
const gridThumbs = Array.from(document.querySelectorAll('.posts > a:not(.notif-item)'));
if (gridThumbs.length > 0) {
const pool = gridThumbs.filter(t => !t.classList.contains('onara-active'));
const chosen = (pool.length > 0 ? pool : gridThumbs)[Math.floor(Math.random() * (pool.length > 0 ? pool : gridThumbs).length)];
if (chosen) {
document.querySelectorAll('.onara-active').forEach(el => el.classList.remove('onara-active'));
chosen.classList.add('onara-active');
if (document.activeElement && document.activeElement !== chosen && typeof document.activeElement.blur === 'function') {
document.activeElement.blur();
}
loadItemAjax(chosen.href, true);
return;
}
}
}
stopMedia(); // Abort media BEFORE fetching random item
// Fade out background canvas for smooth transition
@@ -4590,6 +4937,11 @@ window.cancelAnimFrame = (function () {
window.f0ckDebug("[popstate] Navigation to:", url, { isItem, isSpecial, isGridLike });
if (document.body.classList.contains('onara-modal-open') && !isItem) {
closeOnaraModal({ skipHistory: true });
return;
}
if (isItem) {
loadItemAjax(url, true, { skipPush: true });
} else if (isSpecial || isGridLike) {
@@ -4872,7 +5224,9 @@ window.cancelAnimFrame = (function () {
if (infiniteState.currentPage !== p) {
infiniteState.currentPage = p;
infiniteState.firstPage = p;
history.replaceState({}, '', buildUrl(p));
if (!document.body.classList.contains('onara-modal-open')) {
history.replaceState({}, '', buildUrl(p));
}
}
delete postsContainer.dataset.currentPage; // Clear after reading
@@ -4948,6 +5302,11 @@ window.cancelAnimFrame = (function () {
return;
}
// Never overwrite item URL with /p/N when Onara modal is open!
if (document.body.classList.contains('onara-modal-open')) {
return;
}
// Update URL
infiniteState.visiblePage = newPage;
history.replaceState({}, '', buildUrl(newPage));
@@ -9328,8 +9687,12 @@ document.addEventListener("DOMContentLoaded", function () {
if (newPath === '') newPath = '/';
url.pathname = newPath;
// Update the browser URL without reloading
history.replaceState({}, '', url.toString());
const isOnaraOpen = document.body.classList.contains('onara-modal-open');
// Update the browser URL without reloading (only when not in onara modal)
if (!isOnaraOpen) {
history.replaceState({}, '', url.toString());
}
// Sync UI immediately (Before AJAX)
if (window.updateMimeLabel) window.updateMimeLabel();
@@ -9342,7 +9705,10 @@ document.addEventListener("DOMContentLoaded", function () {
// Set flag so hideAllModals (called inside loadPageAjax) skips the filter overlay
if (fromModal) window._keepFilterModal = true;
if (postsEl) {
if (isOnaraOpen) {
const bgUrl = window._onaraReturnUrl || getOnaraBaseUrl();
reloadPromise = window.loadPageAjax ? window.loadPageAjax(bgUrl, { skipPush: true, skipCache: true }) : null;
} else if (postsEl) {
reloadPromise = window.loadPageAjax ? window.loadPageAjax(url.toString(), { skipPush: true }) : null;
} else if (document.getElementById('main')?.classList.contains('item-view') || document.querySelector('.item-layout-container, .item-main-content')) {
// On item view, refresh the context but KEEP media playing
@@ -10191,7 +10557,7 @@ document.addEventListener('DOMContentLoaded', () => {
}
// Close logic
if (e.target.matches('#report-cancel')) {
if (e.target.matches('#report-cancel') || e.target.id === 'report-modal') {
reportModal.style.display = 'none';
document.body.classList.remove('modal-open');
}
@@ -11486,7 +11852,7 @@ document.addEventListener('click', (e) => {
}
const closeBtn = e.target.closest('#info-modal-close, #info-modal-close-icon');
if (closeBtn) {
if (closeBtn || e.target.id === 'info-modal') {
e.preventDefault();
const modal = document.getElementById('info-modal');
if (modal) {
@@ -11683,21 +12049,25 @@ document.addEventListener('click', (e) => {
if (data.success) {
if (window.flashMessage) window.flashMessage('THUMBNAIL REGENERATED');
else if (window.showFlash) window.showFlash('Thumbnail regenerated');
// Cache-bust thumbnails on page
// Cache-bust thumbnails and player media on page
const timestamp = Date.now();
document.querySelectorAll(`img[src*="/t/${itemId}.webp"]`).forEach(img => {
const url = new URL(img.src, window.location.origin);
url.searchParams.set('t', timestamp);
img.src = url.toString();
});
document.querySelectorAll(`.thumb[data-bg*="/t/${itemId}.webp"]`).forEach(thumb => {
const bg = thumb.dataset.bg;
if (bg) {
const url = new URL(bg, window.location.origin);
if (typeof window.refreshItemThumbnails === 'function') {
window.refreshItemThumbnails(itemId, timestamp);
} else {
document.querySelectorAll(`img[src*="/t/${itemId}.webp"]`).forEach(img => {
const url = new URL(img.src, window.location.origin);
url.searchParams.set('t', timestamp);
thumb.style.setProperty('--thumb-bg', `url('${url.toString()}')`);
}
});
img.src = url.toString();
});
document.querySelectorAll(`.thumb[data-bg*="/t/${itemId}.webp"]`).forEach(thumb => {
const bg = thumb.dataset.bg;
if (bg) {
const url = new URL(bg, window.location.origin);
url.searchParams.set('t', timestamp);
thumb.style.setProperty('--thumb-bg', `url('${url.toString()}')`);
}
});
}
} else {
if (window.flashError) window.flashError(data.msg || 'Regeneration failed');
else alert(data.msg || 'Regeneration failed');