From 2dcd99ed21b0a2780219c045b51d216a135a03af Mon Sep 17 00:00:00 2001 From: Jon Robson Date: Fri, 18 Feb 2022 08:47:44 -0800 Subject: [PATCH] Sticky header dropdown should not contain gadgets in personal menu Bug: T302087 Change-Id: Iae1f42c3c526398d7dea038786ae9001e118307b --- jest.config.js | 8 +-- resources/skins.vector.es6/stickyHeader.js | 61 +++++++++++++--------- tests/jest/stickyHeader.test.js | 44 ++++++++++++++++ 3 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 tests/jest/stickyHeader.test.js diff --git a/jest.config.js b/jest.config.js index 4cd7f907b..18a79a203 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,10 +28,10 @@ module.exports = { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 6, - functions: 12, - lines: 8, - statements: 8 + branches: 14, + functions: 24, + lines: 22, + statements: 22 } }, diff --git a/resources/skins.vector.es6/stickyHeader.js b/resources/skins.vector.es6/stickyHeader.js index 83d7805d4..8d1d9d785 100644 --- a/resources/skins.vector.es6/stickyHeader.js +++ b/resources/skins.vector.es6/stickyHeader.js @@ -112,6 +112,15 @@ function removeClassFromNodes( nodes, className ) { } ); } +/** + * @param {NodeList} nodes + */ +function removeNodes( nodes ) { + Array.prototype.forEach.call( nodes, function ( node ) { + node.parentNode.removeChild( node ); + } ); +} + /** * Ensures a sticky header button has the correct attributes * @@ -327,6 +336,32 @@ function addVisualEditorHooks( targetIntersection, observer ) { } ); } +/** + * @param {HTMLElement} userMenu + * @return {HTMLElement} cloned userMenu + */ +function prepareUserMenu( userMenu ) { + const + // Type declaration needed because of https://github.com/Microsoft/TypeScript/issues/3734#issuecomment-118934518 + userMenuClone = /** @type {HTMLElement} */( userMenu.cloneNode( true ) ), + userMenuStickyElementsWithIds = userMenuClone.querySelectorAll( '[ id ], [ data-event-name ]' ); + // Update all ids of the cloned user menu to make them unique. + makeNodeTrackable( userMenuClone ); + userMenuStickyElementsWithIds.forEach( makeNodeTrackable ); + // Remove portlet links added by gadgets using mw.util.addPortletLink, T291426 + removeNodes( userMenuClone.querySelectorAll( '.mw-list-item-js' ) ); + removeClassFromNodes( + userMenuClone.querySelectorAll( '.user-links-collapsible-item' ), + 'user-links-collapsible-item' + ); + // Prevents user menu from being focusable, T290201 + const userMenuCheckbox = userMenuClone.querySelector( 'input' ); + if ( userMenuCheckbox ) { + userMenuCheckbox.setAttribute( 'tabindex', '-1' ); + } + return userMenuClone; +} + /** * Makes sticky header functional for modern Vector. * @@ -344,35 +379,12 @@ function makeStickyHeaderFunctional( stickyIntersection ) { const - // Type declaration needed because of https://github.com/Microsoft/TypeScript/issues/3734#issuecomment-118934518 - userMenuClone = /** @type {HTMLElement} */( userMenu.cloneNode( true ) ), - userMenuStickyElementsWithIds = userMenuClone.querySelectorAll( '[ id ], [ data-event-name ]' ), userMenuStickyContainerInner = userMenuStickyContainer .querySelector( VECTOR_USER_LINKS_SELECTOR ); - // Update all ids of the cloned user menu to make them unique. - makeNodeTrackable( userMenuClone ); - userMenuStickyElementsWithIds.forEach( makeNodeTrackable ); - - // Remove portlet links added by gadgets using mw.util.addPortletLink, T291426 - const gadgetLinks = userMenuClone.querySelector( 'mw-list-item-js' ); - if ( gadgetLinks ) { - gadgetLinks.remove(); - } - removeClassFromNodes( - userMenuClone.querySelectorAll( '.user-links-collapsible-item' ), - 'user-links-collapsible-item' - ); - - // Prevents user menu from being focusable, T290201 - const userMenuCheckbox = userMenuClone.querySelector( 'input' ); - if ( userMenuCheckbox ) { - userMenuCheckbox.setAttribute( 'tabindex', '-1' ); - } - // Clone the updated user menu to the sticky header. if ( userMenuStickyContainerInner ) { - userMenuStickyContainerInner.appendChild( userMenuClone ); + userMenuStickyContainerInner.appendChild( prepareUserMenu( userMenu ) ); } prepareIcons( headerElement, @@ -513,6 +525,7 @@ function initStickyHeader( observer ) { module.exports = { show, hide, + prepareUserMenu, initStickyHeader, isStickyHeaderAllowed, header, diff --git a/tests/jest/stickyHeader.test.js b/tests/jest/stickyHeader.test.js new file mode 100644 index 000000000..e035ef2ea --- /dev/null +++ b/tests/jest/stickyHeader.test.js @@ -0,0 +1,44 @@ +const sticky = require( '../../resources/skins.vector.es6/stickyHeader.js' ); + +describe( 'sticky header', () => { + test( 'prepareUserMenu removes gadgets from dropdown', async () => { + const menu = document.createElement( 'div' ); + menu.innerHTML = ` + +
+ +
+ Log out +
+
`; + const newMenu = sticky.prepareUserMenu( menu ); + // check classes have been updated and removed. + expect( newMenu.querySelectorAll( '.user-links-collapsible-item' ).length ).toBe( 0 ); + expect( newMenu.querySelectorAll( '.mw-list-item-js' ).length ).toBe( 0 ); + } ); +} );