Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix toggle-expanded script to account for multiple buttons #45

Merged
merged 2 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/scripts/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ import { applyToggleExpanded } from './theme/toggle-expanded';
* This can be used for any other toggle button that expands any element, for
* example, an FAQ section.
*/
applyToggleExpanded( '.menu-toggle' );
applyToggleExpanded( 'main-navigation' );
70 changes: 45 additions & 25 deletions src/scripts/theme/toggle-expanded.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Toggle area-expanded attributes via aria-controls.
*/

const controlled = [];

/**
* Link button with controlled element via aria-controls attribute.
*
Expand All @@ -11,43 +13,59 @@
* @param {object} options Options for the toggle functionality.
* @param {boolean} options.clickOutsideClose Whether to close the target element when clicking outside. Default true.
*/
export function toggleExpanded( button, { clickOutsideClose = true } ) {
if ( ! button.hasAttribute( 'aria-controls' ) ) {
export const toggleExpanded = ( target, { clickOutsideClose = true } ) => {
const targetId = target.id;
const buttons = document.querySelectorAll(
'[aria-controls="' + targetId + '"]'
);

if ( buttons.lenth === 0 ) {
console.warn(
'Element missing aria-controls attribute for toggleExpanded:',
button
'No buttons found with aria-controls="' + targetId + '".'
);
return;
}

const targetId = button.getAttribute( 'aria-controls' );
const target = document.getElementById( targetId );
// Only set event listeners once per target.
if ( controlled.includes( target ) ) {
return;
}

controlled.push( target );

const startExpanded =
target.getAttribute( 'aria-expanded' ) === 'true' ? 'true' : 'false';
target.setAttribute( 'aria-expanded', startExpanded );
button.setAttribute( 'aria-expanded', startExpanded );
buttons.forEach( ( button ) =>
button.setAttribute( 'aria-expanded', startExpanded )
);

// Toggle the aria-expanded value each time the button or outside the target is clicked.
document.addEventListener( 'click', function ( event ) {
console.log( button.contains( event.target ) );
if ( ! clickOutsideClose && ! button.contains( event.target ) ) {
document.addEventListener( 'click', ( event ) => {
// Whether a toggle button was clicked.
let buttonClick = false;
for ( let i = 0; i < buttons.length; i++ ) {
if ( buttons.item( i ).contains( event.target ) ) {
buttonClick = true;
break;
}
}

// If NOT allowing for click outside to close the target, don't continue if the click was outside the target.
if ( ! clickOutsideClose && ! buttonClick ) {
return;
}

// Check if click is inside the menu.
if (
target.contains( event.target ) &&
! button.contains( event.target )
) {
// If click is inside the menu and not a toggle button, don't continue.
if ( target.contains( event.target ) && ! buttonClick ) {
return;
}

// Check if target is currently expanded.
const expanded = target.getAttribute( 'aria-expanded' ) === 'true';

// If not expanded, only the button should expand the target.
if ( ! expanded && ! button.contains( event.target ) ) {
if ( ! expanded && ! buttonClick ) {
return;
}

Expand All @@ -56,22 +74,24 @@ export function toggleExpanded( button, { clickOutsideClose = true } ) {
? 'false'
: 'true';
target.setAttribute( 'aria-expanded', newExpanded );
button.setAttribute( 'aria-expanded', newExpanded );
buttons.forEach( ( button ) =>
button.setAttribute( 'aria-expanded', newExpanded )
);
} );
}
};

/**
* Apply toggleExpanded to all queried elements.
*
* @param {string} buttonsQuery A query selector for all buttons to apply the expanded toggle functionality to.
* @param {string} targetID The id attribute for all targets to apply the expanded toggle functionality to.
* @param {object} options Options for the toggle functionality. @see {@link toggleExpanded} for available options.
*/
export function applyToggleExpanded(
buttonsQuery = '.toggle-expanded',
export const applyToggleExpanded = (
targetID = '#main-navigation',
options = {}
) {
const buttons = document.querySelectorAll( buttonsQuery );
buttons.forEach( ( button ) => toggleExpanded( button, options ) );
}
) => {
const target = document.getElementById( targetID );
toggleExpanded( target, options );
};

export default applyToggleExpanded;