From 706f0d444271575cdbd36f7ba9355d48da1c3139 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Fri, 11 Nov 2022 15:22:01 +0000 Subject: [PATCH 1/9] Use double quotation marks in ``__init__.py`` --- python_docs_theme/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python_docs_theme/__init__.py b/python_docs_theme/__init__.py index bbe1352..68bb9e3 100644 --- a/python_docs_theme/__init__.py +++ b/python_docs_theme/__init__.py @@ -52,12 +52,11 @@ def _html_page_context( def setup(app): current_dir = os.path.abspath(os.path.dirname(__file__)) - app.add_html_theme( - 'python_docs_theme', current_dir) + app.add_html_theme("python_docs_theme", current_dir) app.connect("html-page-context", _html_page_context) return { - 'parallel_read_safe': True, - 'parallel_write_safe': True, + "parallel_read_safe": True, + "parallel_write_safe": True, } From 458d6cd9c452fc795ecdf739f662685c6bb65f05 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:12:57 +0100 Subject: [PATCH 2/9] Drop semicolons in ``menu.js`` --- python_docs_theme/static/menu.js | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/python_docs_theme/static/menu.js b/python_docs_theme/static/menu.js index b2eabb3..5e99f7f 100644 --- a/python_docs_theme/static/menu.js +++ b/python_docs_theme/static/menu.js @@ -1,55 +1,55 @@ document.addEventListener('DOMContentLoaded', function () { // Make tables responsive by wrapping them in a div and making them scrollable - const tables = document.querySelectorAll('table.docutils'); + const tables = document.querySelectorAll('table.docutils') tables.forEach(function(table){ table.outerHTML = '
' + table.outerHTML + '
' - }); + }) - const togglerInput = document.querySelector('.toggler__input'); - const togglerLabel = document.querySelector('.toggler__label'); - const sideMenu = document.querySelector('.menu-wrapper'); + const togglerInput = document.querySelector('.toggler__input') + const togglerLabel = document.querySelector('.toggler__label') + const sideMenu = document.querySelector('.menu-wrapper') const menuItems = document.querySelectorAll('.menu') - const doc = document.querySelector('.document'); - const body = document.querySelector('body'); + const doc = document.querySelector('.document') + const body = document.querySelector('body') function closeMenu() { - togglerInput.checked = false; - sideMenu.setAttribute("aria-expanded", 'false'); - sideMenu.setAttribute('aria-hidden', 'true'); - togglerLabel.setAttribute('aria-pressed', 'false'); - body.style.overflow = 'visible'; + togglerInput.checked = false + sideMenu.setAttribute("aria-expanded", 'false') + sideMenu.setAttribute('aria-hidden', 'true') + togglerLabel.setAttribute('aria-pressed', 'false') + body.style.overflow = 'visible' } function openMenu() { - togglerInput.checked = true; - sideMenu.setAttribute("aria-expanded", 'true'); - sideMenu.setAttribute('aria-hidden', 'false'); - togglerLabel.setAttribute('aria-pressed', 'true'); - body.style.overflow = 'hidden'; + togglerInput.checked = true + sideMenu.setAttribute("aria-expanded", 'true') + sideMenu.setAttribute('aria-hidden', 'false') + togglerLabel.setAttribute('aria-pressed', 'true') + body.style.overflow = 'hidden' } // Close menu when link on the sideMenu is clicked sideMenu.addEventListener('click', function (event) { - let target = event.target; - if (target.tagName.toLowerCase() !== 'a') return; - closeMenu(); + let target = event.target + if (target.tagName.toLowerCase() !== 'a') return + closeMenu() }) // Add accessibility data when sideMenu is opened/closed togglerInput.addEventListener('change', function (e) { - togglerInput.checked ? openMenu() : closeMenu(); - }); + togglerInput.checked ? openMenu() : closeMenu() + }) // Make sideMenu links tabbable only when visible for(let menuItem of menuItems) { if(togglerInput.checked) { - menuItem.setAttribute('tabindex', '0'); + menuItem.setAttribute('tabindex', '0') } else { - menuItem.setAttribute('tabindex', '-1'); + menuItem.setAttribute('tabindex', '-1') } } // Close sideMenu when document body is clicked doc.addEventListener('click', function () { if (togglerInput.checked) { - closeMenu(); + closeMenu() } }) }) \ No newline at end of file From 0986415d9c9b2d4c2c4d6e66f59e86eb755eec25 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:13:21 +0100 Subject: [PATCH 3/9] Use braces for if-statements in ``menu.js`` --- python_docs_theme/static/menu.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python_docs_theme/static/menu.js b/python_docs_theme/static/menu.js index 5e99f7f..6a7bc33 100644 --- a/python_docs_theme/static/menu.js +++ b/python_docs_theme/static/menu.js @@ -31,7 +31,9 @@ document.addEventListener('DOMContentLoaded', function () { // Close menu when link on the sideMenu is clicked sideMenu.addEventListener('click', function (event) { let target = event.target - if (target.tagName.toLowerCase() !== 'a') return + if (target.tagName.toLowerCase() !== 'a') { + return + } closeMenu() }) // Add accessibility data when sideMenu is opened/closed From b0b8e7018bb093bae11ca0c6d5a34d314cba0c74 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:21:26 +0100 Subject: [PATCH 4/9] Use double quotation marks in ``menu.js`` --- python_docs_theme/static/menu.js | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/python_docs_theme/static/menu.js b/python_docs_theme/static/menu.js index 6a7bc33..8c2026e 100644 --- a/python_docs_theme/static/menu.js +++ b/python_docs_theme/static/menu.js @@ -1,55 +1,55 @@ -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { // Make tables responsive by wrapping them in a div and making them scrollable - const tables = document.querySelectorAll('table.docutils') + const tables = document.querySelectorAll("table.docutils") tables.forEach(function(table){ - table.outerHTML = '
' + table.outerHTML + '
' + table.outerHTML = '
' + table.outerHTML + "
" }) - const togglerInput = document.querySelector('.toggler__input') - const togglerLabel = document.querySelector('.toggler__label') - const sideMenu = document.querySelector('.menu-wrapper') - const menuItems = document.querySelectorAll('.menu') - const doc = document.querySelector('.document') - const body = document.querySelector('body') + const togglerInput = document.querySelector(".toggler__input") + const togglerLabel = document.querySelector(".toggler__label") + const sideMenu = document.querySelector(".menu-wrapper") + const menuItems = document.querySelectorAll(".menu") + const doc = document.querySelector(".document") + const body = document.querySelector("body") function closeMenu() { togglerInput.checked = false - sideMenu.setAttribute("aria-expanded", 'false') - sideMenu.setAttribute('aria-hidden', 'true') - togglerLabel.setAttribute('aria-pressed', 'false') - body.style.overflow = 'visible' + sideMenu.setAttribute("aria-expanded", "false") + sideMenu.setAttribute("aria-hidden", "true") + togglerLabel.setAttribute("aria-pressed", "false") + body.style.overflow = "visible" } function openMenu() { togglerInput.checked = true - sideMenu.setAttribute("aria-expanded", 'true') - sideMenu.setAttribute('aria-hidden', 'false') - togglerLabel.setAttribute('aria-pressed', 'true') - body.style.overflow = 'hidden' + sideMenu.setAttribute("aria-expanded", "true") + sideMenu.setAttribute("aria-hidden", "false") + togglerLabel.setAttribute("aria-pressed", "true") + body.style.overflow = "hidden" } // Close menu when link on the sideMenu is clicked - sideMenu.addEventListener('click', function (event) { + sideMenu.addEventListener("click", function (event) { let target = event.target - if (target.tagName.toLowerCase() !== 'a') { + if (target.tagName.toLowerCase() !== "a") { return } closeMenu() }) // Add accessibility data when sideMenu is opened/closed - togglerInput.addEventListener('change', function (e) { + togglerInput.addEventListener("change", function (e) { togglerInput.checked ? openMenu() : closeMenu() }) // Make sideMenu links tabbable only when visible for(let menuItem of menuItems) { if(togglerInput.checked) { - menuItem.setAttribute('tabindex', '0') + menuItem.setAttribute("tabindex", "0") } else { - menuItem.setAttribute('tabindex', '-1') + menuItem.setAttribute("tabindex", "-1") } } // Close sideMenu when document body is clicked - doc.addEventListener('click', function () { + doc.addEventListener("click", function () { if (togglerInput.checked) { closeMenu() } From b0c184d7bc0b392c53554d672d89a75c23afde47 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:21:37 +0100 Subject: [PATCH 5/9] Mark a parameter as unused in ``menu.js`` --- python_docs_theme/static/menu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_docs_theme/static/menu.js b/python_docs_theme/static/menu.js index 8c2026e..e233585 100644 --- a/python_docs_theme/static/menu.js +++ b/python_docs_theme/static/menu.js @@ -37,7 +37,7 @@ document.addEventListener("DOMContentLoaded", function () { closeMenu() }) // Add accessibility data when sideMenu is opened/closed - togglerInput.addEventListener("change", function (e) { + togglerInput.addEventListener("change", function (_event) { togglerInput.checked ? openMenu() : closeMenu() }) // Make sideMenu links tabbable only when visible From 40a3de3352d82578c9b066a1daad06e459c37aa2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 30 May 2022 01:51:54 +0100 Subject: [PATCH 6/9] Drop jQuery in ``sidebars.js`` --- python_docs_theme/static/pydoctheme.css | 29 ++++ python_docs_theme/static/sidebar.js | 182 +++++++++--------------- python_docs_theme/theme.conf | 1 + 3 files changed, 94 insertions(+), 118 deletions(-) diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css index 6c141f8..20058ac 100644 --- a/python_docs_theme/static/pydoctheme.css +++ b/python_docs_theme/static/pydoctheme.css @@ -104,10 +104,12 @@ div.sphinxsidebar h4 { } div.sphinxsidebarwrapper { + width: 217px; box-sizing: border-box; height: 100%; overflow-x: hidden; overflow-y: auto; + float: left; } div.sphinxsidebarwrapper > h3:first-child { @@ -135,6 +137,33 @@ div.sphinxsidebar input[type='text'] { max-width: 150px; } +#sidebarbutton { + /* Sphinx 4.x and earlier compat */ + height: 100%; + background-color: #CCCCCC; + margin-left: 0; + color: #444444; + font-size: 1.2em; + cursor: pointer; + padding-top: 1px; + float: right; + display: table; + /* after Sphinx 4.x and earlier is dropped, only the below is needed */ + width: 12px; + border-radius: 0 5px 5px 0; + border-left: none; +} + +#sidebarbutton span { + /* Sphinx 4.x and earlier compat */ + display: table-cell; + vertical-align: middle; +} + +#sidebarbutton:hover { + background-color: #AAAAAA; +} + div.body { padding: 0 0 0 1.2em; } diff --git a/python_docs_theme/static/sidebar.js b/python_docs_theme/static/sidebar.js index 6b5c694..b5bf1b4 100644 --- a/python_docs_theme/static/sidebar.js +++ b/python_docs_theme/static/sidebar.js @@ -2,142 +2,88 @@ * sidebar.js * ~~~~~~~~~~ * - * This script makes the Sphinx sidebar collapsible. This is a slightly - * modified version of Sphinx's own sidebar.js. + * This file is functionally identical to "sidebar.js" in Sphinx 5.0. + * When support for Sphinx 4 and earlier is dropped from the theme, + * this file can be removed. * - * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in - * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to - * collapse and expand the sidebar. + * This script makes the Sphinx sidebar collapsible. * - * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the - * width of the sidebar and the margin-left of the document are decreased. - * When the sidebar is expanded the opposite happens. This script saves a - * per-browser/per-session cookie used to remember the position of the sidebar - * among the pages. Once the browser is closed the cookie is deleted and the - * position reset to the default (expanded). + * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds + * in .sphinxsidebar, after .sphinxsidebarwrapper, the #sidebarbutton + * used to collapse and expand the sidebar. * - * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden + * and the width of the sidebar and the margin-left of the document + * are decreased. When the sidebar is expanded the opposite happens. + * This script saves a per-browser/per-session cookie used to + * remember the position of the sidebar among the pages. + * Once the browser is closed the cookie is deleted and the position + * reset to the default (expanded). + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ -$(function() { +const initialiseSidebar = () => { // global elements used by the functions. - // the 'sidebarbutton' element is defined as global after its - // creation, in the add_sidebar_button function - var bodywrapper = $('.bodywrapper'); - var sidebar = $('.sphinxsidebar'); - var sidebarwrapper = $('.sphinxsidebarwrapper'); + const bodyWrapper = document.getElementsByClassName("bodywrapper")[0] + const sidebar = document.getElementsByClassName("sphinxsidebar")[0] + const sidebarWrapper = document.getElementsByClassName("sphinxsidebarwrapper")[0] - // original margin-left of the bodywrapper and width of the sidebar - // with the sidebar expanded - var bw_margin_expanded = bodywrapper.css('margin-left'); - var ssb_width_expanded = sidebar.width(); + // exit early if the document has no sidebar for some reason + if (typeof sidebar === "undefined") { + return + } - // margin-left of the bodywrapper and width of the sidebar - // with the sidebar collapsed - var bw_margin_collapsed = '.8em'; - var ssb_width_collapsed = '.8em'; + // create the sidebar button element + const sidebarButton = document.createElement("div") + sidebarButton.id = "sidebarbutton" + // create the sidebar button arrow element + const sidebarArrow = document.createElement("span") + sidebarArrow.innerText = "«" + sidebarButton.appendChild(sidebarArrow) + sidebar.appendChild(sidebarButton) - // colors used by the current theme - var dark_color = '#AAAAAA'; - var light_color = '#CCCCCC'; + const flipArrow = element => element.innerText = (element.innerText === "»") ? "«" : "»" - function sidebar_is_collapsed() { - return sidebarwrapper.is(':not(:visible)'); + const collapse_sidebar = () => { + bodyWrapper.style.marginLeft = ".8em" + sidebar.style.width = ".8em" + sidebarWrapper.style.display = "none" + flipArrow(sidebarArrow) + sidebarButton.title = _("Expand sidebar") + window.localStorage.setItem("sidebar", "collapsed") } - function toggle_sidebar() { - if (sidebar_is_collapsed()) - expand_sidebar(); - else - collapse_sidebar(); + const expand_sidebar = () => { + bodyWrapper.style.marginLeft = "" + sidebar.style.removeProperty("width") + sidebarWrapper.style.display = "" + flipArrow(sidebarArrow) + sidebarButton.title = _("Collapse sidebar") + window.localStorage.setItem("sidebar", "expanded") } - function collapse_sidebar() { - sidebarwrapper.hide(); - sidebar.css('width', ssb_width_collapsed); - bodywrapper.css('margin-left', bw_margin_collapsed); - sidebarbutton.css({ - 'margin-left': '0', - 'border-radius': '5px' - }); - sidebarbutton.find('span').text('»'); - sidebarbutton.attr('title', _('Expand sidebar')); - document.cookie = 'sidebar=collapsed'; - } + sidebarButton.addEventListener("click", () => { + (sidebarWrapper.style.display === "none") ? expand_sidebar() : collapse_sidebar() + }) - function expand_sidebar() { - bodywrapper.css('margin-left', bw_margin_expanded); - sidebar.css('width', ssb_width_expanded); - sidebarwrapper.show(); - sidebarbutton.css({ - 'margin-left': ssb_width_expanded-12, - 'border-radius': '0 5px 5px 0' - }); - sidebarbutton.find('span').text('«'); - sidebarbutton.attr('title', _('Collapse sidebar')); - document.cookie = 'sidebar=expanded'; + if (!window.localStorage.getItem("sidebar")) { + return } - - function add_sidebar_button() { - sidebarwrapper.css({ - 'float': 'left', - 'margin-right': '0', - 'width': ssb_width_expanded - 13 - }); - // create the button - sidebar.append( - '
«
' - ); - var sidebarbutton = $('#sidebarbutton'); - sidebarbutton.find('span').css({ - 'display': 'block', - 'position': 'fixed', - 'top': '50%' - }); - - sidebarbutton.click(toggle_sidebar); - sidebarbutton.attr('title', _('Collapse sidebar')); - sidebarbutton.css({ - 'border-radius': '0 5px 5px 0', - 'color': '#444444', - 'background-color': '#CCCCCC', - 'font-size': '1.2em', - 'cursor': 'pointer', - 'height': '100%', - 'padding-left': '1px', - 'margin-left': ssb_width_expanded - 12 - }); - - sidebarbutton.hover( - function () { - $(this).css('background-color', dark_color); - }, - function () { - $(this).css('background-color', light_color); - } - ); + const value = window.localStorage.getItem("sidebar") + if (value === "collapsed") { + collapse_sidebar() } - - function set_position_from_cookie() { - if (!document.cookie) - return; - var items = document.cookie.split(';'); - for(var k=0; k Date: Mon, 30 May 2022 03:22:23 +0100 Subject: [PATCH 7/9] Drop jQuery in ``copybutton.js`` --- python_docs_theme/static/copybutton.js | 116 +++++++++++++----------- python_docs_theme/static/pydoctheme.css | 20 ++++ 2 files changed, 81 insertions(+), 55 deletions(-) diff --git a/python_docs_theme/static/copybutton.js b/python_docs_theme/static/copybutton.js index 16dee00..2c4042b 100644 --- a/python_docs_theme/static/copybutton.js +++ b/python_docs_theme/static/copybutton.js @@ -1,64 +1,70 @@ -$(document).ready(function() { + +const loadCopyButton = () => { /* Add a [>>>] button on the top-right corner of code samples to hide * the >>> and ... prompts and the output and thus make the code * copyable. */ - var div = $('.highlight-python .highlight,' + - '.highlight-python3 .highlight,' + - '.highlight-pycon .highlight,' + - '.highlight-pycon3 .highlight,' + - '.highlight-default .highlight'); - var pre = div.find('pre'); + const hide_text = "Hide the prompts and output" + const show_text = "Show the prompts and output" - // get the styles from the current theme - pre.parent().parent().css('position', 'relative'); - var hide_text = 'Hide the prompts and output'; - var show_text = 'Show the prompts and output'; - var border_width = pre.css('border-top-width'); - var border_style = pre.css('border-top-style'); - var border_color = pre.css('border-top-color'); - var button_styles = { - 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', - 'border-color': border_color, 'border-style': border_style, - 'border-width': border_width, 'color': border_color, 'text-size': '75%', - 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', - 'border-radius': '0 3px 0 0' + const button = document.createElement("span") + button.classList.add("copybutton") + button.innerText = ">>>" + button.title = hide_text + button.dataset.hidden = "false" + const buttonClick = event => { + // define the behavior of the button when it's clicked + event.preventDefault() + const buttonEl = event.currentTarget + const codeEl = buttonEl.nextElementSibling + if (buttonEl.dataset.hidden === "false") { + // hide the code output + codeEl.querySelectorAll('.go, .gp, .gt').forEach(el => el.hidden = true) + codeEl.querySelectorAll('.gt').forEach(el => { + while ((el = el.nextSibling) && el.nodeType !== Node.DOCUMENT_NODE) { + if (el.nodeType === Node.ELEMENT_NODE && el.matches(".gp, .go")) break; + if (el.nodeType === Node.TEXT_NODE && el.textContent.trim()) { + const wrapper = document.createElement('span'); + el.after(wrapper); + wrapper.appendChild(el); + el = wrapper + } + el.hidden = true + } + }) + buttonEl.title = show_text + buttonEl.dataset.hidden = "true" + } else { + // show the code output + codeEl.childNodes.forEach(el => el.hidden = false) + buttonEl.title = hide_text + buttonEl.dataset.hidden = "false" + } } + const highlightedElements = document.querySelectorAll( + ".highlight-python .highlight," + + ".highlight-python3 .highlight," + + ".highlight-pycon .highlight," + + ".highlight-pycon3 .highlight," + + ".highlight-default .highlight" + ) + // create and add the button to all the code blocks that contain >>> - div.each(function(index) { - var jthis = $(this); - if (jthis.find('.gp').length > 0) { - var button = $('>>>'); - button.css(button_styles) - button.attr('title', hide_text); - button.data('hidden', 'false'); - jthis.prepend(button); - } - // tracebacks (.gt) contain bare text elements that need to be - // wrapped in a span to work with .nextUntil() (see later) - jthis.find('pre:has(.gt)').contents().filter(function() { - return ((this.nodeType == 3) && (this.data.trim().length > 0)); - }).wrap(''); - }); + highlightedElements.forEach(el => { + el.style.position = "relative" - // define the behavior of the button when it's clicked - $('.copybutton').click(function(e){ - e.preventDefault(); - var button = $(this); - if (button.data('hidden') === 'false') { - // hide the code output - button.parent().find('.go, .gp, .gt').hide(); - button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); - button.css('text-decoration', 'line-through'); - button.attr('title', show_text); - button.data('hidden', 'true'); - } else { - // show the code output - button.parent().find('.go, .gp, .gt').show(); - button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); - button.css('text-decoration', 'none'); - button.attr('title', hide_text); - button.data('hidden', 'false'); + // if we find a console prompt (.gp), prepend the (deeply cloned) button + const clonedButton = button.cloneNode(true) + // the onclick attribute is not cloned, set it on the new element + clonedButton.onclick = buttonClick + if (el.querySelector(".gp") !== null) { + el.prepend(clonedButton) } - }); -}); + }) +} + +if (document.readyState !== "loading") { + loadCopyButton() +} else { + document.addEventListener("DOMContentLoaded", loadCopyButton) +} diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css index 20058ac..5c0d394 100644 --- a/python_docs_theme/static/pydoctheme.css +++ b/python_docs_theme/static/pydoctheme.css @@ -308,6 +308,26 @@ div.genindex-jumpbox a { text-align: center; } +.copybutton { + cursor: pointer; + position: absolute; + top: 0; + right: 0; + text-size: 75%; + font-family: monospace; + padding-left: 0.2em; + padding-right: 0.2em; + border-radius: 0 3px 0 0; + color: #ac9; /* follows div.body pre */ + border-color: #ac9; /* follows div.body pre */ + border-style: solid; /* follows div.body pre */ + border-width: 1px; /* follows div.body pre */ +} + +.copybutton[data-hidden='true'] { + text-decoration: line-through; +} + @media (max-width: 1023px) { /* Body layout */ div.body { From aa604d0a4a5a1dd0aa811ff0f1cc8dc96ca6c502 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Sat, 12 Nov 2022 14:40:00 +0000 Subject: [PATCH 8/9] Introduce ``getHideableCopyButtonElements()`` --- python_docs_theme/static/copybutton.js | 52 ++++++++++++++++++-------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/python_docs_theme/static/copybutton.js b/python_docs_theme/static/copybutton.js index 2c4042b..7367c4a 100644 --- a/python_docs_theme/static/copybutton.js +++ b/python_docs_theme/static/copybutton.js @@ -1,6 +1,36 @@ +// ``function*`` denotes a generator in JavaScript, see +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* +function* getHideableCopyButtonElements(rootElement) { + // yield all elements with the "go" (Generic.Output), + // "gp" (Generic.Prompt), or "gt" (Generic.Traceback) CSS class + for (const el of rootElement.querySelectorAll('.go, .gp, .gt')) { + yield el + } + // tracebacks (.gt) contain bare text elements that need to be + // wrapped in a span to hide or show the element + for (let el of rootElement.querySelectorAll('.gt')) { + while ((el = el.nextSibling) && el.nodeType !== Node.DOCUMENT_NODE) { + // stop wrapping text nodes when we hit the next output or + // prompt element + if (el.nodeType === Node.ELEMENT_NODE && el.matches(".gp, .go")) { + break + } + // if the node is a text node with content, wrap it in a + // span element so that we can control visibility + if (el.nodeType === Node.TEXT_NODE && el.textContent.trim()) { + const wrapper = document.createElement("span") + el.after(wrapper) + wrapper.appendChild(el) + el = wrapper + } + yield el + } + } +} + const loadCopyButton = () => { - /* Add a [>>>] button on the top-right corner of code samples to hide + /* Add a [>>>] button in the top-right corner of code samples to hide * the >>> and ... prompts and the output and thus make the code * copyable. */ const hide_text = "Hide the prompts and output" @@ -18,24 +48,16 @@ const loadCopyButton = () => { const codeEl = buttonEl.nextElementSibling if (buttonEl.dataset.hidden === "false") { // hide the code output - codeEl.querySelectorAll('.go, .gp, .gt').forEach(el => el.hidden = true) - codeEl.querySelectorAll('.gt').forEach(el => { - while ((el = el.nextSibling) && el.nodeType !== Node.DOCUMENT_NODE) { - if (el.nodeType === Node.ELEMENT_NODE && el.matches(".gp, .go")) break; - if (el.nodeType === Node.TEXT_NODE && el.textContent.trim()) { - const wrapper = document.createElement('span'); - el.after(wrapper); - wrapper.appendChild(el); - el = wrapper - } - el.hidden = true - } - }) + for (const el of getHideableCopyButtonElements(codeEl)) { + el.hidden = true + } buttonEl.title = show_text buttonEl.dataset.hidden = "true" } else { // show the code output - codeEl.childNodes.forEach(el => el.hidden = false) + for (const el of getHideableCopyButtonElements(codeEl)) { + el.hidden = false + } buttonEl.title = hide_text buttonEl.dataset.hidden = "false" } From df3872d2026220dc15dd5da69924532719712b1c Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:00:38 +0100 Subject: [PATCH 9/9] Mild JavaScript refactor --- python_docs_theme/static/sidebar.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/python_docs_theme/static/sidebar.js b/python_docs_theme/static/sidebar.js index b5bf1b4..70886d4 100644 --- a/python_docs_theme/static/sidebar.js +++ b/python_docs_theme/static/sidebar.js @@ -45,13 +45,11 @@ const initialiseSidebar = () => { sidebarButton.appendChild(sidebarArrow) sidebar.appendChild(sidebarButton) - const flipArrow = element => element.innerText = (element.innerText === "»") ? "«" : "»" - const collapse_sidebar = () => { bodyWrapper.style.marginLeft = ".8em" sidebar.style.width = ".8em" sidebarWrapper.style.display = "none" - flipArrow(sidebarArrow) + sidebarArrow.innerText = "»" sidebarButton.title = _("Expand sidebar") window.localStorage.setItem("sidebar", "collapsed") } @@ -60,7 +58,7 @@ const initialiseSidebar = () => { bodyWrapper.style.marginLeft = "" sidebar.style.removeProperty("width") sidebarWrapper.style.display = "" - flipArrow(sidebarArrow) + sidebarArrow.innerText = "«" sidebarButton.title = _("Collapse sidebar") window.localStorage.setItem("sidebar", "expanded") } @@ -69,14 +67,11 @@ const initialiseSidebar = () => { (sidebarWrapper.style.display === "none") ? expand_sidebar() : collapse_sidebar() }) - if (!window.localStorage.getItem("sidebar")) { - return - } - const value = window.localStorage.getItem("sidebar") - if (value === "collapsed") { + const sidebar_state = window.localStorage.getItem("sidebar") + if (sidebar_state === "collapsed") { collapse_sidebar() } - else if (value === "expanded") { + else if (sidebar_state === "expanded") { expand_sidebar() } }