From a2c7c024df51cac6a48920ac444ccc3a7995e14f Mon Sep 17 00:00:00 2001 From: Jon Robson Date: Thu, 17 Mar 2022 09:54:26 -0700 Subject: [PATCH] Make beginning bold on scroll Bug: T301254 Change-Id: I4469575ea8590ae22023b98c3dbd31bc672d5766 --- resources/skins.vector.es6/config.json | 4 +++ resources/skins.vector.es6/main.js | 39 ++++++++++++++++++------ tests/jest/skins.vector.es6/main.test.js | 28 +++++++++++++++++ 3 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 resources/skins.vector.es6/config.json create mode 100644 tests/jest/skins.vector.es6/main.test.js diff --git a/resources/skins.vector.es6/config.json b/resources/skins.vector.es6/config.json new file mode 100644 index 000000000..c308e6b42 --- /dev/null +++ b/resources/skins.vector.es6/config.json @@ -0,0 +1,4 @@ +{ + "@doc": "This file describes the shape of the AB config. It exists to support jest", + "wgVectorWebABTestEnrollment": {} +} diff --git a/resources/skins.vector.es6/main.js b/resources/skins.vector.es6/main.js index a29756287..a91111575 100644 --- a/resources/skins.vector.es6/main.js +++ b/resources/skins.vector.es6/main.js @@ -14,6 +14,30 @@ const TOC_SECTION_ID_PREFIX = 'toc-', ABTestConfig = require( /** @type {string} */ ( './config.json' ) ).wgVectorWebABTestEnrollment || {}; +/** + * @callback OnIntersection + * @param {HTMLElement} element The section that triggered the new intersection change. + */ + +/** + * @ignore + * @param {Function} changeActiveSection + * @return {OnIntersection} + */ +const getHeadingIntersectionHandler = ( changeActiveSection ) => { + /** + * @param {HTMLElement} section + */ + return ( section ) => { + const headline = section.classList.contains( 'mw-body-content' ) ? + section : + section.querySelector( HEADLINE_SELECTOR ); + if ( headline ) { + changeActiveSection( `${TOC_SECTION_ID_PREFIX}${headline.id}` ); + } + }; +}; + /** * @return {void} */ @@ -126,18 +150,15 @@ const main = () => { } } ); const sectionObserver = initSectionObserver( { - elements: bodyContent.querySelectorAll( 'h1, h2, h3, h4, h5, h6' ), + elements: bodyContent.querySelectorAll( 'h1, h2, h3, h4, h5, h6, .mw-body-content' ), topMargin: targetElement ? targetElement.getBoundingClientRect().height : 0, - onIntersection: ( section ) => { - const headline = section.querySelector( HEADLINE_SELECTOR ); - - if ( headline ) { - tableOfContents.changeActiveSection( TOC_SECTION_ID_PREFIX + headline.id ); - } - } + onIntersection: getHeadingIntersectionHandler( tableOfContents.changeActiveSection ) } ); }; module.exports = { - main: main + main, + test: { + getHeadingIntersectionHandler + } }; diff --git a/tests/jest/skins.vector.es6/main.test.js b/tests/jest/skins.vector.es6/main.test.js new file mode 100644 index 000000000..a637726a3 --- /dev/null +++ b/tests/jest/skins.vector.es6/main.test.js @@ -0,0 +1,28 @@ +const { test } = require( '../../../resources/skins.vector.es6/main.js' ); + +describe( 'main.js', () => { + it( 'getHeadingIntersectionHandler', () => { + const section = document.createElement( 'div' ); + section.setAttribute( 'class', 'mw-body-content' ); + section.setAttribute( 'id', 'mw-content-text' ); + const heading = document.createElement( 'h2' ); + const headline = document.createElement( 'span' ); + headline.classList.add( 'mw-headline' ); + headline.setAttribute( 'id', 'headline' ); + heading.appendChild( headline ); + section.appendChild( + heading + ); + + [ + [ section, 'toc-mw-content-text' ], + [ heading, 'toc-headline' ] + ].forEach( ( testCase ) => { + const node = /** @type {HTMLElement} */ ( testCase[ 0 ] ); + const fn = jest.fn(); + const handler = test.getHeadingIntersectionHandler( fn ); + handler( node ); + expect( fn ).toHaveBeenCalledWith( testCase[ 1 ] ); + } ); + } ); +} );