mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-23 10:16:43 +02:00
feat: Add accessibility fields to requirements diagram
This commit is contained in:
@@ -46,4 +46,69 @@ describe('Requirement diagram', () => {
|
|||||||
);
|
);
|
||||||
cy.get('svg');
|
cy.get('svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render accessibility tags', function () {
|
||||||
|
const expectedTitle = 'Gantt Diagram';
|
||||||
|
const expectedAccDescription = 'Tasks for Q4';
|
||||||
|
renderGraph(
|
||||||
|
`
|
||||||
|
requirementDiagram
|
||||||
|
title: ${expectedTitle}
|
||||||
|
accDescription: ${expectedAccDescription}
|
||||||
|
|
||||||
|
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
|
||||||
|
`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
cy.get('svg').should((svg) => {
|
||||||
|
const el = svg.get(0);
|
||||||
|
const children = Array.from(el.children);
|
||||||
|
|
||||||
|
const titleEl = children.find(function (node) {
|
||||||
|
return node.tagName === 'title';
|
||||||
|
});
|
||||||
|
const descriptionEl = children.find(function (node) {
|
||||||
|
return node.tagName === 'desc';
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(titleEl).to.exist;
|
||||||
|
expect(titleEl.textContent).to.equal(expectedTitle);
|
||||||
|
expect(descriptionEl).to.exist;
|
||||||
|
expect(descriptionEl.textContent).to.equal(expectedAccDescription);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
106
demos/requirements.html
Normal file
106
demos/requirements.html
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<!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>
|
||||||
|
div.mermaid {
|
||||||
|
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||||
|
font-family: 'Courier New', Courier, monospace !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="mermaid">
|
||||||
|
requirementDiagram
|
||||||
|
title This is a title
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceRequirement test_req4 {
|
||||||
|
id: 1.2.1
|
||||||
|
text: the fourth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
physicalRequirement test_req5 {
|
||||||
|
id: 1.2.2
|
||||||
|
text: the fifth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
designConstraint test_req6 {
|
||||||
|
id: 1.2.3
|
||||||
|
text: the sixth test text.
|
||||||
|
risk: medium
|
||||||
|
verifymethod: analysis
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity {
|
||||||
|
type: simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity2 {
|
||||||
|
type: word doc
|
||||||
|
docRef: reqs/test_entity
|
||||||
|
}
|
||||||
|
|
||||||
|
element test_entity3 {
|
||||||
|
type: "test suite"
|
||||||
|
docRef: github.com/all_the_tests
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
test_entity - satisfies -> test_req2
|
||||||
|
test_req - traces -> test_req2
|
||||||
|
test_req - contains -> test_req3
|
||||||
|
test_req3 - contains -> test_req4
|
||||||
|
test_req4 - derives -> test_req5
|
||||||
|
test_req5 - refines -> test_req6
|
||||||
|
test_entity3 - verifies -> test_req5
|
||||||
|
test_req <- copies - test_entity2
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./mermaid.js"></script>
|
||||||
|
<script>
|
||||||
|
mermaid.initialize({
|
||||||
|
theme: 'forest',
|
||||||
|
// themeCSS: '.node rect { fill: red; }',
|
||||||
|
logLevel: 3,
|
||||||
|
securityLevel: 'loose',
|
||||||
|
flowchart: { curve: 'basis' },
|
||||||
|
gantt: { axisFormat: '%m/%d/%Y' },
|
||||||
|
sequence: { actorMargin: 50 },
|
||||||
|
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@@ -185,6 +185,7 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
|
|||||||
|
|
||||||
start
|
start
|
||||||
: mermaidDoc
|
: mermaidDoc
|
||||||
|
| statments
|
||||||
| direction
|
| direction
|
||||||
| directive start
|
| directive start
|
||||||
;
|
;
|
||||||
|
@@ -21,6 +21,9 @@
|
|||||||
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
||||||
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
||||||
|
|
||||||
|
"title"\s[^#\n;]+ return 'title';
|
||||||
|
"accDescription"\s[^#\n;]+ return 'accDescription';
|
||||||
|
|
||||||
(\r?\n)+ return 'NEWLINE';
|
(\r?\n)+ return 'NEWLINE';
|
||||||
\s+ /* skip all whitespace */
|
\s+ /* skip all whitespace */
|
||||||
\#[^\n]* /* skip comments */
|
\#[^\n]* /* skip comments */
|
||||||
@@ -90,7 +93,9 @@ start
|
|||||||
|
|
||||||
directive
|
directive
|
||||||
: openDirective typeDirective closeDirective
|
: openDirective typeDirective closeDirective
|
||||||
| openDirective typeDirective ':' argDirective closeDirective;
|
| openDirective typeDirective ':' argDirective closeDirective
|
||||||
|
| title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
|
||||||
|
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);};
|
||||||
|
|
||||||
openDirective
|
openDirective
|
||||||
: open_directive { yy.parseDirective('%%{', 'open_directive'); };
|
: open_directive { yy.parseDirective('%%{', 'open_directive'); };
|
||||||
@@ -191,6 +196,7 @@ relationship
|
|||||||
| TRACES
|
| TRACES
|
||||||
{ $$=yy.Relationships.TRACES;};
|
{ $$=yy.Relationships.TRACES;};
|
||||||
|
|
||||||
|
|
||||||
requirementName: unqString | qString;
|
requirementName: unqString | qString;
|
||||||
id : unqString | qString;
|
id : unqString | qString;
|
||||||
text : unqString | qString;
|
text : unqString | qString;
|
||||||
|
@@ -72,6 +72,29 @@ describe('when parsing requirement diagram it...', function () {
|
|||||||
expect(Object.keys(requirementDb.getRelationships()).length).toBe(0);
|
expect(Object.keys(requirementDb.getRelationships()).length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('will use a title and accDescription', function () {
|
||||||
|
const expectedTitle = 'test title';
|
||||||
|
const expectedAccDescription = 'my chart description';
|
||||||
|
const expectedDocRef = 'test_ref';
|
||||||
|
|
||||||
|
let lines = [
|
||||||
|
`requirementDiagram`,
|
||||||
|
``,
|
||||||
|
`title ${expectedTitle}`,
|
||||||
|
`accDescription ${expectedAccDescription}`,
|
||||||
|
`element test_name {`,
|
||||||
|
`type: test_type`,
|
||||||
|
`docref: test_ref`,
|
||||||
|
`}`,
|
||||||
|
];
|
||||||
|
let doc = lines.join('\n');
|
||||||
|
|
||||||
|
reqDiagram.parser.parse(doc);
|
||||||
|
|
||||||
|
expect(requirementDb.getTitle()).toBe(expectedTitle);
|
||||||
|
expect(requirementDb.getAccDescription()).toBe(expectedAccDescription);
|
||||||
|
});
|
||||||
|
|
||||||
it('will accept full relationship definition', function () {
|
it('will accept full relationship definition', function () {
|
||||||
const expectedSrc = 'a';
|
const expectedSrc = 'a';
|
||||||
const expectedDest = 'b';
|
const expectedDest = 'b';
|
||||||
|
@@ -1,12 +1,17 @@
|
|||||||
import * as configApi from '../../config';
|
import * as configApi from '../../config';
|
||||||
import { log } from '../../logger';
|
import { log } from '../../logger';
|
||||||
import mermaidAPI from '../../mermaidAPI';
|
import mermaidAPI from '../../mermaidAPI';
|
||||||
|
import common from '../common/common';
|
||||||
|
|
||||||
let relations = [];
|
let relations = [];
|
||||||
let latestRequirement = {};
|
let latestRequirement = {};
|
||||||
let requirements = {};
|
let requirements = {};
|
||||||
let latestElement = {};
|
let latestElement = {};
|
||||||
let elements = {};
|
let elements = {};
|
||||||
|
let title = '';
|
||||||
|
let accDescription = '';
|
||||||
|
|
||||||
|
const sanitizeText = (txt) => common.sanitizeText(txt, configApi.getConfig());
|
||||||
|
|
||||||
const RequirementType = {
|
const RequirementType = {
|
||||||
REQUIREMENT: 'Requirement',
|
REQUIREMENT: 'Requirement',
|
||||||
@@ -134,6 +139,24 @@ const clear = () => {
|
|||||||
elements = {};
|
elements = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setTitle = function (txt) {
|
||||||
|
let sanitizedText = sanitizeText(txt, configApi.getConfig());
|
||||||
|
title = sanitizedText;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTitle = function () {
|
||||||
|
return title;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setAccDescription = function (txt) {
|
||||||
|
let sanitizedText = sanitizeText(txt, configApi.getConfig());
|
||||||
|
accDescription = sanitizedText;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getAccDescription = function () {
|
||||||
|
return accDescription;
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
RequirementType,
|
RequirementType,
|
||||||
RiskLevel,
|
RiskLevel,
|
||||||
@@ -149,6 +172,10 @@ export default {
|
|||||||
setNewReqText,
|
setNewReqText,
|
||||||
setNewReqRisk,
|
setNewReqRisk,
|
||||||
setNewReqVerifyMethod,
|
setNewReqVerifyMethod,
|
||||||
|
setTitle,
|
||||||
|
getTitle,
|
||||||
|
setAccDescription,
|
||||||
|
getAccDescription,
|
||||||
|
|
||||||
addElement,
|
addElement,
|
||||||
getElements,
|
getElements,
|
||||||
|
@@ -9,6 +9,7 @@ import { parser } from './parser/requirementDiagram';
|
|||||||
import requirementDb from './requirementDb';
|
import requirementDb from './requirementDb';
|
||||||
import markers from './requirementMarkers';
|
import markers from './requirementMarkers';
|
||||||
import { getConfig } from '../../config';
|
import { getConfig } from '../../config';
|
||||||
|
import addSVGAccessibilityFields from '../../accessibility';
|
||||||
|
|
||||||
const conf = {};
|
const conf = {};
|
||||||
let relCnt = 0;
|
let relCnt = 0;
|
||||||
@@ -377,6 +378,8 @@ export const draw = (text, id) => {
|
|||||||
configureSvgSize(svg, height, width, conf.useMaxWidth);
|
configureSvgSize(svg, height, width, conf.useMaxWidth);
|
||||||
|
|
||||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||||
|
// Adds title and description to the flow chart
|
||||||
|
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
Reference in New Issue
Block a user