/** * Shared scroll lock for MeetLet modals. * Uses body overflow + scroll guards — no position:fixed on body (avoids white-page flash). * * @package mod_meetletacbfree * @copyright 2026 MeetLet * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ (function (global) { 'use strict'; var scrollLockY = 0; var guardsActive = false; function scrollbarWidth() { return Math.max(0, global.innerWidth - document.documentElement.clientWidth); } function focusNoScroll(el) { if (!el || typeof el.focus !== 'function') { return; } try { el.focus({preventScroll: true}); } catch (e) { el.focus(); } } function restoreScroll() { if (scrollLockY > 0) { global.scrollTo(0, scrollLockY); } } function onScrollGuard() { if (scrollLockY && global.scrollY !== scrollLockY) { global.scrollTo(0, scrollLockY); } } function onMoveGuard(e) { if (e.target.closest && e.target.closest('.meetlet-modal__dialog')) { return; } e.preventDefault(); } function bindGuards() { if (guardsActive) { return; } guardsActive = true; global.addEventListener('scroll', onScrollGuard, true); global.addEventListener('wheel', onMoveGuard, {passive: false, capture: true}); global.addEventListener('touchmove', onMoveGuard, {passive: false, capture: true}); } function unbindGuards() { if (!guardsActive) { return; } guardsActive = false; global.removeEventListener('scroll', onScrollGuard, true); global.removeEventListener('wheel', onMoveGuard, true); global.removeEventListener('touchmove', onMoveGuard, true); } function lockPageScroll() { if (document.documentElement.classList.contains('meetlet-modal-open')) { return; } scrollLockY = global.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0; var pad = scrollbarWidth(); if (pad > 0) { document.body.style.paddingRight = pad + 'px'; } document.documentElement.classList.add('meetlet-modal-open'); restoreScroll(); if (typeof global.requestAnimationFrame === 'function') { global.requestAnimationFrame(restoreScroll); } bindGuards(); } function unlockPageScroll() { if (!document.documentElement.classList.contains('meetlet-modal-open')) { return; } unbindGuards(); var y = scrollLockY; document.documentElement.classList.remove('meetlet-modal-open'); document.body.style.paddingRight = ''; scrollLockY = 0; if (y) { global.scrollTo(0, y); if (typeof global.requestAnimationFrame === 'function') { global.requestAnimationFrame(function () { global.scrollTo(0, y); }); } } } global.MeetletModalScroll = { lock: lockPageScroll, unlock: unlockPageScroll, focusNoScroll: focusNoScroll, }; }(typeof window !== 'undefined' ? window : this));