@@ -10,39 +10,56 @@ let toggleChevron = `
1010
1111var initToggleItems = ( ) => {
1212 var itemsToToggle = document . querySelectorAll ( togglebuttonSelector ) ;
13- console . log ( `[togglebutton]: Adding toggle buttons to ${ itemsToToggle . length } items` )
13+ console . log (
14+ `[togglebutton]: Adding toggle buttons to ${ itemsToToggle . length } items`
15+ ) ;
1416 // Add the button to each admonition and hook up a callback to toggle visibility
1517 itemsToToggle . forEach ( ( item , index ) => {
1618 if ( item . classList . contains ( "admonition" ) ) {
1719 // If it's an admonition block, then we'll add a button inside
18- // Generate unique IDs for this item
19- var toggleID = `toggle-${ index } ` ;
20+ // Generate unique IDs for this item,
21+ // IF AND ONLY IF THE ITEM DOESN'T ALREADY HAVE AN ID
22+ if ( ! item . id ) {
23+ var toggleID = `toggle-${ index } ` ;
24+ } else {
25+ var toggleID = item . id ;
26+ }
2027 var buttonID = `button-${ toggleID } ` ;
2128
22- item . setAttribute ( 'id' , toggleID ) ;
23- if ( ! item . classList . contains ( "toggle" ) ) {
29+ item . setAttribute ( "id" , toggleID ) ;
30+ if ( ! item . classList . contains ( "toggle" ) ) {
2431 item . classList . add ( "toggle" ) ;
2532 }
2633 // This is the button that will be added to each item to trigger the toggle
2734 var collapseButton = `
28- <button type="button" id="${ buttonID } " class="toggle-button" data-target="${ toggleID } " data-button="${ buttonID } " data-toggle-hint="${ toggleHintShow } " aria-label="Toggle hidden content">
35+ <button type="button"
36+ id="${ buttonID } "
37+ class="toggle-button"
38+ data-target="${ toggleID } "
39+ data-button="${ buttonID } "
40+ data-toggle-hint="${ toggleHintShow } "
41+ aria-label="Toggle hidden content"
42+ aria-expanded="false"
43+ >
2944 ${ toggleChevron }
3045 </button>` ;
3146
32- title = item . querySelector ( ".admonition-title" )
47+ title = item . querySelector ( ".admonition-title" ) ;
3348 title . insertAdjacentHTML ( "beforeend" , collapseButton ) ;
3449 thisButton = document . getElementById ( buttonID ) ;
3550
3651 // Add click handlers for the button + admonition title (if admonition)
37- admonitionTitle = document . querySelector ( `#${ toggleID } > .admonition-title` )
52+ admonitionTitle = document . querySelector (
53+ `#${ toggleID } > .admonition-title`
54+ ) ;
3855 if ( admonitionTitle ) {
3956 // If an admonition, then make the whole title block clickable
40- admonitionTitle . addEventListener ( ' click' , toggleClickHandler ) ;
41- admonitionTitle . dataset . target = toggleID
42- admonitionTitle . dataset . button = buttonID
57+ admonitionTitle . addEventListener ( " click" , toggleClickHandler ) ;
58+ admonitionTitle . dataset . target = toggleID ;
59+ admonitionTitle . dataset . button = buttonID ;
4360 } else {
4461 // If not an admonition then we'll listen for the button click
45- thisButton . addEventListener ( ' click' , toggleClickHandler ) ;
62+ thisButton . addEventListener ( " click" , toggleClickHandler ) ;
4663 }
4764
4865 // Now hide the item for this toggle button unless explicitly noted to show
@@ -62,12 +79,12 @@ var initToggleItems = () => {
6279 item . insertAdjacentHTML ( "beforebegin" , detailsBlock ) ;
6380
6481 // Now move the toggle-able content inside of the details block
65- details = item . previousElementSibling
66- details . appendChild ( item )
67- item . classList . add ( "toggle-details__container" )
82+ details = item . previousElementSibling ;
83+ details . appendChild ( item ) ;
84+ item . classList . add ( "toggle-details__container" ) ;
6885
6986 // Set up a click trigger to change the text as needed
70- details . addEventListener ( ' click' , ( click ) => {
87+ details . addEventListener ( " click" , ( click ) => {
7188 let parent = click . target . parentElement ;
7289 if ( parent . tagName . toLowerCase ( ) == "details" ) {
7390 summary = parent . querySelector ( "summary" ) ;
@@ -78,33 +95,57 @@ var initToggleItems = () => {
7895 }
7996 // Update the inner text for the proper hint
8097 if ( details . open ) {
81- summary . querySelector ( "span.toggle-details__summary-text" ) . innerText = toggleHintShow ;
98+ summary . querySelector ( "span.toggle-details__summary-text" ) . innerText =
99+ toggleHintShow ;
82100 } else {
83- summary . querySelector ( "span.toggle-details__summary-text" ) . innerText = toggleHintHide ;
101+ summary . querySelector ( "span.toggle-details__summary-text" ) . innerText =
102+ toggleHintHide ;
84103 }
85-
86104 } ) ;
87105
88106 // If we have a toggle-shown class, open details block should be open
89107 if ( item . classList . contains ( "toggle-shown" ) ) {
90108 details . click ( ) ;
91109 }
92110 }
93- } )
111+ } ) ;
94112} ;
95113
96114// This should simply add / remove the collapsed class and change the button text
97115var toggleHidden = ( button ) => {
98- target = button . dataset [ ' target' ]
116+ target = button . dataset [ " target" ] ;
99117 var itemToToggle = document . getElementById ( target ) ;
100118 if ( itemToToggle . classList . contains ( "toggle-hidden" ) ) {
101119 itemToToggle . classList . remove ( "toggle-hidden" ) ;
102120 button . classList . remove ( "toggle-button-hidden" ) ;
121+ button . dataset . toggleHint = toggleHintHide ;
122+ button . setAttribute ( "aria-expanded" , true ) ;
103123 } else {
104124 itemToToggle . classList . add ( "toggle-hidden" ) ;
105125 button . classList . add ( "toggle-button-hidden" ) ;
126+ button . dataset . toggleHint = toggleHintShow ;
127+ button . setAttribute ( "aria-expanded" , false ) ;
106128 }
107- }
129+ } ;
130+
131+ // Function to synchronize the data-toggle-hint with the current state
132+ var syncToggleHint = ( button ) => {
133+ const target = button . dataset [ "target" ] ;
134+ const itemToToggle = document . getElementById ( target ) ;
135+
136+ if ( itemToToggle && itemToToggle . classList . contains ( "toggle-hidden" ) ) {
137+ button . dataset . toggleHint = toggleHintShow ;
138+ button . setAttribute ( "aria-expanded" , false ) ;
139+ } else if ( itemToToggle ) {
140+ button . dataset . toggleHint = toggleHintHide ;
141+ button . setAttribute ( "aria-expanded" , true ) ;
142+ }
143+ } ;
144+
145+ // Function to sync all toggle buttons - can be called by external extensions
146+ var syncAllToggleHints = ( ) => {
147+ document . querySelectorAll ( '.toggle-button' ) . forEach ( syncToggleHint ) ;
148+ } ;
108149
109150var toggleClickHandler = ( click ) => {
110151 // Be cause the admonition title is clickable and extends to the whole admonition
@@ -122,36 +163,63 @@ var toggleClickHandler = (click) => {
122163 // We've clicked the button itself and so don't need to do anything
123164 button = click . target ;
124165 } else {
125- console . log ( `[togglebutton]: Couldn't find button for ${ click . target } ` )
166+ console . log ( `[togglebutton]: Couldn't find button for ${ click . target } ` ) ;
126167 }
127- target = document . getElementById ( button . dataset [ ' button' ] ) ;
168+ target = document . getElementById ( button . dataset [ " button" ] ) ;
128169 toggleHidden ( target ) ;
129- }
170+ } ;
130171
131172// If we want to blanket-add toggle classes to certain cells
132173var addToggleToSelector = ( ) => {
133174 const selector = "" ;
134175 if ( selector . length > 0 ) {
135176 document . querySelectorAll ( selector ) . forEach ( ( item ) => {
136177 item . classList . add ( "toggle" ) ;
137- } )
178+ } ) ;
138179 }
139- }
180+ } ;
140181
141182// Helper function to run when the DOM is finished
142- const sphinxToggleRunWhenDOMLoaded = cb => {
143- if ( document . readyState != ' loading' ) {
144- cb ( )
183+ const sphinxToggleRunWhenDOMLoaded = ( cb ) => {
184+ if ( document . readyState != " loading" ) {
185+ cb ( ) ;
145186 } else if ( document . addEventListener ) {
146- document . addEventListener ( ' DOMContentLoaded' , cb )
187+ document . addEventListener ( " DOMContentLoaded" , cb ) ;
147188 } else {
148- document . attachEvent ( ' onreadystatechange' , function ( ) {
149- if ( document . readyState == ' complete' ) cb ( )
150- } )
189+ document . attachEvent ( " onreadystatechange" , function ( ) {
190+ if ( document . readyState == " complete" ) cb ( ) ;
191+ } ) ;
151192 }
152- }
153- sphinxToggleRunWhenDOMLoaded ( addToggleToSelector )
154- sphinxToggleRunWhenDOMLoaded ( initToggleItems )
193+ } ;
194+ sphinxToggleRunWhenDOMLoaded ( addToggleToSelector ) ;
195+ sphinxToggleRunWhenDOMLoaded ( initToggleItems ) ;
196+
197+ // Set up MutationObserver to watch for external changes to toggle states
198+ sphinxToggleRunWhenDOMLoaded ( ( ) => {
199+ const observer = new MutationObserver ( ( mutations ) => {
200+ mutations . forEach ( ( mutation ) => {
201+ if ( mutation . type === 'attributes' && mutation . attributeName === 'class' ) {
202+ const target = mutation . target ;
203+ // Check if this is a toggle item that had its class changed
204+ if ( target . classList . contains ( 'toggle' ) ) {
205+ // Find the associated toggle button and sync its hint
206+ const button = target . querySelector ( '.toggle-button' ) ;
207+ if ( button ) {
208+ syncToggleHint ( button ) ;
209+ }
210+ }
211+ }
212+ } ) ;
213+ } ) ;
214+
215+ // Start observing class changes on all toggle elements
216+ document . querySelectorAll ( '.toggle' ) . forEach ( ( toggleElement ) => {
217+ observer . observe ( toggleElement , {
218+ attributes : true ,
219+ attributeFilter : [ 'class' ]
220+ } ) ;
221+ } ) ;
222+ } ) ;
155223
156224/** Toggle details blocks to be open when printing */
157225if ( toggleOpenOnPrint == "true" ) {
@@ -161,21 +229,23 @@ if (toggleOpenOnPrint == "true") {
161229 el . dataset [ "togglestatus" ] = el . open ;
162230 el . open = true ;
163231 } ) ;
164-
232+
165233 // Open the admonitions
166- document . querySelectorAll ( ".admonition.toggle.toggle-hidden" ) . forEach ( ( el ) => {
167- console . log ( el ) ;
168- el . querySelector ( "button.toggle-button" ) . click ( ) ;
169- el . dataset [ "toggle_after_print" ] = "true" ;
170- } ) ;
234+ document
235+ . querySelectorAll ( ".admonition.toggle.toggle-hidden" )
236+ . forEach ( ( el ) => {
237+ console . log ( el ) ;
238+ el . querySelector ( "button.toggle-button" ) . click ( ) ;
239+ el . dataset [ "toggle_after_print" ] = "true" ;
240+ } ) ;
171241 } ) ;
172242 window . addEventListener ( "afterprint" , ( ) => {
173243 // Re-close the details that were closed
174244 document . querySelectorAll ( "details.toggle-details" ) . forEach ( ( el ) => {
175245 el . open = el . dataset [ "togglestatus" ] == "true" ;
176246 delete el . dataset [ "togglestatus" ] ;
177247 } ) ;
178-
248+
179249 // Re-close the admonition toggle buttons
180250 document . querySelectorAll ( ".admonition.toggle" ) . forEach ( ( el ) => {
181251 if ( el . dataset [ "toggle_after_print" ] == "true" ) {
0 commit comments