mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
functions and specs: createUserstyles; minor changes
This commit is contained in:
parent
a3b8c301e2
commit
166dca55f2
@ -2,11 +2,14 @@
|
|||||||
import { vi } from 'vitest';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
import mermaid from './mermaid';
|
import mermaid from './mermaid';
|
||||||
|
import { MermaidConfig } from './config.type';
|
||||||
|
|
||||||
import mermaidAPI from './mermaidAPI';
|
import mermaidAPI from './mermaidAPI';
|
||||||
import {
|
import {
|
||||||
encodeEntities,
|
encodeEntities,
|
||||||
decodeEntities,
|
decodeEntities,
|
||||||
createCssStyles,
|
createCssStyles,
|
||||||
|
createUserStyles,
|
||||||
appendDivSvgG,
|
appendDivSvgG,
|
||||||
cleanUpSvgCode,
|
cleanUpSvgCode,
|
||||||
putIntoIFrame,
|
putIntoIFrame,
|
||||||
@ -14,7 +17,9 @@ import {
|
|||||||
|
|
||||||
import assignWithDepth from './assignWithDepth';
|
import assignWithDepth from './assignWithDepth';
|
||||||
|
|
||||||
// To mock a module, first define a mock for it, then import it. Be sure the path points to exactly the same file as is imported in mermaidAPI (the module being tested)
|
// --------------
|
||||||
|
// Mocks
|
||||||
|
// To mock a module, first define a mock for it, then (if used explicitly in the tests) import it. Be sure the path points to exactly the same file as is imported in mermaidAPI (the module being tested)
|
||||||
vi.mock('./styles', () => {
|
vi.mock('./styles', () => {
|
||||||
return {
|
return {
|
||||||
addStylesForDiagram: vi.fn(),
|
addStylesForDiagram: vi.fn(),
|
||||||
@ -34,6 +39,8 @@ import { compile, serialize } from 'stylis';
|
|||||||
|
|
||||||
import { MockedD3 } from './tests/MockedD3';
|
import { MockedD3 } from './tests/MockedD3';
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
describe('when using mermaidAPI and ', function () {
|
describe('when using mermaidAPI and ', function () {
|
||||||
describe('encodeEntities', () => {
|
describe('encodeEntities', () => {
|
||||||
it('removes the ending ; from style [text1]:[optional word]#[text2]; with ', () => {
|
it('removes the ending ; from style [text1]:[optional word]#[text2]; with ', () => {
|
||||||
@ -184,12 +191,14 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
const fauxGNode = new MockedD3();
|
const fauxGNode = new MockedD3();
|
||||||
const parent_append_spy = vi.spyOn(fauxParentNode, 'append').mockReturnValue(fauxEnclosingDiv);
|
const parent_append_spy = vi.spyOn(fauxParentNode, 'append').mockReturnValue(fauxEnclosingDiv);
|
||||||
const div_append_spy = vi.spyOn(fauxEnclosingDiv, 'append').mockReturnValue(fauxSvgNode);
|
const div_append_spy = vi.spyOn(fauxEnclosingDiv, 'append').mockReturnValue(fauxSvgNode);
|
||||||
|
// @ts-ignore @todo TODO why is this getting a type error?
|
||||||
const div_attr_spy = vi.spyOn(fauxEnclosingDiv, 'attr').mockReturnValue(fauxEnclosingDiv);
|
const div_attr_spy = vi.spyOn(fauxEnclosingDiv, 'attr').mockReturnValue(fauxEnclosingDiv);
|
||||||
const svg_append_spy = vi.spyOn(fauxSvgNode, 'append').mockReturnValue(fauxGNode);
|
const svg_append_spy = vi.spyOn(fauxSvgNode, 'append').mockReturnValue(fauxGNode);
|
||||||
|
// @ts-ignore @todo TODO why is this getting a type error?
|
||||||
const svg_attr_spy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svg_attr_spy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
|
|
||||||
it('appends a div node', () => {
|
it('appends a div node', () => {
|
||||||
appendDivSvgG(fauxParentNode, 'theId');
|
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||||
expect(parent_append_spy).toHaveBeenCalledWith('div');
|
expect(parent_append_spy).toHaveBeenCalledWith('div');
|
||||||
expect(div_append_spy).toHaveBeenCalledWith('svg');
|
expect(div_append_spy).toHaveBeenCalledWith('svg');
|
||||||
});
|
});
|
||||||
@ -208,7 +217,7 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
expect(div_attr_spy).toHaveBeenCalledWith('id', 'dtheId');
|
expect(div_attr_spy).toHaveBeenCalledWith('id', 'dtheId');
|
||||||
});
|
});
|
||||||
it('sets the svg width to 100%', () => {
|
it('sets the svg width to 100%', () => {
|
||||||
appendDivSvgG(fauxParentNode, 'theId');
|
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||||
expect(svg_attr_spy).toHaveBeenCalledWith('width', '100%');
|
expect(svg_attr_spy).toHaveBeenCalledWith('width', '100%');
|
||||||
});
|
});
|
||||||
it('the svg id is the id', () => {
|
it('the svg id is the id', () => {
|
||||||
@ -216,7 +225,7 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
expect(svg_attr_spy).toHaveBeenCalledWith('id', 'theId');
|
expect(svg_attr_spy).toHaveBeenCalledWith('id', 'theId');
|
||||||
});
|
});
|
||||||
it('the svg xml namespace is the 2000 standard', () => {
|
it('the svg xml namespace is the 2000 standard', () => {
|
||||||
appendDivSvgG(fauxParentNode, 'theId');
|
appendDivSvgG(fauxParentNode, 'theId', 'dtheId');
|
||||||
expect(svg_attr_spy).toHaveBeenCalledWith('xmlns', 'http://www.w3.org/2000/svg');
|
expect(svg_attr_spy).toHaveBeenCalledWith('xmlns', 'http://www.w3.org/2000/svg');
|
||||||
});
|
});
|
||||||
it('sets the svg xlink if one is given', () => {
|
it('sets the svg xlink if one is given', () => {
|
||||||
@ -235,11 +244,11 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
describe('createCssStyles', () => {
|
describe('createCssStyles', () => {
|
||||||
const serif = 'serif';
|
const serif = 'serif';
|
||||||
const sansSerif = 'sans-serif';
|
const sansSerif = 'sans-serif';
|
||||||
const mocked_config_with_htmlLabels = {
|
const mocked_config_with_htmlLabels: MermaidConfig = {
|
||||||
themeCSS: 'default',
|
themeCSS: 'default',
|
||||||
fontFamily: serif,
|
fontFamily: serif,
|
||||||
altFontFamily: sansSerif,
|
altFontFamily: sansSerif,
|
||||||
htmlLabels: '',
|
htmlLabels: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
it('gets the cssStyles from the theme', () => {
|
it('gets the cssStyles from the theme', () => {
|
||||||
@ -267,7 +276,7 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
const REGEXP_SPECIALS = ['^', '$', '?', '(', '{', '[', '.', '*', '!'];
|
const REGEXP_SPECIALS = ['^', '$', '?', '(', '{', '[', '.', '*', '!'];
|
||||||
|
|
||||||
// prefix any special RegExp characters in the given string with a \ so we can use the literal character in a RegExp
|
// prefix any special RegExp characters in the given string with a \ so we can use the literal character in a RegExp
|
||||||
function escapeForRegexp(str) {
|
function escapeForRegexp(str: string) {
|
||||||
const strChars = str.split(''); // split into array of every char
|
const strChars = str.split(''); // split into array of every char
|
||||||
const strEscaped = strChars.map((char) => {
|
const strEscaped = strChars.map((char) => {
|
||||||
if (REGEXP_SPECIALS.includes(char)) return `\\${char}`;
|
if (REGEXP_SPECIALS.includes(char)) return `\\${char}`;
|
||||||
@ -275,7 +284,9 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
});
|
});
|
||||||
return strEscaped.join('');
|
return strEscaped.join('');
|
||||||
}
|
}
|
||||||
function expect_styles_matchesHtmlElements(styles, htmlElement) {
|
|
||||||
|
// Common test expecting given styles to have .classDef1 and .classDef2 statements but not .classDef3
|
||||||
|
function expect_styles_matchesHtmlElements(styles: string, htmlElement: string) {
|
||||||
expect(styles).toMatch(
|
expect(styles).toMatch(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`\\.classDef1 ${escapeForRegexp(
|
`\\.classDef1 ${escapeForRegexp(
|
||||||
@ -292,13 +303,14 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expect_textStyles_matchesHtmlElements(styles, htmlElement) {
|
// Common test expecting given textStyles to have .classDef2 and .classDef3 statements but not .classDef1
|
||||||
expect(styles).toMatch(
|
function expect_textStyles_matchesHtmlElements(textStyles: string, htmlElement: string) {
|
||||||
|
expect(textStyles).toMatch(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`\\.classDef2 ${escapeForRegexp(htmlElement)} \\{ textStyle2-1 !important; }`
|
`\\.classDef2 ${escapeForRegexp(htmlElement)} \\{ textStyle2-1 !important; }`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
expect(styles).toMatch(
|
expect(textStyles).toMatch(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`\\.classDef3 ${escapeForRegexp(
|
`\\.classDef3 ${escapeForRegexp(
|
||||||
htmlElement
|
htmlElement
|
||||||
@ -307,14 +319,15 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// no CSS styles are created if there are no textStyles for a classDef
|
// no CSS styles are created if there are no textStyles for a classDef
|
||||||
expect(styles).not.toMatch(
|
expect(textStyles).not.toMatch(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`\\.classDef1 ${escapeForRegexp(htmlElement)} \\{ textStyle(.*) !important; }`
|
`\\.classDef1 ${escapeForRegexp(htmlElement)} \\{ textStyle(.*) !important; }`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expect_correct_styles_with_htmlElements(mocked_config) {
|
// common suite and tests to verify that the right styles are created with the right htmlElements
|
||||||
|
function expect_correct_styles_with_htmlElements(mocked_config: MermaidConfig) {
|
||||||
describe('creates styles for "> *" and "span" elements', () => {
|
describe('creates styles for "> *" and "span" elements', () => {
|
||||||
const htmlElements = ['> *', 'span'];
|
const htmlElements = ['> *', 'span'];
|
||||||
|
|
||||||
@ -335,12 +348,12 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('there are flowchart.htmlLabels in the configuration', () => {
|
it('there are flowchart.htmlLabels in the configuration', () => {
|
||||||
const mocked_config_flowchart_htmlLabels = {
|
const mocked_config_flowchart_htmlLabels: MermaidConfig = {
|
||||||
themeCSS: 'default',
|
themeCSS: 'default',
|
||||||
fontFamily: 'serif',
|
fontFamily: 'serif',
|
||||||
altFontFamily: 'sans-serif',
|
altFontFamily: 'sans-serif',
|
||||||
flowchart: {
|
flowchart: {
|
||||||
htmlLabels: 'flowchart-htmlLables',
|
htmlLabels: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
expect_correct_styles_with_htmlElements(mocked_config_flowchart_htmlLabels);
|
expect_correct_styles_with_htmlElements(mocked_config_flowchart_htmlLabels);
|
||||||
@ -371,39 +384,75 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// describe('createUserStyles', () => {
|
describe('createUserStyles', () => {
|
||||||
// const mockConfig = {
|
const mockConfig = {
|
||||||
// themeCSS: 'default',
|
themeCSS: 'default',
|
||||||
// htmlLabels: 'htmlLabels',
|
htmlLabels: true,
|
||||||
// themeVariables: { fontFamily: 'serif' },
|
themeVariables: { fontFamily: 'serif' },
|
||||||
// };
|
};
|
||||||
// const classDef1 = { id: 'classDef1', styles: ['style1-1'], textStyles: [] };
|
|
||||||
//
|
//
|
||||||
// it('gets the css styles created', () => {
|
// export interface MermaidConfig {
|
||||||
// // @todo TODO if a single function in the module can be mocked, do it for createCssStyles and mock the results.
|
// lazyLoadedDiagrams?: string[];
|
||||||
//
|
// theme?: string;
|
||||||
// createUserStyles(mockConfig, 'flowchart-v2', [classDef1], 'someId');
|
// themeVariables?: any;
|
||||||
// const expectedStyles =
|
// themeCSS?: string;
|
||||||
// '\ndefault' +
|
// maxTextSize?: number;
|
||||||
// '\n.classDef1 > * { style1-1 !important; }' +
|
// darkMode?: boolean;
|
||||||
// '\n.classDef1 span { style1-1 !important; }';
|
// htmlLabels?: boolean;
|
||||||
// expect(getStyles).toHaveBeenCalledWith('flowchart-v2', expectedStyles, {
|
// fontFamily?: string;
|
||||||
// fontFamily: 'serif',
|
// altFontFamily?: string;
|
||||||
// });
|
// logLevel?: number;
|
||||||
// });
|
// securityLevel?: string;
|
||||||
//
|
// startOnLoad?: boolean;
|
||||||
// it('calls getStyles to get css for all graph, user css styles, and config theme variables', () => {
|
// arrowMarkerAbsolute?: boolean;
|
||||||
// createUserStyles(mockConfig, 'someDiagram', null, 'someId');
|
// secure?: string[];
|
||||||
// expect(getStyles).toHaveBeenCalled();
|
// deterministicIds?: boolean;
|
||||||
// });
|
// deterministicIDSeed?: string;
|
||||||
//
|
// flowchart?: FlowchartDiagramConfig;
|
||||||
// it('returns the result of compiling, stringifying, and serializing the css code with stylis', () => {
|
// sequence?: SequenceDiagramConfig;
|
||||||
// const result = createUserStyles(mockConfig, 'someDiagram', null, 'someId');
|
// gantt?: GanttDiagramConfig;
|
||||||
// expect(compile).toHaveBeenCalled();
|
// journey?: JourneyDiagramConfig;
|
||||||
// expect(serialize).toHaveBeenCalled();
|
// class?: ClassDiagramConfig;
|
||||||
// expect(result).toEqual('stylis serialized css');
|
// state?: StateDiagramConfig;
|
||||||
// });
|
// er?: ErDiagramConfig;
|
||||||
// });
|
// pie?: PieDiagramConfig;
|
||||||
|
// requirement?: RequirementDiagramConfig;
|
||||||
|
// mindmap?: MindmapDiagramConfig;
|
||||||
|
// gitGraph?: GitGraphDiagramConfig;
|
||||||
|
// c4?: C4DiagramConfig;
|
||||||
|
// dompurifyConfig?: DOMPurify.Config;
|
||||||
|
// wrap?: boolean;
|
||||||
|
// fontSize?: number;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const classDef1 = { id: 'classDef1', styles: ['style1-1'], textStyles: [] };
|
||||||
|
|
||||||
|
it('gets the css styles created', () => {
|
||||||
|
// @todo TODO if a single function in the module can be mocked, do it for createCssStyles and mock the results.
|
||||||
|
|
||||||
|
createUserStyles(mockConfig, 'flowchart-v2', [classDef1], 'someId');
|
||||||
|
const expectedStyles =
|
||||||
|
'\ndefault' +
|
||||||
|
'\n.classDef1 > * { style1-1 !important; }' +
|
||||||
|
'\n.classDef1 span { style1-1 !important; }';
|
||||||
|
expect(getStyles).toHaveBeenCalledWith('flowchart-v2', expectedStyles, {
|
||||||
|
fontFamily: 'serif',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls getStyles to get css for all graph, user css styles, and config theme variables', () => {
|
||||||
|
createUserStyles(mockConfig, 'someDiagram', null, 'someId');
|
||||||
|
expect(getStyles).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the result of compiling, stringifying, and serializing the css code with stylis', () => {
|
||||||
|
const result = createUserStyles(mockConfig, 'someDiagram', null, 'someId');
|
||||||
|
expect(compile).toHaveBeenCalled();
|
||||||
|
expect(serialize).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual('stylis serialized css');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('doing initialize ', function () {
|
describe('doing initialize ', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
@ -412,16 +461,19 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should copy a literal into the configuration', function () {
|
it('should copy a literal into the configuration', function () {
|
||||||
const orgConfig = mermaidAPI.getConfig();
|
const orgConfig: any = mermaidAPI.getConfig();
|
||||||
expect(orgConfig.testLiteral).toBe(undefined);
|
expect(orgConfig.testLiteral).toBe(undefined);
|
||||||
|
|
||||||
mermaidAPI.initialize({ testLiteral: true });
|
const testConfig: any = { testLiteral: true };
|
||||||
const config = mermaidAPI.getConfig();
|
|
||||||
|
mermaidAPI.initialize(testConfig);
|
||||||
|
const config: any = mermaidAPI.getConfig();
|
||||||
|
|
||||||
expect(config.testLiteral).toBe(true);
|
expect(config.testLiteral).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should copy a an object into the configuration', function () {
|
it('should copy a an object into the configuration', function () {
|
||||||
const orgConfig = mermaidAPI.getConfig();
|
const orgConfig: any = mermaidAPI.getConfig();
|
||||||
expect(orgConfig.testObject).toBe(undefined);
|
expect(orgConfig.testObject).toBe(undefined);
|
||||||
|
|
||||||
const object = {
|
const object = {
|
||||||
@ -429,19 +481,25 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
test2: false,
|
test2: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
mermaidAPI.initialize({ testObject: object });
|
const testConfig: any = { testObject: object };
|
||||||
let config = mermaidAPI.getConfig();
|
|
||||||
|
mermaidAPI.initialize(testConfig);
|
||||||
|
|
||||||
|
let config: any = mermaidAPI.getConfig();
|
||||||
|
|
||||||
expect(config.testObject.test1).toBe(1);
|
expect(config.testObject.test1).toBe(1);
|
||||||
mermaidAPI.updateSiteConfig({ testObject: { test3: true } });
|
|
||||||
|
const testObjSetting: any = { testObject: { test3: true } };
|
||||||
|
mermaidAPI.updateSiteConfig(testObjSetting);
|
||||||
config = mermaidAPI.getConfig();
|
config = mermaidAPI.getConfig();
|
||||||
|
|
||||||
expect(config.testObject.test1).toBe(1);
|
expect(config.testObject.test1).toBe(1);
|
||||||
expect(config.testObject.test2).toBe(false);
|
expect(config.testObject.test2).toBe(false);
|
||||||
expect(config.testObject.test3).toBe(true);
|
expect(config.testObject.test3).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reset mermaid config to global defaults', function () {
|
it('should reset mermaid config to global defaults', function () {
|
||||||
let config = {
|
const config = {
|
||||||
logLevel: 0,
|
logLevel: 0,
|
||||||
securityLevel: 'loose',
|
securityLevel: 'loose',
|
||||||
};
|
};
|
||||||
@ -458,7 +516,7 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should prevent changes to site defaults (sneaky)', function () {
|
it('should prevent changes to site defaults (sneaky)', function () {
|
||||||
let config = {
|
const config: any = {
|
||||||
logLevel: 0,
|
logLevel: 0,
|
||||||
};
|
};
|
||||||
mermaidAPI.initialize(config);
|
mermaidAPI.initialize(config);
|
||||||
@ -477,11 +535,12 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
expect(mermaidAPI.getConfig()).toEqual(siteConfig);
|
expect(mermaidAPI.getConfig()).toEqual(siteConfig);
|
||||||
});
|
});
|
||||||
it('should prevent clobbering global defaults (direct)', function () {
|
it('should prevent clobbering global defaults (direct)', function () {
|
||||||
let config = assignWithDepth({}, mermaidAPI.defaultConfig);
|
const config = assignWithDepth({}, mermaidAPI.defaultConfig);
|
||||||
assignWithDepth(config, { logLevel: 0 });
|
assignWithDepth(config, { logLevel: 0 });
|
||||||
|
|
||||||
let error = { message: '' };
|
let error: any = { message: '' };
|
||||||
try {
|
try {
|
||||||
|
// @ts-ignore This is a read-only property. Typescript will not allow assignment, but regular javascript might.
|
||||||
mermaidAPI['defaultConfig'] = config;
|
mermaidAPI['defaultConfig'] = config;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e;
|
error = e;
|
||||||
@ -492,7 +551,7 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
||||||
});
|
});
|
||||||
it('should prevent changes to global defaults (direct)', function () {
|
it('should prevent changes to global defaults (direct)', function () {
|
||||||
let error = { message: '' };
|
let error: any = { message: '' };
|
||||||
try {
|
try {
|
||||||
mermaidAPI.defaultConfig['logLevel'] = 0;
|
mermaidAPI.defaultConfig['logLevel'] = 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -504,10 +563,10 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
|
||||||
});
|
});
|
||||||
it('should prevent sneaky changes to global defaults (assignWithDepth)', function () {
|
it('should prevent sneaky changes to global defaults (assignWithDepth)', function () {
|
||||||
let config = {
|
const config = {
|
||||||
logLevel: 0,
|
logLevel: 0,
|
||||||
};
|
};
|
||||||
let error = { message: '' };
|
let error: any = { message: '' };
|
||||||
try {
|
try {
|
||||||
assignWithDepth(mermaidAPI.defaultConfig, config);
|
assignWithDepth(mermaidAPI.defaultConfig, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -522,7 +581,8 @@ describe('when using mermaidAPI and ', function () {
|
|||||||
describe('dompurify config', function () {
|
describe('dompurify config', function () {
|
||||||
it('should allow dompurify config to be set', function () {
|
it('should allow dompurify config to be set', function () {
|
||||||
mermaidAPI.initialize({ dompurifyConfig: { ADD_ATTR: ['onclick'] } });
|
mermaidAPI.initialize({ dompurifyConfig: { ADD_ATTR: ['onclick'] } });
|
||||||
expect(mermaidAPI.getConfig().dompurifyConfig.ADD_ATTR).toEqual(['onclick']);
|
|
||||||
|
expect(mermaidAPI!.getConfig()!.dompurifyConfig!.ADD_ATTR).toEqual(['onclick']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('test mermaidApi.parse() for checking validity of input ', function () {
|
describe('test mermaidApi.parse() for checking validity of input ', function () {
|
@ -39,9 +39,9 @@ const MAX_TEXTLENGTH_EXCEEDED_MSG =
|
|||||||
const SECURITY_LVL_SANDBOX = 'sandbox';
|
const SECURITY_LVL_SANDBOX = 'sandbox';
|
||||||
const SECURITY_LVL_LOOSE = 'loose';
|
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_SVG_STD = 'http://www.w3.org/2000/svg';
|
||||||
const XMLNS_XLINK_STD = 'http://www.w3.org/1999/xlink';
|
const XMLNS_XLINK_STD = 'http://www.w3.org/1999/xlink';
|
||||||
|
const XMLNS_XHTML_STD = 'http://www.w3.org/1999/xhtml';
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
// iFrame
|
// iFrame
|
||||||
@ -87,12 +87,10 @@ export const encodeEntities = function (text: string): string {
|
|||||||
let txt = text;
|
let txt = text;
|
||||||
|
|
||||||
txt = txt.replace(/style.*:\S*#.*;/g, function (s) {
|
txt = txt.replace(/style.*:\S*#.*;/g, function (s) {
|
||||||
const innerTxt = s.substring(0, s.length - 1);
|
return s.substring(0, s.length - 1);
|
||||||
return innerTxt;
|
|
||||||
});
|
});
|
||||||
txt = txt.replace(/classDef.*:\S*#.*;/g, function (s) {
|
txt = txt.replace(/classDef.*:\S*#.*;/g, function (s) {
|
||||||
const innerTxt = s.substring(0, s.length - 1);
|
return s.substring(0, s.length - 1);
|
||||||
return innerTxt;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
txt = txt.replace(/#\w+;/g, function (s) {
|
txt = txt.replace(/#\w+;/g, function (s) {
|
||||||
@ -211,6 +209,29 @@ export const createCssStyles = (
|
|||||||
return cssStyles;
|
return cssStyles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createUserStyles = (
|
||||||
|
config: MermaidConfig,
|
||||||
|
graphType: string,
|
||||||
|
classDefs: null | DiagramStyleClassDef,
|
||||||
|
svgId: string
|
||||||
|
): string => {
|
||||||
|
const userCSSstyles = createCssStyles(config, graphType, classDefs);
|
||||||
|
const allStyles = getStyles(graphType, userCSSstyles, config.themeVariables);
|
||||||
|
|
||||||
|
// Now turn all of the styles into a (compiled) string that starts with the id
|
||||||
|
// use the stylis library to compile the css, turn the results into a valid CSS string (serialize(...., stringify))
|
||||||
|
// @see https://github.com/thysultan/stylis
|
||||||
|
return serialize(compile(`${svgId}{${allStyles}}`), stringify);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up svgCode. Do replacements needed
|
||||||
|
*
|
||||||
|
* @param {string} svgCode
|
||||||
|
* @param {boolean} inSandboxMode - security level
|
||||||
|
* @param {boolean} useArrowMarkerUrls - should arrow marker's use full urls? (vs. just the anchors)
|
||||||
|
* @returns {string} the cleaned up svgCode
|
||||||
|
*/
|
||||||
export const cleanUpSvgCode = (
|
export const cleanUpSvgCode = (
|
||||||
svgCode = '',
|
svgCode = '',
|
||||||
inSandboxMode: boolean,
|
inSandboxMode: boolean,
|
||||||
@ -424,23 +445,22 @@ const render = async function (
|
|||||||
parseEncounteredException = error;
|
parseEncounteredException = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the tmp div element containing the svg
|
// Get the temporary div element containing the svg
|
||||||
const element = root.select(enclosingDivID_selector).node();
|
const element = root.select(enclosingDivID_selector).node();
|
||||||
const graphType = diag.type;
|
const graphType = diag.type;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Create and insert the styles (user styles, theme styles, config styles)
|
// Create and insert the styles (user styles, theme styles, config styles)
|
||||||
|
|
||||||
// insert inline style into svg
|
// Insert an element into svg. This is where we put the styles
|
||||||
const svg = element.firstChild;
|
const svg = element.firstChild;
|
||||||
const firstChild = svg.firstChild;
|
const firstChild = svg.firstChild;
|
||||||
|
const rules = createUserStyles(
|
||||||
const userDefClasses: any = flowRenderer.getClasses(text, diag);
|
config,
|
||||||
const cssStyles = createCssStyles(config, graphType, userDefClasses);
|
graphType,
|
||||||
|
flowRenderer.getClasses(text, diag),
|
||||||
const stylis = (selector: string, styles: string) =>
|
idSelector
|
||||||
serialize(compile(`${selector}{${styles}}`), stringify);
|
);
|
||||||
const rules = stylis(`${idSelector}`, getStyles(graphType, cssStyles, config.themeVariables));
|
|
||||||
|
|
||||||
const style1 = document.createElement('style');
|
const style1 = document.createElement('style');
|
||||||
style1.innerHTML = `${idSelector} ` + rules;
|
style1.innerHTML = `${idSelector} ` + rules;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user