Skip to content

Commit

Permalink
refactor(core): ♻️ various performance and style improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
alistair3149 committed May 21, 2024
1 parent 1270d4e commit a405d64
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 136 deletions.
20 changes: 12 additions & 8 deletions resources/skins.citizen.scripts/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,31 +161,35 @@ function renderSearchClearButton( input ) {
let hasClearButton = false;

clearButton.classList.add( 'citizen-search__clear', 'citizen-search__formButton' );
// TODO: Add i18n for the message below
// clearButton.setAttribute( 'aria-label', 'Clear search input' );
clearIcon.classList.add( 'citizen-ui-icon', 'mw-ui-icon-wikimedia-clear' );
clearButton.append( clearIcon );

clearButton.addEventListener( 'click', ( event ) => {
event.preventDefault();
clearButton.remove();
clearButton.classList.add( 'hidden' );
input.value = '';
input.dispatchEvent( new Event( 'input' ) );
setTimeout( () => {
requestAnimationFrame( () => {
input.focus();
}, 10 );
} );
} );

input.addEventListener( 'input', () => {
if ( input.value === '' ) {
clearButton.remove();
hasClearButton = false;
} else if ( hasClearButton === false ) {
const value = input.value;
const shouldDisplay = value !== '';
clearButton.classList.toggle( 'hidden', !shouldDisplay );
if ( shouldDisplay && !hasClearButton ) {
input.after( clearButton );
hasClearButton = true;
}
hasClearButton = shouldDisplay;
} );
}

/**
* Initializes the search functionality for the Citizen search boxes.
*
* @param {Window} window
* @return {void}
*/
Expand Down
49 changes: 26 additions & 23 deletions resources/skins.citizen.scripts/sections.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,42 @@ function init( bodyContent ) {
return;
}

const
headings = bodyContent.querySelectorAll( '.citizen-section-heading' ),
sections = bodyContent.querySelectorAll( '.citizen-section-collapsible' ),
editSections = bodyContent.querySelectorAll( '.mw-editsection, .mw-editsection-like' );
const headings = bodyContent.querySelectorAll( '.citizen-section-heading' );
const sections = bodyContent.querySelectorAll( '.citizen-section-collapsible' );

for ( let i = 0; i < headings.length; i++ ) {
const j = i + 1,
collapsibleID = `citizen-section-collapsible-${ j }`,
/* T13555 */
headline = headings[ i ].querySelector( '.mw-headline' ) || headings[ i ].querySelector( '.mw-heading' );
const toggleAriaExpanded = ( headline ) => {
headline.toggleAttribute( 'aria-expanded' );

};

// Set up ARIA
const setHeadlineAttributes = ( headline, collapsibleID ) => {
headline.setAttribute( 'tabindex', 0 );
headline.setAttribute( 'role', 'button' );
headline.setAttribute( 'aria-controls', collapsibleID );
headline.setAttribute( 'aria-expanded', true );
};

// TODO: Need a keyboard handler
headings[ i ].addEventListener( 'click', function () {
// .section-heading--collapsed
const handleClick = ( i ) => {
const collapsibleID = `citizen-section-collapsible-${ i + 1 }`;
const headline = headings[ i ].querySelector( '.citizen-section-heading .mw-headline' );

this.classList.toggle( 'citizen-section-heading--collapsed' );
// .section-collapsible--collapsed
if ( headline ) {
setHeadlineAttributes( headline, collapsibleID );

sections[ j ].classList.toggle( 'citizen-section-collapsible--collapsed' );
headline.setAttribute( 'aria-expanded', headline.getAttribute( 'aria-expanded' ) === 'true' ? 'false' : 'true' );
} );
}
headings[ i ].addEventListener( 'click', function ( e ) {
this.classList.toggle( 'citizen-section-heading--collapsed' );
sections[ i + 1 ].classList.toggle( 'citizen-section-collapsible--collapsed' );
toggleAriaExpanded( headline );

for ( let i = 0; i < editSections.length; i++ ) {
editSections[ i ].addEventListener( 'click', function ( e ) {
e.stopPropagation();
} );
if ( e.target.closest( '.mw-editsection, .mw-editsection-like' ) ) {
e.stopPropagation();
}
} );
}
};

for ( let i = 0; i < headings.length; i++ ) {
handleClick( i );
}
}

Expand Down
53 changes: 23 additions & 30 deletions resources/skins.citizen.scripts/tableOfContents.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,15 @@ const ACTIVE_SECTION_CLASS = 'citizen-toc__listItem--active';
let /** @type {HTMLElement | undefined} */ activeSection;

/**
* @param {string} id
* Changes the active section in the table of contents based on the provided ID.
*
* @param {HTMLElement} toc - The Table of Content HTML element
* @param {string} id - The ID of the section to make active.
* @return {void}
*/
function changeActiveSection( id ) {
const toc = document.getElementById( 'mw-panel-toc' );

function changeActiveSection( toc, id ) {
const getLink = ( hash ) => {
const
prefix = 'a[href="#',
suffix = '"]';

let el = toc.querySelector( prefix + hash + suffix );

if ( el === null ) {
// Sometimes the href attribute is encoded
el = toc.querySelector( prefix + encodeURIComponent( hash ) + suffix );
}

const el = toc.querySelector( `a[href="#${ hash }"], a[href="#${ encodeURIComponent( hash ) }"]` );
return el;
};

Expand All @@ -44,30 +36,29 @@ function changeActiveSection( id ) {
* @return {void}
*/
function init( bodyContent ) {
const tocEl = document.getElementById( 'mw-panel-toc' );
if ( !tocEl ) {
const toc = document.getElementById( 'mw-panel-toc' );
if ( !toc ) {
return;
}

const getHeadlineElements = () => {
const getHeadlineIds = () => {
const headlineIds = [];
// Nodelist.forEach is forbidden by mediawiki/no-nodelist-unsupported-methods
Array.from( tocEl.querySelectorAll( '.citizen-toc__listItem' ) ).forEach( ( tocListEl ) => {
// Remove 'toc-' prefix from ID
headlineIds.push( '#' + CSS.escape( tocListEl.id.slice( 4 ) ) );
} );
return headlineIds.join( ',' );
};
return bodyContent.querySelectorAll( getHeadlineIds() );
const headlineElements = [];
Array.from( toc.querySelectorAll( '.citizen-toc__listItem' ) ).forEach( ( tocListEl ) => {
// Remove 'toc-' prefix from ID
const headlineElement = bodyContent.querySelector( '#' + CSS.escape( tocListEl.id.slice( 4 ) ) );
if ( headlineElement ) {
headlineElements.push( headlineElement );
}
} );
return headlineElements;
};

// We use scroll-padding-top to handle scrolling with fixed header
// It is better to respect that so it is consistent
const getTopMargin = () => {
const computedStyle = window.getComputedStyle( document.documentElement );
return Number(
window.getComputedStyle( document.documentElement )
.getPropertyValue( 'scroll-padding-top' )
computedStyle.getPropertyValue( 'scroll-padding-top' )
.slice( 0, -2 )
) + 20;
};
Expand All @@ -87,7 +78,9 @@ function init( bodyContent ) {
elements: headlines,
topMargin: getTopMargin(),
onIntersection: ( section ) => {
changeActiveSection( section.id );
if ( section.id && section.id.trim() !== '' ) {
changeActiveSection( toc, section.id );
}
}
} );

Expand Down
Loading

0 comments on commit a405d64

Please sign in to comment.