+erDiagram
+title This is a title
+accDescription Test a description
+CUSTOMER ||--o{ ORDER : places
+ORDER ||--|{ LINE-ITEM : contains
+CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/flowchart.html b/demos/flowchart.html
index 0ab1f64813..864fac6877 100644
--- a/demos/flowchart.html
+++ b/demos/flowchart.html
@@ -230,6 +230,8 @@
graph
flowchart
flowchart TD
+ title Christmas
+ accDescription Get money
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me thinksssssx sssssssssssssssssssuuu tttsssssssssssssssssssssss}
C -->|One| D[Laptop]
diff --git a/demos/index.html b/demos/index.html
index 80975ef0d3..7ce19ea0b1 100644
--- a/demos/index.html
+++ b/demos/index.html
@@ -467,6 +467,7 @@
sequenceDiagram
+ accDescription Hello friends
participant Alice
participant Bob
participant John as John Second Line
diff --git a/demos/sequence.html b/demos/sequence.html
new file mode 100644
index 0000000000..b6930a7225
--- /dev/null
+++ b/demos/sequence.html
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+ Mermaid Quick Test Page
+
+
+
+
+
+
+
+
+ sequenceDiagram
+ title: FancySequenceDiagram
+ accDescription Test a description
+ participant Alice
+ participant Bob
+ participant John as John Second Line
+ rect rgb(200, 220, 100)
+ rect rgb(200, 255, 200)
+ Alice ->> Bob: Hello Bob, how are you?
+ Bob-->>John: How about you John?
+ end
+ Bob--x Alice: I am good thanks!
+ Bob-x John: I am good thanks!
+ Note right of John: John thinks a long long time, so long that the text does not fit on a row.
+ Bob-->Alice: Checking with John...
+ Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
+ Bob-x John: Hey John - we're still waiting to know how you're doing
+ Note over John:nowrap: John's trying hard not to break his train of thought.
+ Bob-x John:wrap: John! Are you still debating about how you're doing? How long does it take??
+ Note over John: After a few more moments, John finally snaps out of it.
+ end
+ alt either this
+ Alice->>John: Yes
+ else or this
+ Alice->>John: No
+ else or this will happen
+ Alice->John: Maybe
+ end
+ par this happens in parallel
+ Alice -->> Bob: Parallel message 1
+ and
+ Alice -->> John: Parallel message 2
+ end
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/launch.json b/launch.json
new file mode 100644
index 0000000000..6a9ed413ae
--- /dev/null
+++ b/launch.json
@@ -0,0 +1,11 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "attach",
+ "name": "Attach",
+ "port": 9229
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/accessibility.js b/src/accessibility.js
index 2b1119580e..046fea6ad5 100644
--- a/src/accessibility.js
+++ b/src/accessibility.js
@@ -9,15 +9,16 @@
* @param id
*/
export default function addSVGAccessibilityFields(yy_parser, svg, id) {
+ if (typeof svg.insert == 'undefined') {
+ return;
+ }
let title_string = yy_parser.getTitle();
let description = yy_parser.getAccDescription();
svg.attr('role', 'img').attr('aria-labelledby', 'chart-title-' + id + ' chart-desc-' + id);
-
svg
.insert('desc', ':first-child')
.attr('id', 'chart-desc-' + id)
.text(description);
-
svg
.insert('title', ':first-child')
.attr('id', 'chart-title-' + id)
diff --git a/src/diagrams/er/erDb.js b/src/diagrams/er/erDb.js
index 9aa94aef14..8fe54ed83a 100644
--- a/src/diagrams/er/erDb.js
+++ b/src/diagrams/er/erDb.js
@@ -5,6 +5,7 @@ import * as configApi from '../../config';
let entities = {};
let relationships = [];
let title = '';
+let description = '';
const Cardinality = {
ZERO_OR_ONE: 'ZERO_OR_ONE',
@@ -75,6 +76,14 @@ const getTitle = function () {
return title;
};
+const setAccDescription = function (txt) {
+ description = txt;
+};
+
+const getAccDescription = function () {
+ return description;
+};
+
const clear = function () {
entities = {};
relationships = [];
@@ -94,4 +103,6 @@ export default {
clear,
setTitle,
getTitle,
+ setAccDescription,
+ getAccDescription,
};
diff --git a/src/diagrams/er/erRenderer.js b/src/diagrams/er/erRenderer.js
index d2e2cc0d9f..a8589da72c 100644
--- a/src/diagrams/er/erRenderer.js
+++ b/src/diagrams/er/erRenderer.js
@@ -7,6 +7,7 @@ import { getConfig } from '../../config';
import { log } from '../../logger';
import erMarkers from './erMarkers';
import { configureSvgSize } from '../../utils';
+import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
@@ -637,6 +638,8 @@ export const draw = function (text, id) {
configureSvgSize(svg, height, width, conf.useMaxWidth);
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
+
+ addSVGAccessibilityFields(parser.yy, svg, id);
}; // draw
export default {
diff --git a/src/diagrams/er/parser/erDiagram.jison b/src/diagrams/er/parser/erDiagram.jison
index 6e06fc2cec..7461cb0646 100644
--- a/src/diagrams/er/parser/erDiagram.jison
+++ b/src/diagrams/er/parser/erDiagram.jison
@@ -2,8 +2,14 @@
%options case-insensitive
%x open_directive type_directive arg_directive block
+%x title
+%x accDescription
%%
+title { this.begin("title");return 'title'; }
+(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
+accDescription { this.begin("accDescription");return 'accDescription'; }
+(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; }
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
":" { this.popState(); this.begin('arg_directive'); return ':'; }
@@ -84,6 +90,8 @@ statement
}
| entityName BLOCK_START BLOCK_STOP { yy.addEntity($1); }
| entityName { yy.addEntity($1); }
+ | title title_value { $$=$2.trim();yy.setTitle($$); }
+ | accDescription description_value { $$=$2.trim();yy.setAccDescription($$); }
;
entityName
diff --git a/src/diagrams/er/parser/erDiagram.spec.js b/src/diagrams/er/parser/erDiagram.spec.js
index 746a091fad..edfec58d6e 100644
--- a/src/diagrams/er/parser/erDiagram.spec.js
+++ b/src/diagrams/er/parser/erDiagram.spec.js
@@ -181,6 +181,17 @@ describe('when parsing ER diagram it...', function () {
expect(Object.keys(erDb.getEntities()).length).toBe(1);
});
+ it('should allow for a title and acc description', function () {
+ const teacherRole = 'is teacher of';
+ const line1 = `TEACHER }o--o{ STUDENT : "${teacherRole}"`;
+
+ erDiagram.parser.parse(
+ `erDiagram\ntitle graph title\n accDescription this graph is about stuff\n${line1}`
+ );
+ expect(erDb.getTitle()).toBe('graph title');
+ expect(erDb.getAccDescription()).toBe('this graph is about stuff');
+ });
+
it('should allow more than one relationship between the same two entities', function () {
const line1 = 'CAR ||--o{ PERSON : "insured for"';
const line2 = 'CAR }o--|| PERSON : "owned by"';
diff --git a/src/diagrams/sequence/parser/sequenceDiagram.jison b/src/diagrams/sequence/parser/sequenceDiagram.jison
index 6608511f27..b649408337 100644
--- a/src/diagrams/sequence/parser/sequenceDiagram.jison
+++ b/src/diagrams/sequence/parser/sequenceDiagram.jison
@@ -33,7 +33,7 @@
\%%(?!\{)[^\n]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
"participant" { this.begin('ID'); return 'participant'; }
-"actor" { this.begin('ID'); return 'participant_actor'; }
+"actor" { this.begin('ID'); return 'participant_actor'; }
[^\->:\n,;]+?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
@@ -56,7 +56,9 @@
"note" return 'note';
"activate" { this.begin('ID'); return 'activate'; }
"deactivate" { this.begin('ID'); return 'deactivate'; }
-"title" return 'title';
+"title"\s[^#\n;]+ return 'title';
+"title:"\s[^#\n;]+ return 'legacy_title';
+"accDescription"\s[^#\n;]+ return 'accDescription';
"sequenceDiagram" return 'SD';
"autonumber" return 'autonumber';
"," return ',';
@@ -121,7 +123,9 @@ statement
| link_statement 'NEWLINE'
| properties_statement 'NEWLINE'
| details_statement 'NEWLINE'
- | title text2 'NEWLINE' {$$=[{type:'setTitle', text:$2}]}
+ | title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
+ | legacy_title {yy.setTitle($1.substring(7));$$=$1.substring(7);}
+ | accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
| 'loop' restOfLine document end
{
$3.unshift({type: 'loopStart', loopText:yy.parseMessage($2), signalType: yy.LINETYPE.LOOP_START});
diff --git a/src/diagrams/sequence/sequenceDb.js b/src/diagrams/sequence/sequenceDb.js
index 60a07a2e30..7b5770bae6 100644
--- a/src/diagrams/sequence/sequenceDb.js
+++ b/src/diagrams/sequence/sequenceDb.js
@@ -8,7 +8,7 @@ let actors = {};
let messages = [];
const notes = [];
let title = '';
-let titleWrapped = false;
+let description = '';
let sequenceNumbersEnabled = false;
let wrapEnabled = false;
@@ -122,9 +122,6 @@ export const getActorKeys = function () {
export const getTitle = function () {
return title;
};
-export const getTitleWrapped = function () {
- return titleWrapped;
-};
export const enableSequenceNumbers = function () {
sequenceNumbersEnabled = true;
};
@@ -324,9 +321,9 @@ export const getActorProperty = function (actor, key) {
return undefined;
};
-export const setTitle = function (titleWrap) {
- title = titleWrap.text;
- titleWrapped = (titleWrap.wrap === undefined && autoWrap()) || !!titleWrap.wrap;
+export const setTitle = function (txt) {
+ let sanitizedText = sanitizeText(txt, configApi.getConfig());
+ title = sanitizedText;
};
export const apply = function (param) {
@@ -409,6 +406,15 @@ export const apply = function (param) {
}
};
+const setAccDescription = function (description_lex) {
+ let sanitizedText = sanitizeText(description_lex, configApi.getConfig());
+ description = sanitizedText;
+};
+
+const getAccDescription = function () {
+ return description;
+};
+
export default {
addActor,
addMessage,
@@ -428,7 +434,6 @@ export default {
getTitle,
parseDirective,
getConfig: () => configApi.getConfig().sequence,
- getTitleWrapped,
clear,
parseMessage,
LINETYPE,
@@ -437,4 +442,6 @@ export default {
addNote,
setTitle,
apply,
+ setAccDescription,
+ getAccDescription,
};
diff --git a/src/diagrams/sequence/sequenceDiagram.spec.js b/src/diagrams/sequence/sequenceDiagram.spec.js
index c20dc54a44..aa73bf28a7 100644
--- a/src/diagrams/sequence/sequenceDiagram.spec.js
+++ b/src/diagrams/sequence/sequenceDiagram.spec.js
@@ -60,7 +60,7 @@ Bob-->Alice: I am good thanks!`;
mermaidAPI.parse(str);
expect(parser.yy.showSequenceNumbers()).toBe(true);
});
- it('it should handle a sequenceDiagram definition with a title', function () {
+ it('it should handle a sequenceDiagram definition with a title:', function () {
const str = `
sequenceDiagram
title: Diagram Title
@@ -73,6 +73,7 @@ Bob-->Alice: I am good thanks!`;
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
+ expect(parser.yy.getAccDescription()).toBe('');
const messages = parser.yy.getMessages();
const title = parser.yy.getTitle();
@@ -81,6 +82,52 @@ Bob-->Alice: I am good thanks!`;
expect(messages[2].from).toBe('Bob');
expect(title).toBe('Diagram Title');
});
+
+ it('it should handle a sequenceDiagram definition with a title without a :', function () {
+ const str = `
+sequenceDiagram
+title Diagram Title
+Alice->Bob:Hello Bob, how are you?
+Note right of Bob: Bob thinks
+Bob-->Alice: I am good thanks!`;
+
+ mermaidAPI.parse(str);
+ const actors = parser.yy.getActors();
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ expect(parser.yy.getAccDescription()).toBe('');
+ const messages = parser.yy.getMessages();
+ const title = parser.yy.getTitle();
+
+ expect(messages.length).toBe(3);
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[2].from).toBe('Bob');
+ expect(title).toBe('Diagram Title');
+ });
+
+ it('it should handle a sequenceDiagram definition with a accDescription', function () {
+ const str = `
+sequenceDiagram
+accDescription Accessibility Description
+Alice->Bob:Hello Bob, how are you?
+Note right of Bob: Bob thinks
+Bob-->Alice: I am good thanks!`;
+
+ mermaidAPI.parse(str);
+ const actors = parser.yy.getActors();
+ expect(actors.Alice.description).toBe('Alice');
+ actors.Bob.description = 'Bob';
+
+ expect(parser.yy.getAccDescription()).toBe('Accessibility Description');
+ const messages = parser.yy.getMessages();
+ const title = parser.yy.getTitle();
+
+ expect(messages.length).toBe(3);
+ expect(messages[0].from).toBe('Alice');
+ expect(messages[2].from).toBe('Bob');
+ });
+
it('it should space in actor names', function () {
const str = `
sequenceDiagram
@@ -1586,6 +1633,7 @@ participant Alice
renderer.bounds.init();
mermaidAPI.parse(str);
+
renderer.draw(str, 'tst');
const { bounds, models } = renderer.bounds.getBounds();
diff --git a/src/diagrams/sequence/sequenceRenderer.js b/src/diagrams/sequence/sequenceRenderer.js
index 138ca7c6bc..48507b9f70 100644
--- a/src/diagrams/sequence/sequenceRenderer.js
+++ b/src/diagrams/sequence/sequenceRenderer.js
@@ -6,6 +6,7 @@ import common from '../common/common';
import sequenceDb from './sequenceDb';
import * as configApi from '../../config';
import utils, { assignWithDepth, configureSvgSize } from '../../utils';
+import addSVGAccessibilityFields from '../../accessibility';
parser.yy = sequenceDb;
@@ -727,6 +728,7 @@ export const draw = function (text, id) {
log.error('error while drawing message', e);
}
}
+
// Increment sequence counter if msg.type is a line (and not another event like activation or note, etc)
if (
[
@@ -802,6 +804,8 @@ export const draw = function (text, id) {
' ' +
(height + extraVertForTitle)
);
+
+ addSVGAccessibilityFields(parser.yy, diagram, id);
log.debug(`models:`, bounds.models);
};