188 lines
7.2 KiB
JavaScript
188 lines
7.2 KiB
JavaScript
/**
|
|
* Add Toggle Buttons to elements
|
|
*/
|
|
|
|
let toggleChevron = `
|
|
<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">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
<polyline points="9 6 15 12 9 18" />
|
|
</svg>`;
|
|
|
|
var initToggleItems = () => {
|
|
var itemsToToggle = document.querySelectorAll(togglebuttonSelector);
|
|
console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`)
|
|
// Add the button to each admonition and hook up a callback to toggle visibility
|
|
itemsToToggle.forEach((item, index) => {
|
|
if (item.classList.contains("admonition")) {
|
|
// If it's an admonition block, then we'll add a button inside
|
|
// Generate unique IDs for this item
|
|
var toggleID = `toggle-${index}`;
|
|
var buttonID = `button-${toggleID}`;
|
|
|
|
item.setAttribute('id', toggleID);
|
|
if (!item.classList.contains("toggle")){
|
|
item.classList.add("toggle");
|
|
}
|
|
// This is the button that will be added to each item to trigger the toggle
|
|
var collapseButton = `
|
|
<button type="button" id="${buttonID}" class="toggle-button" data-target="${toggleID}" data-button="${buttonID}" data-toggle-hint="${toggleHintShow}" aria-label="Toggle hidden content">
|
|
${toggleChevron}
|
|
</button>`;
|
|
|
|
title = item.querySelector(".admonition-title")
|
|
title.insertAdjacentHTML("beforeend", collapseButton);
|
|
thisButton = document.getElementById(buttonID);
|
|
|
|
// Add click handlers for the button + admonition title (if admonition)
|
|
admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`)
|
|
if (admonitionTitle) {
|
|
// If an admonition, then make the whole title block clickable
|
|
admonitionTitle.addEventListener('click', toggleClickHandler);
|
|
admonitionTitle.dataset.target = toggleID
|
|
admonitionTitle.dataset.button = buttonID
|
|
} else {
|
|
// If not an admonition then we'll listen for the button click
|
|
thisButton.addEventListener('click', toggleClickHandler);
|
|
}
|
|
|
|
// Now hide the item for this toggle button unless explicitly noted to show
|
|
if (!item.classList.contains("toggle-shown")) {
|
|
toggleHidden(thisButton);
|
|
}
|
|
} else {
|
|
// If not an admonition, wrap the block in a <details> block
|
|
// Define the structure of the details block and insert it as a sibling
|
|
var detailsBlock = `
|
|
<details class="toggle-details">
|
|
<summary class="toggle-details__summary">
|
|
${toggleChevron}
|
|
<span class="toggle-details__summary-text">${toggleHintShow}</span>
|
|
</summary>
|
|
</details>`;
|
|
item.insertAdjacentHTML("beforebegin", detailsBlock);
|
|
|
|
// Now move the toggle-able content inside of the details block
|
|
details = item.previousElementSibling
|
|
details.appendChild(item)
|
|
item.classList.add("toggle-details__container")
|
|
|
|
// Set up a click trigger to change the text as needed
|
|
details.addEventListener('click', (click) => {
|
|
let parent = click.target.parentElement;
|
|
if (parent.tagName.toLowerCase() == "details") {
|
|
summary = parent.querySelector("summary");
|
|
details = parent;
|
|
} else {
|
|
summary = parent;
|
|
details = parent.parentElement;
|
|
}
|
|
// Update the inner text for the proper hint
|
|
if (details.open) {
|
|
summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow;
|
|
} else {
|
|
summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide;
|
|
}
|
|
|
|
});
|
|
|
|
// If we have a toggle-shown class, open details block should be open
|
|
if (item.classList.contains("toggle-shown")) {
|
|
details.click();
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
// This should simply add / remove the collapsed class and change the button text
|
|
var toggleHidden = (button) => {
|
|
target = button.dataset['target']
|
|
var itemToToggle = document.getElementById(target);
|
|
if (itemToToggle.classList.contains("toggle-hidden")) {
|
|
itemToToggle.classList.remove("toggle-hidden");
|
|
button.classList.remove("toggle-button-hidden");
|
|
} else {
|
|
itemToToggle.classList.add("toggle-hidden");
|
|
button.classList.add("toggle-button-hidden");
|
|
}
|
|
}
|
|
|
|
var toggleClickHandler = (click) => {
|
|
// Be cause the admonition title is clickable and extends to the whole admonition
|
|
// We only look for a click event on this title to trigger the toggle.
|
|
|
|
if (click.target.classList.contains("admonition-title")) {
|
|
button = click.target.querySelector(".toggle-button");
|
|
} else if (click.target.classList.contains("tb-icon")) {
|
|
// We've clicked the icon and need to search up one parent for the button
|
|
button = click.target.parentElement;
|
|
} else if (click.target.tagName == "polyline") {
|
|
// We've clicked the SVG elements inside the button, need to up 2 layers
|
|
button = click.target.parentElement.parentElement;
|
|
} else if (click.target.classList.contains("toggle-button")) {
|
|
// We've clicked the button itself and so don't need to do anything
|
|
button = click.target;
|
|
} else {
|
|
console.log(`[togglebutton]: Couldn't find button for ${click.target}`)
|
|
}
|
|
target = document.getElementById(button.dataset['button']);
|
|
toggleHidden(target);
|
|
}
|
|
|
|
// If we want to blanket-add toggle classes to certain cells
|
|
var addToggleToSelector = () => {
|
|
const selector = "";
|
|
if (selector.length > 0) {
|
|
document.querySelectorAll(selector).forEach((item) => {
|
|
item.classList.add("toggle");
|
|
})
|
|
}
|
|
}
|
|
|
|
// Helper function to run when the DOM is finished
|
|
const sphinxToggleRunWhenDOMLoaded = cb => {
|
|
if (document.readyState != 'loading') {
|
|
cb()
|
|
} else if (document.addEventListener) {
|
|
document.addEventListener('DOMContentLoaded', cb)
|
|
} else {
|
|
document.attachEvent('onreadystatechange', function() {
|
|
if (document.readyState == 'complete') cb()
|
|
})
|
|
}
|
|
}
|
|
sphinxToggleRunWhenDOMLoaded(addToggleToSelector)
|
|
sphinxToggleRunWhenDOMLoaded(initToggleItems)
|
|
|
|
/** Toggle details blocks to be open when printing */
|
|
if (toggleOpenOnPrint == "true") {
|
|
window.addEventListener("beforeprint", () => {
|
|
// Open the details
|
|
document.querySelectorAll("details.toggle-details").forEach((el) => {
|
|
el.dataset["togglestatus"] = el.open;
|
|
el.open = true;
|
|
});
|
|
|
|
// Open the admonitions
|
|
document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => {
|
|
console.log(el);
|
|
el.querySelector("button.toggle-button").click();
|
|
el.dataset["toggle_after_print"] = "true";
|
|
});
|
|
});
|
|
window.addEventListener("afterprint", () => {
|
|
// Re-close the details that were closed
|
|
document.querySelectorAll("details.toggle-details").forEach((el) => {
|
|
el.open = el.dataset["togglestatus"] == "true";
|
|
delete el.dataset["togglestatus"];
|
|
});
|
|
|
|
// Re-close the admonition toggle buttons
|
|
document.querySelectorAll(".admonition.toggle").forEach((el) => {
|
|
if (el.dataset["toggle_after_print"] == "true") {
|
|
el.querySelector("button.toggle-button").click();
|
|
delete el.dataset["toggle_after_print"];
|
|
}
|
|
});
|
|
});
|
|
}
|