From 50f522ae5c4cd8d3462893c9c16ac770b9c281fd Mon Sep 17 00:00:00 2001 From: Cory Gwin Date: Thu, 17 Mar 2022 19:48:22 +0000 Subject: [PATCH] feat: adding more accessibility tooling --- demos/er.html | 45 +++++++++++++++++++ demos/flowchart.html | 2 + demos/sequence.html | 1 + launch.json | 11 +++++ src/accessibility.js | 5 ++- src/diagrams/er/erDb.js | 11 +++++ src/diagrams/er/erRenderer.js | 3 ++ src/diagrams/er/parser/erDiagram.jison | 8 ++++ src/diagrams/er/parser/erDiagram.spec.js | 11 +++++ .../sequence/parser/sequenceDiagram.jison | 6 ++- src/diagrams/sequence/sequenceDb.js | 14 +++--- src/diagrams/sequence/sequenceDiagram.spec.js | 29 +++++++++++- 12 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 demos/er.html create mode 100644 launch.json diff --git a/demos/er.html b/demos/er.html new file mode 100644 index 000000000..62285a2b4 --- /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 0ab1f6481..864fac687 100644 --- a/demos/flowchart.html +++ b/demos/flowchart.html @@ -230,6 +230,8 @@

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/sequence.html b/demos/sequence.html index 6c477114d..b6930a722 100644 --- a/demos/sequence.html +++ b/demos/sequence.html @@ -19,6 +19,7 @@
sequenceDiagram + title: FancySequenceDiagram accDescription Test a description participant Alice participant Bob diff --git a/launch.json b/launch.json new file mode 100644 index 000000000..6a9ed413a --- /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 2b1119580..046fea6ad 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 9aa94aef1..8fe54ed83 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 d2e2cc0d9..a8589da72 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 6e06fc2ce..7461cb064 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 746a091fa..edfec58d6 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 beadc9508..b64940833 100644 --- a/src/diagrams/sequence/parser/sequenceDiagram.jison +++ b/src/diagrams/sequence/parser/sequenceDiagram.jison @@ -56,7 +56,8 @@ "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'; @@ -122,7 +123,8 @@ 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 { diff --git a/src/diagrams/sequence/sequenceDb.js b/src/diagrams/sequence/sequenceDb.js index fd8ae448b..cb7238fec 100644 --- a/src/diagrams/sequence/sequenceDb.js +++ b/src/diagrams/sequence/sequenceDb.js @@ -9,7 +9,6 @@ let messages = []; const notes = []; let title = ''; let description = ''; -let titleWrapped = false; let sequenceNumbersEnabled = false; let wrapEnabled = false; @@ -123,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 +320,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) { @@ -410,7 +406,8 @@ export const apply = function (param) { }; const setAccDescription = function (description_lex) { - description = description_lex; + let sanitizedText = sanitizeText(description_lex, configApi.getConfig()); + description = sanitizedText; }; const getAccDescription = function () { @@ -436,7 +433,6 @@ export default { getTitle, parseDirective, getConfig: () => configApi.getConfig().sequence, - getTitleWrapped, clear, parseMessage, LINETYPE, diff --git a/src/diagrams/sequence/sequenceDiagram.spec.js b/src/diagrams/sequence/sequenceDiagram.spec.js index f305d45de..1016cb9bf 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 @@ -82,10 +82,34 @@ 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 +accDescription Accessibility Description Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; @@ -1609,6 +1633,7 @@ participant Alice renderer.bounds.init(); mermaidAPI.parse(str); + renderer.draw(str, 'tst'); const { bounds, models } = renderer.bounds.getBounds();