Spaces:
Running
Running
const uml = async className => { | |
// Custom element to encapsulate Mermaid content. | |
class MermaidDiv extends HTMLElement { | |
/** | |
* Creates a special Mermaid div shadow DOM. | |
* Works around issues of shared IDs. | |
* @return {void} | |
*/ | |
constructor() { | |
super() | |
// Create the Shadow DOM and attach style | |
const shadow = this.attachShadow({ mode: "open" }) | |
const style = document.createElement("style") | |
style.textContent = ` | |
:host { | |
display: block; | |
line-height: initial; | |
font-size: 16px; | |
} | |
div.diagram { | |
margin: 0; | |
overflow: visible; | |
}` | |
shadow.appendChild(style) | |
} | |
} | |
if (typeof customElements.get("diagram-div") === "undefined") { | |
customElements.define("diagram-div", MermaidDiv) | |
} | |
const getFromCode = parent => { | |
// Handles <pre><code> text extraction. | |
let text = "" | |
for (let j = 0; j < parent.childNodes.length; j++) { | |
const subEl = parent.childNodes[j] | |
if (subEl.tagName.toLowerCase() === "code") { | |
for (let k = 0; k < subEl.childNodes.length; k++) { | |
const child = subEl.childNodes[k] | |
const whitespace = /^\s*$/ | |
if (child.nodeName === "#text" && !(whitespace.test(child.nodeValue))) { | |
text = child.nodeValue | |
break | |
} | |
} | |
} | |
} | |
return text | |
} | |
function createOrUpdateHyperlink(parentElement, linkText, linkHref) { | |
// Search for an existing anchor element within the parentElement | |
let existingAnchor = parentElement.querySelector("a"); | |
// Check if an anchor element already exists | |
if (existingAnchor) { | |
// Update the hyperlink reference if it's different from the current one | |
if (existingAnchor.href !== linkHref) { | |
existingAnchor.href = linkHref; | |
} | |
// Update the target attribute to ensure it opens in a new tab | |
existingAnchor.target = '_blank'; | |
// If the text must be dynamic, uncomment and use the following line: | |
// existingAnchor.textContent = linkText; | |
} else { | |
// If no anchor exists, create one and append it to the parentElement | |
let anchorElement = document.createElement("a"); | |
anchorElement.href = linkHref; // Set hyperlink reference | |
anchorElement.textContent = linkText; // Set text displayed | |
anchorElement.target = '_blank'; // Ensure it opens in a new tab | |
parentElement.appendChild(anchorElement); // Append the new anchor element to the parent | |
} | |
} | |
function removeLastLine(str) { | |
// 将字符串按换行符分割成数组 | |
var lines = str.split('\n'); | |
lines.pop(); | |
// 将数组重新连接成字符串,并按换行符连接 | |
var result = lines.join('\n'); | |
return result; | |
} | |
// 给出配置 Provide a default config in case one is not specified | |
const defaultConfig = { | |
startOnLoad: false, | |
theme: "default", | |
flowchart: { | |
htmlLabels: false | |
}, | |
er: { | |
useMaxWidth: false | |
}, | |
sequence: { | |
useMaxWidth: false, | |
noteFontWeight: "14px", | |
actorFontSize: "14px", | |
messageFontSize: "16px" | |
} | |
} | |
if (document.body.classList.contains("dark")) { | |
defaultConfig.theme = "dark" | |
} | |
const Module = await import('./file=themes/mermaid_editor.js'); | |
function do_render(block, code, codeContent, cnt) { | |
var rendered_content = mermaid.render(`_diagram_${cnt}`, code); | |
////////////////////////////// 记录有哪些代码已经被渲染了 /////////////////////////////////// | |
let codeFinishRenderElement = block.querySelector("code_finish_render"); // 如果block下已存在code_already_rendered元素,则获取它 | |
if (codeFinishRenderElement) { // 如果block下已存在code_already_rendered元素 | |
codeFinishRenderElement.style.display = "none"; | |
} else { | |
// 如果不存在code_finish_render元素,则将code元素中的内容添加到新创建的code_finish_render元素中 | |
let codeFinishRenderElementNew = document.createElement("code_finish_render"); // 创建一个新的code_already_rendered元素 | |
codeFinishRenderElementNew.style.display = "none"; | |
codeFinishRenderElementNew.textContent = ""; | |
block.appendChild(codeFinishRenderElementNew); // 将新创建的code_already_rendered元素添加到block中 | |
codeFinishRenderElement = codeFinishRenderElementNew; | |
} | |
////////////////////////////// 创建一个用于渲染的容器 /////////////////////////////////// | |
let mermaidRender = block.querySelector(".mermaid_render"); // 尝试获取已存在的<div class='mermaid_render'> | |
if (!mermaidRender) { | |
mermaidRender = document.createElement("div"); // 不存在,创建新的<div class='mermaid_render'> | |
mermaidRender.classList.add("mermaid_render"); | |
block.appendChild(mermaidRender); // 将新创建的元素附加到block | |
} | |
mermaidRender.innerHTML = rendered_content | |
codeFinishRenderElement.textContent = code // 标记已经渲染的部分 | |
////////////////////////////// 创建一个“点击这里编辑脑图” /////////////////////////////// | |
let pako_encode = Module.serializeState({ | |
"code": codeContent, | |
"mermaid": "{\n \"theme\": \"default\"\n}", | |
"autoSync": true, | |
"updateDiagram": false | |
}); | |
createOrUpdateHyperlink(block, "点击这里编辑脑图", "https://mermaid.live/edit#" + pako_encode) | |
} | |
// 加载配置 Load up the config | |
mermaid.mermaidAPI.globalReset() // 全局复位 | |
const config = (typeof mermaidConfig === "undefined") ? defaultConfig : mermaidConfig | |
mermaid.initialize(config) | |
// 查找需要渲染的元素 Find all of our Mermaid sources and render them. | |
const blocks = document.querySelectorAll(`pre.mermaid`); | |
for (let i = 0; i < blocks.length; i++) { | |
var block = blocks[i] | |
////////////////////////////// 如果代码没有发生变化,就不渲染了 /////////////////////////////////// | |
var code = getFromCode(block); | |
let codeContent = block.querySelector("code").textContent; // 获取code元素中的文本内容 | |
let codePendingRenderElement = block.querySelector("code_pending_render"); // 如果block下已存在code_already_rendered元素,则获取它 | |
if (codePendingRenderElement) { // 如果block下已存在code_pending_render元素 | |
codePendingRenderElement.style.display = "none"; | |
if (codePendingRenderElement.textContent !== codeContent) { | |
codePendingRenderElement.textContent = codeContent; // 如果现有的code_pending_render元素中的内容与code元素中的内容不同,更新code_pending_render元素中的内容 | |
} | |
else { | |
continue; // 如果相同,就不处理了 | |
} | |
} else { // 如果不存在code_pending_render元素,则将code元素中的内容添加到新创建的code_pending_render元素中 | |
let codePendingRenderElementNew = document.createElement("code_pending_render"); // 创建一个新的code_already_rendered元素 | |
codePendingRenderElementNew.style.display = "none"; | |
codePendingRenderElementNew.textContent = codeContent; | |
block.appendChild(codePendingRenderElementNew); // 将新创建的code_pending_render元素添加到block中 | |
codePendingRenderElement = codePendingRenderElementNew; | |
} | |
////////////////////////////// 在这里才真正开始渲染 /////////////////////////////////// | |
try { | |
do_render(block, code, codeContent, i); | |
// console.log("渲染", codeContent); | |
} catch (err) { | |
try { | |
var lines = code.split('\n'); if (lines.length < 2) { continue; } | |
do_render(block, removeLastLine(code), codeContent, i); | |
// console.log("渲染", codeContent); | |
} catch (err) { | |
console.log("以下代码不能渲染", code, removeLastLine(code), err); | |
} | |
} | |
} | |
} | |