mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-28 19:59:43 +02:00
Merge branch 'master' into develop
This commit is contained in:
@@ -215,6 +215,14 @@ Mermaid is a growing community and is always accepting new contributors. There's
|
||||
|
||||
Detailed information about how to contribute can be found in the [contribution guide](CONTRIBUTING.md)
|
||||
|
||||
## Security and safe diagrams
|
||||
|
||||
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
|
||||
|
||||
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
|
||||
|
||||
*Unfortunately you can not have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code.*
|
||||
|
||||
## Reporting vulnerabilities
|
||||
To report a vulnerability, please e-mail security@mermaid.live with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue.
|
||||
|
||||
|
170
cypress/platform/click_security_sandbox.html
Normal file
170
cypress/platform/click_security_sandbox.html
Normal file
@@ -0,0 +1,170 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
|
||||
<style>
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="display: flex">
|
||||
<div id="FirstLine" class="mermaid">
|
||||
graph TB
|
||||
Function-->URL
|
||||
click Function clickByFlow "Add a div"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</div>
|
||||
<div id="FirstLine" class="mermaid">
|
||||
graph TB
|
||||
1Function--->2URL
|
||||
click 1Function clickByFlow "Add a div"
|
||||
click 2URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</div>
|
||||
<div id="FirstLine" class="mermaid">
|
||||
flowchart TB
|
||||
Function-->URL
|
||||
click Function clickByFlow "Add a div"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>" _self
|
||||
</div>
|
||||
<div id="FirstLine" class="mermaid">
|
||||
flowchart TB
|
||||
1Function--->2URL
|
||||
click 1Function clickByFlow "Add a div"
|
||||
click 2URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>" _self
|
||||
</div>
|
||||
|
||||
<div id="FirstLine" class="mermaid">
|
||||
classDiagram
|
||||
class ShapeLink
|
||||
link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback
|
||||
callback ShapeCallback "clickByClass" "This is a tooltip for a callback"
|
||||
</div>
|
||||
<div id="FirstLine" class="mermaid">
|
||||
classDiagram-v2
|
||||
class ShapeLink2
|
||||
link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback2
|
||||
callback ShapeCallback2 "clickByClass" "This is a tooltip for a callback"
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mermaid">
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d/%m
|
||||
title Adding GANTT diagram to mermaid
|
||||
excludes weekdays 2014-01-10
|
||||
|
||||
section A section
|
||||
Completed task :done, des1, 2014-01-06,2014-01-08
|
||||
Active task :active, des2, 2014-01-09, 3d
|
||||
Future task : des3, after des2, 5d
|
||||
Future task2 : des4, after des3, 5d
|
||||
|
||||
section Critical tasks
|
||||
Completed task in the critical line :crit, done, 2014-01-06,24h
|
||||
Implement parser and jison :crit, done, after des1, 2d
|
||||
Create tests for parser :crit, active, 3d
|
||||
Future task in critical line :crit, 5d
|
||||
Create tests for renderer :2d
|
||||
Add to mermaid :1d
|
||||
|
||||
section Documentation
|
||||
Describe gantt syntax :active, a1, after des1, 3d
|
||||
Add gantt diagram to demo page :after a1 , 20h
|
||||
Add another diagram to demo page :doc1, after a1 , 48h
|
||||
|
||||
section Clickable
|
||||
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
||||
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
||||
Calling a Callback with args :cl3, after cl1, 3d
|
||||
|
||||
click cl1 href "http://localhost:9000/webpackUsage.html"
|
||||
click cl2 call clickByGantt()
|
||||
click cl3 call clickByGantt("test1", test2, test3)
|
||||
|
||||
section Last section
|
||||
Describe gantt syntax :after doc1, 3d
|
||||
Add gantt diagram to demo page : 20h
|
||||
Add another diagram to demo page : 48h
|
||||
</div>
|
||||
<div style="display: flex">
|
||||
<div id="FirstLine" class="mermaid">
|
||||
graph TB
|
||||
FunctionArg-->URL
|
||||
click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</div>
|
||||
<div id="FirstLine" class="mermaid">
|
||||
flowchart TB
|
||||
FunctionArg-->URL
|
||||
click FunctionArg call clickByFlowArg(ARGUMENT) "Add a div"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</div>
|
||||
|
||||
<div id="FirstLine" class="mermaid">
|
||||
classDiagram
|
||||
class ShapeLink
|
||||
link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback
|
||||
click ShapeCallback call clickByClass(123) "This is a tooltip for a callback"
|
||||
</div>
|
||||
|
||||
<div id="FirstLine" class="mermaid">
|
||||
classDiagram-v2
|
||||
class ShapeLink2
|
||||
link ShapeLink2 "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback2
|
||||
click ShapeCallback2 call clickByClass(123) "This is a tooltip for a callback"
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
function clickByFlow(elemName) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByFlowArg(argument) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click-2';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow: ' + argument;
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByGantt(arg1, arg2, arg3) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-gant-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Gant';
|
||||
if (arg1) div.innerText += ' ' + arg1;
|
||||
if (arg2) div.innerText += ' ' + arg2;
|
||||
if (arg3) div.innerText += ' ' + arg3;
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
function clickByClass(arg) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-class-click';
|
||||
div.style = 'padding: 20px; background: purple; color: white;';
|
||||
div.innerText = 'Clicked By Class' + (arg ? arg : '');
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
mermaid.initialize({ startOnLoad: true, securityLevel: 'sandbox', logLevel: 1 });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -14,6 +14,7 @@
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
h1 { color: grey;}
|
||||
.mermaid2,.mermaid3 {
|
||||
@@ -25,15 +26,214 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>info below</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="mermaid2" style="width: 50%;">
|
||||
pie title Pets adopted by volunteers
|
||||
"Dogs" : 386
|
||||
"Cats" : 85
|
||||
"Rats" : 15
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
gantt
|
||||
title Adding GANTT diagram functionality to mermaid
|
||||
excludes :excludes the named dates/days from being included in a charted task..
|
||||
section Screening
|
||||
Lexplore :active, des1, 2023-01-06,2023-01-08
|
||||
H4 :active, des2, 2024-01-09, 3d
|
||||
Future task : des3, after des2, 5d
|
||||
Future task2 : des4, after des3, 5d
|
||||
|
||||
<div class="mermaid" style="width: 100%; height: 20%;">
|
||||
stateDiagram-v2
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
info
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
gitGraph:
|
||||
options
|
||||
{
|
||||
"nodeSpacing": 150,
|
||||
"nodeRadius": 10
|
||||
}
|
||||
end
|
||||
commit
|
||||
branch newbranch
|
||||
checkout newbranch
|
||||
commit
|
||||
commit
|
||||
checkout master
|
||||
commit
|
||||
commit
|
||||
merge newbranch
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%;">
|
||||
sequenceDiagram
|
||||
participant a as Alice
|
||||
participant j as John
|
||||
note right of a: Hello world!
|
||||
properties a: {"class": "internal-service-actor", "type": "@clock"}
|
||||
properties j: {"class": "external-service-actor", "type": "@computer"}
|
||||
links a: {"Repo": "https://www.contoso.com/repo", "Swagger": "https://www.contoso.com/swagger"}
|
||||
links j: {"Repo": "https://www.contoso.com/repo"}
|
||||
links a: {"Dashboard": "https://www.contoso.com/dashboard", "On-Call": "https://www.contoso.com/oncall"}
|
||||
link a: Contacts @ https://contacts.contoso.com/?contact=alice@contoso.com
|
||||
a->>j: Hello John, how are you?
|
||||
j-->>a: Great! </div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
journey
|
||||
title My working day
|
||||
section Go to work
|
||||
Make tea: 5: Me
|
||||
Go upstairs: 3: Me
|
||||
Do work: 1: Me, Cat
|
||||
section Go home
|
||||
Go downstairs: 5: Me
|
||||
Sit down: 5: Me
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
requirementDiagram
|
||||
|
||||
requirement test_req {
|
||||
id: 1
|
||||
text: the test text.
|
||||
risk: high
|
||||
verifymethod: test
|
||||
}
|
||||
|
||||
functionalRequirement test_req2 {
|
||||
id: 1.1
|
||||
text: the second test text.
|
||||
risk: low
|
||||
verifymethod: inspection
|
||||
}
|
||||
|
||||
performanceRequirement test_req3 {
|
||||
id: 1.2
|
||||
text: the third test text.
|
||||
risk: medium
|
||||
verifymethod: demonstration
|
||||
}
|
||||
|
||||
element test_entity {
|
||||
type: simulation
|
||||
}
|
||||
|
||||
element test_entity2 {
|
||||
type: word doc
|
||||
docRef: reqs/test_entity
|
||||
}
|
||||
|
||||
|
||||
test_entity - satisfies -> test_req2
|
||||
test_req - traces -> test_req2
|
||||
test_req - contains -> test_req3
|
||||
test_req <- copies - test_entity2
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
erDiagram
|
||||
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
|
||||
CUSTOMER ||--o{ ORDER : places
|
||||
CUSTOMER ||--o{ INVOICE : "liable for"
|
||||
DELIVERY-ADDRESS ||--o{ ORDER : receives
|
||||
INVOICE ||--|{ ORDER : covers
|
||||
ORDER ||--|{ ORDER-ITEM : includes
|
||||
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
|
||||
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
graph TB
|
||||
subgraph One
|
||||
a1-->a2-->a3
|
||||
end
|
||||
</div>
|
||||
<div class="mermaid" style="width: 50%;">
|
||||
flowchart LR
|
||||
Function-->URL-->A-->B-->C
|
||||
click Function clickByFlow "Add a div"
|
||||
click URL "https://mermaid-js.github.io/mermaid/#/" "Visit <strong>mermaid docs</strong>" _blank
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d/%m
|
||||
title Adding GANTT diagram to mermaid
|
||||
excludes weekdays 2014-01-10
|
||||
|
||||
section A section
|
||||
Completed task :done, des1, 2014-01-06,2014-01-08
|
||||
Active task :active, des2, 2014-01-09, 3d
|
||||
Future task : des3, after des2, 5d
|
||||
Future task2 : des4, after des3, 5d
|
||||
|
||||
section Critical tasks
|
||||
Completed task in the critical line :crit, done, 2014-01-06,24h
|
||||
Implement parser and jison :crit, done, after des1, 2d
|
||||
Create tests for parser :crit, active, 3d
|
||||
Future task in critical line :crit, 5d
|
||||
Create tests for renderer :2d
|
||||
Add to mermaid :1d
|
||||
|
||||
section Documentation
|
||||
Describe gantt syntax :active, a1, after des1, 3d
|
||||
Add gantt diagram to demo page :after a1 , 20h
|
||||
Add another diagram to demo page :doc1, after a1 , 48h
|
||||
|
||||
section Clickable
|
||||
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
||||
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
||||
Calling a Callback with args :cl3, after cl1, 3d
|
||||
|
||||
click cl1 href "https://mermaid-js.github.io/mermaid/#/"
|
||||
click cl2 call clickByGantt()
|
||||
click cl3 call clickByGantt("test1", test2, test3)
|
||||
|
||||
section Last section
|
||||
Describe gantt syntax :after doc1, 3d
|
||||
Add gantt diagram to demo page : 20h
|
||||
Add another diagram to demo page : 48h
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
classDiagram
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
Class09 --> C2 : Where am i?
|
||||
Class09 --* C3
|
||||
Class09 --|> Class07
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
class Class10 {
|
||||
int id
|
||||
size()
|
||||
}
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
stateDiagram
|
||||
[*] --> S1
|
||||
state "Some long name" as S1
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="mermaid2" style="width: 100%;">
|
||||
classDiagram
|
||||
Animal "1" <|-- Duck
|
||||
Animal <|-- Fish
|
||||
Animal <--o Zebra
|
||||
Animal : +int age
|
||||
Animal : +String gender
|
||||
Animal: +isMammal()
|
||||
Animal: +mate()
|
||||
class Duck{
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
class Fish{
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
class Zebra{
|
||||
+bool is_wild
|
||||
+run()
|
||||
}
|
||||
</div>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
@@ -42,29 +242,52 @@ stateDiagram-v2
|
||||
};
|
||||
mermaid.initialize({
|
||||
// theme: 'dark',
|
||||
theme: 'forest',
|
||||
arrowMarkerAbsolute: true,
|
||||
// theme: 'forest',
|
||||
// arrowMarkerAbsolute: true,
|
||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: false },
|
||||
flowchart: {
|
||||
nodeSpacing: 10,
|
||||
curve: 'cardinal',
|
||||
htmlLabels: true,
|
||||
defaultRenderer: 'dagre-d3',
|
||||
},
|
||||
class: {
|
||||
defaultRenderer: 'dagre-d3',
|
||||
htmlLabels: true,
|
||||
},
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
actorMargin: 50,
|
||||
showSequenceNumbers: false,
|
||||
// forceMenus: true,
|
||||
},
|
||||
// sequenceDiagram: { actorMargin: 300, forceMenus: false }, // deprecated
|
||||
// fontFamily: '"times", sans-serif',
|
||||
// fontFamily: 'courier',
|
||||
state: {
|
||||
nodeSpacing: 50,
|
||||
rankSpacing: 50,
|
||||
defaultRenderer: 'dagre-wrapper',
|
||||
defaultRenderer: 'dagre-d3',
|
||||
},
|
||||
logLevel: 0,
|
||||
fontSize: 18,
|
||||
curve: 'cardinal',
|
||||
securityLevel: 'strict',
|
||||
// securityLevel: 'sandbox',
|
||||
// themeVariables: {relationLabelColor: 'red'}
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
|
||||
function clickByFlow(elemName) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -12,9 +12,11 @@
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>mermaid.init({ startOnLoad: false });
|
||||
mermaid.mermaidAPI.initialize();
|
||||
|
||||
mermaid.mermaidAPI.initialize({ securityLevel: 'strict' });
|
||||
|
||||
try {
|
||||
console.log('rendering');
|
||||
mermaid.mermaidAPI.render('graphDiv', `>`);
|
||||
} catch (e) {}
|
||||
|
||||
|
@@ -70,7 +70,7 @@
|
||||
// fontFamily: 'courier',
|
||||
fontSize: 18,
|
||||
curve: 'basis',
|
||||
// securityLevel: 'loose',
|
||||
securityLevel: 'sandbox',
|
||||
startOnLoad: false,
|
||||
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'],
|
||||
// themeVariables: {relationLabelColor: 'red'}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
Binary file not shown.
After Width: | Height: | Size: 162 KiB |
@@ -197,7 +197,8 @@ To Deploy Mermaid:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
<script>mermaid.initialize({startOnLoad:true});</script>
|
||||
<script>mermaid.initialize({startOnLoad:true});
|
||||
</script>
|
||||
```
|
||||
**Doing so will command the mermaid parser to look for the `<div>` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into svg charts.**
|
||||
|
||||
@@ -267,6 +268,15 @@ npm publish
|
||||
|
||||
The above command generates files into the `dist` folder and publishes them to npmjs.org.
|
||||
|
||||
## Security and safe diagrams
|
||||
|
||||
For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes.
|
||||
|
||||
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
|
||||
|
||||
*Unfortunately you can not have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code.*
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
Many thanks to the [d3](http://d3js.org/) and [dagre-d3](https://github.com/cpettitt/dagre-d3) projects for providing the graphical layout and drawing libraries!
|
||||
|
@@ -1057,6 +1057,10 @@ Returns **any**
|
||||
|
||||
- `conf` **any**
|
||||
|
||||
## reinitialize
|
||||
|
||||
To be removed
|
||||
|
||||
## initialize
|
||||
|
||||
### Parameters
|
||||
|
@@ -255,7 +255,7 @@ graph TB
|
||||
B --> D
|
||||
```
|
||||
|
||||
### Beta: New arrow types
|
||||
### New arrow types
|
||||
|
||||
When using flowchart instead of graph there are new types of arrows supported as per below:
|
||||
|
||||
@@ -266,7 +266,7 @@ flowchart LR
|
||||
```
|
||||
|
||||
|
||||
### Beta: Multi directional arrows
|
||||
### Multi directional arrows
|
||||
|
||||
When using flowchart instead of graph there is the possibility to use multidirectional arrows.
|
||||
|
||||
@@ -377,9 +377,9 @@ graph TB
|
||||
end
|
||||
```
|
||||
|
||||
## Beta: flowcharts
|
||||
## flowcharts
|
||||
|
||||
With the graphtype flowcharts it is also possible to set edges to and from subgraphs as in the graph below.
|
||||
With the graphtype flowchart it is also possible to set edges to and from subgraphs as in the graph below.
|
||||
|
||||
```mermaid-example
|
||||
flowchart TB
|
||||
|
@@ -281,11 +281,11 @@ to node _E_, so that it spans two more ranks than regular links:
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A[Start] --> B{Is it?};
|
||||
B -->|Yes| C[OK];
|
||||
C --> D[Rethink];
|
||||
D --> B;
|
||||
B ---->|No| E[End];
|
||||
A[Start] --> B{Is it?}
|
||||
B -->|Yes| C[OK]
|
||||
C --> D[Rethink]
|
||||
D --> B
|
||||
B ---->|No| E[End]
|
||||
```
|
||||
|
||||
> **Note** Links may still be made longer than the requested number of ranks
|
||||
@@ -297,11 +297,11 @@ the previous one:
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A[Start] --> B{Is it?};
|
||||
B -- Yes --> C[OK];
|
||||
C --> D[Rethink];
|
||||
D --> B;
|
||||
B -- No ----> E[End];
|
||||
A[Start] --> B{Is it?}
|
||||
B -- Yes --> C[OK]
|
||||
C --> D[Rethink]
|
||||
D --> B
|
||||
B -- No ----> E[End]
|
||||
```
|
||||
|
||||
For dotted or thick links, the characters to add are equals signs or dots,
|
||||
@@ -370,9 +370,9 @@ flowchart TB
|
||||
end
|
||||
```
|
||||
|
||||
## Beta: flowcharts
|
||||
## flowcharts
|
||||
|
||||
With the graphtype flowcharts it is also possible to set edges to and from subgraphs as in the flowchart below.
|
||||
With the graphtype flowchart it is also possible to set edges to and from subgraphs as in the flowchart below.
|
||||
|
||||
```mermaid-example
|
||||
flowchart TB
|
||||
@@ -437,10 +437,10 @@ Examples of tooltip usage below:
|
||||
The tooltip text is surrounded in double quotes. The styles of the tooltip are set by the class `.mermaidTooltip`.
|
||||
|
||||
```mermaid-example
|
||||
flowchart LR;
|
||||
A-->B;
|
||||
B-->C;
|
||||
C-->D;
|
||||
flowchart LR
|
||||
A-->B
|
||||
B-->C
|
||||
C-->D
|
||||
click A callback "Tooltip for a callback"
|
||||
click B "http://www.github.com" "This is a tooltip for a link"
|
||||
click A call callback() "Tooltip for a callback"
|
||||
@@ -453,11 +453,11 @@ flowchart LR;
|
||||
|
||||
Links are opened in the same browser tab/window by default. It is possible to change this by adding a link target to the click definition (`_self`, `_blank`, `_parent` and `_top` are supported):
|
||||
```mermaid-example
|
||||
flowchart LR;
|
||||
A-->B;
|
||||
B-->C;
|
||||
C-->D;
|
||||
D-->E;
|
||||
flowchart LR
|
||||
A-->B
|
||||
B-->C
|
||||
C-->D
|
||||
D-->E
|
||||
click A "http://www.github.com" _blank
|
||||
click B "http://www.github.com" "Open this in a new tab" _blank
|
||||
click C href "http://www.github.com" _blank
|
||||
@@ -468,10 +468,10 @@ Beginners tip, a full example using interactive links in a html context:
|
||||
```html
|
||||
<body>
|
||||
<div class="mermaid">
|
||||
flowchart LR;
|
||||
A-->B;
|
||||
B-->C;
|
||||
C-->D;
|
||||
flowchart LR
|
||||
A-->B
|
||||
B-->C
|
||||
C-->D
|
||||
click A callback "Tooltip"
|
||||
click B "http://www.github.com" "This is a link"
|
||||
click C call callback() "Tooltip"
|
||||
@@ -587,9 +587,9 @@ below:
|
||||
|
||||
```mermaid-example
|
||||
flowchart LR;
|
||||
A-->B[AAA<span>BBB</span>];
|
||||
B-->D;
|
||||
class A cssClass;
|
||||
A-->B[AAA<span>BBB</span>]
|
||||
B-->D
|
||||
class A cssClass
|
||||
```
|
||||
|
||||
|
||||
@@ -613,7 +613,7 @@ flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B-->C[fa:fa-ban forbidden]
|
||||
B-->D(fa:fa-spinner);
|
||||
B-->E(A fa:fa-camera-retro perhaps?);
|
||||
B-->E(A fa:fa-camera-retro perhaps?)
|
||||
```
|
||||
|
||||
|
||||
|
@@ -50,7 +50,8 @@ The easiest way to integrate mermaid on a web page requires three elements:
|
||||
|
||||
2. The `mermaidAPI` call, in a separate `script` tag. Example:
|
||||
```html
|
||||
<script>mermaid.initialize({startOnLoad:true});</script>
|
||||
<script>mermaid.initialize({startOnLoad:true});
|
||||
</script>
|
||||
```
|
||||
|
||||
3. A graph definition, inside `<div>` tags labeled `class=mermaid`. Example:
|
||||
@@ -82,7 +83,8 @@ locate the graph definitions inside the `div` tags with `class="mermaid"` and re
|
||||
B-->D(fa:fa-spinner);
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
<script>mermaid.initialize({startOnLoad:true});</script>
|
||||
<script>mermaid.initialize({startOnLoad:true});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@@ -105,17 +107,19 @@ Mermaid can load multiple diagrams, in the same page.
|
||||
|
||||
| Parameter | Description | Type | Required | Values |
|
||||
| ------------- | --------------------------------- | ------ | -------- | ------------------------- |
|
||||
| securityLevel | Level of trust for parsed diagram | String | Required | Strict, Loose, antiscript |
|
||||
| securityLevel | Level of trust for parsed diagram | String | Required | Strict, Loose, antiscript , sandbox|
|
||||
|
||||
Values:
|
||||
|
||||
- **strict**: (**default**) tags in text are encoded, click functionality is disabled
|
||||
- **loose**: tags in text are allowed, click functionality is enabled
|
||||
- **antiscript**: html tags in text are allowed, (only script element is removed), click functionality is enabled
|
||||
- **sandbox**: With this security level all rendering takes place in a sandboxed iframe. This prevent any javascript running in the context. This may hinder interactive functionality of the diagram like scripts, popups in sequence diagram or links to other tabs/targets etc.
|
||||
|
||||
|
||||
```note
|
||||
This changes the default behaviour of mermaid so that after upgrade to 8.2,unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled.
|
||||
**sandbox** security level is still in the beta version.
|
||||
```
|
||||
|
||||
**If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.**
|
||||
@@ -203,20 +207,10 @@ The example below show an outline of how this could be used. The example just lo
|
||||
<script src="mermaid.js"></script>
|
||||
|
||||
<script>
|
||||
mermaid.mermaidAPI.initialize({
|
||||
startOnLoad:false
|
||||
});
|
||||
$(function(){
|
||||
// Example of using the API
|
||||
var element = document.querySelector("#graphDiv");
|
||||
|
||||
var insertSvg = function(svgCode, bindFunctions){
|
||||
element.innerHTML = svgCode;
|
||||
};
|
||||
|
||||
var graphDefinition = 'graph TB\na-->b';
|
||||
var graph = mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
|
||||
});
|
||||
mermaid.mermaidAPI.initialize({ startOnLoad:false }); $(function(){ // Example of using the API var
|
||||
element = document.querySelector("#graphDiv"); var insertSvg = function(svgCode, bindFunctions){
|
||||
element.innerHTML = svgCode; }; var graphDefinition = 'graph TB\na-->b'; var graph =
|
||||
mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg); });
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -345,13 +339,7 @@ on what kind of integration you use.
|
||||
```html
|
||||
<script src="../dist/mermaid.js"></script>
|
||||
<script>
|
||||
var config = {
|
||||
startOnLoad:true,
|
||||
flowchart:{
|
||||
useMaxWidth:false,
|
||||
htmlLabels:true
|
||||
}
|
||||
};
|
||||
var config = { startOnLoad:true, flowchart:{ useMaxWidth:false, htmlLabels:true } };
|
||||
mermaid.initialize(config);
|
||||
</script>
|
||||
```
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "8.13.10",
|
||||
"version": "8.14.0",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"main": "dist/mermaid.core.js",
|
||||
"module": "dist/mermaid.esm.min.mjs",
|
||||
|
@@ -6,7 +6,9 @@ import intersect from './intersect/index.js';
|
||||
import createLabel from './createLabel';
|
||||
import note from './shapes/note';
|
||||
import { parseMember } from '../diagrams/class/svgDraw';
|
||||
import { evaluate } from '../diagrams/common/common';
|
||||
import { evaluate, sanitizeText as sanitize } from '../diagrams/common/common';
|
||||
|
||||
const sanitizeText = (txt) => sanitize(txt, getConfig());
|
||||
|
||||
const question = (parent, node) => {
|
||||
const { shapeSvg, bbox } = labelHelper(parent, node, undefined, true);
|
||||
@@ -967,10 +969,13 @@ export const insertNode = (elem, node, dir) => {
|
||||
|
||||
// Add link when appropriate
|
||||
if (node.link) {
|
||||
newEl = elem
|
||||
.insert('svg:a')
|
||||
.attr('xlink:href', node.link)
|
||||
.attr('target', node.linkTarget || '_blank');
|
||||
let target;
|
||||
if (getConfig().securityLevel === 'sandbox') {
|
||||
target = '_top';
|
||||
} else if (node.linkTarget) {
|
||||
target = node.linkTarget || '_blank';
|
||||
}
|
||||
newEl = elem.insert('svg:a').attr('xlink:href', node.link).attr('target', target);
|
||||
el = shapes[node.shape](newEl, node, dir);
|
||||
} else {
|
||||
el = shapes[node.shape](elem, node, dir);
|
||||
|
@@ -143,6 +143,7 @@ export const addMember = function (className, member) {
|
||||
|
||||
if (memberString.startsWith('<<') && memberString.endsWith('>>')) {
|
||||
// Remove leading and trailing brackets
|
||||
// theClass.annotations.push(memberString.substring(2, memberString.length - 2));
|
||||
theClass.annotations.push(sanitizeText(memberString.substring(2, memberString.length - 2)));
|
||||
} else if (memberString.indexOf(')') > 0) {
|
||||
theClass.methods.push(sanitizeText(memberString));
|
||||
@@ -212,8 +213,10 @@ export const setLink = function (ids, linkStr, target) {
|
||||
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
|
||||
if (typeof classes[id] !== 'undefined') {
|
||||
classes[id].link = utils.formatUrl(linkStr, config);
|
||||
if (typeof target === 'string') {
|
||||
classes[id].linkTarget = target;
|
||||
if (config.securityLevel === 'sandbox') {
|
||||
classes[id].linkTarget = '_top';
|
||||
} else if (typeof target === 'string') {
|
||||
classes[id].linkTarget = sanitizeText(target);
|
||||
} else {
|
||||
classes[id].linkTarget = '_blank';
|
||||
}
|
||||
|
@@ -269,101 +269,8 @@ export const setConf = function (cnf) {
|
||||
* @param {string} text
|
||||
* @param {string} id
|
||||
*/
|
||||
export const drawOld = function (text, id) {
|
||||
idCache = {};
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
|
||||
log.info('Rendering diagram ' + text);
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const diagram = select(`[id='${id}']`);
|
||||
// insertMarkers(diagram);
|
||||
|
||||
// Layout graph, Create a new directed graph
|
||||
const g = new graphlib.Graph({
|
||||
multigraph: true,
|
||||
});
|
||||
|
||||
// Set an object for the graph label
|
||||
g.setGraph({
|
||||
isMultiGraph: true,
|
||||
});
|
||||
|
||||
// Default to assigning a new object as a label for each new edge.
|
||||
g.setDefaultEdgeLabel(function () {
|
||||
return {};
|
||||
});
|
||||
|
||||
const classes = classDb.getClasses();
|
||||
log.info('classes:');
|
||||
log.info(classes);
|
||||
const keys = Object.keys(classes);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const classDef = classes[keys[i]];
|
||||
const node = svgDraw.drawClass(diagram, classDef, conf);
|
||||
idCache[node.id] = node;
|
||||
|
||||
// Add nodes to the graph. The first argument is the node id. The second is
|
||||
// metadata about the node. In this case we're going to add labels to each of
|
||||
// our nodes.
|
||||
g.setNode(node.id, node);
|
||||
|
||||
log.info('Org height: ' + node.height);
|
||||
}
|
||||
|
||||
const relations = classDb.getRelations();
|
||||
log.info('relations:', relations);
|
||||
relations.forEach(function (relation) {
|
||||
log.info(
|
||||
'tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)
|
||||
);
|
||||
g.setEdge(
|
||||
getGraphId(relation.id1),
|
||||
getGraphId(relation.id2),
|
||||
{
|
||||
relation: relation,
|
||||
},
|
||||
relation.title || 'DEFAULT'
|
||||
);
|
||||
});
|
||||
|
||||
dagre.layout(g);
|
||||
g.nodes().forEach(function (v) {
|
||||
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
|
||||
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
|
||||
select('#' + lookUpDomId(v)).attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
(g.node(v).x - g.node(v).width / 2) +
|
||||
',' +
|
||||
(g.node(v).y - g.node(v).height / 2) +
|
||||
' )'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
g.edges().forEach(function (e) {
|
||||
if (typeof e !== 'undefined' && typeof g.edge(e) !== 'undefined') {
|
||||
log.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e)));
|
||||
svgDraw.drawEdge(diagram, g.edge(e), g.edge(e).relation, conf);
|
||||
}
|
||||
});
|
||||
|
||||
const svgBounds = diagram.node().getBBox();
|
||||
const width = svgBounds.width + padding * 2;
|
||||
const height = svgBounds.height + padding * 2;
|
||||
|
||||
configureSvgSize(diagram, height, width, conf.useMaxWidth);
|
||||
|
||||
// Ensure the viewBox includes the whole svgBounds area with extra space for padding
|
||||
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
|
||||
log.debug(`viewBox ${vBox}`);
|
||||
diagram.attr('viewBox', vBox);
|
||||
};
|
||||
|
||||
export const draw = function (text, id) {
|
||||
log.info('Drawing class');
|
||||
log.info('Drawing class - ', id);
|
||||
classDb.clear();
|
||||
// const parser = classDb.parser;
|
||||
// parser.yy = classDb;
|
||||
@@ -379,6 +286,7 @@ export const draw = function (text, id) {
|
||||
//let dir = 'TD';
|
||||
|
||||
const conf = getConfig().flowchart;
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
log.info('config:', conf);
|
||||
const nodeSpacing = conf.nodeSpacing || 50;
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
@@ -430,11 +338,19 @@ export const draw = function (text, id) {
|
||||
// flowChartShapes.addToRenderV2(addShape);
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
const svg = select(`[id="${id}"]`);
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = select('#' + id + ' g');
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g, ['aggregation', 'extension', 'composition', 'dependency'], 'classDiagram', id);
|
||||
|
||||
// element.selectAll('g.node').attr('title', function() {
|
||||
@@ -462,14 +378,15 @@ export const draw = function (text, id) {
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf.htmlLabels) {
|
||||
const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (let k = 0; k < labels.length; k++) {
|
||||
const label = labels[k];
|
||||
|
||||
// Get dimensions of label
|
||||
const dim = label.getBBox();
|
||||
|
||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
const rect = doc.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
rect.setAttribute('rx', 0);
|
||||
rect.setAttribute('ry', 0);
|
||||
rect.setAttribute('width', dim.width);
|
||||
|
@@ -6,6 +6,7 @@ import classDb, { lookUpDomId } from './classDb';
|
||||
import { parser } from './parser/classDiagram';
|
||||
import svgDraw from './svgDraw';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
parser.yy = classDb;
|
||||
|
||||
@@ -165,8 +166,20 @@ export const draw = function (text, id) {
|
||||
|
||||
log.info('Rendering diagram ' + text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const diagram = select(`[id='${id}']`);
|
||||
const diagram = root.select(`[id='${id}']`);
|
||||
diagram.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
insertMarkers(diagram);
|
||||
|
||||
@@ -220,14 +233,16 @@ export const draw = function (text, id) {
|
||||
g.nodes().forEach(function (v) {
|
||||
if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') {
|
||||
log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v)));
|
||||
select('#' + lookUpDomId(v)).attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
(g.node(v).x - g.node(v).width / 2) +
|
||||
',' +
|
||||
(g.node(v).y - g.node(v).height / 2) +
|
||||
' )'
|
||||
);
|
||||
root
|
||||
.select('#' + lookUpDomId(v))
|
||||
.attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
(g.node(v).x - g.node(v).width / 2) +
|
||||
',' +
|
||||
(g.node(v).y - g.node(v).height / 2) +
|
||||
' )'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -545,6 +545,17 @@ export const draw = function (text, id) {
|
||||
erDb.clear();
|
||||
const parser = erParser.parser;
|
||||
parser.yy = erDb;
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the text to populate erDb
|
||||
try {
|
||||
@@ -554,7 +565,7 @@ export const draw = function (text, id) {
|
||||
}
|
||||
|
||||
// Get a reference to the svg node that contains the text
|
||||
const svg = select(`[id='${id}']`);
|
||||
const svg = root.select(`[id='${id}']`);
|
||||
|
||||
// Add cardinality marker definitions to the svg
|
||||
erMarkers.insertMarkers(svg, conf);
|
||||
|
@@ -25,9 +25,11 @@ export const setConf = function (cnf) {
|
||||
* @param vert Object containing the vertices.
|
||||
* @param g The graph that is to be drawn.
|
||||
* @param svgId
|
||||
* @param root
|
||||
* @param doc
|
||||
*/
|
||||
export const addVertices = function (vert, g, svgId) {
|
||||
const svg = select(`[id="${svgId}"]`);
|
||||
export const addVertices = function (vert, g, svgId, root, doc) {
|
||||
const svg = root.select(`[id="${svgId}"]`);
|
||||
const keys = Object.keys(vert);
|
||||
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
@@ -62,13 +64,13 @@ export const addVertices = function (vert, g, svgId) {
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
} else {
|
||||
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
|
||||
const rows = vertexText.split(common.lineBreakRegex);
|
||||
|
||||
for (let j = 0; j < rows.length; j++) {
|
||||
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
tspan.setAttribute('dy', '1em');
|
||||
tspan.setAttribute('x', '1');
|
||||
@@ -374,6 +376,18 @@ export const draw = function (text, id) {
|
||||
const nodeSpacing = conf.nodeSpacing || 50;
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Create the input mermaid.graph
|
||||
const g = new graphlib.Graph({
|
||||
multigraph: true,
|
||||
@@ -417,18 +431,18 @@ export const draw = function (text, id) {
|
||||
g.setParent(subG.nodes[j], subG.id);
|
||||
}
|
||||
}
|
||||
addVertices(vert, g, id);
|
||||
addVertices(vert, g, id, root, doc);
|
||||
addEdges(edges, g);
|
||||
|
||||
// Add custom shapes
|
||||
// flowChartShapes.addToRenderV2(addShape);
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
const svg = select(`[id="${id}"]`);
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = select('#' + id + ' g');
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);
|
||||
|
||||
const padding = conf.diagramPadding;
|
||||
@@ -452,14 +466,14 @@ export const draw = function (text, id) {
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf.htmlLabels) {
|
||||
const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (let k = 0; k < labels.length; k++) {
|
||||
const label = labels[k];
|
||||
|
||||
// Get dimensions of label
|
||||
const dim = label.getBBox();
|
||||
|
||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
const rect = doc.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
rect.setAttribute('rx', 0);
|
||||
rect.setAttribute('ry', 0);
|
||||
rect.setAttribute('width', dim.width);
|
||||
@@ -478,11 +492,13 @@ export const draw = function (text, id) {
|
||||
if (vertex.link) {
|
||||
const node = select('#' + id + ' [id="' + key + '"]');
|
||||
if (node) {
|
||||
const link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.classes.join(' '));
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
||||
if (vertex.linkTarget) {
|
||||
if (securityLevel === 'sandbox') {
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top');
|
||||
} else if (vertex.linkTarget) {
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
|
||||
}
|
||||
|
||||
|
@@ -26,9 +26,15 @@ export const setConf = function (cnf) {
|
||||
* @param vert Object containing the vertices.
|
||||
* @param g The graph that is to be drawn.
|
||||
* @param svgId
|
||||
* @param root
|
||||
* @param doc
|
||||
* @param _doc
|
||||
*/
|
||||
export const addVertices = function (vert, g, svgId) {
|
||||
const svg = select(`[id="${svgId}"]`);
|
||||
export const addVertices = function (vert, g, svgId, root, _doc) {
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
|
||||
const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`);
|
||||
const doc = !_doc ? document : _doc;
|
||||
const keys = Object.keys(vert);
|
||||
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
@@ -63,13 +69,13 @@ export const addVertices = function (vert, g, svgId) {
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
} else {
|
||||
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('style', styles.labelStyle.replace('color:', 'fill:'));
|
||||
|
||||
const rows = vertexText.split(common.lineBreakRegex);
|
||||
|
||||
for (let j = 0; j < rows.length; j++) {
|
||||
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
|
||||
tspan.setAttribute('dy', '1em');
|
||||
tspan.setAttribute('x', '1');
|
||||
@@ -293,6 +299,17 @@ export const draw = function (text, id) {
|
||||
const parser = flow.parser;
|
||||
parser.yy = flowDb;
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the graph definition
|
||||
// try {
|
||||
parser.parse(text);
|
||||
@@ -355,7 +372,7 @@ export const draw = function (text, id) {
|
||||
g.setParent(flowDb.lookUpDomId(subG.nodes[j]), flowDb.lookUpDomId(subG.id));
|
||||
}
|
||||
}
|
||||
addVertices(vert, g, id);
|
||||
addVertices(vert, g, id, root, doc);
|
||||
addEdges(edges, g);
|
||||
|
||||
// Create the renderer
|
||||
@@ -404,13 +421,13 @@ export const draw = function (text, id) {
|
||||
};
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
const svg = select(`[id="${id}"]`);
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
log.warn(g);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = select('#' + id + ' g');
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g);
|
||||
|
||||
element.selectAll('g.node').attr('title', function () {
|
||||
@@ -436,10 +453,10 @@ export const draw = function (text, id) {
|
||||
for (i = 0; i < subGraphs.length; i++) {
|
||||
subG = subGraphs[i];
|
||||
if (subG.title !== 'undefined') {
|
||||
const clusterRects = document.querySelectorAll(
|
||||
const clusterRects = doc.querySelectorAll(
|
||||
'#' + id + ' [id="' + flowDb.lookUpDomId(subG.id) + '"] rect'
|
||||
);
|
||||
const clusterEl = document.querySelectorAll(
|
||||
const clusterEl = doc.querySelectorAll(
|
||||
'#' + id + ' [id="' + flowDb.lookUpDomId(subG.id) + '"]'
|
||||
);
|
||||
|
||||
@@ -459,14 +476,14 @@ export const draw = function (text, id) {
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!evaluate(conf.htmlLabels) || true) { // eslint-disable-line
|
||||
const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (let k = 0; k < labels.length; k++) {
|
||||
const label = labels[k];
|
||||
|
||||
// Get dimensions of label
|
||||
const dim = label.getBBox();
|
||||
|
||||
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
const rect = doc.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
rect.setAttribute('rx', 0);
|
||||
rect.setAttribute('ry', 0);
|
||||
rect.setAttribute('width', dim.width);
|
||||
@@ -483,13 +500,15 @@ export const draw = function (text, id) {
|
||||
const vertex = vert[key];
|
||||
|
||||
if (vertex.link) {
|
||||
const node = select('#' + id + ' [id="' + flowDb.lookUpDomId(key) + '"]');
|
||||
const node = root.select('#' + id + ' [id="' + flowDb.lookUpDomId(key) + '"]');
|
||||
if (node) {
|
||||
const link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||
const link = doc.createElementNS('http://www.w3.org/2000/svg', 'a');
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'class', vertex.classes.join(' '));
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link);
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener');
|
||||
if (vertex.linkTarget) {
|
||||
if (securityLevel === 'sandbox') {
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', '_top');
|
||||
} else if (vertex.linkTarget) {
|
||||
link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@ let axisFormat = '';
|
||||
let todayMarker = '';
|
||||
let includes = [];
|
||||
let excludes = [];
|
||||
let links = {};
|
||||
let title = '';
|
||||
let sections = [];
|
||||
let tasks = [];
|
||||
@@ -44,6 +45,7 @@ export const clear = function () {
|
||||
inclusiveEndDates = false;
|
||||
topAxis = false;
|
||||
lastOrder = 0;
|
||||
links = {};
|
||||
};
|
||||
|
||||
export const setAxisFormat = function (txt) {
|
||||
@@ -101,6 +103,10 @@ export const getExcludes = function () {
|
||||
return excludes;
|
||||
};
|
||||
|
||||
export const getLinks = function () {
|
||||
return links;
|
||||
};
|
||||
|
||||
export const setTitle = function (txt) {
|
||||
title = txt;
|
||||
};
|
||||
@@ -505,6 +511,7 @@ export const setLink = function (ids, _linkStr) {
|
||||
pushFun(id, () => {
|
||||
window.open(linkStr, '_self');
|
||||
});
|
||||
links[id] = linkStr;
|
||||
}
|
||||
});
|
||||
setClass(ids, 'clickable');
|
||||
@@ -642,6 +649,7 @@ export default {
|
||||
getExcludes,
|
||||
setClickEvent,
|
||||
setLink,
|
||||
getLinks,
|
||||
bindFunctions,
|
||||
durationToDate,
|
||||
isInvalidDate,
|
||||
|
@@ -29,7 +29,19 @@ export const draw = function (text, id) {
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
|
||||
const elem = document.getElementById(id);
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
const elem = doc.getElementById(id);
|
||||
w = elem.parentElement.offsetWidth;
|
||||
|
||||
if (typeof w === 'undefined') {
|
||||
@@ -47,7 +59,7 @@ export const draw = function (text, id) {
|
||||
|
||||
// Set viewBox
|
||||
elem.setAttribute('viewBox', '0 0 ' + w + ' ' + h);
|
||||
const svg = select(`[id="${id}"]`);
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
|
||||
// Set timescale
|
||||
const timeScale = scaleTime()
|
||||
@@ -173,6 +185,10 @@ export const draw = function (text, id) {
|
||||
// Draw the rects representing the tasks
|
||||
const rectangles = svg.append('g').selectAll('rect').data(theArray).enter();
|
||||
|
||||
const links = ganttDb.getLinks();
|
||||
|
||||
// Render the tasks with links
|
||||
// Render the other tasks
|
||||
rectangles
|
||||
.append('rect')
|
||||
.attr('id', function (d) {
|
||||
@@ -369,6 +385,32 @@ export const draw = function (text, id) {
|
||||
return classStr + ' taskText taskText' + secNum + ' ' + taskType + ' width-' + textWidth;
|
||||
}
|
||||
});
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
|
||||
// Wrap the tasks in an a tag for working links without javascript
|
||||
if (securityLevel === 'sandbox') {
|
||||
let sandboxElement;
|
||||
sandboxElement = select('#i' + id);
|
||||
const root = select(sandboxElement.nodes()[0].contentDocument.body);
|
||||
const doc = sandboxElement.nodes()[0].contentDocument;
|
||||
|
||||
rectangles
|
||||
.filter(function (d) {
|
||||
return typeof links[d.id] !== 'undefined';
|
||||
})
|
||||
.each(function (o) {
|
||||
var taskRect = doc.querySelector('#' + o.id);
|
||||
var taskText = doc.querySelector('#' + o.id + '-text');
|
||||
const oldParent = taskRect.parentNode;
|
||||
var Link = doc.createElement('a');
|
||||
Link.setAttribute('xlink:href', links[o.id]);
|
||||
Link.setAttribute('target', '_top');
|
||||
oldParent.appendChild(Link);
|
||||
Link.appendChild(taskRect);
|
||||
Link.appendChild(taskText);
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param theGap
|
||||
@@ -505,11 +547,11 @@ export const draw = function (text, id) {
|
||||
const rows = d[0].split(common.lineBreakRegex);
|
||||
const dy = -(rows.length - 1) / 2;
|
||||
|
||||
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
const svgLabel = doc.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgLabel.setAttribute('dy', dy + 'em');
|
||||
|
||||
for (let j = 0; j < rows.length; j++) {
|
||||
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspan.setAttribute('alignment-baseline', 'central');
|
||||
tspan.setAttribute('x', '10');
|
||||
if (j > 0) tspan.setAttribute('dy', '1em');
|
||||
|
@@ -4,6 +4,7 @@ import db from './gitGraphAst';
|
||||
import gitGraphParser from './parser/gitGraph';
|
||||
import { log } from '../../logger';
|
||||
import { interpolateToCurve } from '../../utils';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
let allCommitsDict = {};
|
||||
let branchNum;
|
||||
@@ -338,6 +339,18 @@ export const draw = function (txt, id, ver) {
|
||||
parser.yy = db;
|
||||
parser.yy.clear();
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
|
||||
// Parse the graph definition
|
||||
parser.parse(txt + '\n');
|
||||
@@ -352,7 +365,7 @@ export const draw = function (txt, id, ver) {
|
||||
config.nodeLabel.width = '100%';
|
||||
config.nodeLabel.y = -1 * 2 * config.nodeRadius;
|
||||
}
|
||||
const svg = select(`[id="${id}"]`);
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svgCreateDefs(svg);
|
||||
branchNum = 1;
|
||||
for (let branch in branches) {
|
||||
|
@@ -3,6 +3,7 @@ import { select } from 'd3';
|
||||
import db from './infoDb';
|
||||
import infoParser from './parser/info';
|
||||
import { log } from '../../logger';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
@@ -25,11 +26,24 @@ export const draw = (text, id, version) => {
|
||||
const parser = infoParser.parser;
|
||||
parser.yy = db;
|
||||
log.debug('Renering info diagram\n' + text);
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the graph definition
|
||||
parser.parse(text);
|
||||
log.debug('Parsed info diagram');
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const svg = select('#' + id);
|
||||
const svg = root.select('#' + id);
|
||||
|
||||
const g = svg.append('g');
|
||||
|
||||
|
@@ -22,11 +22,24 @@ export const draw = (txt, id) => {
|
||||
const parser = pieParser.parser;
|
||||
parser.yy = pieData;
|
||||
log.debug('Rendering info diagram\n' + txt);
|
||||
|
||||
const securityLevel = configApi.getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
// Parse the Pie Chart definition
|
||||
parser.yy.clear();
|
||||
parser.parse(txt);
|
||||
log.debug('Parsed info diagram');
|
||||
const elem = document.getElementById(id);
|
||||
const elem = doc.getElementById(id);
|
||||
width = elem.parentElement.offsetWidth;
|
||||
|
||||
if (typeof width === 'undefined') {
|
||||
@@ -40,7 +53,7 @@ export const draw = (txt, id) => {
|
||||
width = conf.pie.useWidth;
|
||||
}
|
||||
|
||||
const diagram = select('#' + id);
|
||||
const diagram = root.select('#' + id);
|
||||
configureSvgSize(diagram, height, width, conf.pie.useMaxWidth);
|
||||
|
||||
// Set viewBox
|
||||
|
@@ -8,6 +8,7 @@ import common from '../common/common';
|
||||
import { parser } from './parser/requirementDiagram';
|
||||
import requirementDb from './requirementDb';
|
||||
import markers from './requirementMarkers';
|
||||
import { getConfig } from '../../config';
|
||||
|
||||
const conf = {};
|
||||
let relCnt = 0;
|
||||
@@ -321,7 +322,19 @@ export const draw = (text, id) => {
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
|
||||
const svg = select(`[id='${id}']`);
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
const svg = root.select(`[id='${id}']`);
|
||||
markers.insertLineEndings(svg, conf);
|
||||
|
||||
const g = new graphlib.Graph({
|
||||
|
@@ -452,13 +452,20 @@ export const drawActors = function (diagram, actors, actorKeys, verticalPos) {
|
||||
bounds.bumpVerticalPos(maxHeight);
|
||||
};
|
||||
|
||||
export const drawActorsPopup = function (diagram, actors, actorKeys) {
|
||||
export const drawActorsPopup = function (diagram, actors, actorKeys, doc) {
|
||||
var maxHeight = 0;
|
||||
var maxWidth = 0;
|
||||
for (let i = 0; i < actorKeys.length; i++) {
|
||||
const actor = actors[actorKeys[i]];
|
||||
const minMenuWidth = getRequiredPopupWidth(actor);
|
||||
var menuDimensions = svgDraw.drawPopup(diagram, actor, minMenuWidth, conf, conf.forceMenus);
|
||||
var menuDimensions = svgDraw.drawPopup(
|
||||
diagram,
|
||||
actor,
|
||||
minMenuWidth,
|
||||
conf,
|
||||
conf.forceMenus,
|
||||
doc
|
||||
);
|
||||
if (menuDimensions.height > maxHeight) {
|
||||
maxHeight = menuDimensions.height;
|
||||
}
|
||||
@@ -539,13 +546,26 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
conf = configApi.getConfig().sequence;
|
||||
const securityLevel = configApi.getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
parser.yy.clear();
|
||||
parser.yy.setWrap(conf.wrap);
|
||||
parser.parse(text + '\n');
|
||||
bounds.init();
|
||||
log.debug(`C:${JSON.stringify(conf, null, 2)}`);
|
||||
|
||||
const diagram = select(`[id="${id}"]`);
|
||||
const diagram =
|
||||
securityLevel === 'sandbox' ? root.select(`[id="${id}"]`) : select(`[id="${id}"]`);
|
||||
|
||||
// Fetch data from the parsing
|
||||
const actors = parser.yy.getActors();
|
||||
@@ -733,7 +753,7 @@ export const draw = function (text, id) {
|
||||
}
|
||||
|
||||
// only draw popups for the top row of actors.
|
||||
var requiredBoxSize = drawActorsPopup(diagram, actors, actorKeys);
|
||||
var requiredBoxSize = drawActorsPopup(diagram, actors, actorKeys, doc);
|
||||
|
||||
const { bounds: box } = bounds.getBounds();
|
||||
|
||||
|
@@ -30,6 +30,8 @@ export const drawRect = function (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');
|
||||
});
|
||||
|
@@ -258,6 +258,8 @@ export const draw = function (text, id) {
|
||||
const nodeSpacing = conf.nodeSpacing || 50;
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
|
||||
log.info(stateDb.getRootDocV2());
|
||||
stateDb.extract(stateDb.getRootDocV2());
|
||||
log.info(stateDb.getRootDocV2());
|
||||
@@ -281,10 +283,20 @@ export const draw = function (text, id) {
|
||||
setupNode(g, undefined, stateDb.getRootDocV2(), true);
|
||||
|
||||
// Set up an SVG group so that we can translate the final graph.
|
||||
const svg = select(`[id="${id}"]`);
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = select('#' + id + ' g');
|
||||
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g, ['barb'], 'statediagram', id);
|
||||
|
||||
const padding = 8;
|
||||
|
@@ -46,12 +46,24 @@ const insertMarkers = function (elem) {
|
||||
*/
|
||||
export const draw = function (text, id) {
|
||||
conf = getConfig().state;
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
parser.yy.clear();
|
||||
parser.parse(text);
|
||||
log.debug('Rendering diagram ' + text);
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
const diagram = select(`[id='${id}']`);
|
||||
const diagram = root.select(`[id='${id}']`);
|
||||
insertMarkers(diagram);
|
||||
|
||||
// Layout graph, Create a new directed graph
|
||||
@@ -69,7 +81,7 @@ export const draw = function (text, id) {
|
||||
});
|
||||
|
||||
const rootDoc = stateDb.getRootDoc();
|
||||
renderDoc(rootDoc, diagram, undefined, false);
|
||||
renderDoc(rootDoc, diagram, undefined, false, root, doc);
|
||||
|
||||
const padding = conf.padding;
|
||||
const bounds = diagram.node().getBBox();
|
||||
@@ -90,7 +102,7 @@ const getLabelWidth = (text) => {
|
||||
return text ? text.length * conf.fontSizeFactor : 1;
|
||||
};
|
||||
|
||||
const renderDoc = (doc, diagram, parentId, altBkg) => {
|
||||
const renderDoc = (doc, diagram, parentId, altBkg, root, domDocument) => {
|
||||
// Layout graph, Create a new directed graph
|
||||
const graph = new graphlib.Graph({
|
||||
compound: true,
|
||||
@@ -159,7 +171,7 @@ const renderDoc = (doc, diagram, parentId, altBkg) => {
|
||||
let node;
|
||||
if (stateDef.doc) {
|
||||
let sub = diagram.append('g').attr('id', stateDef.id).attr('class', 'stateGroup');
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id, !altBkg);
|
||||
node = renderDoc(stateDef.doc, sub, stateDef.id, !altBkg, root, domDocument);
|
||||
|
||||
if (first) {
|
||||
// first = false;
|
||||
@@ -234,21 +246,22 @@ const renderDoc = (doc, diagram, parentId, altBkg) => {
|
||||
graph.nodes().forEach(function (v) {
|
||||
if (typeof v !== 'undefined' && typeof graph.node(v) !== 'undefined') {
|
||||
log.warn('Node ' + v + ': ' + JSON.stringify(graph.node(v)));
|
||||
select('#' + svgElem.id + ' #' + v).attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
(graph.node(v).x - graph.node(v).width / 2) +
|
||||
',' +
|
||||
(graph.node(v).y +
|
||||
(transformationLog[v] ? transformationLog[v].y : 0) -
|
||||
graph.node(v).height / 2) +
|
||||
' )'
|
||||
);
|
||||
select('#' + svgElem.id + ' #' + v).attr(
|
||||
'data-x-shift',
|
||||
graph.node(v).x - graph.node(v).width / 2
|
||||
);
|
||||
const dividers = document.querySelectorAll('#' + svgElem.id + ' #' + v + ' .divider');
|
||||
root
|
||||
.select('#' + svgElem.id + ' #' + v)
|
||||
.attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
(graph.node(v).x - graph.node(v).width / 2) +
|
||||
',' +
|
||||
(graph.node(v).y +
|
||||
(transformationLog[v] ? transformationLog[v].y : 0) -
|
||||
graph.node(v).height / 2) +
|
||||
' )'
|
||||
);
|
||||
root
|
||||
.select('#' + svgElem.id + ' #' + v)
|
||||
.attr('data-x-shift', graph.node(v).x - graph.node(v).width / 2);
|
||||
const dividers = domDocument.querySelectorAll('#' + svgElem.id + ' #' + v + ' .divider');
|
||||
dividers.forEach((divider) => {
|
||||
const parent = divider.parentElement;
|
||||
let pWidth = 0;
|
||||
|
@@ -54,8 +54,20 @@ export const draw = function (text, id) {
|
||||
parser.yy.clear();
|
||||
parser.parse(text + '\n');
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
|
||||
bounds.init();
|
||||
const diagram = select('#' + id);
|
||||
const diagram = root.select('#' + id);
|
||||
diagram.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
svgDraw.initGraphics(diagram);
|
||||
|
@@ -83,6 +83,7 @@ const init = function () {
|
||||
let txt;
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
// element is the current div with mermaid class
|
||||
const element = nodes[i];
|
||||
|
||||
/*! Check if previously processed */
|
||||
|
@@ -232,10 +232,43 @@ const render = function (id, _txt, cb, container) {
|
||||
txt = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
|
||||
}
|
||||
|
||||
// let d3Iframe;
|
||||
let root = select('body');
|
||||
|
||||
// In regular execurtion the container will be the div with a mermaid class
|
||||
if (typeof container !== 'undefined') {
|
||||
if (cnf.securityLevel === 'sandbox') {
|
||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
||||
// in a sandboxed div
|
||||
const iframe = select('body')
|
||||
.append('iframe')
|
||||
.attr('id', 'i' + id)
|
||||
.attr('style', 'width: 100%; height: 100%;')
|
||||
.attr('sandbox', '');
|
||||
// const iframeBody = ;
|
||||
root = select(iframe.nodes()[0].contentDocument.body);
|
||||
root.node().style.margin = 0;
|
||||
}
|
||||
|
||||
// A container was provided by the caller
|
||||
container.innerHTML = '';
|
||||
|
||||
select(container)
|
||||
if (cnf.securityLevel === 'sandbox') {
|
||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
||||
// in a sandboxed div
|
||||
const iframe = select(container)
|
||||
.append('iframe')
|
||||
.attr('id', 'i' + id)
|
||||
.attr('style', 'width: 100%; height: 100%;')
|
||||
.attr('sandbox', '');
|
||||
// const iframeBody = ;
|
||||
root = select(iframe.nodes()[0].contentDocument.body);
|
||||
root.node().style.margin = 0;
|
||||
} else {
|
||||
root = select(container);
|
||||
}
|
||||
|
||||
root
|
||||
.append('div')
|
||||
.attr('id', 'd' + id)
|
||||
.attr('style', 'font-family: ' + cnf.fontFamily)
|
||||
@@ -245,18 +278,57 @@ const render = function (id, _txt, cb, container) {
|
||||
.attr('xmlns', 'http://www.w3.org/2000/svg')
|
||||
.append('g');
|
||||
} else {
|
||||
// No container was provided
|
||||
// If there is an existsing element with the id, we remove it
|
||||
// this likley a previously rendered diagram
|
||||
const existingSvg = document.getElementById(id);
|
||||
if (existingSvg) {
|
||||
existingSvg.remove();
|
||||
}
|
||||
const element = document.querySelector('#' + 'd' + id);
|
||||
|
||||
// Remove previous tpm element if it exists
|
||||
let element;
|
||||
if (cnf.securityLevel !== 'sandbox') {
|
||||
element = document.querySelector('#' + 'd' + id);
|
||||
} else {
|
||||
element = document.querySelector('#' + 'i' + id);
|
||||
}
|
||||
if (element) {
|
||||
element.remove();
|
||||
}
|
||||
|
||||
select('body')
|
||||
// if (cnf.securityLevel === 'sandbox') {
|
||||
// const iframe = select('body')
|
||||
// .append('iframe')
|
||||
// .attr('id', 'i' + id)
|
||||
// .attr('sandbox', '');
|
||||
// // const iframeBody = ;
|
||||
// root = select(iframe.nodes()[0].contentDocument.body);
|
||||
// }
|
||||
|
||||
// Add the tmp div used for rendering with the id `d${id}`
|
||||
// d+id it will contain a svg with the id "id"
|
||||
|
||||
if (cnf.securityLevel === 'sandbox') {
|
||||
// IF we are in sandboxed mode, we do everyting mermaid related
|
||||
// in a sandboxed div
|
||||
const iframe = select('body')
|
||||
.append('iframe')
|
||||
.attr('id', 'i' + id)
|
||||
.attr('style', 'width: 100%; height: 100%;')
|
||||
.attr('sandbox', '');
|
||||
// const iframeBody = ;
|
||||
root = select(iframe.nodes()[0].contentDocument.body);
|
||||
root.node().style.margin = 0;
|
||||
} else {
|
||||
root = select('body');
|
||||
}
|
||||
|
||||
// This is the temporary div
|
||||
root
|
||||
.append('div')
|
||||
.attr('id', 'd' + id)
|
||||
// this is the seed of the svg to be rendered
|
||||
.append('svg')
|
||||
.attr('id', id)
|
||||
.attr('width', '100%')
|
||||
@@ -264,10 +336,10 @@ const render = function (id, _txt, cb, container) {
|
||||
.append('g');
|
||||
}
|
||||
|
||||
window.txt = txt;
|
||||
txt = encodeEntities(txt);
|
||||
|
||||
const element = select('#d' + id).node();
|
||||
// Get the tmp element containing the the svg
|
||||
const element = root.select('#d' + id).node();
|
||||
const graphType = utils.detectType(txt, cnf);
|
||||
|
||||
// insert inline style into svg
|
||||
@@ -430,14 +502,19 @@ const render = function (id, _txt, cb, container) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
select(`[id="${id}"]`)
|
||||
root
|
||||
.select(`[id="${id}"]`)
|
||||
.selectAll('foreignobject > *')
|
||||
.attr('xmlns', 'http://www.w3.org/1999/xhtml');
|
||||
|
||||
// Fix for when the base tag is used
|
||||
let svgCode = select('#d' + id).node().innerHTML;
|
||||
let svgCode = root.select('#d' + id).node().innerHTML;
|
||||
|
||||
log.debug('cnf.arrowMarkerAbsolute', cnf.arrowMarkerAbsolute);
|
||||
if (!cnf.arrowMarkerAbsolute || cnf.arrowMarkerAbsolute === 'false') {
|
||||
if (
|
||||
(!cnf.arrowMarkerAbsolute || cnf.arrowMarkerAbsolute === 'false') &&
|
||||
cnf.arrowMarkerAbsolute !== 'sandbox'
|
||||
) {
|
||||
svgCode = svgCode.replace(/marker-end="url\(.*?#/g, 'marker-end="url(#', 'g');
|
||||
}
|
||||
|
||||
@@ -446,6 +523,21 @@ const render = function (id, _txt, cb, container) {
|
||||
// Fix for when the br tag is used
|
||||
svgCode = svgCode.replace(/<br>/g, '<br/>');
|
||||
|
||||
if (cnf.securityLevel === 'sandbox') {
|
||||
let svgEl = root.select('#d' + id + ' svg').node();
|
||||
let width = '100%';
|
||||
let height = '100%';
|
||||
if (svgEl) {
|
||||
// width = svgEl.viewBox.baseVal.width + 'px';
|
||||
height = svgEl.viewBox.baseVal.height + 'px';
|
||||
}
|
||||
svgCode = `<iframe style="width:${width};height:${height};border:0;margin:0;" src="data:text/html;base64,${btoa(
|
||||
'<body style="margin:0">' + svgCode + '</body>'
|
||||
)}" sandbox="allow-top-navigation-by-user-activation allow-popups">
|
||||
The “iframe” tag is not supported by your browser.
|
||||
</iframe>`;
|
||||
}
|
||||
|
||||
if (typeof cb !== 'undefined') {
|
||||
switch (graphType) {
|
||||
case 'flowchart':
|
||||
@@ -467,11 +559,10 @@ const render = function (id, _txt, cb, container) {
|
||||
}
|
||||
attachFunctions();
|
||||
|
||||
const node = select('#d' + id).node();
|
||||
const tmpElementSelector = cnf.securityLevel === 'sandbox' ? '#i' + id : '#d' + id;
|
||||
const node = select(tmpElementSelector).node();
|
||||
if (node !== null && typeof node.remove === 'function') {
|
||||
select('#d' + id)
|
||||
.node()
|
||||
.remove();
|
||||
select(tmpElementSelector).node().remove();
|
||||
}
|
||||
|
||||
return svgCode;
|
||||
@@ -570,6 +661,7 @@ function updateRendererConfigs(conf) {
|
||||
errorRenderer.setConf(conf.class);
|
||||
}
|
||||
|
||||
/** To be removed */
|
||||
function reinitialize() {
|
||||
// `mermaidAPI.reinitialize: v${pkg.version}`,
|
||||
// JSON.stringify(options),
|
||||
|
Reference in New Issue
Block a user