// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * @module mod_meetletacbfree/meetlet_modal_scroll * @copyright 2026 MeetLet * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ define([], function() { 'use strict'; var scrollLockY = 0; var guardsActive = false; function scrollbarWidth() { return Math.max(0, window.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) { window.scrollTo(0, scrollLockY); } } function onScrollGuard() { if (scrollLockY && window.scrollY !== scrollLockY) { window.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; window.addEventListener('scroll', onScrollGuard, true); window.addEventListener('wheel', onMoveGuard, {passive: false, capture: true}); window.addEventListener('touchmove', onMoveGuard, {passive: false, capture: true}); } function unbindGuards() { if (!guardsActive) { return; } guardsActive = false; window.removeEventListener('scroll', onScrollGuard, true); window.removeEventListener('wheel', onMoveGuard, true); window.removeEventListener('touchmove', onMoveGuard, true); } function lockPageScroll() { if (document.documentElement.classList.contains('meetlet-modal-open')) { return; } scrollLockY = window.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 window.requestAnimationFrame === 'function') { window.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) { window.scrollTo(0, y); if (typeof window.requestAnimationFrame === 'function') { window.requestAnimationFrame(function() { window.scrollTo(0, y); }); } } } return { init: function() {}, lock: lockPageScroll, unlock: unlockPageScroll, focusNoScroll: focusNoScroll }; });