diff --git a/app/static/js/screen.js b/app/static/js/screen.js index 646c6d2..5344f67 100644 --- a/app/static/js/screen.js +++ b/app/static/js/screen.js @@ -3,82 +3,113 @@ * Provides fullscreen and exitFullscreen functionality: * - fullscreen(): hides header/footer, expands container, recalculates main height, sets ?fullscreen=1 * - exitFullscreen(): restores header/footer, container, recalculates main height, removes parameter - * - toggleFullscreen(): toggles between modes + * - toggleFullscreen(): toggles based on current state + * - updateButtonIcon(): updates a button's icon/text based on fullscreen state * Reacts to URL ?fullscreen=1 on page load + * Mirrors browser fullscreen (F11) via fullscreenchange and resize events */ -function fullscreen() { - // Hide header and footer - const header = document.querySelector('header'); - const footer = document.querySelector('footer'); - if (header) header.style.display = 'none'; - if (footer) footer.style.display = 'none'; +// Update the toggle button's icon/text +function updateButtonIcon() { + const btn = document.getElementById('fullscreen-btn'); + if (!btn) return; + if (document.fullscreenElement) { + btn.innerHTML = ''; + btn.title = 'Exit Fullscreen'; + } else { + btn.innerHTML = ''; + btn.title = 'Enter Fullscreen'; + } +} +async function fullscreen() { + // Hide header and footer + document.querySelectorAll('header, footer').forEach(el => el && (el.style.display = 'none')); // Expand container to full width const container = document.querySelector('.container'); if (container && !container.classList.contains('container-fluid')) { container.classList.replace('container', 'container-fluid'); } - - // Recalculate main height + // Recalculate main height (guarded) if (typeof adjustScrollContainerHeight === 'function') { - adjustScrollContainerHeight(); + try { adjustScrollContainerHeight(); } catch (e) { console.warn('adjustScrollContainerHeight failed:', e); } } if (typeof updateCustomScrollbar === 'function') { - updateCustomScrollbar(); + try { updateCustomScrollbar(); } catch (e) { console.warn('updateCustomScrollbar failed:', e); } } - // Update URL parameter const url = new URL(window.location); url.searchParams.set('fullscreen', '1'); window.history.replaceState({}, '', url); + // Update toggle button + updateButtonIcon(); } function exitFullscreen() { // Show header and footer - const header = document.querySelector('header'); - const footer = document.querySelector('footer'); - if (header) header.style.display = ''; - if (footer) footer.style.display = ''; - + document.querySelectorAll('header, footer').forEach(el => el && (el.style.display = '')); // Revert container to default width const container = document.querySelector('.container-fluid'); - if (container) { - container.classList.replace('container-fluid', 'container'); - } - - // Recalculate main height + if (container) container.classList.replace('container-fluid', 'container'); + // Recalculate main height (guarded) if (typeof adjustScrollContainerHeight === 'function') { - adjustScrollContainerHeight(); + try { adjustScrollContainerHeight(); } catch (e) { console.warn('adjustScrollContainerHeight failed:', e); } } if (typeof updateCustomScrollbar === 'function') { - updateCustomScrollbar(); + try { updateCustomScrollbar(); } catch (e) { console.warn('updateCustomScrollbar failed:', e); } } - // Remove URL parameter const url = new URL(window.location); url.searchParams.delete('fullscreen'); window.history.replaceState({}, '', url); + // Update toggle button + updateButtonIcon(); } function toggleFullscreen() { - const header = document.querySelector('header'); - if (header && header.style.display === 'none') { - exitFullscreen(); - } else { - fullscreen(); - } + if (document.fullscreenElement) exitFullscreen(); + else fullscreen(); } -// On load, check URL param and react +// On load: check URL param and set state window.addEventListener('DOMContentLoaded', () => { const params = new URLSearchParams(window.location.search); - if (params.get('fullscreen') === '1') { - fullscreen(); - } + if (params.get('fullscreen') === '1') fullscreen(); + else updateButtonIcon(); +}); + +function isAnyBrowserFullscreen() { + // Fullscreen API + const apiFs = !!( + document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement || + document.msFullscreenElement + ); + + // Browser-chrome F11 fullscreen + const uiFs = Math.abs(window.innerHeight - screen.height) < 2; + + // PWA fullscreen + const pwaFs = window.matchMedia('(display-mode: fullscreen)').matches; + + return apiFs || uiFs || pwaFs; +} + +// 1) Fullscreen API change (for JS-driven requestFullscreen) +document.addEventListener('fullscreenchange', () => { + if (isAnyBrowserFullscreen()) fullscreen(); + else exitFullscreen(); +}); + +// 2) Chromium F11 fallback +window.addEventListener('resize', () => { + if (isAnyBrowserFullscreen()) fullscreen(); + else exitFullscreen(); }); // Expose functions globally window.fullscreen = fullscreen; window.exitFullscreen = exitFullscreen; window.toggleFullscreen = toggleFullscreen; +window.updateButtonIcon = updateButtonIcon;