diff --git a/resources/skins.vector.es6/main.js b/resources/skins.vector.es6/main.js index 7c8145af6..bc61bf619 100644 --- a/resources/skins.vector.es6/main.js +++ b/resources/skins.vector.es6/main.js @@ -79,11 +79,10 @@ const main = () => { return; } - // eslint-disable-next-line prefer-const - let /** @type {initSectionObserver.SectionObserver} */ sectionObserver; const tableOfContents = initTableOfContents( { container: tocElement, onSectionClick: () => { + // eslint-disable-next-line no-use-before-define sectionObserver.pause(); // T297614: We want the link that the user has clicked inside the TOC to @@ -105,15 +104,14 @@ const main = () => { // the user clicked even after waiting 2 frames. After further // investigation, it sometimes waits up to 3 frames before painting the // new scroll position so we have that as the limit. + // + // eslint-disable-next-line no-use-before-define deferUntilFrame( () => sectionObserver.resume(), 3 ); } } ); - sectionObserver = initSectionObserver( { + const sectionObserver = initSectionObserver( { elements: bodyContent.querySelectorAll( 'h1, h2, h3, h4, h5, h6' ), topMargin: targetElement ? targetElement.getBoundingClientRect().height : 0, - /** - * @param {HTMLElement} section - */ onIntersection: ( section ) => { const headline = section.querySelector( HEADLINE_SELECTOR ); diff --git a/resources/skins.vector.es6/sectionObserver.js b/resources/skins.vector.es6/sectionObserver.js index 5c67bf2bf..80186b856 100644 --- a/resources/skins.vector.es6/sectionObserver.js +++ b/resources/skins.vector.es6/sectionObserver.js @@ -1,20 +1,8 @@ /** - * Called when a new intersection is observed. - * * @callback OnIntersection * @param {HTMLElement} element The section that triggered the new intersection change. */ -/** - * @typedef {Object} SectionObserver - * @property {Function} pause Pauses intersection observation until `resume` is called. - * @property {Function} resume Resumes intersection observation. - * @property {Function} unmount Cleans up event listeners and intersection - * observer. Should be called when the observer is permanently no longer needed. - * @property {NodeList} elements A list of HTML elements to observe for - * intersection changes. - */ - /** * Observe intersection changes with the viewport for one or more elements. This * is intended to be used with the headings in the content so that the @@ -35,7 +23,7 @@ * @param {Object} props * @param {NodeList} props.elements A list of HTML elements to observe for * intersection changes. This list can be updated through the `elements` setter. - * @param {OnIntersection} props.onIntersection + * @param {OnIntersection} props.onIntersection Called when a new intersection is observed. * @param {number} [props.topMargin] The number of pixels to shrink the top of * the viewport's bounding box before calculating intersections. This is useful * for sticky elements (e.g. sticky headers). Defaults to 0 pixels. @@ -133,28 +121,55 @@ module.exports = function sectionObserver( props ) { window.removeEventListener( 'scroll', handleScroll ); } + /** + * Pauses intersection observation until `resume` is called. + */ + function pause() { + unbindScrollListener(); + // Assume current is no longer valid while paused. + current = undefined; + } + + /** + * Resumes intersection observation. + */ + function resume() { + bindScrollListener(); + } + + /** + * Cleans up event listeners and intersection observer. Should be called when + * the observer is permanently no longer needed. + */ + function unmount() { + unbindScrollListener(); + observer.disconnect(); + } + + /** + * Set a list of HTML elements to observe for intersection changes. + * + * @param {NodeList} list + */ + function setElements( list ) { + props.elements = list; + } + bindScrollListener(); // Calculate intersection on page load. calcIntersection(); + /** + * @typedef {Object} SectionObserver + * @property {pause} pause + * @property {resume} resume + * @property {unmount} unmount + * @property {setElements} setElements + */ return { - pause() { - unbindScrollListener(); - // Assume current is no longer valid while paused. - current = undefined; - }, - resume() { - bindScrollListener(); - }, - unmount() { - unbindScrollListener(); - observer.disconnect(); - }, - /** - * @param {NodeList} list - */ - set elements( list ) { - props.elements = list; - } + pause, + resume, + unmount, + setElements }; };