Skip to content

Commit

Permalink
Replace bootstrap alert-info/warning <div>s with custom admonitions (#47
Browse files Browse the repository at this point in the history
)

This is an experimental work-around feature!

See also #46.
  • Loading branch information
mgeier committed Apr 27, 2016
1 parent 608df67 commit db86484
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 4 deletions.
52 changes: 50 additions & 2 deletions doc/markdown-cells.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,56 @@
"\n",
"The alternative text is shown in browsers that don't support those elements. The same text is also shown in Sphinx's LaTeX output.\n",
"\n",
"> **Note:** You can also use local files for the `<audio>` and `<video>` elements, but you have to create a link to the source file somewhere, because only then are the local files copied to the HTML output directory!\n",
"You should do that anyway to make the audio/video file accessible to browsers that don't support the `<audio>` and `<video>` elements."
"<div class=\"alert alert-info\">\n",
"\n",
"**Note:** You can also use local files for the `<audio>` and `<video>` elements, but you have to create a link to the source file somewhere, because only then are the local files copied to the HTML output directory!\n",
"You should do that anyway to make the audio/video file accessible to browsers that don't support the `<audio>` and `<video>` elements.\n",
"\n",
"</div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Info/Warning Boxes\n",
"\n",
"<div class=\"alert alert-warning\">\n",
"\n",
"**Warning:** This is an *experimental feature*!\n",
"\n",
"Its usage will probably change in the future or it might be removed completely!\n",
"\n",
"</div>\n",
"\n",
"Until there is an info/warning extension for Markdown/CommonMark (see [this issue](https://github.com/jupyter/notebook/issues/1292)), such boxes can be created by using HTML `<div>` elements like this:\n",
"\n",
"```html\n",
"<div class=\"alert alert-info\">\n",
"\n",
"**Note:** This is a note!\n",
"\n",
"</div>\n",
"```\n",
"\n",
"For this to work reliably, you should obey the following guidelines:\n",
"\n",
"* The `class` attribute has to be either `\"alert alert-info\"` or `\"alert alert-warning\"`, other values will not be converted correctly.\n",
"* No further attributes are allowed.\n",
"* For compatibility with CommonMark, you should add an empty line between the `<div>` start tag and the beginning of the content.\n",
"\n",
"<div class=\"alert alert-info\">\n",
"\n",
"**Note:** The text can contain further Markdown formatting.\n",
"\n",
"It is even possible to have nested boxes:\n",
"\n",
"<div class=\"alert alert-warning\">\n",
"\n",
"... but please don't *overuse* this!\n",
"\n",
"</div>\n",
"</div>"
]
},
{
Expand Down
58 changes: 56 additions & 2 deletions nbsphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,8 @@ class NotebookParser(rst.Parser):

def get_transforms(self):
"""List of transforms for documents parsed by this parser."""
return rst.Parser.get_transforms(self) + [ProcessLocalLinks,
CreateSectionLabels]
return rst.Parser.get_transforms(self) + [
ProcessLocalLinks, CreateSectionLabels, ReplaceAlertDivs]

def parse(self, inputstring, document):
"""Parse `inputstring`, write results to `document`."""
Expand Down Expand Up @@ -836,6 +836,60 @@ def apply(self):
i_still_have_to_create_the_notebook_label = False


class ReplaceAlertDivs(docutils.transforms.Transform):
"""Replace certain <div> elements with AdmonitionNode containers.
This is a quick-and-dirty work-around until a proper
Mardown/CommonMark extension for note/warning boxes is available.
"""

default_priority = 500 # Doesn't really matter

_start_re = re.compile(
r'\s*<div\s*class\s*=\s*(?P<q>"|\')([a-z\s-]*)(?P=q)\s*>\s*\Z',
flags=re.IGNORECASE)
_class_re = re.compile(r'\s*alert\s*alert-(info|warning)\s*\Z')
_end_re = re.compile(r'\s*</div\s*>\s*\Z', flags=re.IGNORECASE)

def apply(self):
start_tags = []
for node in self.document.traverse(docutils.nodes.raw):
if node['format'] != 'html':
continue
start_match = self._start_re.match(node.astext())
if not start_match:
continue
class_match = self._class_re.match(start_match.group(2))
if not class_match:
continue
admonition_class = class_match.group(1)
if admonition_class == 'info':
admonition_class = 'note'
start_tags.append((node, admonition_class))

# Reversed order to allow nested <div> elements:
for node, admonition_class in reversed(start_tags):
content = []
for sibling in node.traverse(include_self=False, descend=False,
siblings=True, ascend=False):
end_tag = (isinstance(sibling, docutils.nodes.raw) and
sibling['format'] == 'html' and
self._end_re.match(sibling.astext()))
if end_tag:
admonition_node = AdmonitionNode(
classes=['admonition', admonition_class])
admonition_node.extend(content)
parent = node.parent
parent.replace(node, admonition_node)
for n in content:
parent.remove(n)
parent.remove(sibling)
break
else:
content.append(sibling)


def builder_inited(app):
"""Add color definitions to LaTeX preamble."""
latex_elements = app.builder.config.latex_elements
Expand Down

0 comments on commit db86484

Please sign in to comment.