Skip to content

Commit

Permalink
add mermaidjs 10.2.3 (#1957)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Steven Silvester <steven.silvester@ieee.org>
  • Loading branch information
3 people committed Jun 13, 2023
1 parent 4a9d589 commit 3dd3a67
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 0 deletions.
10 changes: 10 additions & 0 deletions nbconvert/exporters/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ class HTMLExporter(TemplateExporter):
""",
).tag(config=True)

mermaid_js_url = Unicode(
"https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.2.3/mermaid.esm.min.mjs",
help="""
URL to load MermaidJS from.
Defaults to loading from cdnjs.
""",
)

jquery_url = Unicode(
"https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js",
help="""
Expand Down Expand Up @@ -303,6 +312,7 @@ def resources_include_url(name):
resources["include_url"] = resources_include_url
resources["require_js_url"] = self.require_js_url
resources["mathjax_url"] = self.mathjax_url
resources["mermaid_js_url"] = self.mermaid_js_url
resources["jquery_url"] = self.jquery_url
resources["jupyter_widgets_base_url"] = self.jupyter_widgets_base_url
resources["widget_renderer_url"] = self.widget_renderer_url
Expand Down
12 changes: 12 additions & 0 deletions nbconvert/filters/markdown_mistune.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ def block_code(self, code, info=None):
"""Handle block code."""
lang = ""
lexer = None

if info and info.startswith("mermaid"):
return self.block_mermaidjs(code)

if info:
try:
lang = info.strip().split(None, 1)[0]
Expand All @@ -190,6 +194,14 @@ def block_code(self, code, info=None):
formatter = HtmlFormatter()
return highlight(code, lexer, formatter)

def block_mermaidjs(self, code, info=None):
"""Handle mermaid syntax."""
return (
"""<div class="jp-Mermaid"><pre class="mermaid">\n"""
f"""{code.strip()}"""
"""\n</pre></div>"""
)

def block_html(self, html):
"""Handle block html."""
if self.embed_images:
Expand Down
13 changes: 13 additions & 0 deletions nbconvert/filters/tests/test_markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,19 @@ def test_markdown2rst(self):
tokens[index],
)

def test_mermaid_markdown(self):
code = """flowchart LR
chicken --> egg --> chicken"""
case = f"""```mermaid\n {code}\n```"""

output_check = (
"""<div class="jp-Mermaid"><pre class="mermaid">\n"""
f"""{code.strip()}"""
"""\n</pre></div>"""
)

self._try_markdown(markdown2html, case, output_check)

def _try_markdown(self, method, test, tokens):
results = method(test)
if isinstance(tokens, (str,)):
Expand Down
6 changes: 6 additions & 0 deletions share/templates/classic/index.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
{%- block html_head_js_requirejs -%}
<script src="{{ resources.require_js_url }}"></script>
{%- endblock html_head_js_requirejs -%}
{%- block html_head_js_mermaidjs -%}
<script type="module">
import mermaid from '{{ resources.mermaid_js_url }}';
mermaid.initialize({ startOnLoad: true });
</script>
{%- endblock html_head_js_mermaidjs -%}
{%- endblock html_head_js -%}

{% block jupyter_widgets %}
Expand Down
5 changes: 5 additions & 0 deletions share/templates/lab/index.html.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{%- extends 'base.html.j2' -%}
{% from 'mathjax.html.j2' import mathjax %}
{% from 'mermaidjs.html.j2' import mermaid_js %}
{% from 'jupyter_widgets.html.j2' import jupyter_widgets %}

