diff --git a/demos/er.html b/demos/er.html new file mode 100644 index 0000000000..62285a2b45 --- /dev/null +++ b/demos/er.html @@ -0,0 +1,45 @@ + + + + + + +Mermaid Quick Test Page + + + + + + + +
+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'; } +<accDescription>(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; } \%\%\{ { this.begin('open_directive'); return 'open_directive'; } <open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; } <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'; } <ID>[^\->:\n,;]+?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; } <ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; } <ALIAS>(?:) { 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); };