1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-05 18:17:19 +00:00

Refactor markup and pdf-viewer to use new init framework (#33772)

1. Add some "render-content" classes to "markup" elements when the
content is rendered
2. Use correct "markup" wrapper for "preview" (but not set that class on
the tab)
3. Remove incorrect "markup" class from LFS file view, because there is
no markup content
    * "edit-diff" is also removed because it does nothing
5. Use "initPdfViewer" for PDF viewer
6. Remove incorrect "content" class from milestone markup
7. Init all ".markup" elements by new init framework

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Kerwin Bryant
2025-03-04 03:49:15 +08:00
committed by GitHub
parent 43c8d85f19
commit f0f1737d4d
29 changed files with 195 additions and 227 deletions

View File

@ -10,9 +10,9 @@ body {margin: 0; padding: 0; overflow: hidden}
#mermaid {display: block; margin: 0 auto}
blockquote, dd, dl, figure, h1, h2, h3, h4, h5, h6, hr, p, pre {margin: 0}`;
export async function renderMermaid(): Promise<void> {
const els = document.querySelectorAll('.markup code.language-mermaid');
if (!els.length) return;
export async function initMarkupCodeMermaid(elMarkup: HTMLElement): Promise<void> {
const el = elMarkup.querySelector('code.language-mermaid'); // .markup code.language-mermaid
if (!el) return;
const {default: mermaid} = await import(/* webpackChunkName: "mermaid" */'mermaid');
@ -23,67 +23,65 @@ export async function renderMermaid(): Promise<void> {
suppressErrorRendering: true,
});
for (const el of els) {
const pre = el.closest('pre');
if (pre.hasAttribute('data-render-done')) continue;
const pre = el.closest('pre');
if (pre.hasAttribute('data-render-done')) return;
const source = el.textContent;
if (mermaidMaxSourceCharacters >= 0 && source.length > mermaidMaxSourceCharacters) {
displayError(pre, new Error(`Mermaid source of ${source.length} characters exceeds the maximum allowed length of ${mermaidMaxSourceCharacters}.`));
continue;
}
const source = el.textContent;
if (mermaidMaxSourceCharacters >= 0 && source.length > mermaidMaxSourceCharacters) {
displayError(pre, new Error(`Mermaid source of ${source.length} characters exceeds the maximum allowed length of ${mermaidMaxSourceCharacters}.`));
return;
}
try {
await mermaid.parse(source);
} catch (err) {
displayError(pre, err);
continue;
}
try {
await mermaid.parse(source);
} catch (err) {
displayError(pre, err);
return;
}
try {
// can't use bindFunctions here because we can't cross the iframe boundary. This
// means js-based interactions won't work but they aren't intended to work either
const {svg} = await mermaid.render('mermaid', source);
try {
// can't use bindFunctions here because we can't cross the iframe boundary. This
// means js-based interactions won't work but they aren't intended to work either
const {svg} = await mermaid.render('mermaid', source);
const iframe = document.createElement('iframe');
iframe.classList.add('markup-render', 'tw-invisible');
iframe.srcdoc = `<html><head><style>${iframeCss}</style></head><body>${svg}</body></html>`;
const iframe = document.createElement('iframe');
iframe.classList.add('markup-content-iframe', 'tw-invisible');
iframe.srcdoc = `<html><head><style>${iframeCss}</style></head><body>${svg}</body></html>`;
const mermaidBlock = document.createElement('div');
mermaidBlock.classList.add('mermaid-block', 'is-loading', 'tw-hidden');
mermaidBlock.append(iframe);
const mermaidBlock = document.createElement('div');
mermaidBlock.classList.add('mermaid-block', 'is-loading', 'tw-hidden');
mermaidBlock.append(iframe);
const btn = makeCodeCopyButton();
btn.setAttribute('data-clipboard-text', source);
mermaidBlock.append(btn);
const btn = makeCodeCopyButton();
btn.setAttribute('data-clipboard-text', source);
mermaidBlock.append(btn);
const updateIframeHeight = () => {
const body = iframe.contentWindow?.document?.body;
if (body) {
iframe.style.height = `${body.clientHeight}px`;
}
};
const updateIframeHeight = () => {
const body = iframe.contentWindow?.document?.body;
if (body) {
iframe.style.height = `${body.clientHeight}px`;
}
};
iframe.addEventListener('load', () => {
pre.replaceWith(mermaidBlock);
mermaidBlock.classList.remove('tw-hidden');
iframe.addEventListener('load', () => {
pre.replaceWith(mermaidBlock);
mermaidBlock.classList.remove('tw-hidden');
updateIframeHeight();
setTimeout(() => { // avoid flash of iframe background
mermaidBlock.classList.remove('is-loading');
iframe.classList.remove('tw-invisible');
}, 0);
// update height when element's visibility state changes, for example when the diagram is inside
// a <details> + <summary> block and the <details> block becomes visible upon user interaction, it
// would initially set a incorrect height and the correct height is set during this callback.
(new IntersectionObserver(() => {
updateIframeHeight();
setTimeout(() => { // avoid flash of iframe background
mermaidBlock.classList.remove('is-loading');
iframe.classList.remove('tw-invisible');
}, 0);
}, {root: document.documentElement})).observe(iframe);
});
// update height when element's visibility state changes, for example when the diagram is inside
// a <details> + <summary> block and the <details> block becomes visible upon user interaction, it
// would initially set a incorrect height and the correct height is set during this callback.
(new IntersectionObserver(() => {
updateIframeHeight();
}, {root: document.documentElement})).observe(iframe);
});
document.body.append(mermaidBlock);
} catch (err) {
displayError(pre, err);
}
document.body.append(mermaidBlock);
} catch (err) {
displayError(pre, err);
}
}