11import { isDarkTheme } from '../utils.ts' ;
22import { makeCodeCopyButton } from './codecopy.ts' ;
33import { displayError } from './common.ts' ;
4+ import { queryElems } from '../utils/dom.ts' ;
45
56const { mermaidMaxSourceCharacters} = window . config ;
67
@@ -11,77 +12,77 @@ body {margin: 0; padding: 0; overflow: hidden}
1112blockquote, dd, dl, figure, h1, h2, h3, h4, h5, h6, hr, p, pre {margin: 0}` ;
1213
1314export async function initMarkupCodeMermaid ( elMarkup : HTMLElement ) : Promise < void > {
14- const el = elMarkup . querySelector ( 'code.language-mermaid' ) ; // .markup code.language-mermaid
15- if ( ! el ) return ;
16-
17- const { default : mermaid } = await import ( /* webpackChunkName: "mermaid" */ 'mermaid' ) ;
18-
19- mermaid . initialize ( {
20- startOnLoad : false ,
21- theme : isDarkTheme ( ) ? 'dark' : 'neutral' ,
22- securityLevel : 'strict' ,
23- suppressErrorRendering : true ,
24- } ) ;
25-
26- const pre = el . closest ( 'pre' ) ;
27- if ( pre . hasAttribute ( 'data-render-done' ) ) return ;
28-
29- const source = el . textContent ;
30- if ( mermaidMaxSourceCharacters >= 0 && source . length > mermaidMaxSourceCharacters ) {
31- displayError ( pre , new Error ( `Mermaid source of ${ source . length } characters exceeds the maximum allowed length of ${ mermaidMaxSourceCharacters } .` ) ) ;
32- return ;
33- }
34-
35- try {
36- await mermaid . parse ( source ) ;
37- } catch ( err ) {
38- displayError ( pre , err ) ;
39- return ;
40- }
41-
42- try {
43- // can't use bindFunctions here because we can't cross the iframe boundary. This
44- // means js-based interactions won't work but they aren't intended to work either
45- const { svg} = await mermaid . render ( 'mermaid' , source ) ;
46-
47- const iframe = document . createElement ( 'iframe' ) ;
48- iframe . classList . add ( 'markup-content-iframe' , 'tw-invisible' ) ;
49- iframe . srcdoc = `<html><head><style>${ iframeCss } </style></head><body>${ svg } </body></html>` ;
50-
51- const mermaidBlock = document . createElement ( 'div' ) ;
52- mermaidBlock . classList . add ( 'mermaid-block' , 'is-loading' , 'tw-hidden' ) ;
53- mermaidBlock . append ( iframe ) ;
54-
55- const btn = makeCodeCopyButton ( ) ;
56- btn . setAttribute ( 'data-clipboard-text' , source ) ;
57- mermaidBlock . append ( btn ) ;
58-
59- const updateIframeHeight = ( ) => {
60- const body = iframe . contentWindow ?. document ?. body ;
61- if ( body ) {
62- iframe . style . height = `${ body . clientHeight } px` ;
63- }
64- } ;
65-
66- iframe . addEventListener ( 'load' , ( ) => {
67- pre . replaceWith ( mermaidBlock ) ;
68- mermaidBlock . classList . remove ( 'tw-hidden' ) ;
69- updateIframeHeight ( ) ;
70- setTimeout ( ( ) => { // avoid flash of iframe background
71- mermaidBlock . classList . remove ( 'is-loading' ) ;
72- iframe . classList . remove ( 'tw-invisible' ) ;
73- } , 0 ) ;
74-
75- // update height when element's visibility state changes, for example when the diagram is inside
76- // a <details> + <summary> block and the <details> block becomes visible upon user interaction, it
77- // would initially set a incorrect height and the correct height is set during this callback.
78- ( new IntersectionObserver ( ( ) => {
79- updateIframeHeight ( ) ;
80- } , { root : document . documentElement } ) ) . observe ( iframe ) ;
15+ // .markup code.language-mermaid
16+ queryElems ( elMarkup , 'code.language-mermaid' , async ( el ) => {
17+ const { default : mermaid } = await import ( /* webpackChunkName: "mermaid" */ 'mermaid' ) ;
18+
19+ mermaid . initialize ( {
20+ startOnLoad : false ,
21+ theme : isDarkTheme ( ) ? 'dark' : 'neutral' ,
22+ securityLevel : 'strict' ,
23+ suppressErrorRendering : true ,
8124 } ) ;
8225
83- document . body . append ( mermaidBlock ) ;
84- } catch ( err ) {
85- displayError ( pre , err ) ;
86- }
26+ const pre = el . closest ( 'pre' ) ;
27+ if ( pre . hasAttribute ( 'data-render-done' ) ) return ;
28+
29+ const source = el . textContent ;
30+ if ( mermaidMaxSourceCharacters >= 0 && source . length > mermaidMaxSourceCharacters ) {
31+ displayError ( pre , new Error ( `Mermaid source of ${ source . length } characters exceeds the maximum allowed length of ${ mermaidMaxSourceCharacters } .` ) ) ;
32+ return ;
33+ }
34+
35+ try {
36+ await mermaid . parse ( source ) ;
37+ } catch ( err ) {
38+ displayError ( pre , err ) ;
39+ return ;
40+ }
41+
42+ try {
43+ // can't use bindFunctions here because we can't cross the iframe boundary. This
44+ // means js-based interactions won't work but they aren't intended to work either
45+ const { svg} = await mermaid . render ( 'mermaid' , source ) ;
46+
47+ const iframe = document . createElement ( 'iframe' ) ;
48+ iframe . classList . add ( 'markup-content-iframe' , 'tw-invisible' ) ;
49+ iframe . srcdoc = `<html><head><style>${ iframeCss } </style></head><body>${ svg } </body></html>` ;
50+
51+ const mermaidBlock = document . createElement ( 'div' ) ;
52+ mermaidBlock . classList . add ( 'mermaid-block' , 'is-loading' , 'tw-hidden' ) ;
53+ mermaidBlock . append ( iframe ) ;
54+
55+ const btn = makeCodeCopyButton ( ) ;
56+ btn . setAttribute ( 'data-clipboard-text' , source ) ;
57+ mermaidBlock . append ( btn ) ;
58+
59+ const updateIframeHeight = ( ) => {
60+ const body = iframe . contentWindow ?. document ?. body ;
61+ if ( body ) {
62+ iframe . style . height = `${ body . clientHeight } px` ;
63+ }
64+ } ;
65+
66+ iframe . addEventListener ( 'load' , ( ) => {
67+ pre . replaceWith ( mermaidBlock ) ;
68+ mermaidBlock . classList . remove ( 'tw-hidden' ) ;
69+ updateIframeHeight ( ) ;
70+ setTimeout ( ( ) => { // avoid flash of iframe background
71+ mermaidBlock . classList . remove ( 'is-loading' ) ;
72+ iframe . classList . remove ( 'tw-invisible' ) ;
73+ } , 0 ) ;
74+
75+ // update height when element's visibility state changes, for example when the diagram is inside
76+ // a <details> + <summary> block and the <details> block becomes visible upon user interaction, it
77+ // would initially set a incorrect height and the correct height is set during this callback.
78+ ( new IntersectionObserver ( ( ) => {
79+ updateIframeHeight ( ) ;
80+ } , { root : document . documentElement } ) ) . observe ( iframe ) ;
81+ } ) ;
82+
83+ document . body . append ( mermaidBlock ) ;
84+ } catch ( err ) {
85+ displayError ( pre , err ) ;
86+ }
87+ } ) ;
8788}
0 commit comments