mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-14 06:43:25 +08:00
Merge branch 'mermaid-js:develop' into add-pie-langium-parser
This commit is contained in:
commit
a2a99485f9
@ -583,4 +583,106 @@ describe('Gantt diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a semicolon in the title", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title ;Gantt With a Semicolon in the Title
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a semicolon in a section is true", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title Gantt Digram
|
||||
dateFormat YYYY-MM-DD
|
||||
section ;Section With a Semicolon
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a semicolon in the task data", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title Gantt Digram
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
;A task with a semiclon :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a hashtag in the title", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title #Gantt With a Hashtag in the Title
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a hashtag in a section is true", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title Gantt Digram
|
||||
dateFormat YYYY-MM-DD
|
||||
section #Section With a Hashtag
|
||||
A task :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it("should render when there's a hashtag in the task data", () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title Gantt Digram
|
||||
dateFormat YYYY-MM-DD
|
||||
section Section
|
||||
#A task with a hashtag :a1, 2014-01-01, 30d
|
||||
Another task :after a1 , 20d
|
||||
section Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -792,6 +792,34 @@ context('Sequence diagram', () => {
|
||||
});
|
||||
});
|
||||
context('links', () => {
|
||||
it('should support actor links', () => {
|
||||
renderGraph(
|
||||
`
|
||||
sequenceDiagram
|
||||
link Alice: Dashboard @ https://dashboard.contoso.com/alice
|
||||
link Alice: Wiki @ https://wiki.contoso.com/alice
|
||||
link John: Dashboard @ https://dashboard.contoso.com/john
|
||||
link John: Wiki @ https://wiki.contoso.com/john
|
||||
Alice->>John: Hello John<br/>
|
||||
John-->>Alice: Great<br/><br/>day!
|
||||
`,
|
||||
{ securityLevel: 'loose' }
|
||||
);
|
||||
cy.get('#actor0_popup').should((popupMenu) => {
|
||||
const style = popupMenu.attr('style');
|
||||
expect(style).to.undefined;
|
||||
});
|
||||
cy.get('#root-0').click();
|
||||
cy.get('#actor0_popup').should((popupMenu) => {
|
||||
const style = popupMenu.attr('style');
|
||||
expect(style).to.match(/^display: block;$/);
|
||||
});
|
||||
cy.get('#root-0').click();
|
||||
cy.get('#actor0_popup').should((popupMenu) => {
|
||||
const style = popupMenu.attr('style');
|
||||
expect(style).to.match(/^display: none;$/);
|
||||
});
|
||||
});
|
||||
it('should support actor links and properties EXPERIMENTAL: USE WITH CAUTION', () => {
|
||||
//Be aware that the syntax for "properties" is likely to be changed.
|
||||
imgSnapshotTest(
|
||||
|
@ -30,6 +30,21 @@
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
gantt
|
||||
title #; Gantt Diagrams Allow Semicolons and Hashtags #;!
|
||||
accTitle: A simple sample gantt diagram
|
||||
accDescr: 2 sections with 2 tasks each, from 2014
|
||||
dateFormat YYYY-MM-DD
|
||||
section #;Section
|
||||
#;A task :a1, 2014-01-01, 30d
|
||||
#;Another task :after a1 , 20d
|
||||
section #;Another
|
||||
Task in sec :2014-01-12 , 12d
|
||||
another task : 24d
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
gantt
|
||||
title Airworks roadmap
|
||||
|
@ -23,6 +23,10 @@
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant John as John<br />Second Line
|
||||
link Alice: Dashboard @ https://dashboard.contoso.com/alice
|
||||
link Alice: Wiki @ https://wiki.contoso.com/alice
|
||||
link John: Dashboard @ https://dashboard.contoso.com/john
|
||||
link John: Wiki @ https://wiki.contoso.com/john
|
||||
autonumber 10 10
|
||||
rect rgb(200, 220, 100)
|
||||
rect rgb(200, 255, 200)
|
||||
@ -62,6 +66,26 @@
|
||||
</pre>
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: With forced menus
|
||||
config:
|
||||
sequence:
|
||||
forceMenus: true
|
||||
---
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
link Alice: Dashboard @ https://dashboard.contoso.com/alice
|
||||
link Alice: Wiki @ https://wiki.contoso.com/alice
|
||||
link John: Dashboard @ https://dashboard.contoso.com/john
|
||||
link John: Wiki @ https://wiki.contoso.com/john
|
||||
Alice->>John: Hello John, how are you?
|
||||
John-->>Alice: Great!
|
||||
Alice-)John: See you later!
|
||||
</pre
|
||||
>
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
accTitle: Sequence diagram title is here
|
||||
accDescr: Hello friends
|
||||
|
@ -18,13 +18,18 @@ export const getRows = (s?: string): string[] => {
|
||||
return str.split('#br#');
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes script tags from a text
|
||||
*
|
||||
* @param txt - The text to sanitize
|
||||
* @returns The safer text
|
||||
*/
|
||||
export const removeScript = (txt: string): string => {
|
||||
const setupDompurifyHooksIfNotSetup = (() => {
|
||||
let setup = false;
|
||||
|
||||
return () => {
|
||||
if (!setup) {
|
||||
setupDompurifyHooks();
|
||||
setup = true;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
function setupDompurifyHooks() {
|
||||
const TEMPORARY_ATTRIBUTE = 'data-temp-href-target';
|
||||
|
||||
DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => {
|
||||
@ -33,8 +38,6 @@ export const removeScript = (txt: string): string => {
|
||||
}
|
||||
});
|
||||
|
||||
const sanitizedText = DOMPurify.sanitize(txt);
|
||||
|
||||
DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => {
|
||||
if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
|
||||
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) || '');
|
||||
@ -44,6 +47,18 @@ export const removeScript = (txt: string): string => {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes script tags from a text
|
||||
*
|
||||
* @param txt - The text to sanitize
|
||||
* @returns The safer text
|
||||
*/
|
||||
export const removeScript = (txt: string): string => {
|
||||
setupDompurifyHooksIfNotSetup();
|
||||
|
||||
const sanitizedText = DOMPurify.sanitize(txt);
|
||||
|
||||
return sanitizedText;
|
||||
};
|
||||
|
@ -27,11 +27,10 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
|
||||
\%\%(?!\{)*[^\n]* /* skip comments */
|
||||
[^\}]\%\%*[^\n]* /* skip comments */
|
||||
\%\%*[^\n]*[\n]* /* do nothing */
|
||||
\%\%*[^\n]*[\n]* /* do nothing */
|
||||
|
||||
[\n]+ return 'NL';
|
||||
\s+ /* skip whitespace */
|
||||
\#[^\n]* /* skip comments */
|
||||
\%%[^\n]* /* skip comments */
|
||||
|
||||
/*
|
||||
@ -86,10 +85,10 @@ weekday\s+friday return 'weekday_friday'
|
||||
weekday\s+saturday return 'weekday_saturday'
|
||||
weekday\s+sunday return 'weekday_sunday'
|
||||
\d\d\d\d"-"\d\d"-"\d\d return 'date';
|
||||
"title"\s[^#\n;]+ return 'title';
|
||||
"title"\s[^\n]+ return 'title';
|
||||
"accDescription"\s[^#\n;]+ return 'accDescription'
|
||||
"section"\s[^#:\n;]+ return 'section';
|
||||
[^#:\n;]+ return 'taskTxt';
|
||||
"section"\s[^\n]+ return 'section';
|
||||
[^:\n]+ return 'taskTxt';
|
||||
":"[^#\n;]+ return 'taskData';
|
||||
":" return ':';
|
||||
<<EOF>> return 'EOF';
|
||||
|
@ -28,8 +28,12 @@ describe('when parsing a gantt diagram it', function () {
|
||||
});
|
||||
it('should handle a title definition', function () {
|
||||
const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid';
|
||||
const semi = 'gantt\ndateFormat yyyy-mm-dd\ntitle ;Gantt diagram titles support semicolons';
|
||||
const hash = 'gantt\ndateFormat yyyy-mm-dd\ntitle #Gantt diagram titles support hashtags';
|
||||
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(parserFnConstructor(semi)).not.toThrow();
|
||||
expect(parserFnConstructor(hash)).not.toThrow();
|
||||
});
|
||||
it('should handle an excludes definition', function () {
|
||||
const str =
|
||||
@ -53,7 +57,23 @@ describe('when parsing a gantt diagram it', function () {
|
||||
'excludes weekdays 2019-02-01\n' +
|
||||
'section Documentation';
|
||||
|
||||
const semi =
|
||||
'gantt\n' +
|
||||
'dateFormat yyyy-mm-dd\n' +
|
||||
'title Adding gantt diagram functionality to mermaid\n' +
|
||||
'excludes weekdays 2019-02-01\n' +
|
||||
'section ;Documentation';
|
||||
|
||||
const hash =
|
||||
'gantt\n' +
|
||||
'dateFormat yyyy-mm-dd\n' +
|
||||
'title Adding gantt diagram functionality to mermaid\n' +
|
||||
'excludes weekdays 2019-02-01\n' +
|
||||
'section #Documentation';
|
||||
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(parserFnConstructor(semi)).not.toThrow();
|
||||
expect(parserFnConstructor(hash)).not.toThrow();
|
||||
});
|
||||
it('should handle multiline section titles with different line breaks', function () {
|
||||
const str =
|
||||
@ -73,7 +93,23 @@ describe('when parsing a gantt diagram it', function () {
|
||||
'section Documentation\n' +
|
||||
'Design jison grammar:des1, 2014-01-01, 2014-01-04';
|
||||
|
||||
const semi =
|
||||
'gantt\n' +
|
||||
'dateFormat YYYY-MM-DD\n' +
|
||||
'title Adding gantt diagram functionality to mermaid\n' +
|
||||
'section Documentation\n' +
|
||||
';Design jison grammar:des1, 2014-01-01, 2014-01-04';
|
||||
|
||||
const hash =
|
||||
'gantt\n' +
|
||||
'dateFormat YYYY-MM-DD\n' +
|
||||
'title Adding gantt diagram functionality to mermaid\n' +
|
||||
'section Documentation\n' +
|
||||
'#Design jison grammar:des1, 2014-01-01, 2014-01-04';
|
||||
|
||||
expect(parserFnConstructor(str)).not.toThrow();
|
||||
expect(parserFnConstructor(semi)).not.toThrow();
|
||||
expect(parserFnConstructor(hash)).not.toThrow();
|
||||
|
||||
const tasks = parser.yy.getTasks();
|
||||
|
||||
|
@ -10,22 +10,6 @@ export const drawRect = function (elem, rectData) {
|
||||
return svgDrawCommon.drawRect(elem, rectData);
|
||||
};
|
||||
|
||||
const addPopupInteraction = (id, actorCnt) => {
|
||||
addFunction(() => {
|
||||
const arr = document.querySelectorAll(id);
|
||||
// This will be the case when running in sandboxed mode
|
||||
if (arr.length === 0) {
|
||||
return;
|
||||
}
|
||||
arr[0].addEventListener('mouseover', function () {
|
||||
popupMenuUpFunc('actor' + actorCnt + '_popup');
|
||||
});
|
||||
arr[0].addEventListener('mouseout', function () {
|
||||
popupMenuDownFunc('actor' + actorCnt + '_popup');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const drawPopup = function (elem, actor, minMenuWidth, textAttrs, forceMenus) {
|
||||
if (actor.links === undefined || actor.links === null || Object.keys(actor.links).length === 0) {
|
||||
return { height: 0, width: 0 };
|
||||
@ -44,7 +28,6 @@ export const drawPopup = function (elem, actor, minMenuWidth, textAttrs, forceMe
|
||||
g.attr('id', 'actor' + actorCnt + '_popup');
|
||||
g.attr('class', 'actorPopupMenu');
|
||||
g.attr('display', displayValue);
|
||||
addPopupInteraction('#actor' + actorCnt + '_popup', actorCnt);
|
||||
var actorClass = '';
|
||||
if (rectData.class !== undefined) {
|
||||
actorClass = ' ' + rectData.class;
|
||||
@ -90,36 +73,14 @@ export const drawPopup = function (elem, actor, minMenuWidth, textAttrs, forceMe
|
||||
return { height: rectData.height + linkY, width: menuWidth };
|
||||
};
|
||||
|
||||
export const popupMenu = function (popid) {
|
||||
const popupMenuToggle = function (popid) {
|
||||
return (
|
||||
"var pu = document.getElementById('" +
|
||||
popid +
|
||||
"'); if (pu != null) { pu.style.display = 'block'; }"
|
||||
"'); if (pu != null) { pu.style.display = pu.style.display == 'block' ? 'none' : 'block'; }"
|
||||
);
|
||||
};
|
||||
|
||||
export const popdownMenu = function (popid) {
|
||||
return (
|
||||
"var pu = document.getElementById('" +
|
||||
popid +
|
||||
"'); if (pu != null) { pu.style.display = 'none'; }"
|
||||
);
|
||||
};
|
||||
|
||||
const popupMenuUpFunc = function (popupId) {
|
||||
var pu = document.getElementById(popupId);
|
||||
if (pu != null) {
|
||||
pu.style.display = 'block';
|
||||
}
|
||||
};
|
||||
|
||||
const popupMenuDownFunc = function (popupId) {
|
||||
var pu = document.getElementById(popupId);
|
||||
if (pu != null) {
|
||||
pu.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
export const drawText = function (elem, textData) {
|
||||
let prevTextHeight = 0;
|
||||
let textHeight = 0;
|
||||
@ -329,6 +290,9 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
if (Object.keys(actor.links || {}).length && !conf.forceMenus) {
|
||||
g.attr('onclick', popupMenuToggle(`actor${actorCnt}_popup`)).attr('cursor', 'pointer');
|
||||
}
|
||||
g.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
@ -345,7 +309,6 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
|
||||
if (actor.links != null) {
|
||||
g.attr('id', 'root-' + actorCnt);
|
||||
addPopupInteraction('#root-' + actorCnt, actorCnt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1053,8 +1016,6 @@ export default {
|
||||
insertClockIcon,
|
||||
getTextObj,
|
||||
getNoteRect,
|
||||
popupMenu,
|
||||
popdownMenu,
|
||||
fixLifeLineHeights,
|
||||
sanitizeUrl,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user