Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Escape markmap source to avoid conflicts with other plugins #63

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*]
indent_style = space
indent_size = 4
quote_type = double
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ plugins:
encoding: utf-8
file_extension: .mm.md
d3_version: 7
lib_version: 0.15.3
view_version: 0.15.3
lib_version: 0.18
view_version: 0.18
```

In addition, feel free to define your favourite source urls like this:
Expand All @@ -89,8 +89,8 @@ plugins:

extra_javascript:
- https://unpkg.com/d3@7/dist/d3.min.js
- https://unpkg.com/markmap-lib@0.15.3/dist/browser/index.js
- https://unpkg.com/markmap-view@0.15.3/dist/browser/index.js
- https://unpkg.com/markmap-lib@0.18/dist/browser/index.iife.js
- https://unpkg.com/markmap-view@0.18/dist/browser/index.js
```

## Troubleshooting
Expand Down
4 changes: 2 additions & 2 deletions mkdocs_markmap/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ class JsModuleConfig(object):
)

MARKMAP_LIB: JsModuleConfig = JsModuleConfig(
version="0.15.4",
version="0.18",
uri="https://unpkg.com/markmap-lib@{}",
)

MARKMAP_VIEW: JsModuleConfig = JsModuleConfig(
version="0.15.4",
version="0.18",
uri="https://unpkg.com/markmap-view@{}",
)

Expand Down
23 changes: 13 additions & 10 deletions mkdocs_markmap/extension.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import base64
import logging
import re
from functools import partial
Expand Down Expand Up @@ -49,29 +50,31 @@ def run(self, lines: List[str]) -> List[str]:
included_paths.append(path)
try:
with open(path, "r", encoding=self.encoding) as r:
markmap: List[str] = r.readlines()
markmap = r.read()

except Exception as e:
log.error("unable to include file {}. Ignoring statement. Error: {}".format(path, e))
lines[loc] = INCLUDE_SYNTAX.sub("",line)
break

line_split: List[str] = INCLUDE_SYNTAX.split(line)
output: List[str] = []
if len(markmap) == 0:
markmap.append("")
output.append("")
else:
markmap.insert(0, "```markmap")
markmap.append("```")

output.append('<pre class="language-markmap"><code encoding="base64">')
output.append(base64.b64encode(markmap.encode()).decode())
output.append("</code></pre>")

if line_split[0].strip() != "":
markmap.insert(0, line_split[0])
output.insert(0, line_split[0])

if line_split[2].strip() != "":
markmap.append(line_split[2])
output.append(line_split[2])

lines = lines[:loc] + markmap + lines[loc+1:]
lines = lines[:loc] + output + lines[loc+1:]
break

else:
done = True

Expand Down
8 changes: 6 additions & 2 deletions mkdocs_markmap/plugin.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import base64
import logging
from pathlib import Path
import re
from typing import Dict, Tuple

from bs4 import BeautifulSoup, ResultSet, Tag

from mkdocs.config.base import Config, load_config
from mkdocs.config.config_options import Type as PluginType
from mkdocs.plugins import BasePlugin
from mkdocs.structure.pages import Page

from mkdocs_markmap.extension import MarkmapExtension

from .defaults import MARKMAP
Expand Down Expand Up @@ -116,7 +117,6 @@ def on_page_content(self, html: str, page: Page, **kwargs) -> str:

for index, markmap in enumerate(markmaps):
markmap: Tag
tag_id: str = f"markmap-{index}"
pre: Tag
code: Tag
if markmap.name == "pre":
Expand All @@ -129,5 +129,9 @@ def on_page_content(self, html: str, page: Page, **kwargs) -> str:
pre["class"] = pre.get("class", []) + ["mkdocs-markmap"]
code.name = "markmap-data"
code.attrs["hidden"] = "true"
if not code.attrs.get("encoding"):
# Encode content as base64 to avoid being handled by other plugins like KaTeX
code.attrs["encoding"] = "base64"
code.string = base64.b64encode(code.get_text().strip().encode()).decode()

return str(soup)
49 changes: 32 additions & 17 deletions mkdocs_markmap/static_files/mkdocs-markmap.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,68 @@
(function initializeMarkmap() {
const transformer = new markmap.Transformer();
const preloadAssets = transformer.getPreloadScripts();
const assets = transformer.getAssets();
const loading = Promise.all([
assets.styles && markmap.loadCSS(assets.styles),
assets.scripts && markmap.loadJS(assets.scripts),
markmap.loadJS([...preloadAssets.scripts, ...assets.scripts]),
]);

function parseData(content) {
const { root, frontmatter } = transformer.transform(content);
let options = markmap.deriveOptions(frontmatter?.markmap);
options = Object.assign({
fitRatio: 0.85,
}, options);
options = Object.assign(
{
fitRatio: 0.85,
},
options
);
return { root, options };
}

function resetMarkmap(m, el) {
const { minX, maxX, minY, maxY } = m.state;
const height = el.clientWidth * (maxX - minX) / (maxY - minY);
if (!m.state.rect) return;
const { x1, y1, x2, y2 } = m.state.rect;
const height = (el.offsetWidth / (x2 - x1)) * (y2 - y1);
el.style.height = height + "px";
m.fit();
}

function decodeBase64(encoded) {
const binary = atob(encoded);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return new TextDecoder().decode(bytes);
}

function renderMarkmap(el) {
let svg = el.querySelector('svg');
if (svg) return;
const content = el.textContent;
el.innerHTML = '<svg>';
const dataEl = el.querySelector("markmap-data");
if (!dataEl) return;
let content = el.textContent;
if (dataEl.getAttribute("encoding") === "base64") {
content = decodeBase64(content);
}
el.innerHTML = "<svg>";
svg = el.firstChild;
const { root, options } = parseData(content);
const m = markmap.Markmap.create(svg, options, root);
resetMarkmap(m, el);
transformer.hooks.retransform.tap(() => {
const { root, options } = parseData(content);
m.setData(root, options);
const m = markmap.Markmap.create(svg, options);
m.setData(root);
requestAnimationFrame(() => {
resetMarkmap(m, el);
});
}

function updateMarkmaps(node) {
for (const el of node.querySelectorAll('.mkdocs-markmap')) {
for (const el of node.querySelectorAll(".mkdocs-markmap")) {
renderMarkmap(el);
}
}

loading.then(() => {
const observer = new MutationObserver((mutationList) => {
for (const mutation of mutationList) {
if (mutation.type === 'childList') {
if (mutation.type === "childList") {
for (const node of mutation.addedNodes) {
updateMarkmaps(node);
}
Expand Down
Loading