mirror of
https://github.com/StarCitizenTools/mediawiki-skins-Citizen.git
synced 2024-11-28 16:21:11 +00:00
c9d98e477a
--height-sticky-header will always return the current height of sticky header. It can be used to offset sticky elements so that it adjusts to the sticky header.
105 lines
3.3 KiB
JavaScript
105 lines
3.3 KiB
JavaScript
const SCROLL_DOWN_CLASS = 'citizen-scroll--down';
|
|
const SCROLL_UP_CLASS = 'citizen-scroll--up';
|
|
const STICKY_CLASS = 'citizen-page-header--sticky';
|
|
const { initDirectionObserver, initIntersectionObserver } = require( './scrollObserver.js' );
|
|
|
|
/**
|
|
* Observes the scroll direction and adds/removes corresponding classes to the body element.
|
|
*
|
|
* @return {void}
|
|
*/
|
|
function observeScrollDirection() {
|
|
const toggleScrollClass = ( removeClass, addClass ) => () => {
|
|
window.requestAnimationFrame( () => {
|
|
document.body.classList.remove( removeClass );
|
|
document.body.classList.add( addClass );
|
|
} );
|
|
};
|
|
const addScrollDownClass = toggleScrollClass( SCROLL_UP_CLASS, SCROLL_DOWN_CLASS );
|
|
const addScrollUpClass = toggleScrollClass( SCROLL_DOWN_CLASS, SCROLL_UP_CLASS );
|
|
|
|
initDirectionObserver( addScrollDownClass, addScrollUpClass, 50 );
|
|
}
|
|
|
|
/**
|
|
* Initializes the sticky header functionality for Citizen
|
|
*
|
|
* @return {void}
|
|
*/
|
|
function init() {
|
|
observeScrollDirection();
|
|
|
|
const header = document.querySelector( '.citizen-page-header' );
|
|
const sentinel = document.createElement( 'div' );
|
|
sentinel.id = 'citizen-page-header-sticky-sentinel';
|
|
header.insertAdjacentElement( 'afterend', sentinel );
|
|
|
|
const shouldStickyHeader = getComputedStyle( sentinel ).getPropertyValue( 'display' ) !== 'none';
|
|
if ( !shouldStickyHeader ) {
|
|
return;
|
|
}
|
|
|
|
const placeholder = document.createElement( 'div' );
|
|
placeholder.id = 'citizen-page-header-sticky-placeholder';
|
|
header.insertAdjacentElement( 'afterend', placeholder );
|
|
|
|
let staticHeaderHeight = header.getBoundingClientRect().height;
|
|
let stickyHeaderHeight = 0;
|
|
let placeholderHeight = 0;
|
|
let shouldRecalcHeight = true;
|
|
|
|
const toggleStickyHeader = ( isSticky ) => {
|
|
window.requestAnimationFrame( () => {
|
|
if ( !shouldRecalcHeight ) {
|
|
// The previous height is valid, set the height first
|
|
placeholder.style.height = isSticky ? `${ placeholderHeight }px` : '0px';
|
|
document.body.classList.toggle( STICKY_CLASS, isSticky );
|
|
} else {
|
|
// The previous height is invalid, need to set to sticky to get the sticky height
|
|
document.body.classList.toggle( STICKY_CLASS, isSticky );
|
|
if ( isSticky ) {
|
|
stickyHeaderHeight = header.getBoundingClientRect().height;
|
|
placeholderHeight = staticHeaderHeight - stickyHeaderHeight;
|
|
placeholder.style.height = `${ placeholderHeight }px`;
|
|
shouldRecalcHeight = false;
|
|
}
|
|
placeholder.style.height = `${ isSticky ? placeholderHeight : 0 }px`;
|
|
}
|
|
// Update sticky header CSS variable, used by other sticky elements
|
|
document.documentElement.style.setProperty(
|
|
'--height-sticky-header',
|
|
`${ isSticky ? stickyHeaderHeight : 0 }px`
|
|
);
|
|
} );
|
|
};
|
|
|
|
const onResize = () => {
|
|
toggleStickyHeader( false );
|
|
};
|
|
|
|
const onResizeEnd = mw.util.debounce( () => {
|
|
// Refresh static header height after resize
|
|
staticHeaderHeight = header.getBoundingClientRect().height;
|
|
shouldRecalcHeight = true;
|
|
toggleStickyHeader( true );
|
|
}, 250 );
|
|
|
|
const observer = initIntersectionObserver(
|
|
() => {
|
|
toggleStickyHeader( true );
|
|
window.addEventListener( 'resize', onResize );
|
|
window.addEventListener( 'resize', onResizeEnd );
|
|
},
|
|
() => {
|
|
toggleStickyHeader( false );
|
|
window.removeEventListener( 'resize', onResize );
|
|
window.removeEventListener( 'resize', onResizeEnd );
|
|
}
|
|
);
|
|
observer.observe( sentinel );
|
|
}
|
|
|
|
module.exports = {
|
|
init: init
|
|
};
|