|
|
|
|
@@ -357,6 +357,17 @@ const isIOS = () => {
|
|
|
|
|
let lastAppliedScale = null;
|
|
|
|
|
let lastAppliedKioskMode = null;
|
|
|
|
|
|
|
|
|
|
// Helper function to clear CSS properties from elements
|
|
|
|
|
const clearElementStyles = (element, properties) => {
|
|
|
|
|
properties.forEach((prop) => element.style.removeProperty(prop));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Define property groups for different scaling modes
|
|
|
|
|
const SCALING_PROPERTIES = {
|
|
|
|
|
wrapper: ['width', 'height', 'transform', 'transform-origin'],
|
|
|
|
|
positioning: ['transform', 'transform-origin', 'width', 'height', 'position', 'left', 'top', 'margin-left', 'margin-top'],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// resize the container on a page resize
|
|
|
|
|
const resize = (force = false) => {
|
|
|
|
|
// Ignore resize events caused by pinch-to-zoom on mobile
|
|
|
|
|
@@ -376,9 +387,8 @@ const resize = (force = false) => {
|
|
|
|
|
// Standard scaling: fit within both dimensions
|
|
|
|
|
const scale = Math.min(widthZoomPercent, heightZoomPercent);
|
|
|
|
|
|
|
|
|
|
// For Mobile Safari in kiosk mode, always use centering behavior regardless of scale
|
|
|
|
|
// For other platforms, only use fullscreen/centering behavior for actual fullscreen or kiosk mode where content fits naturally
|
|
|
|
|
const isKioskLike = isFullscreen || (isKioskMode && scale >= 1.0) || isMobileSafariKiosk;
|
|
|
|
|
// Use centering behavior for fullscreen, kiosk mode, or Mobile Safari kiosk mode
|
|
|
|
|
const isKioskLike = isFullscreen || isKioskMode || isMobileSafariKiosk;
|
|
|
|
|
|
|
|
|
|
if (debugFlag('resize') || debugFlag('fullscreen')) {
|
|
|
|
|
console.log(`🖥️ Resize: force=${force} isKioskLike=${isKioskLike} window=${window.innerWidth}x${window.innerHeight} targetWidth=${targetWidth} widthZoom=${widthZoomPercent.toFixed(3)} heightZoom=${heightZoomPercent.toFixed(3)} finalScale=${scale.toFixed(3)} fullscreenElement=${!!document.fullscreenElement} isIOS=${isIOS()} standalone=${window.navigator.standalone} isMobileSafariKiosk=${isMobileSafariKiosk} kioskMode=${settings.kiosk?.value} wideMode=${settings.wide.value}`);
|
|
|
|
|
@@ -412,40 +422,35 @@ const resize = (force = false) => {
|
|
|
|
|
console.log('🖥️ Resetting fullscreen/kiosk styles to normal');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset wrapper styles (only properties that are actually set in fullscreen/scaling modes)
|
|
|
|
|
wrapper.style.removeProperty('width');
|
|
|
|
|
wrapper.style.removeProperty('height');
|
|
|
|
|
wrapper.style.removeProperty('overflow');
|
|
|
|
|
wrapper.style.removeProperty('transform');
|
|
|
|
|
wrapper.style.removeProperty('transform-origin');
|
|
|
|
|
|
|
|
|
|
// Reset container styles that might have been applied during fullscreen
|
|
|
|
|
mainContainer.style.removeProperty('transform');
|
|
|
|
|
mainContainer.style.removeProperty('transform-origin');
|
|
|
|
|
mainContainer.style.removeProperty('width');
|
|
|
|
|
mainContainer.style.removeProperty('height');
|
|
|
|
|
mainContainer.style.removeProperty('position');
|
|
|
|
|
mainContainer.style.removeProperty('left');
|
|
|
|
|
mainContainer.style.removeProperty('top');
|
|
|
|
|
mainContainer.style.removeProperty('margin-left');
|
|
|
|
|
mainContainer.style.removeProperty('margin-top');
|
|
|
|
|
// Reset all scaling-related styles
|
|
|
|
|
const container = document.querySelector('#container');
|
|
|
|
|
clearElementStyles(wrapper, SCALING_PROPERTIES.wrapper);
|
|
|
|
|
clearElementStyles(container, SCALING_PROPERTIES.positioning);
|
|
|
|
|
clearElementStyles(mainContainer, SCALING_PROPERTIES.positioning);
|
|
|
|
|
|
|
|
|
|
applyScanlineScaling(1.0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MOBILE SCALING: Use wrapper scaling for mobile devices (but not Mobile Safari kiosk mode)
|
|
|
|
|
if ((scale < 1.0 || (isKioskMode && !isKioskLike)) && !isMobileSafariKiosk) {
|
|
|
|
|
// MOBILE SCALING: Use wrapper scaling for mobile devices (but not when in fullscreen/kiosk mode)
|
|
|
|
|
if ((scale < 1.0 || (isKioskMode && !isKioskLike)) && !isMobileSafariKiosk && !isKioskLike) {
|
|
|
|
|
/*
|
|
|
|
|
* MOBILE SCALING (Wrapper Scaling)
|
|
|
|
|
*
|
|
|
|
|
* This path is used for regular mobile browsing (NOT fullscreen/kiosk modes).
|
|
|
|
|
* Why scale the wrapper instead of mainContainer?
|
|
|
|
|
* - For mobile devices where content is larger than viewport, we need to scale the entire layout
|
|
|
|
|
* - The wrapper (#divTwc) contains both the main content AND the bottom navigation bar
|
|
|
|
|
* - Scaling the wrapper ensures both elements are scaled together as a unit
|
|
|
|
|
* - No centering is applied - content aligns to top-left for typical mobile behavior
|
|
|
|
|
* - Content aligns to top-left for typical mobile web browsing behavior (no centering)
|
|
|
|
|
* - Uses explicit dimensions to prevent layout issues and eliminate gaps after scaling
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Reset any container/mainContainer styles that might have been set during fullscreen/kiosk mode
|
|
|
|
|
const container = document.querySelector('#container');
|
|
|
|
|
clearElementStyles(container, SCALING_PROPERTIES.positioning);
|
|
|
|
|
clearElementStyles(mainContainer, SCALING_PROPERTIES.positioning);
|
|
|
|
|
|
|
|
|
|
wrapper.style.setProperty('transform', `scale(${scale})`);
|
|
|
|
|
wrapper.style.setProperty('transform-origin', 'top left'); // Scale from top-left corner
|
|
|
|
|
|
|
|
|
|
@@ -458,7 +463,7 @@ const resize = (force = false) => {
|
|
|
|
|
const scaledHeight = totalHeight * scale; // Height after scaling
|
|
|
|
|
|
|
|
|
|
wrapper.style.setProperty('width', `${wrapperWidth}px`);
|
|
|
|
|
wrapper.style.setProperty('height', `${scaledHeight}px`); // Use scaled height to eliminate gap
|
|
|
|
|
wrapper.style.setProperty('height', `${scaledHeight}px`); // Use scaled height to eliminate gap under #divTwc on index page
|
|
|
|
|
applyScanlineScaling(scale);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -468,10 +473,7 @@ const resize = (force = false) => {
|
|
|
|
|
const wrapperHeight = 480;
|
|
|
|
|
|
|
|
|
|
// Reset wrapper styles to avoid double scaling (wrapper remains unstyled)
|
|
|
|
|
wrapper.style.removeProperty('width');
|
|
|
|
|
wrapper.style.removeProperty('height');
|
|
|
|
|
wrapper.style.removeProperty('transform');
|
|
|
|
|
wrapper.style.removeProperty('transform-origin');
|
|
|
|
|
clearElementStyles(wrapper, SCALING_PROPERTIES.wrapper);
|
|
|
|
|
|
|
|
|
|
// Platform-specific positioning logic
|
|
|
|
|
let transformOrigin;
|
|
|
|
|
@@ -529,7 +531,7 @@ const resize = (force = false) => {
|
|
|
|
|
const offsetY = (window.innerHeight - scaledHeight) / 2;
|
|
|
|
|
|
|
|
|
|
if (debugFlag('fullscreen')) {
|
|
|
|
|
console.log(`🖥️ Applying fullscreen/kiosk scaling: wrapper=${wrapperWidth}x${wrapperHeight} scale=${scale.toFixed(3)} offset=${offsetX.toFixed(1)},${offsetY.toFixed(1)} transform: scale(${scale}) translate(${offsetX / scale}px, ${offsetY / scale}px)`);
|
|
|
|
|
console.log(`🖥️ Applying fullscreen/kiosk scaling: wrapper=${wrapperWidth}x${wrapperHeight} scale=${scale.toFixed(3)} offset=${offsetX.toFixed(1)},${offsetY.toFixed(1)} target=${isFullscreen ? '#container' : '#divTwcMain'}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set positioning values for CSS-based centering
|
|
|
|
|
@@ -540,25 +542,39 @@ const resize = (force = false) => {
|
|
|
|
|
marginTop = `-${wrapperHeight / 2}px`; // Pull back by half height
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply shared mainContainer properties (same for both kiosk modes)
|
|
|
|
|
mainContainer.style.setProperty('transform', `scale(${scale})`, 'important');
|
|
|
|
|
mainContainer.style.setProperty('transform-origin', transformOrigin, 'important');
|
|
|
|
|
mainContainer.style.setProperty('width', `${wrapperWidth}px`, 'important');
|
|
|
|
|
mainContainer.style.setProperty('height', `${wrapperHeight}px`, 'important');
|
|
|
|
|
mainContainer.style.setProperty('position', 'absolute', 'important');
|
|
|
|
|
mainContainer.style.setProperty('left', leftPosition, 'important');
|
|
|
|
|
mainContainer.style.setProperty('top', topPosition, 'important');
|
|
|
|
|
// Chrome fullscreen compatibility: apply transform to #container instead of #divTwcMain
|
|
|
|
|
// This works around Chrome's restriction on styling fullscreen elements directly
|
|
|
|
|
const container = document.querySelector('#container');
|
|
|
|
|
const targetElement = isFullscreen ? container : mainContainer;
|
|
|
|
|
|
|
|
|
|
// Reset the other element's styles to avoid conflicts
|
|
|
|
|
if (isFullscreen) {
|
|
|
|
|
// Reset mainContainer styles when using container for fullscreen
|
|
|
|
|
clearElementStyles(mainContainer, SCALING_PROPERTIES.positioning);
|
|
|
|
|
} else {
|
|
|
|
|
// Reset container styles when using mainContainer for kiosk mode
|
|
|
|
|
clearElementStyles(container, SCALING_PROPERTIES.positioning);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply shared properties to the target element
|
|
|
|
|
targetElement.style.setProperty('transform', `scale(${scale})`, 'important');
|
|
|
|
|
targetElement.style.setProperty('transform-origin', transformOrigin, 'important');
|
|
|
|
|
targetElement.style.setProperty('width', `${wrapperWidth}px`, 'important');
|
|
|
|
|
targetElement.style.setProperty('height', `${wrapperHeight}px`, 'important');
|
|
|
|
|
targetElement.style.setProperty('position', 'absolute', 'important');
|
|
|
|
|
targetElement.style.setProperty('left', leftPosition, 'important');
|
|
|
|
|
targetElement.style.setProperty('top', topPosition, 'important');
|
|
|
|
|
|
|
|
|
|
// Apply or clear margin properties based on positioning method
|
|
|
|
|
if (marginLeft !== null) {
|
|
|
|
|
mainContainer.style.setProperty('margin-left', marginLeft, 'important');
|
|
|
|
|
targetElement.style.setProperty('margin-left', marginLeft, 'important');
|
|
|
|
|
} else {
|
|
|
|
|
mainContainer.style.removeProperty('margin-left');
|
|
|
|
|
targetElement.style.removeProperty('margin-left');
|
|
|
|
|
}
|
|
|
|
|
if (marginTop !== null) {
|
|
|
|
|
mainContainer.style.setProperty('margin-top', marginTop, 'important');
|
|
|
|
|
targetElement.style.setProperty('margin-top', marginTop, 'important');
|
|
|
|
|
} else {
|
|
|
|
|
mainContainer.style.removeProperty('margin-top');
|
|
|
|
|
targetElement.style.removeProperty('margin-top');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
applyScanlineScaling(scale);
|
|
|
|
|
|