From 6635ff9a6972d4f123d1990d14b39ab328149e63 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 22 Sep 2023 15:23:01 +0100 Subject: [PATCH] Rework mermaid integration to support off-DOM rendering --- Gruntfile.js | 1 - package.json | 2 +- .../src/js/ui/editors/markdown.js | 4 +- .../src/js/ui/editors/mermaid.js | 53 +++++++++++++++++++ .../editor-client/src/js/ui/mermaid.js | 46 ---------------- .../src/js/ui/projects/projectSettings.js | 2 +- .../editor-client/src/js/ui/tab-help.js | 1 + .../editor-client/src/js/ui/tab-info.js | 2 +- .../editor-client/src/js/ui/utils.js | 24 +-------- 9 files changed, 61 insertions(+), 74 deletions(-) create mode 100644 packages/node_modules/@node-red/editor-client/src/js/ui/editors/mermaid.js delete mode 100644 packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js diff --git a/Gruntfile.js b/Gruntfile.js index 44f4c97f6..09b057837 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -151,7 +151,6 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js", "packages/node_modules/@node-red/editor-client/src/js/history.js", "packages/node_modules/@node-red/editor-client/src/js/validators.js", - "packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js", "packages/node_modules/@node-red/editor-client/src/js/ui/utils.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js", diff --git a/package.json b/package.json index 885e4f9c4..ea42f8c2e 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "jquery-i18next": "1.2.1", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", "marked": "4.3.0", - "mermaid": "^9.4.3", + "mermaid": "^10.4.0", "minami": "1.2.3", "mocha": "9.2.2", "node-red-node-test-helper": "^0.3.2", diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/markdown.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/markdown.js index bd7a11b3f..c4d7bf26d 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/markdown.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/markdown.js @@ -169,7 +169,7 @@ var currentScrollTop = $(".red-ui-editor-type-markdown-panel-preview").scrollTop(); $(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue())); $(".red-ui-editor-type-markdown-panel-preview").scrollTop(currentScrollTop); - mermaid.init(); + RED.editor.mermaid.render() },200); }) if (options.header) { @@ -178,7 +178,7 @@ if (value) { $(".red-ui-editor-type-markdown-panel-preview").html(RED.utils.renderMarkdown(expressionEditor.getValue())); - mermaid.init(); + RED.editor.mermaid.render() } panels = RED.panels.create({ id:"red-ui-editor-type-markdown-panels", diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/mermaid.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/mermaid.js new file mode 100644 index 000000000..50b7a20a9 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/mermaid.js @@ -0,0 +1,53 @@ +RED.editor.mermaid = (function () { + let initializing = false + let loaded = false + let pendingEvals = [] + let diagramIds = 0 + + function render(selector = '.mermaid') { + // $(selector).hide() + if (!loaded) { + pendingEvals.push(selector) + + if (!initializing) { + initializing = true + $.getScript( + 'vendor/mermaid/mermaid.min.js', + function (data, stat, jqxhr) { + mermaid.initialize({ + startOnLoad: false + }) + loaded = true + while(pendingEvals.length > 0) { + const pending = pendingEvals.shift() + render(pending) + } + } + ) + } + } else { + const nodes = document.querySelectorAll(selector) + + nodes.forEach(async node => { + if (!node.getAttribute('mermaid-processed')) { + const mermaidContent = node.innerText + node.setAttribute('mermaid-processed', true) + try { + const { svg } = await mermaid.render('mermaid-render-'+Date.now()+'-'+(diagramIds++), mermaidContent); + node.innerHTML = svg + } catch (err) { + $('
').css({ + fontSize: '0.8em', + border: '1px solid var(--red-ui-border-color-error)', + padding: '5px', + marginBottom: '10px', + }).text(err.toString()).prependTo(node) + } + } + }) + } + } + return { + render: render, + }; +})(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js b/packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js deleted file mode 100644 index d126cf188..000000000 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js +++ /dev/null @@ -1,46 +0,0 @@ -// Mermaid diagram stub library for on-demand dynamic loading -// Will be overwritten after script loading by $.getScript -var mermaid = (function () { - var enabled /* = undefined */; - - var initializing = false; - var initCalled = false; - - function initialize(opt) { - if (enabled === undefined) { - if (RED.settings.markdownEditor && - RED.settings.markdownEditor.mermaid) { - enabled = RED.settings.markdownEditor.mermaid.enabled; - } - else { - enabled = true; - } - } - if (enabled) { - initializing = true; - $.getScript("vendor/mermaid/mermaid.min.js", - function (data, stat, jqxhr) { - $(".mermaid").show(); - // invoke loaded mermaid API - initializing = false; - mermaid.initialize(opt); - if (initCalled) { - mermaid.init(); - initCalled = false; - } - }); - } - } - - function init() { - if (initializing) { - $(".mermaid").hide(); - initCalled = true; - } - } - - return { - initialize: initialize, - init: init, - }; -})(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js b/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js index b8f1558a6..37a5ef1a8 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js @@ -166,7 +166,7 @@ RED.projects.settings = (function() { var description = addTargetToExternalLinks($(''+desc+'')).appendTo(container); description.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "" ); setTimeout(function () { - mermaid.init(); + RED.editor.mermaid.render() }, 200); } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js index ee4bad2d8..bf66611b1 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js @@ -383,6 +383,7 @@ RED.sidebar.help = (function() { $(this).toggleClass('expanded',!isExpanded); }) helpSection.parent().scrollTop(0); + RED.editor.mermaid.render() } function set(html,title) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js index e38b0b67e..f72a7b3f2 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js @@ -464,7 +464,7 @@ RED.sidebar.info = (function() { } $(this).toggleClass('expanded',!isExpanded); }); - mermaid.init(); + RED.editor.mermaid.render() } var tips = (function() { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js b/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js index 4d8ccdd9d..552674936 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/utils.js @@ -101,28 +101,8 @@ RED.utils = (function() { renderer.code = function (code, lang) { if(lang === "mermaid") { - // mermaid diagram rendering - if (mermaidIsEnabled === undefined) { - if (RED.settings.markdownEditor && - RED.settings.markdownEditor.mermaid) { - mermaidIsEnabled = RED.settings.markdownEditor.mermaid.enabled; - } - else { - mermaidIsEnabled = true; - } - } - if (mermaidIsEnabled) { - if (!mermaidIsInitialized) { - mermaidIsInitialized = true; - mermaid.initialize({startOnLoad:false}); - } - return `
${code}
`; - } - else { - return `
${RED._("markdownEditor.mermaid.summary")}
${code}
`; - } - } - else { + return `
${code}
`; + } else { return "
" +code +"
"; } };