mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-09 17:19:45 +02:00
Merge branch 'develop' into cg-sanitize
This commit is contained in:
@@ -187,6 +187,7 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
|
||||
|
||||
start
|
||||
: mermaidDoc
|
||||
| statments
|
||||
| direction
|
||||
| directive start
|
||||
;
|
||||
|
@@ -17,16 +17,36 @@ let tooltips = {};
|
||||
let subCount = 0;
|
||||
let firstGraphFlag = true;
|
||||
let direction;
|
||||
let title = 'Flow chart';
|
||||
let description = '';
|
||||
|
||||
let version; // As in graph
|
||||
|
||||
// Functions to be run after graph rendering
|
||||
let funs = [];
|
||||
|
||||
const sanitizeText = (txt) => common.sanitizeText(txt, config);
|
||||
|
||||
export const parseDirective = function (statement, context, type) {
|
||||
mermaidAPI.parseDirective(this, statement, context, type);
|
||||
};
|
||||
|
||||
const setTitle = function (txt) {
|
||||
title = sanitizeText(txt);
|
||||
};
|
||||
|
||||
const getTitle = function () {
|
||||
return title;
|
||||
};
|
||||
|
||||
const setAccDescription = function (txt) {
|
||||
description = sanitizeText(txt);
|
||||
};
|
||||
|
||||
const getAccDescription = function () {
|
||||
return description;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to lookup domId from id in the graph definition.
|
||||
*
|
||||
@@ -77,7 +97,7 @@ export const addVertex = function (_id, text, type, style, classes, dir, props =
|
||||
vertexCounter++;
|
||||
if (typeof text !== 'undefined') {
|
||||
config = configApi.getConfig();
|
||||
txt = common.sanitizeText(text.trim(), config);
|
||||
txt = sanitizeText(text.trim());
|
||||
|
||||
// strip quotes if string starts and ends with a quote
|
||||
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
|
||||
@@ -132,7 +152,7 @@ export const addSingleLink = function (_start, _end, type, linktext) {
|
||||
linktext = type.text;
|
||||
|
||||
if (typeof linktext !== 'undefined') {
|
||||
edge.text = common.sanitizeText(linktext.trim(), config);
|
||||
edge.text = sanitizeText(linktext.trim());
|
||||
|
||||
// strip quotes if string starts and exnds with a quote
|
||||
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
|
||||
@@ -255,7 +275,7 @@ export const setClass = function (ids, className) {
|
||||
const setTooltip = function (ids, tooltip) {
|
||||
ids.split(',').forEach(function (id) {
|
||||
if (typeof tooltip !== 'undefined') {
|
||||
tooltips[version === 'gen-1' ? lookUpDomId(id) : id] = common.sanitizeText(tooltip, config);
|
||||
tooltips[version === 'gen-1' ? lookUpDomId(id) : id] = sanitizeText(tooltip);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -488,7 +508,7 @@ export const addSubGraph = function (_id, list, _title) {
|
||||
id = id || 'subGraph' + subCount;
|
||||
// if (id[0].match(/\d/)) id = lookUpDomId(id);
|
||||
title = title || '';
|
||||
title = common.sanitizeText(title, config);
|
||||
title = sanitizeText(title);
|
||||
subCount = subCount + 1;
|
||||
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [], dir };
|
||||
|
||||
@@ -736,6 +756,10 @@ const makeUniq = (sg, allSubgraphs) => {
|
||||
export default {
|
||||
parseDirective,
|
||||
defaultConfig: () => configApi.defaultConfig.flowchart,
|
||||
setTitle,
|
||||
getTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
addVertex,
|
||||
lookUpDomId,
|
||||
addLink,
|
||||
|
@@ -10,6 +10,7 @@ import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
|
||||
import { log } from '../../logger';
|
||||
import common, { evaluate } from '../common/common';
|
||||
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
@@ -181,7 +182,7 @@ export const addVertices = function (vert, g, svgId, root, doc) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Add edges to graph based on parsed graph defninition
|
||||
* Add edges to graph based on parsed graph definition
|
||||
*
|
||||
* @param {object} edges The edges to add to the graph
|
||||
* @param {object} g The graph object
|
||||
@@ -380,7 +381,7 @@ export const draw = function (text, id) {
|
||||
const rankSpacing = conf.rankSpacing || 50;
|
||||
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
// Handle root and ocument for when rendering in sanbox mode
|
||||
// Handle root and document for when rendering in sandbox mode
|
||||
let sandboxElement;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = select('#i' + id);
|
||||
@@ -416,7 +417,7 @@ export const draw = function (text, id) {
|
||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes, subG.dir);
|
||||
}
|
||||
|
||||
// Fetch the verices/nodes and edges/links from the parsed graph definition
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = flowDb.getVertices();
|
||||
|
||||
const edges = flowDb.getEdges();
|
||||
@@ -444,6 +445,9 @@ export const draw = function (text, id) {
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
|
||||
|
||||
// Adds title and description to the flow chart
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);
|
||||
|
@@ -11,6 +11,7 @@ import { log } from '../../logger';
|
||||
import common, { evaluate } from '../common/common';
|
||||
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
|
||||
import flowChartShapes from './flowChartShapes';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
@@ -158,7 +159,7 @@ export const addVertices = function (vert, g, svgId, root, _doc) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Add edges to graph based on parsed graph defninition
|
||||
* Add edges to graph based on parsed graph definition
|
||||
*
|
||||
* @param {object} edges The edges to add to the graph
|
||||
* @param {object} g The graph object
|
||||
@@ -350,7 +351,7 @@ export const draw = function (text, id) {
|
||||
flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
|
||||
}
|
||||
|
||||
// Fetch the verices/nodes and edges/links from the parsed graph definition
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const vert = flowDb.getVertices();
|
||||
log.warn('Get vertices', vert);
|
||||
|
||||
@@ -426,6 +427,9 @@ export const draw = function (text, id) {
|
||||
|
||||
log.warn(g);
|
||||
|
||||
// Adds title and description to the flow chart
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
const element = root.select('#' + id + ' g');
|
||||
render(element, g);
|
||||
|
@@ -7,6 +7,8 @@
|
||||
/* lexical grammar */
|
||||
%lex
|
||||
%x string
|
||||
%x title
|
||||
%x accDescription
|
||||
%x dir
|
||||
%x vertex
|
||||
%x click
|
||||
@@ -26,6 +28,10 @@
|
||||
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
||||
\%\%(?!\{)[^\n]* /* skip comments */
|
||||
[^\}]\%\%[^\n]* /* skip comments */
|
||||
title { this.begin("title");return 'title'; }
|
||||
<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
|
||||
accDescription { this.begin("accDescription");return 'accDescription'; }
|
||||
<accDescription>(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; }
|
||||
["] this.begin("string");
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return "STR";
|
||||
@@ -337,6 +343,8 @@ statement
|
||||
| subgraph separator document end
|
||||
{$$=yy.addSubGraph(undefined,$3,undefined);}
|
||||
| direction
|
||||
| title title_value { $$=$2.trim();yy.setTitle($$); }
|
||||
| accDescription description_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||
;
|
||||
|
||||
separator: NEWLINE | SEMI | EOF ;
|
||||
|
@@ -6,13 +6,13 @@ setConfig({
|
||||
securityLevel: 'strict',
|
||||
});
|
||||
|
||||
describe('when parsing ', function () {
|
||||
describe('parsing a flow chart', function () {
|
||||
beforeEach(function () {
|
||||
flow.parser.yy = flowDb;
|
||||
flow.parser.yy.clear();
|
||||
});
|
||||
|
||||
it('it should handle a trailing whitespaces after statememnts', function () {
|
||||
it('should handle a trailing whitespaces after statememnts', function () {
|
||||
const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;');
|
||||
|
||||
const vert = flow.parser.yy.getVertices();
|
||||
@@ -80,47 +80,47 @@ describe('when parsing ', function () {
|
||||
flow.parser.yy.clear();
|
||||
};
|
||||
|
||||
it("it should be able to parse a '.'", function () {
|
||||
it("should be able to parse a '.'", function () {
|
||||
charTest('.');
|
||||
charTest('Start 103a.a1');
|
||||
});
|
||||
|
||||
// it('it should be able to parse text containing \'_\'', function () {
|
||||
// it('should be able to parse text containing \'_\'', function () {
|
||||
// charTest('_')
|
||||
// })
|
||||
|
||||
it("it should be able to parse a ':'", function () {
|
||||
it("should be able to parse a ':'", function () {
|
||||
charTest(':');
|
||||
});
|
||||
|
||||
it("it should be able to parse a ','", function () {
|
||||
it("should be able to parse a ','", function () {
|
||||
charTest(',');
|
||||
});
|
||||
|
||||
it("it should be able to parse text containing '-'", function () {
|
||||
it("should be able to parse text containing '-'", function () {
|
||||
charTest('a-b');
|
||||
});
|
||||
|
||||
it("it should be able to parse a '+'", function () {
|
||||
it("should be able to parse a '+'", function () {
|
||||
charTest('+');
|
||||
});
|
||||
|
||||
it("it should be able to parse a '*'", function () {
|
||||
it("should be able to parse a '*'", function () {
|
||||
charTest('*');
|
||||
});
|
||||
|
||||
it("it should be able to parse a '<'", function () {
|
||||
it("should be able to parse a '<'", function () {
|
||||
charTest('<', '<');
|
||||
});
|
||||
|
||||
// it("it should be able to parse a '>'", function() {
|
||||
// it("should be able to parse a '>'", function() {
|
||||
// charTest('>', '>');
|
||||
// });
|
||||
|
||||
// it("it should be able to parse a '='", function() {
|
||||
// it("should be able to parse a '='", function() {
|
||||
// charTest('=', '=');
|
||||
// });
|
||||
it("it should be able to parse a '&'", function () {
|
||||
it("should be able to parse a '&'", function () {
|
||||
charTest('&');
|
||||
});
|
||||
});
|
||||
@@ -146,6 +146,7 @@ describe('when parsing ', function () {
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
expect(vertices['A'].id).toBe('A');
|
||||
});
|
||||
|
||||
it('should be possible to use numbers as labels', function () {
|
||||
let statement = '';
|
||||
|
||||
@@ -155,4 +156,19 @@ describe('when parsing ', function () {
|
||||
const classes = flow.parser.yy.getClasses();
|
||||
expect(vertices['1'].id).toBe('1');
|
||||
});
|
||||
|
||||
it('should add title and description to flow chart', function () {
|
||||
const flowChart = `graph LR
|
||||
title Big decisions
|
||||
accDescription Flow chart of the decision making process
|
||||
A[Hard] -->|Text| B(Round)
|
||||
B --> C{Decision}
|
||||
C -->|One| D[Result 1]
|
||||
C -->|Two| E[Result 2]
|
||||
`;
|
||||
|
||||
flow.parser.parse(flowChart);
|
||||
expect(flow.parser.yy.getTitle()).toBe('Big decisions');
|
||||
expect(flow.parser.yy.getAccDescription()).toBe('Flow chart of the decision making process');
|
||||
});
|
||||
});
|
||||
|
@@ -13,6 +13,7 @@ let includes = [];
|
||||
let excludes = [];
|
||||
let links = {};
|
||||
let title = '';
|
||||
let accDescription = '';
|
||||
let sections = [];
|
||||
let tasks = [];
|
||||
let currentSection = '';
|
||||
@@ -24,6 +25,10 @@ let topAxis = false;
|
||||
// The serial order of the task in the script
|
||||
let lastOrder = 0;
|
||||
|
||||
const sanitizeText = function (txt) {
|
||||
return common.sanitizeText(txt, configApi.getConfig());
|
||||
};
|
||||
|
||||
export const parseDirective = function (statement, context, type) {
|
||||
mermaidAPI.parseDirective(this, statement, context, type);
|
||||
};
|
||||
@@ -109,14 +114,21 @@ export const getLinks = function () {
|
||||
};
|
||||
|
||||
export const setTitle = function (txt) {
|
||||
let sanitizedText = common.sanitizeText(txt, configApi.getConfig());
|
||||
title = sanitizedText;
|
||||
title = sanitizeText(txt);
|
||||
};
|
||||
|
||||
export const getTitle = function () {
|
||||
return title;
|
||||
};
|
||||
|
||||
export const setAccDescription = function (txt) {
|
||||
accDescription = sanitizeText(txt);
|
||||
};
|
||||
|
||||
export const getAccDescription = function () {
|
||||
return accDescription;
|
||||
};
|
||||
|
||||
export const addSection = function (txt) {
|
||||
currentSection = txt;
|
||||
sections.push(txt);
|
||||
@@ -639,6 +651,8 @@ export default {
|
||||
getTodayMarker,
|
||||
setTitle,
|
||||
getTitle,
|
||||
setAccDescription,
|
||||
getAccDescription,
|
||||
addSection,
|
||||
getSections,
|
||||
getTasks,
|
||||
|
@@ -32,6 +32,7 @@ describe('when using the ganttDb', function () {
|
||||
fn | expected
|
||||
${'getTasks'} | ${[]}
|
||||
${'getTitle'} | ${''}
|
||||
${'getAccDescription'} | ${''}
|
||||
${'getDateFormat'} | ${''}
|
||||
${'getAxisFormat'} | ${''}
|
||||
${'getTodayMarker'} | ${''}
|
||||
|
@@ -15,6 +15,7 @@ import common from '../common/common';
|
||||
import ganttDb from './ganttDb';
|
||||
import { getConfig } from '../../config';
|
||||
import { configureSvgSize } from '../../utils';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
parser.yy = ganttDb;
|
||||
export const setConf = function () {
|
||||
@@ -114,6 +115,8 @@ export const draw = function (text, id) {
|
||||
.attr('y', conf.titleTopMargin)
|
||||
.attr('class', 'titleText');
|
||||
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
|
||||
/**
|
||||
* @param tasks
|
||||
* @param pageWidth
|
||||
|
@@ -65,22 +65,23 @@ that id.
|
||||
<click>[\s\n] this.popState();
|
||||
<click>[^\s\n]* return 'click';
|
||||
|
||||
"gantt" return 'gantt';
|
||||
"dateFormat"\s[^#\n;]+ return 'dateFormat';
|
||||
"inclusiveEndDates" return 'inclusiveEndDates';
|
||||
"topAxis" return 'topAxis';
|
||||
"axisFormat"\s[^#\n;]+ return 'axisFormat';
|
||||
"includes"\s[^#\n;]+ return 'includes';
|
||||
"excludes"\s[^#\n;]+ return 'excludes';
|
||||
"todayMarker"\s[^\n;]+ return 'todayMarker';
|
||||
\d\d\d\d"-"\d\d"-"\d\d return 'date';
|
||||
"title"\s[^#\n;]+ return 'title';
|
||||
"section"\s[^#:\n;]+ return 'section';
|
||||
[^#:\n;]+ return 'taskTxt';
|
||||
":"[^#\n;]+ return 'taskData';
|
||||
":" return ':';
|
||||
<<EOF>> return 'EOF';
|
||||
. return 'INVALID';
|
||||
"gantt" return 'gantt';
|
||||
"dateFormat"\s[^#\n;]+ return 'dateFormat';
|
||||
"inclusiveEndDates" return 'inclusiveEndDates';
|
||||
"topAxis" return 'topAxis';
|
||||
"axisFormat"\s[^#\n;]+ return 'axisFormat';
|
||||
"includes"\s[^#\n;]+ return 'includes';
|
||||
"excludes"\s[^#\n;]+ return 'excludes';
|
||||
"todayMarker"\s[^\n;]+ return 'todayMarker';
|
||||
\d\d\d\d"-"\d\d"-"\d\d return 'date';
|
||||
"title"\s[^#\n;]+ return 'title';
|
||||
"accDescription"\s[^#\n;]+ return 'accDescription'
|
||||
"section"\s[^#:\n;]+ return 'section';
|
||||
[^#:\n;]+ return 'taskTxt';
|
||||
":"[^#\n;]+ return 'taskData';
|
||||
":" return ':';
|
||||
<<EOF>> return 'EOF';
|
||||
. return 'INVALID';
|
||||
|
||||
/lex
|
||||
|
||||
@@ -116,6 +117,7 @@ statement
|
||||
| includes {yy.setIncludes($1.substr(9));$$=$1.substr(9);}
|
||||
| todayMarker {yy.setTodayMarker($1.substr(12));$$=$1.substr(12);}
|
||||
| title {yy.setTitle($1.substr(6));$$=$1.substr(6);}
|
||||
| accDescription {yy.setAccDescription($1.substr(15));$$=$1.substr(15);}
|
||||
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
|
||||
| clickStatement
|
||||
| taskTxt taskData {yy.addTask($1,$2);$$='task';}
|
||||
|
@@ -156,4 +156,21 @@ describe('when parsing a gantt diagram it', function () {
|
||||
'"test0", test1, test2'
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow for a title and accDescription', function () {
|
||||
const expectedTitle = 'Gantt Diagram';
|
||||
const expectedAccDescription = 'Tasks for Q4';
|
||||
const ganttString =
|
||||
'gantt\n' +
|
||||
`title ${expectedTitle}\n` +
|
||||
`accDescription ${expectedAccDescription}\n` +
|
||||
'dateFormat YYYY-MM-DD\n' +
|
||||
'section Section\n' +
|
||||
'A task :a1, 2014-01-01, 30d\n';
|
||||
|
||||
const output = parser.parse(ganttString);
|
||||
|
||||
expect(ganttDb.getTitle()).toBe(expectedTitle);
|
||||
expect(ganttDb.getAccDescription()).toBe(expectedAccDescription);
|
||||
});
|
||||
});
|
||||
|
@@ -2,11 +2,15 @@ import { log } from '../../logger';
|
||||
import { random } from '../../utils';
|
||||
import mermaidAPI from '../../mermaidAPI';
|
||||
import * as configApi from '../../config';
|
||||
import { getConfig } from '../../config';
|
||||
import common from '../common/common';
|
||||
|
||||
let mainBranchName = getConfig().gitGraph.mainBranchName;
|
||||
let commits = {};
|
||||
let head = null;
|
||||
let branches = { main: head };
|
||||
let curBranch = 'main';
|
||||
let branches = {};
|
||||
branches[mainBranchName] = head;
|
||||
let curBranch = mainBranchName;
|
||||
let direction = 'LR';
|
||||
let seq = 0;
|
||||
|
||||
@@ -316,8 +320,10 @@ export const prettyPrint = function () {
|
||||
export const clear = function () {
|
||||
commits = {};
|
||||
head = null;
|
||||
branches = { main: head };
|
||||
curBranch = 'main';
|
||||
let mainBranch = getConfig().gitGraph.mainBranchName;
|
||||
branches = {};
|
||||
branches[mainBranch] = null;
|
||||
curBranch = mainBranch;
|
||||
seq = 0;
|
||||
};
|
||||
|
||||
|
@@ -21,6 +21,9 @@
|
||||
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
|
||||
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
|
||||
|
||||
"title"\s[^#\n;]+ return 'title';
|
||||
"accDescription"\s[^#\n;]+ return 'accDescription';
|
||||
|
||||
(\r?\n)+ return 'NEWLINE';
|
||||
\s+ /* skip all whitespace */
|
||||
\#[^\n]* /* skip comments */
|
||||
@@ -90,7 +93,9 @@ start
|
||||
|
||||
directive
|
||||
: 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
|
||||
: open_directive { yy.parseDirective('%%{', 'open_directive'); };
|
||||
@@ -191,6 +196,7 @@ relationship
|
||||
| TRACES
|
||||
{ $$=yy.Relationships.TRACES;};
|
||||
|
||||
|
||||
requirementName: unqString | qString;
|
||||
id : unqString | qString;
|
||||
text : unqString | qString;
|
||||
|
@@ -72,6 +72,29 @@ describe('when parsing requirement diagram it...', function () {
|
||||
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 () {
|
||||
const expectedSrc = 'a';
|
||||
const expectedDest = 'b';
|
||||
|
@@ -1,12 +1,17 @@
|
||||
import * as configApi from '../../config';
|
||||
import { log } from '../../logger';
|
||||
import mermaidAPI from '../../mermaidAPI';
|
||||
import common from '../common/common';
|
||||
|
||||
let relations = [];
|
||||
let latestRequirement = {};
|
||||
let requirements = {};
|
||||
let latestElement = {};
|
||||
let elements = {};
|
||||
let title = '';
|
||||
let accDescription = '';
|
||||
|
||||
const sanitizeText = (txt) => common.sanitizeText(txt, configApi.getConfig());
|
||||
|
||||
const RequirementType = {
|
||||
REQUIREMENT: 'Requirement',
|
||||
@@ -134,6 +139,24 @@ const clear = () => {
|
||||
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 {
|
||||
RequirementType,
|
||||
RiskLevel,
|
||||
@@ -149,6 +172,10 @@ export default {
|
||||
setNewReqText,
|
||||
setNewReqRisk,
|
||||
setNewReqVerifyMethod,
|
||||
setTitle,
|
||||
getTitle,
|
||||
setAccDescription,
|
||||
getAccDescription,
|
||||
|
||||
addElement,
|
||||
getElements,
|
||||
|
@@ -9,6 +9,7 @@ import { parser } from './parser/requirementDiagram';
|
||||
import requirementDb from './requirementDb';
|
||||
import markers from './requirementMarkers';
|
||||
import { getConfig } from '../../config';
|
||||
import addSVGAccessibilityFields from '../../accessibility';
|
||||
|
||||
const conf = {};
|
||||
let relCnt = 0;
|
||||
@@ -377,6 +378,8 @@ export const draw = (text, id) => {
|
||||
configureSvgSize(svg, height, width, conf.useMaxWidth);
|
||||
|
||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||
// Adds title and description to the requirements diagram
|
||||
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@@ -21,7 +21,7 @@ describe('when parsing a sequenceDiagram', function () {
|
||||
parser.yy = sequenceDb;
|
||||
parser.yy.clear();
|
||||
});
|
||||
it('it should handle a sequenceDiagram definition', function () {
|
||||
it('should handle a sequenceDiagram definition', function () {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
Alice->Bob:Hello Bob, how are you?
|
||||
|
@@ -272,20 +272,65 @@ const actorFont = (cnf) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a message
|
||||
* Process a message by adding its dimensions to the bound. It returns the Y coordinate of the
|
||||
* message so it can be drawn later. We do not draw the message at this point so the arrowhead can
|
||||
* be on top of the activation box.
|
||||
*
|
||||
* @param {any} g - The parent of the message element
|
||||
* @param {any} diagram - The parent of the message element
|
||||
* @param {any} msgModel - The model containing fields describing a message
|
||||
* @returns {number} LineStarty - The Y coordinate at which the message line starts
|
||||
*/
|
||||
const drawMessage = function (g, msgModel) {
|
||||
const boundMessage = function (diagram, msgModel) {
|
||||
bounds.bumpVerticalPos(10);
|
||||
const { startx, stopx, starty, message, type, sequenceIndex } = msgModel;
|
||||
const { startx, stopx, message } = msgModel;
|
||||
const lines = common.splitBreaks(message).length;
|
||||
let textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||
const lineHeight = textDims.height / lines;
|
||||
msgModel.height += lineHeight;
|
||||
|
||||
bounds.bumpVerticalPos(lineHeight);
|
||||
|
||||
let lineStarty;
|
||||
let totalOffset = textDims.height - 10;
|
||||
let textWidth = textDims.width;
|
||||
|
||||
if (startx === stopx) {
|
||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
||||
if (!conf.rightAngles) {
|
||||
totalOffset += conf.boxMargin;
|
||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
||||
}
|
||||
totalOffset += 30;
|
||||
const dx = Math.max(textWidth / 2, conf.width / 2);
|
||||
bounds.insert(
|
||||
startx - dx,
|
||||
bounds.getVerticalPos() - 10 + totalOffset,
|
||||
stopx + dx,
|
||||
bounds.getVerticalPos() + 30 + totalOffset
|
||||
);
|
||||
} else {
|
||||
totalOffset += conf.boxMargin;
|
||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
||||
bounds.insert(startx, lineStarty - 10, stopx, lineStarty);
|
||||
}
|
||||
bounds.bumpVerticalPos(totalOffset);
|
||||
msgModel.height += totalOffset;
|
||||
msgModel.stopy = msgModel.starty + msgModel.height;
|
||||
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
|
||||
|
||||
return lineStarty;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a message. Note that the bounds have previously been updated by boundMessage.
|
||||
*
|
||||
* @param {any} diagram - The parent of the message element
|
||||
* @param {any} msgModel - The model containing fields describing a message
|
||||
* @param {float} lineStarty - The Y coordinate at which the message line starts
|
||||
*/
|
||||
const drawMessage = function (diagram, msgModel, lineStarty) {
|
||||
const { startx, stopx, starty, message, type, sequenceIndex } = msgModel;
|
||||
let textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||
const textObj = svgDraw.getTextObj();
|
||||
textObj.x = startx;
|
||||
textObj.y = starty + 10;
|
||||
@@ -301,17 +346,14 @@ const drawMessage = function (g, msgModel) {
|
||||
textObj.textMargin = conf.wrapPadding;
|
||||
textObj.tspan = false;
|
||||
|
||||
drawText(g, textObj);
|
||||
|
||||
let totalOffset = textDims.height - 10;
|
||||
drawText(diagram, textObj);
|
||||
|
||||
let textWidth = textDims.width;
|
||||
|
||||
let line, lineStarty;
|
||||
let line;
|
||||
if (startx === stopx) {
|
||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
||||
if (conf.rightAngles) {
|
||||
line = g
|
||||
line = diagram
|
||||
.append('path')
|
||||
.attr(
|
||||
'd',
|
||||
@@ -320,10 +362,7 @@ const drawMessage = function (g, msgModel) {
|
||||
} H ${startx}`
|
||||
);
|
||||
} else {
|
||||
totalOffset += conf.boxMargin;
|
||||
|
||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
||||
line = g
|
||||
line = diagram
|
||||
.append('path')
|
||||
.attr(
|
||||
'd',
|
||||
@@ -345,24 +384,12 @@ const drawMessage = function (g, msgModel) {
|
||||
(lineStarty + 20)
|
||||
);
|
||||
}
|
||||
|
||||
totalOffset += 30;
|
||||
const dx = Math.max(textWidth / 2, conf.width / 2);
|
||||
bounds.insert(
|
||||
startx - dx,
|
||||
bounds.getVerticalPos() - 10 + totalOffset,
|
||||
stopx + dx,
|
||||
bounds.getVerticalPos() + 30 + totalOffset
|
||||
);
|
||||
} else {
|
||||
totalOffset += conf.boxMargin;
|
||||
lineStarty = bounds.getVerticalPos() + totalOffset;
|
||||
line = g.append('line');
|
||||
line = diagram.append('line');
|
||||
line.attr('x1', startx);
|
||||
line.attr('y1', lineStarty);
|
||||
line.attr('x2', stopx);
|
||||
line.attr('y2', lineStarty);
|
||||
bounds.insert(startx, lineStarty - 10, stopx, lineStarty);
|
||||
}
|
||||
// Make an SVG Container
|
||||
// Draw the line
|
||||
@@ -407,7 +434,8 @@ const drawMessage = function (g, msgModel) {
|
||||
// add node number
|
||||
if (sequenceDb.showSequenceNumbers() || conf.showSequenceNumbers) {
|
||||
line.attr('marker-start', 'url(' + url + '#sequencenumber)');
|
||||
g.append('text')
|
||||
diagram
|
||||
.append('text')
|
||||
.attr('x', startx)
|
||||
.attr('y', lineStarty + 4)
|
||||
.attr('font-family', 'sans-serif')
|
||||
@@ -417,10 +445,6 @@ const drawMessage = function (g, msgModel) {
|
||||
.attr('class', 'sequenceNumber')
|
||||
.text(sequenceIndex);
|
||||
}
|
||||
bounds.bumpVerticalPos(totalOffset);
|
||||
msgModel.height += totalOffset;
|
||||
msgModel.stopy = msgModel.starty + msgModel.height;
|
||||
bounds.insert(msgModel.fromBounds, msgModel.starty, msgModel.toBounds, msgModel.stopy);
|
||||
};
|
||||
|
||||
export const drawActors = function (diagram, actors, actorKeys, verticalPos) {
|
||||
@@ -613,6 +637,7 @@ export const draw = function (text, id) {
|
||||
|
||||
// Draw the messages/signals
|
||||
let sequenceIndex = 1;
|
||||
let messagesToDraw = Array();
|
||||
messages.forEach(function (msg) {
|
||||
let loopModel, noteModel, msgModel;
|
||||
|
||||
@@ -722,7 +747,8 @@ export const draw = function (text, id) {
|
||||
msgModel = msg.msgModel;
|
||||
msgModel.starty = bounds.getVerticalPos();
|
||||
msgModel.sequenceIndex = sequenceIndex;
|
||||
drawMessage(diagram, msgModel);
|
||||
let lineStarty = boundMessage(diagram, msgModel);
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStarty: lineStarty });
|
||||
bounds.models.addMessage(msgModel);
|
||||
} catch (e) {
|
||||
log.error('error while drawing message', e);
|
||||
@@ -746,6 +772,8 @@ export const draw = function (text, id) {
|
||||
}
|
||||
});
|
||||
|
||||
messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStarty));
|
||||
|
||||
if (conf.mirrorActors) {
|
||||
// Draw actors below diagram
|
||||
bounds.bumpVerticalPos(conf.boxMargin * 2);
|
||||
|
Reference in New Issue
Block a user