mediawiki-skins-Citizen/resources/skins.citizen.scripts/scrollObserver.js
2024-11-07 20:53:21 -05:00

65 lines
1.9 KiB
JavaScript

/**
* Initialize a direction observer based on scroll behavior.
*
* @param {Function} onScrollDown - Function to be called when scrolling down.
* @param {Function} onScrollUp - Function to be called when scrolling up.
* @param {number} threshold - The threshold for significant scroll position change.
* @return {Object}
*/
function initDirectionObserver( onScrollDown, onScrollUp, threshold = 0 ) {
let lastScrollPosition = 0;
let lastScrollDirection = '';
const onScroll = () => {
const currentScrollPosition = window.scrollY;
const scrollDiff = currentScrollPosition - lastScrollPosition;
if ( Math.abs( scrollDiff ) < threshold ) {
return;
}
if ( scrollDiff > 0 && lastScrollDirection !== 'down' ) {
lastScrollDirection = 'down';
onScrollDown();
} else if ( scrollDiff < 0 && lastScrollDirection !== 'up' ) {
lastScrollDirection = 'up';
onScrollUp();
}
lastScrollPosition = currentScrollPosition <= 0 ? 0 : currentScrollPosition;
};
return {
resume: () => {
window.addEventListener( 'scroll', mw.util.throttle( onScroll, 100 ) );
},
pause: () => {
window.removeEventListener( 'scroll', mw.util.throttle( onScroll, 100 ) );
}
};
}
/**
* Create an observer for showing/hiding feature and for firing scroll event hooks.
*
* @param {Function} show functionality for when feature is visible
* @param {Function} hide functionality for when feature is hidden
* @return {IntersectionObserver}
*/
function initScrollObserver( show, hide ) {
/* eslint-disable-next-line compat/compat */
return new IntersectionObserver( ( entries ) => {
if ( !entries[ 0 ].isIntersecting && entries[ 0 ].boundingClientRect.top < 0 ) {
// Viewport has crossed the bottom edge of the target element.
show();
} else {
// Viewport is above the bottom edge of the target element.
hide();
}
} );
}
module.exports = {
initDirectionObserver,
initScrollObserver
};