From 5c9b9331f707fdc6e78c215fa87f0ce8c0f69231 Mon Sep 17 00:00:00 2001 From: abhira0 <82208485+abhira0@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:20:15 +0530 Subject: [PATCH 1/4] support for custom hint text - on python side --- sphinx_togglebutton/__init__.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/sphinx_togglebutton/__init__.py b/sphinx_togglebutton/__init__.py index 0792641..fada9ca 100644 --- a/sphinx_togglebutton/__init__.py +++ b/sphinx_togglebutton/__init__.py @@ -2,6 +2,7 @@ import os from docutils.parsers.rst import Directive, directives from docutils import nodes +import base64 __version__ = "0.3.2" @@ -31,18 +32,33 @@ def insert_custom_selection_config(app): class Toggle(Directive): """Hide a block of markup text by wrapping it in a container.""" - optional_arguments = 1 + optional_arguments = 3 final_argument_whitespace = True has_content = True - option_spec = {"id": directives.unchanged, "show": directives.flag} - + option_spec = { + "id": directives.unchanged, + "show": directives.flag, + "hint": directives.unchanged, + "hint_hide": directives.unchanged, + } + def run(self): self.assert_has_content() classes = ["toggle"] if "show" in self.options: classes.append("toggle-shown") + # Retrieve global hints if specific hints are not provided + env = self.state.document.settings.env + hint = self.options.get('hint', env.config.togglebutton_hint) + hint_hide = self.options.get('hint_hide', env.config.togglebutton_hint_hide) + + hint_encoded = base64.urlsafe_b64encode(hint.encode()).decode().replace('=', 'EQ') + classes.append(f"hint-show-{hint_encoded}") + hint_hide_encoded = base64.urlsafe_b64encode(hint_hide.encode()).decode().replace('=', 'EQ') + classes.append(f"hint-hide-{hint_hide_encoded}") + parent = nodes.container(classes=classes) self.state.nested_parse(self.content, self.content_offset, parent) return [parent] From d97d3ca804ff2b598e0420a1784e036fa4fada73 Mon Sep 17 00:00:00 2001 From: abhira0 <82208485+abhira0@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:20:59 +0530 Subject: [PATCH 2/4] support for custom hint text - on js side --- sphinx_togglebutton/_static/togglebutton.js | 27 ++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/sphinx_togglebutton/_static/togglebutton.js b/sphinx_togglebutton/_static/togglebutton.js index f0ee206..36962aa 100644 --- a/sphinx_togglebutton/_static/togglebutton.js +++ b/sphinx_togglebutton/_static/togglebutton.js @@ -13,6 +13,23 @@ var initToggleItems = () => { 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) => { + // Use custom hint and hint_hide if available + let customHintShow = toggleHintShow; + let customHintHide = toggleHintHide; + + const classes = item.className.split(/\s+/); + classes.forEach(cls => { + if (cls.startsWith("hint-show-")) { + const encoded = cls.substring(10).replace(/EQ/g, '='); + const decoded = atob(encoded.replace(/_/g, '/').replace(/-/g, '+')); + customHintShow = decoded; + } else if (cls.startsWith("hint-hide-")) { + const encoded = cls.substring(10).replace(/EQ/g, '='); + const decoded = atob(encoded.replace(/_/g, '/').replace(/-/g, '+')); + customHintHide = decoded; + } + }); + if (item.classList.contains("admonition")) { // If it's an admonition block, then we'll add a button inside // Generate unique IDs for this item @@ -25,7 +42,7 @@ var initToggleItems = () => { } // This is the button that will be added to each item to trigger the toggle var collapseButton = ` - `; @@ -56,7 +73,7 @@ var initToggleItems = () => {
${toggleChevron} - ${toggleHintShow} + ${customHintShow}
`; item.insertAdjacentHTML("beforebegin", detailsBlock); @@ -78,9 +95,9 @@ var initToggleItems = () => { } // Update the inner text for the proper hint if (details.open) { - summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + summary.querySelector("span.toggle-details__summary-text").innerText = customHintShow; } else { - summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + summary.querySelector("span.toggle-details__summary-text").innerText = customHintHide; } }); @@ -100,11 +117,9 @@ var toggleHidden = (button) => { if (itemToToggle.classList.contains("toggle-hidden")) { itemToToggle.classList.remove("toggle-hidden"); button.classList.remove("toggle-button-hidden"); - button.dataset.toggleHint = toggleHintHide; } else { itemToToggle.classList.add("toggle-hidden"); button.classList.add("toggle-button-hidden"); - button.dataset.toggleHint = toggleHintShow; } } From 4e375f3faffab67b96ac384082172c6f4b446e62 Mon Sep 17 00:00:00 2001 From: abhira0 <82208485+abhira0@users.noreply.github.com> Date: Sat, 16 Nov 2024 21:18:23 -0500 Subject: [PATCH 3/4] bugfix: :show: on ..toggle didnt use to work, but now it does --- sphinx_togglebutton/_static/togglebutton.js | 95 ++++++++++----------- 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/sphinx_togglebutton/_static/togglebutton.js b/sphinx_togglebutton/_static/togglebutton.js index f510d91..2f16319 100644 --- a/sphinx_togglebutton/_static/togglebutton.js +++ b/sphinx_togglebutton/_static/togglebutton.js @@ -10,9 +10,7 @@ let toggleChevron = ` var initToggleItems = () => { var itemsToToggle = document.querySelectorAll(togglebuttonSelector); - console.log( - `[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items` - ); + 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) => { // Use custom hint and hint_hide if available @@ -38,8 +36,8 @@ var initToggleItems = () => { var toggleID = `toggle-${index}`; var buttonID = `button-${toggleID}`; - item.setAttribute("id", toggleID); - if (!item.classList.contains("toggle")) { + 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 @@ -48,22 +46,20 @@ var initToggleItems = () => { ${toggleChevron} `; - title = item.querySelector(".admonition-title"); + 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` - ); + 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; + 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); + thisButton.addEventListener('click', toggleClickHandler); } // Now hide the item for this toggle button unless explicitly noted to show @@ -83,12 +79,12 @@ var initToggleItems = () => { 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"); + 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) => { + details.addEventListener('click', (click) => { let parent = click.target.parentElement; if (parent.tagName.toLowerCase() == "details") { summary = parent.querySelector("summary"); @@ -99,38 +95,37 @@ var initToggleItems = () => { } // Update the inner text for the proper hint if (details.open) { - summary.querySelector("span.toggle-details__summary-text").innerText = - toggleHintShow; + summary.querySelector("span.toggle-details__summary-text").innerText = customHintShow; } else { - summary.querySelector("span.toggle-details__summary-text").innerText = - toggleHintHide; + summary.querySelector("span.toggle-details__summary-text").innerText = customHintHide; } + }); // If we have a toggle-shown class, open details block should be open if (item.classList.contains("toggle-shown")) { - details.click(); + details.open = true; + let summary = details.querySelector("summary"); + summary.querySelector("span.toggle-details__summary-text").innerText = customHintHide; } } - }); + }) }; // This should simply add / remove the collapsed class and change the button text var toggleHidden = (button) => { - target = button.dataset["target"]; + 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"); button.dataset.toggleHint = toggleHintHide; - button.setAttribute("aria-expanded", true); } else { itemToToggle.classList.add("toggle-hidden"); button.classList.add("toggle-button-hidden"); button.dataset.toggleHint = toggleHintShow; - button.setAttribute("aria-expanded", false); } -}; +} var toggleClickHandler = (click) => { // Be cause the admonition title is clickable and extends to the whole admonition @@ -148,11 +143,11 @@ var toggleClickHandler = (click) => { // 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}`); + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) } - target = document.getElementById(button.dataset["button"]); + target = document.getElementById(button.dataset['button']); toggleHidden(target); -}; +} // If we want to blanket-add toggle classes to certain cells var addToggleToSelector = () => { @@ -160,24 +155,24 @@ var addToggleToSelector = () => { 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(); +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() } else if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", cb); + document.addEventListener('DOMContentLoaded', cb) } else { - document.attachEvent("onreadystatechange", function () { - if (document.readyState == "complete") cb(); - }); + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) } -}; -sphinxToggleRunWhenDOMLoaded(addToggleToSelector); -sphinxToggleRunWhenDOMLoaded(initToggleItems); +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) /** Toggle details blocks to be open when printing */ if (toggleOpenOnPrint == "true") { @@ -187,15 +182,13 @@ if (toggleOpenOnPrint == "true") { 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"; - }); + 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 @@ -203,7 +196,7 @@ if (toggleOpenOnPrint == "true") { 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") { From f766242a13de7c34d0315fb2678569479fd6261b Mon Sep 17 00:00:00 2001 From: abhira0 <82208485+abhira0@users.noreply.github.com> Date: Sat, 16 Nov 2024 21:19:31 -0500 Subject: [PATCH 4/4] prettier format togglebutton.js --- sphinx_togglebutton/_static/togglebutton.js | 112 +++++++++++--------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/sphinx_togglebutton/_static/togglebutton.js b/sphinx_togglebutton/_static/togglebutton.js index 2f16319..056add3 100644 --- a/sphinx_togglebutton/_static/togglebutton.js +++ b/sphinx_togglebutton/_static/togglebutton.js @@ -10,7 +10,9 @@ let toggleChevron = ` var initToggleItems = () => { var itemsToToggle = document.querySelectorAll(togglebuttonSelector); - console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + 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) => { // Use custom hint and hint_hide if available @@ -18,16 +20,16 @@ var initToggleItems = () => { let customHintHide = toggleHintHide; const classes = item.className.split(/\s+/); - classes.forEach(cls => { - if (cls.startsWith("hint-show-")) { - const encoded = cls.substring(10).replace(/EQ/g, '='); - const decoded = atob(encoded.replace(/_/g, '/').replace(/-/g, '+')); - customHintShow = decoded; - } else if (cls.startsWith("hint-hide-")) { - const encoded = cls.substring(10).replace(/EQ/g, '='); - const decoded = atob(encoded.replace(/_/g, '/').replace(/-/g, '+')); - customHintHide = decoded; - } + classes.forEach((cls) => { + if (cls.startsWith("hint-show-")) { + const encoded = cls.substring(10).replace(/EQ/g, "="); + const decoded = atob(encoded.replace(/_/g, "/").replace(/-/g, "+")); + customHintShow = decoded; + } else if (cls.startsWith("hint-hide-")) { + const encoded = cls.substring(10).replace(/EQ/g, "="); + const decoded = atob(encoded.replace(/_/g, "/").replace(/-/g, "+")); + customHintHide = decoded; + } }); if (item.classList.contains("admonition")) { @@ -36,8 +38,8 @@ var initToggleItems = () => { var toggleID = `toggle-${index}`; var buttonID = `button-${toggleID}`; - item.setAttribute('id', toggleID); - if (!item.classList.contains("toggle")){ + 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 @@ -46,20 +48,22 @@ var initToggleItems = () => { ${toggleChevron} `; - title = item.querySelector(".admonition-title") + 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`) + 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 + 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); + thisButton.addEventListener("click", toggleClickHandler); } // Now hide the item for this toggle button unless explicitly noted to show @@ -79,12 +83,12 @@ var initToggleItems = () => { 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") + 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) => { + details.addEventListener("click", (click) => { let parent = click.target.parentElement; if (parent.tagName.toLowerCase() == "details") { summary = parent.querySelector("summary"); @@ -95,26 +99,28 @@ var initToggleItems = () => { } // Update the inner text for the proper hint if (details.open) { - summary.querySelector("span.toggle-details__summary-text").innerText = customHintShow; + summary.querySelector("span.toggle-details__summary-text").innerText = + customHintShow; } else { - summary.querySelector("span.toggle-details__summary-text").innerText = customHintHide; + summary.querySelector("span.toggle-details__summary-text").innerText = + customHintHide; } - }); // If we have a toggle-shown class, open details block should be open if (item.classList.contains("toggle-shown")) { details.open = true; let summary = details.querySelector("summary"); - summary.querySelector("span.toggle-details__summary-text").innerText = customHintHide; + summary.querySelector("span.toggle-details__summary-text").innerText = + customHintHide; } } - }) + }); }; // This should simply add / remove the collapsed class and change the button text var toggleHidden = (button) => { - target = button.dataset['target'] + target = button.dataset["target"]; var itemToToggle = document.getElementById(target); if (itemToToggle.classList.contains("toggle-hidden")) { itemToToggle.classList.remove("toggle-hidden"); @@ -125,7 +131,7 @@ var toggleHidden = (button) => { button.classList.add("toggle-button-hidden"); button.dataset.toggleHint = toggleHintShow; } -} +}; var toggleClickHandler = (click) => { // Be cause the admonition title is clickable and extends to the whole admonition @@ -143,11 +149,11 @@ var toggleClickHandler = (click) => { // 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}`) + console.log(`[togglebutton]: Couldn't find button for ${click.target}`); } - target = document.getElementById(button.dataset['button']); + target = document.getElementById(button.dataset["button"]); toggleHidden(target); -} +}; // If we want to blanket-add toggle classes to certain cells var addToggleToSelector = () => { @@ -155,24 +161,24 @@ var addToggleToSelector = () => { 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() +const sphinxToggleRunWhenDOMLoaded = (cb) => { + if (document.readyState != "loading") { + cb(); } else if (document.addEventListener) { - document.addEventListener('DOMContentLoaded', cb) + document.addEventListener("DOMContentLoaded", cb); } else { - document.attachEvent('onreadystatechange', function() { - if (document.readyState == 'complete') cb() - }) + document.attachEvent("onreadystatechange", function () { + if (document.readyState == "complete") cb(); + }); } -} -sphinxToggleRunWhenDOMLoaded(addToggleToSelector) -sphinxToggleRunWhenDOMLoaded(initToggleItems) +}; +sphinxToggleRunWhenDOMLoaded(addToggleToSelector); +sphinxToggleRunWhenDOMLoaded(initToggleItems); /** Toggle details blocks to be open when printing */ if (toggleOpenOnPrint == "true") { @@ -182,13 +188,15 @@ if (toggleOpenOnPrint == "true") { 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"; - }); + 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 @@ -196,7 +204,7 @@ if (toggleOpenOnPrint == "true") { 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") {