11import re
2+ import json
23import mkdocs
34import string
45import logging
56from lxml import etree
7+ from typing import Dict
8+ from html import escape
69from pathlib import Path
710from bs4 import BeautifulSoup
811from mkdocs .plugins import BasePlugin
1114# Constants and utilities
1215# ------------------------
1316SUB_TEMPLATE = string .Template (
14- '<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{"highlight":"#0000ff","nav":true,"resize":true,"toolbar":"zoom layers tags lightbox","edit":"_blank","xml":"$xml_drawio"} "></div>'
17+ '<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="$config "></div>'
1518)
1619
1720LOGGER = logging .getLogger ("mkdocs.plugins.diagrams" )
@@ -25,26 +28,31 @@ class DrawioPlugin(BasePlugin):
2528 """
2629
2730 config_scheme = (
28- (
29- "viewer_js" ,
30- mkdocs .config .config_options .Type (
31- str , default = "https://viewer.diagrams.net/js/viewer-static.min.js"
32- ),
33- ),
31+ ("viewer_js" ,mkdocs .config .config_options .Type (str , default = "https://viewer.diagrams.net/js/viewer-static.min.js" )),
32+ ("toolbar" ,mkdocs .config .config_options .Type (bool , default = True )),
33+ ("tooltips" ,mkdocs .config .config_options .Type (bool , default = True )),
34+ ("border" ,mkdocs .config .config_options .Type (int , default = 0 )),
3435 )
3536
3637 def on_post_page (self , output_content , config , page , ** kwargs ):
3738 return self .render_drawio_diagrams (output_content , page )
3839
3940 def render_drawio_diagrams (self , output_content , page ):
4041 if ".drawio" not in output_content .lower ():
41- # Skip unecessary HTML parsing
4242 return output_content
4343
4444 plugin_config = self .config .copy ()
4545
4646 soup = BeautifulSoup (output_content , "html.parser" )
4747
48+ diagram_config = {
49+ "toolbar" : "zoom" if plugin_config ["toolbar" ] else None ,
50+ "tooltips" : "1" if plugin_config ["tooltips" ] else "0" ,
51+ "border" : plugin_config ["border" ] + 5 ,
52+ "resize" : "1" ,
53+ "edit" : "_blank" ,
54+ }
55+
4856 # search for images using drawio extension
4957 diagrams = soup .findAll ("img" , src = re .compile (r".*\.drawio$" , re .IGNORECASE ))
5058 if len (diagrams ) == 0 :
@@ -57,31 +65,44 @@ def render_drawio_diagrams(self, output_content, page):
5765 # substitute images with embedded drawio diagram
5866 path = Path (page .file .abs_dest_path ).parent
5967
68+
6069 for diagram in diagrams :
61- diagram . replace_with (
62- BeautifulSoup (
63- DrawioPlugin .substitute_image ( path , diagram ["src" ], diagram [ "alt " ]),
70+ if re . search ( "^https?://" , diagram [ "src" ]):
71+ mxgraph = BeautifulSoup (
72+ DrawioPlugin .substitute_with_url ( diagram_config , diagram ["src" ]),
6473 "html.parser" ,
6574 )
66- )
75+ else :
76+ mxgraph = BeautifulSoup (
77+ DrawioPlugin .substitute_with_file (diagram_config , path , diagram ["src" ], diagram ["alt" ]),
78+ "html.parser" ,
79+ )
80+
81+ diagram .replace_with (mxgraph )
6782
6883 return str (soup )
6984
7085 @staticmethod
71- def substitute_image (path : Path , src : str , alt : str ):
86+ def substitute_with_url (config : Dict , url : str ) -> str :
87+ config ["url" ] = url
88+
89+ return SUB_TEMPLATE .substitute (config = escape (json .dumps (config )))
90+
91+ @staticmethod
92+ def substitute_with_file (config : Dict , path : Path , src : str , alt : str ) -> str :
7293 try :
7394 diagram_xml = etree .parse (path .joinpath (src ).resolve ())
7495 except Exception :
7596 LOGGER .error (f"Error: Provided diagram file '{ src } ' on path '{ path } ' is not a valid diagram" )
7697 diagram_xml = etree .fromstring ('<invalid/>' )
7798
78- diagram = DrawioPlugin .parse_diagram (diagram_xml , alt , src , path )
79- escaped_xml = DrawioPlugin . escape_diagram ( diagram )
99+ diagram = DrawioPlugin .parse_diagram (diagram_xml , alt )
100+ config [ "xml" ] = diagram
80101
81- return SUB_TEMPLATE .substitute (xml_drawio = escaped_xml )
102+ return SUB_TEMPLATE .substitute (config = escape ( json . dumps ( config )) )
82103
83104 @staticmethod
84- def parse_diagram (data , alt , src = "" , path = None ):
105+ def parse_diagram (data , alt , src = "" , path = None ) -> str :
85106 if alt is None or len (alt ) == 0 :
86107 return etree .tostring (data , encoding = str )
87108
@@ -104,13 +125,3 @@ def parse_diagram(data, alt, src="", path=None):
104125 except Exception :
105126 LOGGER .error (f"Error: Could not properly parse page name '{ alt } ' for diagram '{ src } ' on path '{ path } '" )
106127 return ""
107-
108- @staticmethod
109- def escape_diagram (str_xml : str ):
110- str_xml = str_xml .replace ("&" , r"&" )
111- str_xml = str_xml .replace ("<" , r"<" )
112- str_xml = str_xml .replace (">" , r">" )
113- str_xml = str_xml .replace ('"' , r"\"" )
114- str_xml = str_xml .replace ("'" , r"'" )
115- str_xml = str_xml .replace ("\n " , r"" )
116- return str_xml
0 commit comments