1/** 2 * Add Toggle Buttons to elements 3 */ 4 5let toggleChevron = ` 6<svg xmlns="http://www.w3.org/2000/svg" class="tb-icon toggle-chevron-right" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round"> 7<path stroke="none" d="M0 0h24v24H0z" fill="none"/> 8<polyline points="9 6 15 12 9 18" /> 9</svg>`; 10 11var initToggleItems = () => { 12 var itemsToToggle = document.querySelectorAll(togglebuttonSelector); 13 console.log( 14 `[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items` 15 ); 16 // Add the button to each admonition and hook up a callback to toggle visibility 17 itemsToToggle.forEach((item, index) => { 18 if (item.classList.contains("admonition")) { 19 // If it's an admonition block, then we'll add a button inside 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 } 27 var buttonID = `button-${toggleID}`; 28 29 item.setAttribute("id", toggleID); 30 if (!item.classList.contains("toggle")) { 31 item.classList.add("toggle"); 32 } 33 // This is the button that will be added to each item to trigger the toggle 34 var collapseButton = ` 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 > 44 ${toggleChevron} 45 </button>`; 46 47 title = item.querySelector(".admonition-title"); 48 title.insertAdjacentHTML("beforeend", collapseButton); 49 thisButton = document.getElementById(buttonID); 50 51 // Add click handlers for the button + admonition title (if admonition) 52 admonitionTitle = document.querySelector( 53 `#` + CSS.escape(toggleID) + ` > .admonition-title` 54 ); 55 if (admonitionTitle) { 56 // If an admonition, then make the whole title block clickable 57 admonitionTitle.addEventListener("click", toggleClickHandler); 58 admonitionTitle.dataset.target = toggleID; 59 admonitionTitle.dataset.button = buttonID; 60 } else { 61 // If not an admonition then we'll listen for the button click 62 thisButton.addEventListener("click", toggleClickHandler); 63 } 64 65 // Now hide the item for this toggle button unless explicitly noted to show 66 if (!item.classList.contains("toggle-shown")) { 67 toggleHidden(thisButton); 68 } 69 } else { 70 // If not an admonition, wrap the block in a <details> block 71 // Define the structure of the details block and insert it as a sibling 72 var detailsBlock = ` 73 <details class="toggle-details"> 74 <summary class="toggle-details__summary"> 75 ${toggleChevron} 76 <span class="toggle-details__summary-text">${toggleHintShow}</span> 77 </summary> 78 </details>`; 79 item.insertAdjacentHTML("beforebegin", detailsBlock); 80 81 // Now move the toggle-able content inside of the details block 82 details = item.previousElementSibling; 83 details.appendChild(item); 84 item.classList.add("toggle-details__container"); 85 86 // Set up a click trigger to change the text as needed 87 details.addEventListener("click", (click) => { 88 let parent = click.target.parentElement; 89 if (parent.tagName.toLowerCase() == "details") { 90 summary = parent.querySelector("summary"); 91 details = parent; 92 } else { 93 summary = parent; 94 details = parent.parentElement; 95 } 96 // Update the inner text for the proper hint 97 if (details.open) { 98 summary.querySelector("span.toggle-details__summary-text").innerText = 99 toggleHintShow; 100 } else { 101 summary.querySelector("span.toggle-details__summary-text").innerText = 102 toggleHintHide; 103 } 104 }); 105 106 // If we have a toggle-shown class, open details block should be open 107 if (item.classList.contains("toggle-shown")) { 108 details.click(); 109 } 110 } 111 }); 112}; 113 114// This should simply add / remove the collapsed class and change the button text 115var toggleHidden = (button) => { 116 target = button.dataset["target"]; 117 var itemToToggle = document.getElementById(target); 118 if (itemToToggle.classList.contains("toggle-hidden")) { 119 itemToToggle.classList.remove("toggle-hidden"); 120 button.classList.remove("toggle-button-hidden"); 121 button.dataset.toggleHint = toggleHintHide; 122 button.setAttribute("aria-expanded", true); 123 } else { 124 itemToToggle.classList.add("toggle-hidden"); 125 button.classList.add("toggle-button-hidden"); 126 button.dataset.toggleHint = toggleHintShow; 127 button.setAttribute("aria-expanded", false); 128 } 129}; 130 131// Function to synchronize the data-toggle-hint with the current state 132var 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 146var syncAllToggleHints = () => { 147 document.querySelectorAll('.toggle-button').forEach(syncToggleHint); 148}; 149 150var toggleClickHandler = (click) => { 151 // Be cause the admonition title is clickable and extends to the whole admonition 152 // We only look for a click event on this title to trigger the toggle. 153 154 if (click.target.classList.contains("admonition-title")) { 155 button = click.target.querySelector(".toggle-button"); 156 } else if (click.target.classList.contains("tb-icon")) { 157 // We've clicked the icon and need to search up one parent for the button 158 button = click.target.parentElement; 159 } else if (click.target.tagName == "polyline") { 160 // We've clicked the SVG elements inside the button, need to up 2 layers 161 button = click.target.parentElement.parentElement; 162 } else if (click.target.classList.contains("toggle-button")) { 163 // We've clicked the button itself and so don't need to do anything 164 button = click.target; 165 } else { 166 console.log(`[togglebutton]: Couldn't find button for ${click.target}`); 167 } 168 target = document.getElementById(button.dataset["button"]); 169 toggleHidden(target); 170}; 171 172// If we want to blanket-add toggle classes to certain cells 173var addToggleToSelector = () => { 174 const selector = ""; 175 if (selector.length > 0) { 176 document.querySelectorAll(selector).forEach((item) => { 177 item.classList.add("toggle"); 178 }); 179 } 180}; 181 182// Helper function to run when the DOM is finished 183const sphinxToggleRunWhenDOMLoaded = (cb) => { 184 if (document.readyState != "loading") { 185 cb(); 186 } else if (document.addEventListener) { 187 document.addEventListener("DOMContentLoaded", cb); 188 } else { 189 document.attachEvent("onreadystatechange", function () { 190 if (document.readyState == "complete") cb(); 191 }); 192 } 193}; 194sphinxToggleRunWhenDOMLoaded(addToggleToSelector); 195sphinxToggleRunWhenDOMLoaded(initToggleItems); 196
197// Set up MutationObserver to watch for external changes to toggle states 198sphinxToggleRunWhenDOMLoaded(() => { 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}); 223 224/** Toggle details blocks to be open when printing */ 225if (toggleOpenOnPrint == "true") { 226 window.addEventListener("beforeprint", () => { 227 // Open the details 228 document.querySelectorAll("details.toggle-details").forEach((el) => { 229 el.dataset["togglestatus"] = el.open; 230 el.open = true; 231 }); 232 233 // Open the admonitions 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 }); 241 }); 242 window.addEventListener("afterprint", () => { 243 // Re-close the details that were closed 244 document.querySelectorAll("details.toggle-details").forEach((el) => { 245 el.open = el.dataset["togglestatus"] == "true"; 246 delete el.dataset["togglestatus"]; 247 }); 248 249 // Re-close the admonition toggle buttons 250 document.querySelectorAll(".admonition.toggle").forEach((el) => { 251 if (el.dataset["toggle_after_print"] == "true") { 252 el.querySelector("button.toggle-button").click(); 253 delete el.dataset["toggle_after_print"]; 254 } 255 }); 256 }); 257}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.