functions and specs: removeExistingElements

This commit is contained in:
Ashley Engelund (weedySeaDragon @ github)
2022-10-16 11:08:01 -07:00
parent 166dca55f2
commit fcba29f774
2 changed files with 101 additions and 17 deletions

View File

@@ -4,7 +4,7 @@ import { vi } from 'vitest';
import mermaid from './mermaid';
import { MermaidConfig } from './config.type';
import mermaidAPI from './mermaidAPI';
import mermaidAPI, { removeExistingElements } from './mermaidAPI';
import {
encodeEntities,
decodeEntities,
@@ -454,6 +454,76 @@ describe('when using mermaidAPI and ', function () {
});
});
describe('removeExistingElements', () => {
const svgId = 'svgId';
const tempDivId = 'tempDivId';
const tempIframeId = 'tempIFrameId';
const givenDocument = new Document();
const rootHtml = givenDocument.createElement('html');
givenDocument.append(rootHtml);
const svgElement = givenDocument.createElement('svg'); // doesn't matter what the tag is in the test
svgElement.id = svgId;
const tempDivElement = givenDocument.createElement('div'); // doesn't matter what the tag is in the test
tempDivElement.id = tempDivId;
const tempiFrameElement = givenDocument.createElement('div'); // doesn't matter what the tag is in the test
tempiFrameElement.id = tempIframeId;
it('removes an existing element with given id', () => {
rootHtml.appendChild(svgElement);
expect(givenDocument.getElementById(svgElement.id)).toEqual(svgElement);
removeExistingElements(givenDocument, false, svgId, tempDivId, tempIframeId);
expect(givenDocument.getElementById(svgElement.id)).toBeNull();
});
describe('is in sandboxed mode', () => {
const inSandboxedMode = true;
it('removes an existing element with the given iFrame selector', () => {
tempiFrameElement.append(svgElement);
rootHtml.append(tempiFrameElement);
rootHtml.append(tempDivElement);
expect(givenDocument.getElementById(tempIframeId)).toEqual(tempiFrameElement);
expect(givenDocument.getElementById(tempDivId)).toEqual(tempDivElement);
expect(givenDocument.getElementById(svgId)).toEqual(svgElement);
removeExistingElements(
givenDocument,
inSandboxedMode,
svgId,
'#' + tempDivId,
'#' + tempIframeId
);
expect(givenDocument.getElementById(tempDivId)).toEqual(tempDivElement);
expect(givenDocument.getElementById(tempIframeId)).toBeNull();
expect(givenDocument.getElementById(svgId)).toBeNull();
});
});
describe('not in sandboxed mode', () => {
const inSandboxedMode = false;
it('removes an existing element with the given enclosing div selector', () => {
tempDivElement.append(svgElement);
rootHtml.append(tempDivElement);
rootHtml.append(tempiFrameElement);
expect(givenDocument.getElementById(tempIframeId)).toEqual(tempiFrameElement);
expect(givenDocument.getElementById(tempDivId)).toEqual(tempDivElement);
expect(givenDocument.getElementById(svgId)).toEqual(svgElement);
removeExistingElements(
givenDocument,
inSandboxedMode,
svgId,
'#' + tempDivId,
'#' + tempIframeId
);
expect(givenDocument.getElementById(tempIframeId)).toEqual(tempiFrameElement);
expect(givenDocument.getElementById(tempDivId)).toBeNull();
expect(givenDocument.getElementById(svgId)).toBeNull();
});
});
});
describe('doing initialize ', function () {
beforeEach(function () {
document.body.innerHTML = '';

View File

@@ -86,10 +86,10 @@ function parse(text: string, parseError?: ParseErrorFunction): boolean {
export const encodeEntities = function (text: string): string {
let txt = text;
txt = txt.replace(/style.*:\S*#.*;/g, function (s) {
txt = txt.replace(/style.*:\S*#.*;/g, function (s): string {
return s.substring(0, s.length - 1);
});
txt = txt.replace(/classDef.*:\S*#.*;/g, function (s) {
txt = txt.replace(/classDef.*:\S*#.*;/g, function (s): string {
return s.substring(0, s.length - 1);
});
@@ -319,6 +319,31 @@ function sandboxedIframe(parentNode: D3Element, iFrameId: string): D3Element {
.attr('sandbox', '');
}
/**
* Remove any existing elements from the given document
*
* @param {Document} doc - the document to removed elements from
* @param {string} isSandboxed - whether or not we are in sandboxed mode
* @param {string} id - id for any existing SVG element
* @param {string} divSelector - selector for any existing enclosing div element
* @param {string} iFrameSelector - selector for any existing iFrame element
*/
export const removeExistingElements = (
doc: Document,
isSandboxed: boolean,
id: string,
divSelector: string,
iFrameSelector: string
) => {
// Remove existing SVG element if it exists
const existingSvg = doc.getElementById(id);
if (existingSvg) existingSvg.remove();
// Remove previous temporary element if it exists
const element = isSandboxed ? doc.querySelector(iFrameSelector) : doc.querySelector(divSelector);
if (element) element.remove();
};
/**
* Function that renders an svg with a graph from a chart definition. Usage example below.
*
@@ -384,8 +409,8 @@ const render = async function (
// -------------------------------------------------------------------------------
// Define the root d3 node
// In regular execution the svgContainingElement will be the element with a mermaid class
if (typeof svgContainingElement !== 'undefined') {
if (svgContainingElement) svgContainingElement.innerHTML = '';
@@ -400,19 +425,9 @@ const render = async function (
appendDivSvgG(root, id, enclosingDivID, `font-family: ${fontFamily}`, XMLNS_XLINK_STD);
} else {
// No svgContainingElement was provided
// If there is an existing element with the id, we remove it
// this likely a previously rendered diagram
const existingSvg = document.getElementById(id);
if (existingSvg) existingSvg.remove();
// Remove previous temporary element if it exists
let element;
if (isSandboxed) {
element = document.querySelector(iFrameID_selector);
} else {
element = document.querySelector(enclosingDivID_selector);
}
if (element) element.remove();
// If there is an existing element with the id, we remove it. This likely a previously rendered diagram
removeExistingElements(document, isSandboxed, id, iFrameID_selector, enclosingDivID_selector);
// Add the temporary div used for rendering with the enclosingDivID.
// This temporary div will contain a svg with the id == id
@@ -420,7 +435,6 @@ const render = async function (
if (isSandboxed) {
// If we are in sandboxed mode, we do everything mermaid related in a (sandboxed) iFrame
const iframe = sandboxedIframe(select('body'), iFrameID);
root = select(iframe.nodes()[0]!.contentDocument!.body);
root.node().style.margin = 0;
} else root = select('body');