126 lines
3.3 KiB
TypeScript
126 lines
3.3 KiB
TypeScript
import { nextTick } from 'vue'
|
|
import router from '@/router'
|
|
|
|
let recoveryTimers: ReturnType<typeof setTimeout>[] = []
|
|
|
|
function clearRecoveryTimers() {
|
|
recoveryTimers.forEach(clearTimeout)
|
|
recoveryTimers = []
|
|
}
|
|
|
|
function blurFocusedField() {
|
|
const active = document.activeElement
|
|
if (active instanceof HTMLElement && active !== document.body) {
|
|
active.blur()
|
|
}
|
|
}
|
|
|
|
function clearBodyScrollLock() {
|
|
document.body.classList.remove('van-overflow-hidden')
|
|
document.body.style.removeProperty('position')
|
|
document.body.style.removeProperty('top')
|
|
document.body.style.removeProperty('left')
|
|
document.body.style.removeProperty('right')
|
|
document.body.style.removeProperty('width')
|
|
document.body.style.removeProperty('height')
|
|
document.body.style.removeProperty('min-height')
|
|
document.body.style.removeProperty('overflow')
|
|
document.body.style.removeProperty('transform')
|
|
document.documentElement.style.removeProperty('overflow')
|
|
document.documentElement.style.removeProperty('height')
|
|
document.documentElement.style.removeProperty('transform')
|
|
|
|
const appRoot = document.getElementById('app')
|
|
if (appRoot) {
|
|
appRoot.style.removeProperty('position')
|
|
appRoot.style.removeProperty('top')
|
|
appRoot.style.removeProperty('height')
|
|
appRoot.style.removeProperty('min-height')
|
|
appRoot.style.removeProperty('overflow')
|
|
appRoot.style.removeProperty('transform')
|
|
}
|
|
}
|
|
|
|
function resetAllScrollPositions() {
|
|
window.scrollTo(0, 0)
|
|
document.documentElement.scrollTop = 0
|
|
document.body.scrollTop = 0
|
|
|
|
document
|
|
.querySelectorAll('.main-with-bottom-chrome-inner, .login-page, .login-page-root')
|
|
.forEach((node) => {
|
|
if (node instanceof HTMLElement) {
|
|
node.scrollTop = 0
|
|
}
|
|
})
|
|
}
|
|
|
|
function kickViewportReflow() {
|
|
window.dispatchEvent(new Event('resize'))
|
|
|
|
if (window.visualViewport) {
|
|
window.scrollTo(0, 0)
|
|
}
|
|
}
|
|
|
|
function runViewportRecovery() {
|
|
clearBodyScrollLock()
|
|
resetAllScrollPositions()
|
|
kickViewportReflow()
|
|
}
|
|
|
|
function scheduleViewportRecovery() {
|
|
clearRecoveryTimers()
|
|
runViewportRecovery()
|
|
|
|
nextTick(() => {
|
|
requestAnimationFrame(() => {
|
|
runViewportRecovery()
|
|
|
|
for (const delay of [50, 150, 300, 500]) {
|
|
recoveryTimers.push(window.setTimeout(runViewportRecovery, delay))
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
/** Reset scroll offsets after navigation — fixes iOS safe-area drift. */
|
|
export function resetMobileAppScroll() {
|
|
runViewportRecovery()
|
|
|
|
nextTick(() => {
|
|
requestAnimationFrame(runViewportRecovery)
|
|
})
|
|
}
|
|
|
|
export async function dismissMobileKeyboard() {
|
|
blurFocusedField()
|
|
await new Promise((resolve) => window.setTimeout(resolve, 120))
|
|
}
|
|
|
|
export async function prepareMobileViewportForAppShell() {
|
|
blurFocusedField()
|
|
resetAllScrollPositions()
|
|
await dismissMobileKeyboard()
|
|
}
|
|
|
|
/** Full recovery after auth — runs after home shell is mounted. */
|
|
export function recoverMobileViewportAfterAuth() {
|
|
scheduleViewportRecovery()
|
|
}
|
|
|
|
export const resetMobileAppScrollAfterLogin = recoverMobileViewportAfterAuth
|
|
|
|
export async function completeLoginNavigation() {
|
|
await prepareMobileViewportForAppShell()
|
|
await router.push({ name: 'home' })
|
|
await router.isReady()
|
|
recoverMobileViewportAfterAuth()
|
|
}
|
|
|
|
export function initMobileScrollRestoration() {
|
|
if (typeof history !== 'undefined' && 'scrollRestoration' in history) {
|
|
history.scrollRestoration = 'manual'
|
|
}
|
|
}
|