mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-13 02:59:36 +02:00
render: constants
This commit is contained in:

parent
9ac3992fd2
commit
d248952d9e
@@ -33,6 +33,29 @@ import DOMPurify from 'dompurify';
|
|||||||
import { MermaidConfig } from './config.type';
|
import { MermaidConfig } from './config.type';
|
||||||
import { evaluate } from './diagrams/common/common';
|
import { evaluate } from './diagrams/common/common';
|
||||||
|
|
||||||
|
const MAX_TEXTLENGTH_EXCEEDED_MSG =
|
||||||
|
'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
|
||||||
|
|
||||||
|
const SECURITY_LVL_SANDBOX = 'sandbox';
|
||||||
|
const SECURITY_LVL_LOOSE = 'loose';
|
||||||
|
|
||||||
|
const XMLNS_XHTML_STD = 'http://www.w3.org/1999/xhtml';
|
||||||
|
const XMLNS_SVG_STD = 'http://www.w3.org/2000/svg';
|
||||||
|
const XMLNS_XLINK_STD = 'http://www.w3.org/1999/xlink';
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// iFrame
|
||||||
|
const IFRAME_WIDTH = '100%';
|
||||||
|
const IFRAME_HEIGHT = '100%';
|
||||||
|
const IFRAME_STYLES = 'border:0;margin:0;';
|
||||||
|
const IFRAME_BODY_STYLE = 'margin:0';
|
||||||
|
const IFRAME_SANDBOX_OPTS = 'allow-top-navigation-by-user-activation allow-popups';
|
||||||
|
const IFRAME_NOT_SUPPORTED_MSG = 'The “iframe” tag is not supported by your browser.';
|
||||||
|
|
||||||
|
const DOMPURIFY_TAGS = 'foreignobject';
|
||||||
|
const DOMPURIFY_ATTR = 'dominant-baseline';
|
||||||
|
// --------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param text
|
* @param text
|
||||||
* @param parseError
|
* @param parseError
|
||||||
@@ -84,6 +107,7 @@ export const decodeEntities = function (text: string): string {
|
|||||||
|
|
||||||
return txt;
|
return txt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that renders an svg with a graph from a chart definition. Usage example below.
|
* Function that renders an svg with a graph from a chart definition. Usage example below.
|
||||||
*
|
*
|
||||||
@@ -116,6 +140,7 @@ const render = async function (
|
|||||||
container?: Element
|
container?: Element
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
addDiagrams();
|
addDiagrams();
|
||||||
|
|
||||||
configApi.reset();
|
configApi.reset();
|
||||||
text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;;
|
text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;;
|
||||||
const graphInit = utils.detectInit(text);
|
const graphInit = utils.detectInit(text);
|
||||||
@@ -129,19 +154,19 @@ const render = async function (
|
|||||||
|
|
||||||
// Check the maximum allowed text size
|
// Check the maximum allowed text size
|
||||||
if (text.length > cnf.maxTextSize!) {
|
if (text.length > cnf.maxTextSize!) {
|
||||||
text = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
|
text = MAX_TEXTLENGTH_EXCEEDED_MSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
let root: any = select('body');
|
let root: any = select('body');
|
||||||
|
|
||||||
// In regular execution the container will be the div with a mermaid class
|
// In regular execution the container will be the div with a mermaid class
|
||||||
if (typeof container !== 'undefined') {
|
if (typeof container !== 'undefined') {
|
||||||
// A container was provided by the caller
|
// A container was provided by the caller. Clear the inner HTML if there is any
|
||||||
if (container) {
|
if (container) {
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnf.securityLevel === 'sandbox') {
|
if (cnf.securityLevel === SECURITY_LVL_SANDBOX) {
|
||||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
// IF we are in sandboxed mode, we do everyting mermaid related
|
||||||
// in a sandboxed div
|
// in a sandboxed div
|
||||||
const iframe = select(container)
|
const iframe = select(container)
|
||||||
@@ -163,8 +188,8 @@ const render = async function (
|
|||||||
.append('svg')
|
.append('svg')
|
||||||
.attr('id', id)
|
.attr('id', id)
|
||||||
.attr('width', '100%')
|
.attr('width', '100%')
|
||||||
.attr('xmlns', 'http://www.w3.org/2000/svg')
|
.attr('xmlns', XMLNS_SVG_STD)
|
||||||
.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink')
|
.attr('xmlns:xlink', XMLNS_XLINK_STD)
|
||||||
.append('g');
|
.append('g');
|
||||||
} else {
|
} else {
|
||||||
// No container was provided
|
// No container was provided
|
||||||
@@ -177,7 +202,7 @@ const render = async function (
|
|||||||
|
|
||||||
// Remove previous tpm element if it exists
|
// Remove previous tpm element if it exists
|
||||||
let element;
|
let element;
|
||||||
if (cnf.securityLevel === 'sandbox') {
|
if (cnf.securityLevel === SECURITY_LVL_SANDBOX) {
|
||||||
element = document.querySelector('#i' + id);
|
element = document.querySelector('#i' + id);
|
||||||
} else {
|
} else {
|
||||||
element = document.querySelector('#d' + id);
|
element = document.querySelector('#d' + id);
|
||||||
@@ -190,7 +215,7 @@ const render = async function (
|
|||||||
// Add the tmp div used for rendering with the id `d${id}`
|
// Add the tmp div used for rendering with the id `d${id}`
|
||||||
// d+id it will contain a svg with the id "id"
|
// d+id it will contain a svg with the id "id"
|
||||||
|
|
||||||
if (cnf.securityLevel === 'sandbox') {
|
if (cnf.securityLevel === SECURITY_LVL_SANDBOX) {
|
||||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
// IF we are in sandboxed mode, we do everyting mermaid related
|
||||||
// in a sandboxed div
|
// in a sandboxed div
|
||||||
const iframe = select('body')
|
const iframe = select('body')
|
||||||
@@ -213,7 +238,7 @@ const render = async function (
|
|||||||
.append('svg')
|
.append('svg')
|
||||||
.attr('id', id)
|
.attr('id', id)
|
||||||
.attr('width', '100%')
|
.attr('width', '100%')
|
||||||
.attr('xmlns', 'http://www.w3.org/2000/svg')
|
.attr('xmlns', XMLNS_SVG_STD)
|
||||||
.append('g');
|
.append('g');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,16 +330,13 @@ const render = async function (
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
root
|
root.select(`[id="${id}"]`).selectAll('foreignobject > *').attr('xmlns', XMLNS_XHTML_STD);
|
||||||
.select(`[id="${id}"]`)
|
|
||||||
.selectAll('foreignobject > *')
|
|
||||||
.attr('xmlns', 'http://www.w3.org/1999/xhtml');
|
|
||||||
|
|
||||||
// Fix for when the base tag is used
|
// Fix for when the base tag is used
|
||||||
let svgCode = root.select('#d' + id).node().innerHTML;
|
let svgCode = root.select('#d' + id).node().innerHTML;
|
||||||
|
|
||||||
log.debug('cnf.arrowMarkerAbsolute', cnf.arrowMarkerAbsolute);
|
log.debug('cnf.arrowMarkerAbsolute', cnf.arrowMarkerAbsolute);
|
||||||
if (!evaluate(cnf.arrowMarkerAbsolute) && cnf.securityLevel !== 'sandbox') {
|
if (!evaluate(cnf.arrowMarkerAbsolute) && cnf.securityLevel !== SECURITY_LVL_SANDBOX) {
|
||||||
svgCode = svgCode.replace(/marker-end="url\(.*?#/g, 'marker-end="url(#', 'g');
|
svgCode = svgCode.replace(/marker-end="url\(.*?#/g, 'marker-end="url(#', 'g');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,23 +345,23 @@ const render = async function (
|
|||||||
// Fix for when the br tag is used
|
// Fix for when the br tag is used
|
||||||
svgCode = svgCode.replace(/<br>/g, '<br/>');
|
svgCode = svgCode.replace(/<br>/g, '<br/>');
|
||||||
|
|
||||||
if (cnf.securityLevel === 'sandbox') {
|
if (cnf.securityLevel === SECURITY_LVL_SANDBOX) {
|
||||||
const svgEl = root.select('#d' + id + ' svg').node();
|
const svgEl = root.select('#d' + id + ' svg').node();
|
||||||
const width = '100%';
|
const width = IFRAME_WIDTH;
|
||||||
let height = '100%';
|
let height = IFRAME_HEIGHT;
|
||||||
if (svgEl) {
|
if (svgEl) {
|
||||||
height = svgEl.viewBox.baseVal.height + 'px';
|
height = svgEl.viewBox.baseVal.height + 'px';
|
||||||
}
|
}
|
||||||
svgCode = `<iframe style="width:${width};height:${height};border:0;margin:0;" src="data:text/html;base64,${btoa(
|
svgCode = `<iframe style="width:${width};height:${height};${IFRAME_STYLES}" src="data:text/html;base64,${btoa(
|
||||||
'<body style="margin:0">' + svgCode + '</body>'
|
`<body style="${IFRAME_BODY_STYLE}">` + svgCode + '</body>'
|
||||||
)}" sandbox="allow-top-navigation-by-user-activation allow-popups">
|
)}" sandbox="${IFRAME_SANDBOX_OPTS}">
|
||||||
The “iframe” tag is not supported by your browser.
|
${IFRAME_NOT_SUPPORTED_MSG}
|
||||||
</iframe>`;
|
</iframe>`;
|
||||||
} else {
|
} else {
|
||||||
if (cnf.securityLevel !== 'loose') {
|
if (cnf.securityLevel !== SECURITY_LVL_LOOSE) {
|
||||||
svgCode = DOMPurify.sanitize(svgCode, {
|
svgCode = DOMPurify.sanitize(svgCode, {
|
||||||
ADD_TAGS: ['foreignobject'],
|
ADD_TAGS: [DOMPURIFY_TAGS],
|
||||||
ADD_ATTR: ['dominant-baseline'],
|
ADD_ATTR: [DOMPURIFY_ATTR],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,7 +387,7 @@ const render = async function (
|
|||||||
}
|
}
|
||||||
attachFunctions();
|
attachFunctions();
|
||||||
|
|
||||||
const tmpElementSelector = cnf.securityLevel === 'sandbox' ? '#i' + id : '#d' + id;
|
const tmpElementSelector = cnf.securityLevel === SECURITY_LVL_SANDBOX ? '#i' + id : '#d' + id;
|
||||||
const node = select(tmpElementSelector).node();
|
const node = select(tmpElementSelector).node();
|
||||||
if (node && 'remove' in node) {
|
if (node && 'remove' in node) {
|
||||||
node.remove();
|
node.remove();
|
||||||
|
Reference in New Issue
Block a user