diff --git a/app/assets/javascripts/discourse/app/instance-initializers/viewport-setup.js b/app/assets/javascripts/discourse/app/instance-initializers/viewport-setup.js index 55b727809e1..7e2d3f312f9 100644 --- a/app/assets/javascripts/discourse/app/instance-initializers/viewport-setup.js +++ b/app/assets/javascripts/discourse/app/instance-initializers/viewport-setup.js @@ -14,11 +14,6 @@ export default { } let value = viewport.getAttribute("content"); - if (caps.isIOS) { - // In iOS Safari, setting user-scalable=no doesn't actually prevent the user from zooming in. - // But, it does prevent the annoying 'auto zoom' when focussing input fields with small font-sizes. - value += ", user-scalable=no"; - } if (!caps.isSafari) { // Safari prints a big red warning because it doesn't support this property. @@ -26,6 +21,39 @@ export default { value += ", interactive-widget=resizes-content"; } + if (caps.isIOS) { + // iOS 'auto-zooms' into inputs with font sizes smaller than 16px. To prevent this, + // we use two different strategies. + if (caps.isiOSPWA || caps.isAppWebview) { + // For PWA/Hub, we lock the viewport zoom temporarily during `focusin` events. + // Unfortunately this doesn't catch the case when an input is already autofocussed, but the + // keyboard isn't open yet. But it's better than nothing. + this.lockViewportDuringFocus(viewport, value); + } else { + // In the full Safari browser, user-scalable=no doesn't actually prevent the user from zooming in. + // So we can keep it in place all the time to prevent the auto-zoom. + value += ", user-scalable=no"; + } + } + viewport.setAttribute("content", value); }, + + lockViewportDuringFocus(viewport, initialValue) { + let timer; + + window.addEventListener("focusin", (event) => { + if (!["INPUT", "TEXTAREA"].includes(event.target.tagName)) { + return; + } + + viewport.setAttribute("content", `${initialValue}, user-scalable=no`); + + clearTimeout(timer); + timer = setTimeout( + () => viewport.setAttribute("content", initialValue), + 100 + ); + }); + }, };