From fce467fa8711fb4a5d961a5f7975ae3121250236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Mummert?= Date: Mon, 23 Feb 2026 20:00:36 +0100 Subject: [PATCH] Harden SlimSelect scroll lock on macOS browsers --- .../templates/frontend/event_filter.html.twig | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/contao/templates/frontend/event_filter.html.twig b/contao/templates/frontend/event_filter.html.twig index 894a266..4e4331b 100644 --- a/contao/templates/frontend/event_filter.html.twig +++ b/contao/templates/frontend/event_filter.html.twig @@ -342,17 +342,57 @@ return null; } - return target.closest('#eventfilters .ss-content, #eventfilters .ss-list'); + return target.closest('.ss-content, .ss-list'); }; - const shouldBlockBoundaryScroll = (dropdown, delta) => { - if (!dropdown || dropdown.scrollHeight <= dropdown.clientHeight) { + const getOpenDropdown = () => { + const openContent = document.querySelector('.ss-content.ss-open'); + + if (openContent) { + return openContent; + } + + const openMain = document.querySelector('.ss-main.ss-open'); + + if (!openMain) { + return null; + } + + const scope = openMain.parentElement || document; + return scope.querySelector('.ss-content'); + }; + + const getScrollContainer = (targetDropdown) => { + const openDropdown = getOpenDropdown(); + + if (!openDropdown) { + return null; + } + + if (!targetDropdown) { + return openDropdown; + } + + const contentContainer = targetDropdown.closest('.ss-content'); + return contentContainer || openDropdown; + }; + + const shouldBlockBoundaryScroll = (scrollContainer, delta) => { + if (!scrollContainer) { return false; } - const top = dropdown.scrollTop; - const height = dropdown.clientHeight; - const scrollHeight = dropdown.scrollHeight; + if (scrollContainer.scrollHeight <= scrollContainer.clientHeight) { + return true; + } + + if (delta === 0) { + return false; + } + + const top = scrollContainer.scrollTop; + const height = scrollContainer.clientHeight; + const scrollHeight = scrollContainer.scrollHeight; const atTop = top <= 0; const atBottom = top + height >= scrollHeight - 1; @@ -364,16 +404,24 @@ document.addEventListener('wheel', (event) => { const dropdown = getDropdownFromTarget(event.target); + const scrollContainer = getScrollContainer(dropdown); - if (shouldBlockBoundaryScroll(dropdown, event.deltaY)) { + if (!scrollContainer) { + return; + } + + if (shouldBlockBoundaryScroll(scrollContainer, event.deltaY)) { event.preventDefault(); } + + event.stopPropagation(); }, { passive: false, capture: true }); document.addEventListener('touchstart', (event) => { const dropdown = getDropdownFromTarget(event.target); + const scrollContainer = getScrollContainer(dropdown); - if (!dropdown || event.touches.length === 0) { + if (!scrollContainer || event.touches.length === 0) { lastTouchY = null; return; } @@ -383,18 +431,21 @@ document.addEventListener('touchmove', (event) => { const dropdown = getDropdownFromTarget(event.target); + const scrollContainer = getScrollContainer(dropdown); - if (!dropdown || event.touches.length === 0 || lastTouchY === null) { + if (!scrollContainer || event.touches.length === 0 || lastTouchY === null) { return; } const currentTouchY = event.touches[0].clientY; const delta = lastTouchY - currentTouchY; - if (shouldBlockBoundaryScroll(dropdown, delta)) { + if (shouldBlockBoundaryScroll(scrollContainer, delta)) { event.preventDefault(); } + event.stopPropagation(); + lastTouchY = currentTouchY; }, { passive: false, capture: true });