11Drupal . behaviors . accordion = {
22 attach ( context ) {
3- // Selectors
43 const items = context . querySelectorAll ( '.js-accordion-item' ) ;
54 const controls = context . querySelectorAll ( '.accordion__controls__item' ) ;
6- // Classes
75 const itemToggle = '.js-accordion-item__toggle' ;
86 const itemContent = '.accordion-item__content' ;
97 const itemState = 'data-accordion-expanded' ;
108 const buttonState = 'aria-expanded' ;
119 const contentState = 'aria-hidden' ;
1210
13- // Function to expand an accordion item.
1411 const expand = ( item , button , content ) => {
1512 item . setAttribute ( itemState , 'true' ) ;
1613 button . setAttribute ( buttonState , 'true' ) ;
1714 content . setAttribute ( contentState , 'false' ) ;
1815 } ;
1916
20- // Function to collapse an accordion item.
2117 const collapse = ( item , button , content ) => {
2218 item . setAttribute ( itemState , 'false' ) ;
2319 button . setAttribute ( buttonState , 'false' ) ;
2420 content . setAttribute ( contentState , 'true' ) ;
2521 } ;
2622
27- /* eslint-disable */
28- /**
29- * getUrl
30- * @description Get the value of the anchor link in the URL.
31- * @returns The string value after the hash.
32- */
23+ // Get base URL and anchor (unchanged)
3324 function getUrl ( ) {
3425 return (
3526 window . location . protocol +
@@ -38,36 +29,62 @@ Drupal.behaviors.accordion = {
3829 window . location . pathname
3930 ) ;
4031 }
41- /* eslint-enable */
4232
43- /**
44- * getAnchor
45- * @description Get the value of the anchor link in the URL.
46- * @return {string } The string value after the hash.
47- */
4833 function getAnchor ( ) {
4934 return document . URL . split ( '#' ) . length > 1
5035 ? document . URL . split ( '#' ) [ 1 ]
5136 : null ;
5237 }
5338
54- // Toggle accordion content when toggle is activated.
39+ // Utility to update aria-disabled on "Expand all" / "Collapse all"
40+ const updateControlStates = ( accordionRoot ) => {
41+ const expandButton = accordionRoot . querySelector (
42+ '.js-accordion__toggle-all--expand' ,
43+ ) ;
44+ const collapseButton = accordionRoot . querySelector (
45+ '.js-accordion__toggle-all--collapse' ,
46+ ) ;
47+ const allItems = accordionRoot . querySelectorAll ( '.js-accordion-item' ) ;
48+
49+ const allExpanded = Array . from ( allItems ) . every (
50+ ( item ) => item . getAttribute ( itemState ) === 'true' ,
51+ ) ;
52+ const allCollapsed = Array . from ( allItems ) . every (
53+ ( item ) => item . getAttribute ( itemState ) === 'false' ,
54+ ) ;
55+
56+ // Set aria-disabled accordingly
57+ if ( expandButton ) {
58+ expandButton . setAttribute (
59+ 'aria-disabled' ,
60+ allExpanded ? 'true' : 'false' ,
61+ ) ;
62+ }
63+ if ( collapseButton ) {
64+ collapseButton . setAttribute (
65+ 'aria-disabled' ,
66+ allCollapsed ? 'true' : 'false' ,
67+ ) ;
68+ }
69+ } ;
70+
71+ // Initialize accordion items
5572 items . forEach ( ( item ) => {
5673 const button = item . querySelector ( itemToggle ) ;
5774 const content = item . querySelector ( itemContent ) ;
75+ const accordionRoot = item . closest ( '.accordion' ) ;
5876
59- const anchor = item . id ;
60- // eslint-disable-next-line
61- const newUrl = `${ getUrl ( ) } ` + '#' + `${ anchor } ` ;
62-
63- // Hide all accordion content sections if JavaScript is enabled.
6477 collapse ( item , button , content ) ;
6578
6679 if ( item . getAttribute ( 'id' ) && item . getAttribute ( 'id' ) === getAnchor ( ) ) {
6780 expand ( item , button , content ) ;
6881 }
6982
7083 button . addEventListener ( 'click' , ( ) => {
84+ const anchor = item . id ;
85+ const newUrl = `${ getUrl ( ) } #${ anchor } ` ;
86+
87+ // Update URL hash
7188 if ( window . location . href !== newUrl ) {
7289 window . history . replaceState ( '' , '' , newUrl ) ;
7390 } else {
@@ -77,39 +94,48 @@ Drupal.behaviors.accordion = {
7794 window . location . origin + window . location . pathname ,
7895 ) ;
7996 }
80- // Toggle the item's state.
81- return button . getAttribute ( buttonState ) === 'true'
82- ? collapse ( item , button , content )
83- : expand ( item , button , content ) ;
97+
98+ // Toggle state
99+ if ( button . getAttribute ( buttonState ) === 'true' ) {
100+ collapse ( item , button , content ) ;
101+ } else {
102+ expand ( item , button , content ) ;
103+ }
104+
105+ // Update control buttons state after toggling
106+ updateControlStates ( accordionRoot ) ;
84107 } ) ;
85108 } ) ;
86109
110+ // Initialize control buttons (Expand All / Collapse All)
87111 controls . forEach ( ( control ) => {
88- // Get all items relevant to the control.
89- const allItems =
90- control . parentNode . parentNode . querySelectorAll ( '.js-accordion-item' ) ;
91- // Add click listener on the parent <ul>
92- control
93- . querySelector ( '.js-accordion-item__toggle_all' )
94- . addEventListener ( 'click' , ( e ) => {
95- // Determine which control was activated. `action` will re turn a
96- // boolean. `true` if the expand control was clicked, otherwise false.
97- const action = e . target . classList . contains (
98- 'js-accordion__toggle-all--expand' ,
99- ) ;
112+ const accordionRoot = control . closest ( '.accordion' ) ;
113+ const allItems = accordionRoot . querySelectorAll ( '.js-accordion-item' ) ;
114+ const toggleAllButton = control . querySelector (
115+ '.js-accordion-item__toggle_all' ,
116+ ) ;
117+
118+ toggleAllButton . addEventListener ( 'click' , ( e ) => {
119+ const action = e . target . classList . contains (
120+ 'js-accordion__toggle-all--expand' ,
121+ ) ;
100122
101- // Iterate over
102- allItems . forEach ( ( item ) => {
103- const button = item . querySelector ( itemToggle ) ;
104- const content = item . querySelector ( itemContent ) ;
105-
106- if ( action === false ) {
107- collapse ( item , button , content ) ;
108- } else {
109- expand ( item , button , content ) ;
110- }
111- } ) ;
123+ allItems . forEach ( ( item ) => {
124+ const button = item . querySelector ( itemToggle ) ;
125+ const content = item . querySelector ( itemContent ) ;
126+ if ( action ) {
127+ expand ( item , button , content ) ;
128+ } else {
129+ collapse ( item , button , content ) ;
130+ }
112131 } ) ;
132+
133+ // Refresh aria-disabled states after bulk toggle
134+ updateControlStates ( accordionRoot ) ;
135+ } ) ;
136+
137+ // Initialize on page load
138+ updateControlStates ( accordionRoot ) ;
113139 } ) ;
114140 } ,
115141} ;
0 commit comments