mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add `collapsible` option to admonition directives (#12507)
This PR adds the `collapsible` and option to the core admonition type directives, which are propagated to the nodes, e.g. ```restructuredtext .. admonition:: title :collapsible: content .. note:: content :collapsible: closed ``` For the HTML5 writer, this replaces the outer `div` with a `details` tag, and the title `p` with a `summary` tag (with an `open` attribute if set), e.g. ```html <div class="admonition note"> <p class="admonition-title">Note</p> <p>hallo</p> </div> ``` changes to ```html <details class="admonition note" open="open"> <summary class="admonition-title">Note</summary> <p>hallo</p> </details> ``` Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
@@ -88,6 +88,9 @@ Features added
|
||||
* #13271: Support the ``:abstract:`` option for
|
||||
classes, methods, and properties in the Python domain.
|
||||
Patch by Adam Turner.
|
||||
* #12507: Add the :ref:`collapsible <collapsible-admonitions>` option
|
||||
to admonition directives.
|
||||
Patch by Chris Sewell.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
106
doc/_themes/sphinx13/static/sphinx13.css
vendored
106
doc/_themes/sphinx13/static/sphinx13.css
vendored
@@ -31,6 +31,9 @@
|
||||
--icon-warning: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 14h-2v-4h2m0 8h-2v-2h2M1 21h22L12 2 1 21z"/></svg>');
|
||||
--icon-failure: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12 6.47 2 12 2m3.59 5L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41 15.59 7z"/></svg>');
|
||||
--icon-spark: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.5 20l4.86-9.73H13V4l-5 9.73h3.5V20M12 2c2.75 0 5.1 1 7.05 2.95C21 6.9 22 9.25 22 12s-1 5.1-2.95 7.05C17.1 21 14.75 22 12 22s-5.1-1-7.05-2.95C3 17.1 2 14.75 2 12s1-5.1 2.95-7.05C6.9 3 9.25 2 12 2z"/></svg>');
|
||||
|
||||
/* icons used for details summaries */
|
||||
--icon-details-open: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.59 16.58 13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.42Z"/></svg>');
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -409,7 +412,7 @@ table td, table th {
|
||||
padding: 0.2em 0.5em 0.2em 0.5em;
|
||||
}
|
||||
|
||||
div.admonition, div.warning {
|
||||
div.admonition, div.warning, details.admonition {
|
||||
font-size: 0.9em;
|
||||
margin: 1em 0 1em 0;
|
||||
border: 1px solid #86989B;
|
||||
@@ -418,16 +421,16 @@ div.admonition, div.warning {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
div.admonition > p, div.warning > p {
|
||||
div.admonition > p, div.warning > p, details.admonition > p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.admonition > pre, div.warning > pre {
|
||||
div.admonition > pre, div.warning > pre, details.admonition > pre {
|
||||
margin: 0.4em 1em 0.4em 1em;
|
||||
}
|
||||
|
||||
div.admonition > p.admonition-title {
|
||||
div.admonition > p.admonition-title, details.admonition > summary.admonition-title {
|
||||
position: relative;
|
||||
font-weight: 500;
|
||||
background-color: var(--color-admonition-bg);
|
||||
@@ -436,33 +439,78 @@ div.admonition > p.admonition-title {
|
||||
border-radius: var(--admonition-radius) var(--admonition-radius) 0 0;
|
||||
}
|
||||
|
||||
details.admonition:not([open]) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
details.admonition > summary.admonition-title {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
padding-right: .5rem;
|
||||
}
|
||||
details.admonition > summary.admonition-title::after {
|
||||
background-color: currentcolor;
|
||||
content: "";
|
||||
height: 1.2rem;
|
||||
width: 1.2rem;
|
||||
-webkit-mask-image: var(--icon-details-open);
|
||||
mask-image: var(--icon-details-open);
|
||||
-webkit-mask-position: center;
|
||||
mask-position: center;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: contain;
|
||||
mask-size: contain;
|
||||
transform: rotate(0deg);
|
||||
transition: transform .25s;
|
||||
float: right;
|
||||
}
|
||||
details.admonition[open] > summary.admonition-title::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
details.admonition:not([open]) > summary.admonition-title {
|
||||
margin-bottom: 0;
|
||||
border-radius: var(--admonition-radius);
|
||||
}
|
||||
|
||||
div.attention > p.admonition-title,
|
||||
div.danger > p.admonition-title,
|
||||
div.error > p.admonition-title {
|
||||
div.error > p.admonition-title,
|
||||
details.attention > summary.admonition-title,
|
||||
details.danger > summary.admonition-title,
|
||||
details.error > summary.admonition-title {
|
||||
background-color: var(--colour-error-bg);
|
||||
}
|
||||
|
||||
div.important > p.admonition-title,
|
||||
div.caution > p.admonition-title,
|
||||
div.warning > p.admonition-title {
|
||||
div.warning > p.admonition-title,
|
||||
details.important > summary.admonition-title,
|
||||
details.caution > summary.admonition-title,
|
||||
details.warning > summary.admonition-title {
|
||||
background-color: var(--colour-warning-bg);
|
||||
}
|
||||
|
||||
div.note > p.admonition-title {
|
||||
div.note > p.admonition-title,
|
||||
details.note > summary.admonition-title {
|
||||
background-color: var(--colour-note-bg);
|
||||
}
|
||||
|
||||
div.hint > p.admonition-title,
|
||||
div.tip > p.admonition-title,
|
||||
div.seealso > p.admonition-title {
|
||||
div.seealso > p.admonition-title,
|
||||
details.hint > summary.admonition-title,
|
||||
details.tip > summary.admonition-title,
|
||||
details.seealso > summary.admonition-title {
|
||||
background-color: var(--colour-success-bg);
|
||||
}
|
||||
|
||||
div.admonition-todo > p.admonition-title {
|
||||
div.admonition-todo > p.admonition-title,
|
||||
details.admonition-todo > summary.admonition-title {
|
||||
background-color: var(--colour-todo-bg);
|
||||
}
|
||||
|
||||
p.admonition-title::before {
|
||||
p.admonition-title::before,
|
||||
summary.admonition-title::before {
|
||||
content: "";
|
||||
height: 1rem;
|
||||
left: .5rem;
|
||||
@@ -472,69 +520,81 @@ p.admonition-title::before {
|
||||
background-color: #5f5f5f;
|
||||
}
|
||||
|
||||
div.admonition > p.admonition-title::before {
|
||||
div.admonition > p.admonition-title::before,
|
||||
details.admonition > summary.admonition-title::before {
|
||||
background-color: var(--color-admonition-fg);
|
||||
-webkit-mask-image: var(--icon-abstract);
|
||||
mask-image: var(--icon-abstract);
|
||||
}
|
||||
div.attention > p.admonition-title::before {
|
||||
div.attention > p.admonition-title::before,
|
||||
details.attention > summary.admonition-title::before {
|
||||
background-color: var(--colour-error-fg);
|
||||
-webkit-mask-image: var(--icon-warning);
|
||||
mask-image: var(--icon-warning);
|
||||
}
|
||||
div.caution > p.admonition-title::before {
|
||||
div.caution > p.admonition-title::before,
|
||||
details.caution > summary.admonition-title::before {
|
||||
background-color: var(--colour-warning-fg);
|
||||
-webkit-mask-image: var(--icon-spark);
|
||||
mask-image: var(--icon-spark);
|
||||
}
|
||||
div.danger > p.admonition-title::before {
|
||||
div.danger > p.admonition-title::before,
|
||||
details.danger > summary.admonition-title::before {
|
||||
background-color: var(--colour-error-fg);
|
||||
-webkit-mask-image: var(--icon-spark);
|
||||
mask-image: var(--icon-spark);
|
||||
}
|
||||
div.error > p.admonition-title::before {
|
||||
div.error > p.admonition-title::before,
|
||||
details.error > summary.admonition-title::before {
|
||||
background-color: var(--colour-error-fg);
|
||||
-webkit-mask-image: var(--icon-failure);
|
||||
mask-image: var(--icon-failure);
|
||||
}
|
||||
div.hint > p.admonition-title::before {
|
||||
div.hint > p.admonition-title::before,
|
||||
details.hint > summary.admonition-title::before {
|
||||
background-color: var(--colour-success-fg);
|
||||
-webkit-mask-image: var(--icon-question);
|
||||
mask-image: var(--icon-question);
|
||||
}
|
||||
div.important > p.admonition-title::before {
|
||||
div.important > p.admonition-title::before,
|
||||
details.important > summary.admonition-title::before {
|
||||
background-color: var(--colour-warning-fg);
|
||||
-webkit-mask-image: var(--icon-flame);
|
||||
mask-image: var(--icon-flame);
|
||||
}
|
||||
div.note > p.admonition-title::before {
|
||||
div.note > p.admonition-title::before,
|
||||
details.note > summary.admonition-title::before {
|
||||
background-color: var(--colour-note-fg);
|
||||
-webkit-mask-image: var(--icon-pencil);
|
||||
mask-image: var(--icon-pencil);
|
||||
}
|
||||
div.seealso > p.admonition-title::before {
|
||||
div.seealso > p.admonition-title::before,
|
||||
details.seealso > summary.admonition-title::before {
|
||||
background-color: var(--colour-success-fg);
|
||||
-webkit-mask-image: var(--icon-info);
|
||||
mask-image: var(--icon-info);
|
||||
}
|
||||
div.tip > p.admonition-title::before {
|
||||
div.tip > p.admonition-title::before,
|
||||
details.tip > summary.admonition-title::before {
|
||||
background-color: var(--colour-success-fg);
|
||||
-webkit-mask-image: var(--icon-info);
|
||||
mask-image: var(--icon-info);
|
||||
}
|
||||
div.admonition-todo > p.admonition-title::before {
|
||||
div.admonition-todo > p.admonition-title::before,
|
||||
details.admonition-todo > summary.admonition-title::before {
|
||||
background-color: var(--colour-todo-fg);
|
||||
-webkit-mask-image: var(--icon-pencil);
|
||||
mask-image: var(--icon-pencil);
|
||||
}
|
||||
div.warning > p.admonition-title::before {
|
||||
div.warning > p.admonition-title::before,
|
||||
details.warning > summary.admonition-title::before {
|
||||
background-color: var(--colour-warning-fg);
|
||||
-webkit-mask-image: var(--icon-warning);
|
||||
mask-image: var(--icon-warning);
|
||||
}
|
||||
div.caution,
|
||||
div.important,
|
||||
div.warning {
|
||||
div.warning, details.warning {
|
||||
border-color: var(--colour-warning-fg);
|
||||
}
|
||||
div.attention,
|
||||
|
||||
@@ -480,6 +480,56 @@ and the generic :rst:dir:`admonition` directive.
|
||||
Documentation for tar archive files, including GNU tar extensions.
|
||||
|
||||
|
||||
.. _collapsible-admonitions:
|
||||
|
||||
.. rubric:: Collapsible text
|
||||
|
||||
.. versionadded:: 8.2
|
||||
|
||||
Each admonition directive supports a ``:collapsible:`` option,
|
||||
to make the content of the admonition collapsible
|
||||
(where supported by the output format).
|
||||
This can be useful for content that is not always relevant.
|
||||
By default, collapsible admonitions are initially open,
|
||||
but this can be controlled with the ``open`` and ``closed`` arguments
|
||||
to the ``:collapsible:`` option, which change the default state.
|
||||
In output formats that don't support collapsible content,
|
||||
the text is always included.
|
||||
For example:
|
||||
|
||||
.. code-block:: rst
|
||||
|
||||
.. note::
|
||||
:collapsible:
|
||||
|
||||
This note is collapsible, and initially open by default.
|
||||
|
||||
.. admonition:: Example
|
||||
:collapsible: open
|
||||
|
||||
This example is collapsible, and initially open.
|
||||
|
||||
.. hint::
|
||||
:collapsible: closed
|
||||
|
||||
This hint is collapsible, but initially closed.
|
||||
|
||||
.. note::
|
||||
:collapsible:
|
||||
|
||||
This note is collapsible, and initially open by default.
|
||||
|
||||
.. admonition:: Example
|
||||
:collapsible: open
|
||||
|
||||
This example is collapsible, and initially open.
|
||||
|
||||
.. hint::
|
||||
:collapsible: closed
|
||||
|
||||
This hint is collapsible, but initially closed.
|
||||
|
||||
|
||||
Describing changes between versions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ builtin_extensions: tuple[str, ...] = (
|
||||
'sphinx.domains.rst',
|
||||
'sphinx.domains.std',
|
||||
'sphinx.directives',
|
||||
'sphinx.directives.admonitions',
|
||||
'sphinx.directives.code',
|
||||
'sphinx.directives.other',
|
||||
'sphinx.directives.patches',
|
||||
|
||||
107
sphinx/directives/admonitions.py
Normal file
107
sphinx/directives/admonitions.py
Normal file
@@ -0,0 +1,107 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import ClassVar
|
||||
|
||||
from docutils.nodes import Node
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util.typing import ExtensionMetadata, OptionSpec
|
||||
|
||||
|
||||
def _collapsible_arg(argument: str | None) -> str:
|
||||
if argument is None:
|
||||
return 'open'
|
||||
if (value := argument.lower().strip()) in {'open', 'closed'}:
|
||||
return value
|
||||
msg = f'"{argument}" unknown; choose from "open" or "closed".'
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class SphinxAdmonition(BaseAdmonition, SphinxDirective):
|
||||
option_spec: ClassVar[OptionSpec] = BaseAdmonition.option_spec.copy() # type: ignore[union-attr]
|
||||
option_spec |= {
|
||||
'collapsible': _collapsible_arg,
|
||||
}
|
||||
|
||||
node_class: type[nodes.Admonition] = nodes.admonition
|
||||
"""Subclasses must set this to the appropriate admonition node class."""
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
(admonition_node,) = super().run()
|
||||
return [admonition_node]
|
||||
|
||||
|
||||
class Admonition(SphinxAdmonition):
|
||||
required_arguments = 1
|
||||
node_class = nodes.admonition
|
||||
|
||||
|
||||
class Attention(SphinxAdmonition):
|
||||
node_class = nodes.attention
|
||||
|
||||
|
||||
class Caution(SphinxAdmonition):
|
||||
node_class = nodes.caution
|
||||
|
||||
|
||||
class Danger(SphinxAdmonition):
|
||||
node_class = nodes.danger
|
||||
|
||||
|
||||
class Error(SphinxAdmonition):
|
||||
node_class = nodes.error
|
||||
|
||||
|
||||
class Hint(SphinxAdmonition):
|
||||
node_class = nodes.hint
|
||||
|
||||
|
||||
class Important(SphinxAdmonition):
|
||||
node_class = nodes.important
|
||||
|
||||
|
||||
class Note(SphinxAdmonition):
|
||||
node_class = nodes.note
|
||||
|
||||
|
||||
class Tip(SphinxAdmonition):
|
||||
node_class = nodes.tip
|
||||
|
||||
|
||||
class Warning(SphinxAdmonition):
|
||||
node_class = nodes.warning
|
||||
|
||||
|
||||
class SeeAlso(SphinxAdmonition):
|
||||
"""An admonition mentioning things to look at as reference."""
|
||||
|
||||
node_class = addnodes.seealso
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
app.add_directive('admonition', Admonition, override=True)
|
||||
app.add_directive('attention', Attention, override=True)
|
||||
app.add_directive('caution', Caution, override=True)
|
||||
app.add_directive('danger', Danger, override=True)
|
||||
app.add_directive('error', Error, override=True)
|
||||
app.add_directive('hint', Hint, override=True)
|
||||
app.add_directive('important', Important, override=True)
|
||||
app.add_directive('note', Note, override=True)
|
||||
app.add_directive('tip', Tip, override=True)
|
||||
app.add_directive('warning', Warning, override=True)
|
||||
app.add_directive('seealso', SeeAlso, override=True)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
@@ -7,7 +7,6 @@ from typing import TYPE_CHECKING, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
|
||||
from docutils.parsers.rst.directives.misc import Class
|
||||
from docutils.parsers.rst.directives.misc import Include as BaseInclude
|
||||
from docutils.statemachine import StateMachine
|
||||
@@ -215,12 +214,6 @@ class Author(SphinxDirective):
|
||||
return ret
|
||||
|
||||
|
||||
class SeeAlso(BaseAdmonition):
|
||||
"""An admonition mentioning things to look at as reference."""
|
||||
|
||||
node_class = addnodes.seealso
|
||||
|
||||
|
||||
class TabularColumns(SphinxDirective):
|
||||
"""Directive to give an explicit tabulary column definition to LaTeX."""
|
||||
|
||||
@@ -427,7 +420,6 @@ def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
directives.register_directive('sectionauthor', Author)
|
||||
directives.register_directive('moduleauthor', Author)
|
||||
directives.register_directive('codeauthor', Author)
|
||||
directives.register_directive('seealso', SeeAlso)
|
||||
directives.register_directive('tabularcolumns', TabularColumns)
|
||||
directives.register_directive('centered', Centered)
|
||||
directives.register_directive('acks', Acks)
|
||||
|
||||
@@ -12,11 +12,10 @@ import operator
|
||||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
|
||||
|
||||
import sphinx
|
||||
from sphinx import addnodes
|
||||
from sphinx.directives.admonitions import SphinxAdmonition
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.errors import NoUri
|
||||
from sphinx.locale import _, __
|
||||
@@ -46,35 +45,25 @@ class todolist(nodes.General, nodes.Element):
|
||||
pass
|
||||
|
||||
|
||||
class Todo(BaseAdmonition, SphinxDirective):
|
||||
class Todo(SphinxAdmonition):
|
||||
"""A todo entry, displayed (if configured) in the form of an admonition."""
|
||||
|
||||
node_class = todo_node
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec: ClassVar[OptionSpec] = {
|
||||
'class': directives.class_option,
|
||||
'name': directives.unchanged,
|
||||
}
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
if not self.options.get('class'):
|
||||
self.options['class'] = ['admonition-todo']
|
||||
|
||||
(todo,) = super().run()
|
||||
if isinstance(todo, nodes.system_message):
|
||||
if not isinstance(todo, todo_node):
|
||||
return [todo]
|
||||
elif isinstance(todo, todo_node):
|
||||
todo.insert(0, nodes.title(text=_('Todo')))
|
||||
todo['docname'] = self.env.docname
|
||||
self.add_name(todo)
|
||||
self.set_source_info(todo)
|
||||
self.state.document.note_explicit_target(todo)
|
||||
return [todo]
|
||||
else:
|
||||
raise TypeError # never reached here
|
||||
|
||||
todo.insert(0, nodes.title(text=_('Todo')))
|
||||
todo['docname'] = self.env.docname
|
||||
self.add_name(todo)
|
||||
self.set_source_info(todo)
|
||||
self.state.document.note_explicit_target(todo)
|
||||
return [todo]
|
||||
|
||||
|
||||
class TodoDomain(Domain):
|
||||
|
||||
@@ -367,12 +367,21 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
||||
|
||||
# overwritten
|
||||
def visit_admonition(self, node: Element, name: str = '') -> None:
|
||||
self.body.append(self.starttag(node, 'div', CLASS=('admonition ' + name)))
|
||||
attributes = {}
|
||||
tag_name = 'div'
|
||||
if collapsible := node.get('collapsible'):
|
||||
tag_name = 'details'
|
||||
if collapsible == 'open':
|
||||
attributes['open'] = 'open'
|
||||
self.body.append(
|
||||
self.starttag(node, tag_name, CLASS=f'admonition {name}', **attributes)
|
||||
)
|
||||
self.context.append(f'</{tag_name}>\n')
|
||||
if name:
|
||||
node.insert(0, nodes.title(name, admonitionlabels[name]))
|
||||
|
||||
def depart_admonition(self, node: Element | None = None) -> None:
|
||||
self.body.append('</div>\n')
|
||||
self.body.append(self.context.pop())
|
||||
|
||||
def visit_seealso(self, node: Element) -> None:
|
||||
self.visit_admonition(node, 'seealso')
|
||||
@@ -500,6 +509,15 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
||||
)
|
||||
self.body.append('<span class="caption-text">')
|
||||
self.context.append('</span></p>\n')
|
||||
elif (
|
||||
isinstance(node.parent, nodes.Admonition)
|
||||
and isinstance(node.parent, nodes.Element)
|
||||
and 'collapsible' in node.parent
|
||||
):
|
||||
self.body.append(
|
||||
self.starttag(node, 'summary', '', CLASS='admonition-title')
|
||||
)
|
||||
self.context.append('</summary>\n')
|
||||
else:
|
||||
super().visit_title(node)
|
||||
self.add_secnumber(node)
|
||||
|
||||
22
tests/roots/test-directives-admonition-collapse/index.rst
Normal file
22
tests/roots/test-directives-admonition-collapse/index.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
test-directives-admonition-collapse
|
||||
===================================
|
||||
|
||||
.. note::
|
||||
:class: standard
|
||||
|
||||
This is a standard note.
|
||||
|
||||
.. note::
|
||||
:collapsible:
|
||||
|
||||
This note is collapsible, and initially open by default.
|
||||
|
||||
.. admonition:: Example
|
||||
:collapsible: open
|
||||
|
||||
This example is collapsible, and initially open.
|
||||
|
||||
.. hint::
|
||||
:collapsible: closed
|
||||
|
||||
This hint is collapsible, but initially closed.
|
||||
@@ -715,3 +715,47 @@ def test_html_pep_695_trailing_comma_in_multi_line_signatures(app):
|
||||
r'.//dt[@id="MyList"][1]',
|
||||
chk('class MyList[\nT\n](list[T])'),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='directives-admonition-collapse')
|
||||
def test_html_admonition_collapse(app):
|
||||
app.build()
|
||||
fname = app.outdir / 'index.html'
|
||||
etree = etree_parse(fname)
|
||||
|
||||
def _create_check(text: str, open: bool): # type: ignore[no-untyped-def]
|
||||
def _check(els):
|
||||
assert len(els) == 1
|
||||
el = els[0]
|
||||
if open:
|
||||
assert el.attrib['open'] == 'open'
|
||||
else:
|
||||
assert 'open' not in el.attrib
|
||||
assert el.find('p').text == text
|
||||
|
||||
return _check
|
||||
|
||||
check_xpath(
|
||||
etree,
|
||||
fname,
|
||||
r'.//div[@class="standard admonition note"]//p',
|
||||
'This is a standard note.',
|
||||
)
|
||||
check_xpath(
|
||||
etree,
|
||||
fname,
|
||||
r'.//details[@class="admonition note"]',
|
||||
_create_check('This note is collapsible, and initially open by default.', True),
|
||||
)
|
||||
check_xpath(
|
||||
etree,
|
||||
fname,
|
||||
r'.//details[@class="admonition-example admonition"]',
|
||||
_create_check('This example is collapsible, and initially open.', True),
|
||||
)
|
||||
check_xpath(
|
||||
etree,
|
||||
fname,
|
||||
r'.//details[@class="admonition hint"]',
|
||||
_create_check('This hint is collapsible, but initially closed.', False),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user