diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js
index 0bae442e1..9e510c112 100644
--- a/cypress/integration/rendering/flowchart.spec.js
+++ b/cypress/integration/rendering/flowchart.spec.js
@@ -529,17 +529,19 @@ describe('Flowchart', () => {
imgSnapshotTest(
`graph TB
TITLE["Link Click Events
(click the nodes below)"]
- A[link test]
- B[anchor test]
- C[mailto test]
- D[other protocol test]
- E[script test]
- TITLE --> A & B & C & D & E
- click A "https://mermaid-js.github.io/mermaid/#/" "link test"
- click B "#link-clicked" "anchor test"
- click C "mailto:user@user.user" "mailto test"
- click D "notes://do-your-thing/id" "other protocol test"
- click E "javascript:alert('test')" "script test"
+ A["link test (open in same tab)"]
+ B["link test (open in new tab)"]
+ C[anchor test]
+ D[mailto test]
+ E[other protocol test]
+ F[script test]
+ TITLE --> A & B & C & D & E & F
+ click A "https://mermaid-js.github.io/mermaid/#/" "link test (open in same tab)"
+ click B "https://mermaid-js.github.io/mermaid/#/" "link test (open in new tab)" _blank
+ click C "#link-clicked"
+ click D "mailto:user@user.user" "mailto test"
+ click E "notes://do-your-thing/id" "other protocol test"
+ click F "javascript:alert('test')" "script test"
`,
{ securityLevel: 'loose' }
);
diff --git a/dist/index.html b/dist/index.html
index f33151662..78b3ed8cb 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -393,17 +393,19 @@ graph TB
graph TB
TITLE["Link Click Events
(click the nodes below)"]
- A[link test]
- B[anchor test]
- C[mailto test]
- D[other protocol test]
- E[script test]
- TITLE --> A & B & C & D & E
- click A "https://mermaid-js.github.io/mermaid/#/" "link test"
- click B "#link-clicked" "anchor test"
- click C "mailto:user@user.user" "mailto test"
- click D "notes://do-your-thing/id" "other protocol test"
- click E "javascript:alert('test')" "script test"
+ A["link test (open in same tab)"]
+ B["link test (open in new tab)"]
+ C[anchor test]
+ D[mailto test]
+ E[other protocol test]
+ F[script test]
+ TITLE --> A & B & C & D & E & F
+ click A "https://mermaid-js.github.io/mermaid/#/" "link test (open in same tab)"
+ click B "https://mermaid-js.github.io/mermaid/#/" "link test (open in new tab)" _blank
+ click C "#link-clicked"
+ click D "mailto:user@user.user" "mailto test"
+ click E "notes://do-your-thing/id" "other protocol test"
+ click F "javascript:alert('test')" "script test"
diff --git a/docs/flowchart.md b/docs/flowchart.md
index e00fbe1ff..115f2a24b 100644
--- a/docs/flowchart.md
+++ b/docs/flowchart.md
@@ -562,6 +562,23 @@ graph LR
?> Due to limitations with how Docsify handles JavaScript callback functions, an alternate working demo for the above code can be viewed at [this jsfiddle](https://jsfiddle.net/s37cjoau/3/).
+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):
+```
+graph LR;
+ A-->B;
+ B-->C;
+ click A "http://www.github.com" _blank
+ click B "http://www.github.com" "Open this in a new tab" _blank
+```
+
+```mermaid
+graph LR;
+ A-->B;
+ B-->C;
+ click A "http://www.github.com" _blank
+ click B "http://www.github.com" "Open this in a new tab" _blank
+```
+
Beginners tip, a full example using interactive links in a html context:
```
diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js
index c99325145..b18fedc6f 100644
--- a/src/diagrams/flowchart/flowDb.js
+++ b/src/diagrams/flowchart/flowDb.js
@@ -248,12 +248,13 @@ const setClickFun = function(_id, functionName) {
* @param linkStr URL to create a link for
* @param tooltip Tooltip for the clickable element
*/
-export const setLink = function(ids, linkStr, tooltip) {
+export const setLink = function(ids, linkStr, tooltip, target) {
ids.split(',').forEach(function(_id) {
let id = _id;
if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id;
if (typeof vertices[id] !== 'undefined') {
vertices[id].link = utils.formatUrl(linkStr, config);
+ vertices[id].linkTarget = target;
}
});
setTooltip(ids, tooltip);
diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js
index 1bd2db9de..a6a6bdb8e 100644
--- a/src/diagrams/flowchart/flowRenderer-v2.js
+++ b/src/diagrams/flowchart/flowRenderer-v2.js
@@ -486,6 +486,9 @@ export const draw = function(text, id) {
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) {
+ link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
+ }
const linkNode = node.insert(function() {
return link;
diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js
index 51ef4edd5..390809d6c 100644
--- a/src/diagrams/flowchart/flowRenderer.js
+++ b/src/diagrams/flowchart/flowRenderer.js
@@ -469,6 +469,9 @@ export const draw = function(text, id) {
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) {
+ link.setAttributeNS('http://www.w3.org/2000/svg', 'target', vertex.linkTarget);
+ }
const linkNode = node.insert(function() {
return link;
diff --git a/src/diagrams/flowchart/parser/flow-interactions.spec.js b/src/diagrams/flowchart/parser/flow-interactions.spec.js
index 1ddb710a8..9255b9ce9 100644
--- a/src/diagrams/flowchart/parser/flow-interactions.spec.js
+++ b/src/diagrams/flowchart/parser/flow-interactions.spec.js
@@ -39,7 +39,7 @@ describe('[Interactions] when parsing', () => {
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
- expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', undefined);
+ expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', undefined, undefined);
});
it('should handle interaction - click to a link with tooltip', function() {
@@ -49,6 +49,26 @@ describe('[Interactions] when parsing', () => {
const vert = flow.parser.yy.getVertices();
const edges = flow.parser.yy.getEdges();
- expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', 'tooltip');
+ expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', 'tooltip', undefined);
+ });
+
+ it('should handle interaction - click to a link with target', function() {
+ spyOn(flowDb, 'setLink');
+ const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" _blank');
+
+ const vert = flow.parser.yy.getVertices();
+ const edges = flow.parser.yy.getEdges();
+
+ expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', undefined, '_blank');
+ });
+
+ it('should handle interaction - click to a link with tooltip and target', function() {
+ spyOn(flowDb, 'setLink');
+ const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" "tooltip" _blank');
+
+ const vert = flow.parser.yy.getVertices();
+ const edges = flow.parser.yy.getEdges();
+
+ expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', 'tooltip', '_blank');
});
});
diff --git a/src/diagrams/flowchart/parser/flow.jison b/src/diagrams/flowchart/parser/flow.jison
index 6cd7c6af8..0f553d34f 100644
--- a/src/diagrams/flowchart/parser/flow.jison
+++ b/src/diagrams/flowchart/parser/flow.jison
@@ -25,6 +25,10 @@
"flowchart" {if(yy.lex.firstGraph()){this.begin("dir");} return 'GRAPH';}
"subgraph" return 'subgraph';
"end"\b\s* return 'end';
+"_self" return 'LINK_TARGET';
+"_blank" return 'LINK_TARGET';
+"_parent" return 'LINK_TARGET';
+"_top" return 'LINK_TARGET';
\s*"LR" { this.popState(); return 'DIR'; }
\s*"RL" { this.popState(); return 'DIR'; }
\s*"TB" { this.popState(); return 'DIR'; }
@@ -397,10 +401,12 @@ classStatement:CLASS SPACE alphaNum SPACE alphaNum
;
clickStatement
- : CLICK SPACE alphaNum SPACE alphaNum {$$ = $1;yy.setClickEvent($3, $5, undefined);}
- | CLICK SPACE alphaNum SPACE alphaNum SPACE STR {$$ = $1;yy.setClickEvent($3, $5, $7) ;}
- | CLICK SPACE alphaNum SPACE STR {$$ = $1;yy.setLink($3, $5, undefined);}
- | CLICK SPACE alphaNum SPACE STR SPACE STR {$$ = $1;yy.setLink($3, $5, $7 );}
+ : CLICK SPACE alphaNum SPACE alphaNum {$$ = $1;yy.setClickEvent($3, $5, undefined);}
+ | CLICK SPACE alphaNum SPACE alphaNum SPACE STR {$$ = $1;yy.setClickEvent($3, $5, $7) ;}
+ | CLICK SPACE alphaNum SPACE STR {$$ = $1;yy.setLink($3, $5, undefined, undefined);}
+ | CLICK SPACE alphaNum SPACE STR SPACE STR {$$ = $1;yy.setLink($3, $5, $7, undefined );}
+ | CLICK SPACE alphaNum SPACE STR SPACE LINK_TARGET {$$ = $1;yy.setLink($3, $5, undefined, $7 );}
+ | CLICK SPACE alphaNum SPACE STR SPACE STR SPACE LINK_TARGET {$$ = $1;yy.setLink($3, $5, $7, $9 );}
;
styleStatement:STYLE SPACE alphaNum SPACE stylesOpt