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;