mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add loading spinners and mermaid error handling (#12358)
- Add loading spinners on editor and mermaid renderers - Add error handling and inline error box for mermaid - Fix Mermaid rendering by using the .init api
This commit is contained in:
		@@ -1,5 +1,5 @@
 | 
			
		||||
import {renderMermaid} from './mermaid.js';
 | 
			
		||||
 | 
			
		||||
export default async function renderMarkdownContent() {
 | 
			
		||||
  await renderMermaid(document.querySelectorAll('.language-mermaid'));
 | 
			
		||||
  await renderMermaid(document.querySelectorAll('code.language-mermaid'));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,56 @@
 | 
			
		||||
import {random} from '../utils.js';
 | 
			
		||||
const MAX_SOURCE_CHARACTERS = 5000;
 | 
			
		||||
 | 
			
		||||
function displayError(el, err) {
 | 
			
		||||
  el.closest('pre').classList.remove('is-loading');
 | 
			
		||||
  const errorNode = document.createElement('div');
 | 
			
		||||
  errorNode.setAttribute('class', 'ui message error markdown-block-error mono');
 | 
			
		||||
  errorNode.textContent = err.str || err.message || String(err);
 | 
			
		||||
  el.closest('pre').before(errorNode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function renderMermaid(els) {
 | 
			
		||||
  if (!els || !els.length) return;
 | 
			
		||||
 | 
			
		||||
  const {mermaidAPI} = await import(/* webpackChunkName: "mermaid" */'mermaid');
 | 
			
		||||
  const mermaid = await import(/* webpackChunkName: "mermaid" */'mermaid');
 | 
			
		||||
 | 
			
		||||
  mermaidAPI.initialize({
 | 
			
		||||
    startOnLoad: false,
 | 
			
		||||
  mermaid.initialize({
 | 
			
		||||
    mermaid: {
 | 
			
		||||
      startOnLoad: false,
 | 
			
		||||
    },
 | 
			
		||||
    flowchart: {
 | 
			
		||||
      useMaxWidth: true,
 | 
			
		||||
      htmlLabels: false,
 | 
			
		||||
    },
 | 
			
		||||
    theme: 'neutral',
 | 
			
		||||
    securityLevel: 'strict',
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  for (const el of els) {
 | 
			
		||||
    mermaidAPI.render(`mermaid-${random(12)}`, el.textContent, (svg, bindFunctions) => {
 | 
			
		||||
      const div = document.createElement('div');
 | 
			
		||||
      div.classList.add('mermaid-chart');
 | 
			
		||||
      div.innerHTML = svg;
 | 
			
		||||
      if (typeof bindFunctions === 'function') bindFunctions(div);
 | 
			
		||||
      el.closest('pre').replaceWith(div);
 | 
			
		||||
    });
 | 
			
		||||
    if (el.textContent.length > MAX_SOURCE_CHARACTERS) {
 | 
			
		||||
      displayError(el, new Error(`Mermaid source of ${el.textContent.length} characters exceeds the maximum allowed length of ${MAX_SOURCE_CHARACTERS}.`));
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let valid;
 | 
			
		||||
    try {
 | 
			
		||||
      valid = mermaid.parse(el.textContent);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      displayError(el, err);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!valid) {
 | 
			
		||||
      el.closest('pre').classList.remove('is-loading');
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      mermaid.init(undefined, el, (id) => {
 | 
			
		||||
        const svg = document.getElementById(id);
 | 
			
		||||
        svg.classList.add('mermaid-chart');
 | 
			
		||||
        svg.closest('pre').replaceWith(svg);
 | 
			
		||||
      });
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      displayError(el, err);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user