Skip to content
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
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
[![Publish Badge](https://github.com/tuunit/mkdocs-drawio/workflows/Publish/badge.svg)](https://github.com/tuunit/mkdocs-drawio/actions)
[![PyPI](https://img.shields.io/pypi/v/mkdocs-drawio)](https://pypi.org/project/mkdocs-drawio/)

Sergey ([onixpro](https://github.com/onixpro)) is the original creator of this plugin but since his repository isn't maintained anymore we forked it on the 19th December of 2023 and have been keeping it up-to-date and expanding on the features since then.
[Buy Sergey a ☕](https://www.buymeacoffee.com/SergeyLukin)
Sergey ([onixpro](https://github.com/onixpro)) is the original creator of this plugin but since his repository isn't maintained anymore we forked it on the 19th December of 2023 and have been keeping it up-to-date and expanding on the features since then.
[Buy Sergey a ☕](https://www.buymeacoffee.com/SergeyLukin)

## Features

Expand Down Expand Up @@ -39,6 +39,8 @@ Or use the page attribute:
![Bar Diagram](my-diagram.drawio){ page="my-custom-page-name" }
```

If you prefer to keep the caption purely descriptive, set `use_page_attribute: true` in your plugin configuration. When enabled, the plugin no longer uses the alt text for page selection and instead expects the `page` attribute provided by the `attr_list` markdown extension.

## Setup

Install plugin using pip:
Expand Down Expand Up @@ -66,16 +68,34 @@ plugins:
viewer_js: "https://viewer.diagrams.net/js/viewer-static.min.js"
```

Further options are:
Further options are the following, with their default value:

```yaml
plugins:
- drawio:
toolbar: true # control if hovering on a diagram shows a toolbar for zooming or not (default: true)
tooltips: true # control if tooltips will be shown (default: true)
edit: true # control if edit button will be shown in the lightbox view (default: true)
border: 10 # increase or decrease the border / margin around your diagrams (default: 0)
darkmode: true # support darkmode. allows for automatic switching between dark and lightmode based on the theme toggle. (default: false)
# control if hovering on a diagram shows a
# toolbar for zooming or not
toolbar: true

# control if tooltips will be shown
tooltips: true

# control if edit button will be shown in the
# lightbox view
edit: true

# increase or decrease the border / margin around your diagrams
border: 0

# support darkmode. allows for automatic switching
# between dark and lightmode based on the theme toggle.
darkmode: false

# treat the image caption as the diagram page name.
# Set to true to use the attr_list 'page' attribute instead.
# this option is not enabled by default to maintain backward
# compatibility.
use_page_attribute: false
```

## Material Integration
Expand Down
35 changes: 23 additions & 12 deletions examples/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,35 @@ Further options are the following with their default value:
```yaml
plugins:
- drawio:
# Control if hovering on a diagram shows a toolbar for zooming or not
# control if hovering on a diagram shows a
# toolbar for zooming or not
toolbar: true

# Control if tooltips will be shown (data-tooltips)
# control if tooltips will be shown
tooltips: true

# Increase or decrease the padding around your diagrams
# (data-border)
border: 5

# Control if edit button will be shown in the lightbox view
# (data-edit)
# control if edit button will be shown in the
# lightbox view
edit: true

# Control if darkmode is supported
# When activated the color scheme for your diagrams is automatically toggled
# based on the selected theme. Supports classic mkdocs and mkdocs-material.
darkmode: true
# increase or decrease the border / margin around your diagrams
border: 0

# support darkmode. allows for automatic switching
# between dark and lightmode based on the theme toggle.
darkmode: false

# treat the image caption as the diagram page name.
# Set to true to use the attr_list 'page' attribute instead.
# this option is not enabled by default to maintain backward
# compatibility.
use_page_attribute: false
```

## HTML Attributes

For each global configuration option you can also use the attribute in the diagram itself. This will override the global configuration. Here is an example:

```markdown
![](my-diagram.drawio){ data-toolbar-zoom="false" }
```
Expand All @@ -46,6 +54,9 @@ To use these attributes you need to enable the markdown extension `attr_list` in
markdown_extensions:
- attr_list
```

> Note: When `use_page_attribute` is set to `true`, enabling the `attr_list` extension becomes mandatory because page selection is driven exclusively through the `page` attribute.

## Material Integration

If you are using the Material Theme and want to use the [instant-loading](https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/?h=instant#instant-loading) feature. You will have to configure the following:
Expand Down
20 changes: 17 additions & 3 deletions examples/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

This plugin allows you to embed draw.io diagrams in your MkDocs documentation. It is compatible with most MkDocs themes, but specifically tested with the Material theme and the MkDocs default theme.

Sergey ([onixpro](https://github.com/onixpro)) is the original creator of this plugin but since his repository isn't maintained anymore we forked it on the 19th December of 2023 and have been keeping it up-to-date and expanding on the features since then.
[Buy Sergey a ☕](https://www.buymeacoffee.com/SergeyLukin)
Sergey ([onixpro](https://github.com/onixpro)) is the original creator of this plugin but since his repository isn't maintained anymore we forked it on the 19th December of 2023 and have been keeping it up-to-date and expanding on the features since then.
[Buy Sergey a ☕](https://www.buymeacoffee.com/SergeyLukin)

## Installation

Expand Down Expand Up @@ -57,9 +57,23 @@ Or you can use external urls:
![](https://example.com/diagram.drawio)
```

Additionally this plugin supports multi page diagrams by using the `alt` text to select the pages by name:
Additionally this plugin supports multi page diagrams by using the `alt` text (caption) to select the pages by name. This behaviour is controlled by the `use_page_attribute` configuration option, which is set to `false` by default.

```markdown
![Page-2](my-diagram.drawio)
![my-custom-page-name](my-diagram.drawio)
```

If you prefer to keep the caption descriptive and select pages via attributes instead, disable the option in your `mkdocs.yml`:

```yaml
plugins:
- drawio:
use_page_attribute: false
```

With the option disabled, enable the `attr_list` markdown extension and use the `page` attribute:

```markdown
![Diagram caption](my-diagram.drawio){ page="Page-2" }
```
8 changes: 5 additions & 3 deletions examples/docs/tests/pagging/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Pagging

You can either use the `alt` text of the image for pagging or use an attribute
page for pagging if you have the `attr_list` markdown extension installed in
page for pagging if you have the `attr_list` markdown extension installed in
your `mkdocs.yaml`.

> By default the plugin uses the caption (`alt` text) as the page selector. Set `use_page_attribute: true` in your plugin configuration if you always want to rely on the `page` attribute instead.

```yaml
markdown_extensions:
- attr_list
Expand Down Expand Up @@ -47,9 +49,9 @@ markdown_extensions:
=== "Diagram"
Below you should see Page-1 (default) because the specified Page-3 has not been found:
![Page-3](test.drawio)

Furthoremore, you should see a warning in your mkdocs server similar to:

```bash
WARNING - Warning: Found 0 results for page name 'Page-3' for diagram 'test.drawio' on path '/tmp/mkdocs_ce1qjhyn/test2'
```
Expand Down
80 changes: 57 additions & 23 deletions mkdocs_drawio/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from mkdocs.utils import copy_file
from mkdocs.plugins import BasePlugin
from mkdocs.config import base, config_options as c
from mkdocs.exceptions import ConfigurationError

SUB_TEMPLATE = string.Template(
'<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="$config"></div>'
Expand All @@ -29,6 +30,7 @@ class DrawioConfig(base.Config):
border = c.Type(int, default=0)
edit = c.Type(bool, default=True)
darkmode = c.Type(bool, default=False)
use_page_attribute = c.Type(bool, default=False)


class DrawioPlugin(BasePlugin[DrawioConfig]):
Expand Down Expand Up @@ -74,10 +76,9 @@ def render_drawio_diagrams(self, output_content, page):
"html.parser",
)
else:
diagram_page = diagram["alt"]
# Use page attribute instead of alt if it is set
if "page" in diagram:
diagram_page = diagram["page"]
diagram_page = diagram.get(
"page" if self.config.use_page_attribute else "alt"
)
mxgraph = BeautifulSoup(
DrawioPlugin.substitute_with_file(
diagram_config, path, diagram["src"], diagram_page
Expand All @@ -96,51 +97,62 @@ def substitute_with_url(config: Dict, url: str) -> str:
return SUB_TEMPLATE.substitute(config=escape(json.dumps(config)))

@staticmethod
def substitute_with_file(config: Dict, path: Path, src: str, alt: str) -> str:
def substitute_with_file(config: Dict, path: Path, src: str, page: str) -> str:
try:
diagram_xml = etree.parse(path.joinpath(src).resolve())
except Exception:
LOGGER.error(
f"Error: Provided diagram file '{src}' on path '{path}' is not a valid diagram"
f"Error: Provided diagram file '{src}' on path "
f"'{path}' is not a valid diagram"
)
diagram_xml = etree.fromstring("<invalid/>")

diagram = DrawioPlugin.parse_diagram(diagram_xml, alt)
diagram = DrawioPlugin.parse_diagram(diagram_xml, page, src, path)
config["xml"] = diagram

return SUB_TEMPLATE.substitute(config=escape(json.dumps(config)))

@staticmethod
def parse_diagram(data, alt, src="", path=None) -> str:
if alt is None or len(alt) == 0:
def parse_diagram(data, page, src="", path=None) -> str:
if page is None or len(page) == 0:
return etree.tostring(data, encoding=str)

try:
mxfile = data.xpath("//mxfile")[0]

# try to parse for a specific page by using the alt attribute
page = mxfile.xpath(f"//diagram[@name='{alt}']")
# try to parse for a specific page by using the page attribute
pages = mxfile.xpath(f"//diagram[@name='{page}']")

if len(page) == 1:
parser = etree.XMLParser()
result = parser.makeelement(mxfile.tag, mxfile.attrib)

result.append(page[0])
return etree.tostring(result, encoding=str)
else:
if len(pages) > 1:
LOGGER.warning(
f"Warning: Found {len(page)} results for page name '{alt}' for diagram '{src}' on path '{path}'"
f"Warning: Found multiple ({len(pages)}) pages with "
f"same name '{page}' in diagram '{src}' "
f"on path '{path}', using first one."
)
return etree.tostring(mxfile, encoding=str)

parser = etree.XMLParser()
result = parser.makeelement(mxfile.tag, mxfile.attrib)

result.append(pages[0])
return etree.tostring(result, encoding=str)

return etree.tostring(mxfile, encoding=str)
except Exception:
LOGGER.error(
f"Error: Could not properly parse page name '{alt}' for diagram '{src}' on path '{path}'"
"Error: Could not properly parse page name "
f"'{page}' for diagram '{src}' on path '{path}'"
)
return ""

def on_config(self, config: base.Config):
"""Load embedded files"""
if not self.config.use_page_attribute and not self._has_attr_list_extension(
config.get("markdown_extensions", [])
):
raise ConfigurationError(
"The markdown extension 'attr_list' must be enabled "
"when 'use_page_attribute' is set to false."
)

self.base = Path(__file__).parent
self.css = []
self.js = []
Expand All @@ -154,8 +166,30 @@ def on_config(self, config: base.Config):
for path in self.js:
config.extra_javascript.append(str(path))

def on_post_build(self, config: base.Config):
def on_post_build(self, config: base.Config) -> None:
"""Copy embedded files to the site directory"""
site = Path(config["site_dir"])
for path in self.css + self.js:
copy_file(self.base / path, site / path)

@staticmethod
def _has_attr_list_extension(extensions) -> bool:
for extension in extensions:
name = DrawioPlugin._get_extension_name(extension)
normalized = name.lower()
if normalized in {
"attr_list",
"attrlist",
"markdown.extensions.attr_list",
"markdown.extensions.attrlist",
}:
return True
return False

@staticmethod
def _get_extension_name(extension) -> str:
if isinstance(extension, str):
return extension
if isinstance(extension, dict) and extension:
return next(iter(extension.keys()))
return ""
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ black = ">=24.0"
ruff = "^0.9.2"
mkdocs-print-site-plugin = "^2.6.0"
mkdocs-material = "^9.5.50"
mkdocs = "^1.6.1"
lxml = "^6.0.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down