{%- block header -%}
Expand Down Expand Up @@ -149,6 +150,10 @@ body[data-format='mobile'] .jp-OutputArea-child .jp-OutputArea-output {
{{ mathjax(resources.mathjax_url) }}
{%- endblock html_head_js_mathjax -%}

{%- block html_head_js_mermaidjs -%}
{{ mermaid_js(resources.mermaid_js_url) }}
{%- endblock html_head_js_mermaidjs -%}

{%- block html_head_css -%}
{%- endblock html_head_css -%}

Expand Down
114 changes: 114 additions & 0 deletions share/templates/lab/mermaidjs.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
{%- macro mermaid_js(
url="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.0.2/mermaid.esm.min.mjs"
) -%}
<script type="module">
document.addEventListener("DOMContentLoaded", async () => {
const diagrams = document.querySelectorAll(".jp-Mermaid > pre.mermaid");
// do not load mermaidjs if not needed
if (!diagrams.length) {
return;
}
const mermaid = (await import("{{ url }}")).default;
mermaid.initialize({
maxTextSize: 100000,
startOnLoad: false,
fontFamily: window
.getComputedStyle(document.body)
.getPropertyValue("--jp-ui-font-family"),
theme: document.querySelector("body[data-jp-theme-light='true']")
? "default"
: "dark",
});
let _nextMermaidId = 0;
function makeMermaidImage(svg) {
const img = document.createElement('img');
const maxWidth = svg.match(/max-width: (\d+)/);
if (maxWidth && maxWidth[1]) {
const width = parseInt(maxWidth[1]);
if (width && !Number.isNaN(width) && Number.isFinite(width)) {
img.width = width;
}
}
img.setAttribute('src', `data:image/svg+xml,${encodeURIComponent(svg)}`);
return img;
}
async function makeMermaidError(text) {
let errorMessage = '';
try {
await mermaid.parse(text);
} catch (err) {
errorMessage = `${err}`;
}
const result = document.createElement('details');
const summary = document.createElement('summary');
const pre = document.createElement('pre');
const code = document.createElement('code');
code.innerText = text;
pre.appendChild(code);
summary.appendChild(pre);
result.appendChild(summary);
const warning = document.createElement('pre');
warning.innerText = errorMessage;
result.appendChild(warning);
return result;
}
async function renderOneMarmaid(src) {
const id = `jp-mermaid-${_nextMermaidId++}`;
const parent = src.parentNode;
let raw = src.textContent.trim();
const el = document.createElement("div");
el.style.visibility = "hidden";
document.body.appendChild(el);
let result = null;
try {
const { svg } = await mermaid.render(id, raw, el);
result = makeMermaidImage(svg);
} catch (err) {
parent.classList.add("jp-mod-warning");
result = await makeMermaidError(raw);
} finally {
el.remove();
}
parent.classList.add("jp-RenderedMermaid");
parent.appendChild(result);
}
void Promise.all([...diagrams].map(renderOneMarmaid));
});
</script>
<style>
.jp-RenderedMarkdown .jp-Mermaid:not(.jp-RenderedMermaid) {
display: none;
}
.jp-RenderedMarkdown .jp-RenderedMermaid.jp-mod-warning {
width: auto;
padding: 10px;
border: var(--jp-border-width) solid var(--jp-warn-color2);
border-radius: var(--jp-border-radius);
color: var(--jp-ui-font-color1);
font-size: var(--jp-ui-font-size1);
white-space: pre-wrap;
word-wrap: break-word;
}
.jp-RenderedMarkdown .jp-RenderedMermaid.jp-mod-warning details > pre {
margin-top: 1em;
}
.jp-RenderedMarkdown .jp-RenderedMermaid.jp-mod-warning summary {
color: var(--jp-warn-color2);
}
.jp-RenderedMarkdown .jp-RenderedMermaid.jp-mod-warning summary > pre {
display: inline-block;
}
.jp-RenderedMermaid > .mermaid {
display: none;
}
</style>
<!-- End of mermaid configuration -->
{%- endmacro %}
6 changes: 6 additions & 0 deletions share/templates/reveal/index.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
{%- block html_head_js_requirejs -%}
<script src="{{ resources.require_js_url }}"></script>
{%- endblock html_head_js_requirejs -%}
{%- block html_head_js_mermaidjs -%}
<script type="module">
import mermaid from '{{ resources.mermaid_js_url }}';
mermaid.initialize({ startOnLoad: true });
</script>
{%- endblock html_head_js_mermaidjs -%}
{%- endblock html_head_js -%}

{% block jupyter_widgets %}
Expand Down

0 comments on commit 3dd3a67

Please sign in to comment.