refactor(core): move intersection observer into a module

* We will likely use it for other things in the future
* Based on Vector's implementation
* Also do not get toc element twice
This commit is contained in:
alistair3149 2022-05-13 00:21:08 -04:00
parent 23795e05e3
commit d59ca5c83a
No known key found for this signature in database
GPG key ID: 94D081060FD3DD9C
5 changed files with 50 additions and 16 deletions

View file

@ -0,0 +1,24 @@
/**
* Create an observer for showing/hiding feature and for firing scroll event hooks.
* Based on Vector
*
* @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 = {
initScrollObserver
};

View file

@ -66,13 +66,16 @@ function onTitleHidden( document ) {
const title = document.getElementById( 'firstHeading' );
if ( title ) {
const observer = new IntersectionObserver( ( entries ) => {
if ( !entries[ 0 ].isIntersecting ) {
const scrollObserver = require( './scrollObserver.js' );
const observer = scrollObserver.initScrollObserver(
() => {
document.body.classList.add( 'skin-citizen--titlehidden' );
} else {
},
() => {
document.body.classList.remove( 'skin-citizen--titlehidden' );
}
} );
);
observer.observe( title );
}
}
@ -82,9 +85,11 @@ function onTitleHidden( document ) {
* @return {void}
*/
function main( window ) {
const theme = require( './theme.js' ),
search = require( './search.js' ),
tocContainer = document.getElementById( 'toc' );
const
theme = require( './theme.js' ),
search = require( './search.js' );
const tocContainer = document.getElementById( 'toc' );
enableCssAnimations( window.document );
theme.init( window );
@ -102,7 +107,7 @@ function main( window ) {
// TODO: There must be a cleaner way to do this
if ( tocContainer ) {
const toc = require( './tableOfContents.js' );
toc.init();
toc.init( tocContainer );
checkboxHack.bind(
window,

View file

@ -1,11 +1,14 @@
const ACTIVE_ITEM_CLASS = 'toc__item--active';
/**
* Toggle active HTML class to items in table of content based on user viewport.
*
* @param {Element} toc TOC element
* @return {void}
*/
function initToC() {
const headlines = document.querySelectorAll( '.mw-headline' ),
toc = document.getElementById( 'toc' ),
function initToC( toc ) {
const
headlines = document.querySelectorAll( '.mw-headline' ),
marginTop = '-' + window.getComputedStyle( document.documentElement ).getPropertyValue( 'scroll-padding-top' );
for ( let i = 0; i < headlines.length; i++ ) {
@ -13,20 +16,21 @@ function initToC() {
const observer = new IntersectionObserver( ( entry ) => {
/* eslint-enable compat/compat */
if ( entry[ 0 ].isIntersecting ) {
const headlineId = headlines[ i ].id,
const
headlineId = headlines[ i ].id,
// Get the decoded ID from the span before
decodedId = ( headlines[ i ].previousSibling !== null ) ?
headlines[ i ].previousSibling.id : '',
links = toc.querySelector( "a[href='#" + headlineId + "']" ) ||
toc.querySelector( "a[href='#" + decodedId + "']" ),
targetLink = links.parentNode,
activeLink = toc.querySelector( '.active' );
activeLink = toc.querySelector( '.' + ACTIVE_ITEM_CLASS );
if ( activeLink !== null ) {
activeLink.classList.remove( 'active' );
activeLink.classList.remove( ACTIVE_ITEM_CLASS );
}
if ( targetLink !== null ) {
targetLink.classList.add( 'active' );
targetLink.classList.add( ACTIVE_ITEM_CLASS );
}
}
}, {

View file

@ -52,7 +52,7 @@
}
}
li.active {
.toc__item--active {
border-color: var( --color-primary );
color: var( --color-primary );

View file

@ -187,6 +187,7 @@
"callback": "Citizen\\Hooks\\ResourceLoaderHooks::getCitizenResourceLoaderConfig"
},
"resources/skins.citizen.scripts/checkboxHack.js",
"resources/skins.citizen.scripts/scrollObserver.js",
"resources/skins.citizen.scripts/search.js",
"resources/skins.citizen.scripts/tableOfContents.js",
"resources/skins.citizen.scripts/theme.js"