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, } diff --git a/python_docs_theme/static/copybutton.js b/python_docs_theme/static/copybutton.js index 16dee00..7367c4a 100644 --- a/python_docs_theme/static/copybutton.js +++ b/python_docs_theme/static/copybutton.js @@ -1,64 +1,92 @@ -$(document).ready(function() { - /* Add a [>>>] button on the top-right corner of code samples to hide +// ``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 in 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 + for (const el of getHideableCopyButtonElements(codeEl)) { + el.hidden = true + } + buttonEl.title = show_text + buttonEl.dataset.hidden = "true" + } else { + // show the code output + for (const el of getHideableCopyButtonElements(codeEl)) { + 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/menu.js b/python_docs_theme/static/menu.js index b2eabb3..e233585 100644 --- a/python_docs_theme/static/menu.js +++ b/python_docs_theme/static/menu.js @@ -1,55 +1,57 @@ -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'; + 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(); + sideMenu.addEventListener("click", function (event) { + 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.addEventListener("change", function (_event) { + 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(); + closeMenu() } }) }) \ No newline at end of file diff --git a/python_docs_theme/static/pydoctheme.css b/python_docs_theme/static/pydoctheme.css index 6c141f8..5c0d394 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; } @@ -279,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 { diff --git a/python_docs_theme/static/sidebar.js b/python_docs_theme/static/sidebar.js index 6b5c694..70886d4 100644 --- a/python_docs_theme/static/sidebar.js +++ b/python_docs_theme/static/sidebar.js @@ -2,142 +2,83 @@ * 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'); - - // 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(); - - // margin-left of the bodywrapper and width of the sidebar - // with the sidebar collapsed - var bw_margin_collapsed = '.8em'; - var ssb_width_collapsed = '.8em'; - - // colors used by the current theme - var dark_color = '#AAAAAA'; - var light_color = '#CCCCCC'; + const bodyWrapper = document.getElementsByClassName("bodywrapper")[0] + const sidebar = document.getElementsByClassName("sphinxsidebar")[0] + const sidebarWrapper = document.getElementsByClassName("sphinxsidebarwrapper")[0] - function sidebar_is_collapsed() { - return sidebarwrapper.is(':not(:visible)'); + // exit early if the document has no sidebar for some reason + if (typeof sidebar === "undefined") { + return } - function toggle_sidebar() { - if (sidebar_is_collapsed()) - expand_sidebar(); - else - collapse_sidebar(); - } + // 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) - 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'; + const collapse_sidebar = () => { + bodyWrapper.style.marginLeft = ".8em" + sidebar.style.width = ".8em" + sidebarWrapper.style.display = "none" + sidebarArrow.innerText = "»" + sidebarButton.title = _("Expand sidebar") + window.localStorage.setItem("sidebar", "collapsed") } - 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'; + const expand_sidebar = () => { + bodyWrapper.style.marginLeft = "" + sidebar.style.removeProperty("width") + sidebarWrapper.style.display = "" + sidebarArrow.innerText = "«" + sidebarButton.title = _("Collapse sidebar") + window.localStorage.setItem("sidebar", "expanded") } - 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.addEventListener("click", () => { + (sidebarWrapper.style.display === "none") ? expand_sidebar() : collapse_sidebar() + }) - sidebarbutton.hover( - function () { - $(this).css('background-color', dark_color); - }, - function () { - $(this).css('background-color', light_color); - } - ); + const sidebar_state = window.localStorage.getItem("sidebar") + if (sidebar_state === "collapsed") { + collapse_sidebar() } - - function set_position_from_cookie() { - if (!document.cookie) - return; - var items = document.cookie.split(';'); - for(var k=0; k pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy