Merge pull request #1202 from GDFaber/bug/1200_unify_regex_for_br_tags

Unify regex for finding <br> tags throughout mermaid
This commit is contained in:
Knut Sveidqvist 2020-01-15 16:53:06 +01:00 committed by GitHub
commit c564a843fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 112 additions and 45 deletions

View File

@ -121,6 +121,18 @@ describe('State diagram', () => {
{} {}
); );
}); });
it('should handle multiline notes with different line breaks', () => {
imgSnapshotTest(
`
stateDiagram
State1
note right of State1
Line1<br>Line2<br/>Line3<br />Line4<br />Line5
end note
`,
{}
);
});
it('should render a states with descriptions including multi-line descriptions', () => { it('should render a states with descriptions including multi-line descriptions', () => {
imgSnapshotTest( imgSnapshotTest(

77
dist/index.html vendored
View File

@ -519,45 +519,46 @@ class Class10 {
int id int id
size() size()
} }
</div> </div>
<div class="mermaid"> <div class="mermaid">
classDiagram classDiagram
Class01~T~ <|-- AveryLongClass : Cool Class01~T~ <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01 &lt;&lt;interface&gt;&gt; Class01
Class03~T~ "0" *-- "0..n" Class04 Class03~T~ "0" *-- "0..n" Class04
Class05 "1" o-- "many" Class06 Class05 "1" o-- "many" Class06
Class07~T~ .. Class08 Class07~T~ .. Class08
Class09 "many" --> "1" C2 : Where am i? Class09 "many" --> "1" C2 : Where am i?
Class09 "0" --* "1..n" C3 Class09 "0" --* "1..n" C3
Class09 --|> Class07 Class09 --|> Class07
Class07 : equals() Class07 : equals()
Class07 : Object[] elementData Class07 : Object[] elementData
Class01 : #size() Class01 : #size()
Class01 : -int chimp Class01 : -int chimp
Class01 : +int gorilla Class01 : +int gorilla
Class08 <--> C2: Cool label Class08 <--> C2: Cool label
class Class10 { class Class10 {
&lt;&lt;service&gt;&gt; &lt;&lt;service&gt;&gt;
int id int id
size() size()
} }
</div> </div>
<div class="mermaid"> <div class="mermaid">
stateDiagram stateDiagram
State1 State1
</div> </div>
<hr> <hr>
<div class="mermaid">
stateDiagram <div class="mermaid">
[*] --> First stateDiagram
state First { [*] --> First
[*] --> second state First {
second --> [*] [*] --> second
} second --> [*]
</div> }
</div>
<div class="mermaid"> <div class="mermaid">
stateDiagram stateDiagram
State1: The state with a note State1: The state with a note
@ -567,8 +568,14 @@ class Class10 {
end note end note
State1 --> State2 State1 --> State2
note left of State2 : This is the note to the left. note left of State2 : This is the note to the left.
</div> </div>
<div class="mermaid">
stateDiagram
State1
note right of State1
Line1<br>Line2<br/>Line3<br />Line4<br />Line5
end note
</div>
<script src="./mermaid.js"></script> <script src="./mermaid.js"></script>
<script> <script>

View File

@ -88,7 +88,7 @@ export const addVertices = function(vert, g, svgId) {
} else { } else {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text'); const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
const rows = vertexText.split(/<br[/]{0,1}>/); const rows = vertexText.split(/<br\s*\/?>/gi);
for (let j = 0; j < rows.length; j++) { for (let j = 0; j < rows.length; j++) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan'); const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
@ -237,7 +237,7 @@ export const addEdges = function(edges, g) {
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>'; edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
} else { } else {
edgeData.labelType = 'text'; edgeData.labelType = 'text';
edgeData.label = edge.text.replace(/<br\s*\/?>/g, '\n'); edgeData.label = edge.text.replace(/<br\s*\/?>/gi, '\n');
if (typeof edge.style === 'undefined') { if (typeof edge.style === 'undefined') {
edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none'; edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none';

View File

@ -55,6 +55,43 @@ describe('the flowchart renderer', function() {
expect(addedNodes[0][1]).toHaveProperty('ry', expectedRadios); expect(addedNodes[0][1]).toHaveProperty('ry', expectedRadios);
}); });
}); });
[
'Multi<br>Line',
'Multi<br/>Line',
'Multi<br />Line',
'Multi<br\t/>Line'
].forEach(function(labelText) {
it('should handle multiline texts with different line breaks', function() {
const addedNodes = [];
const mockG = {
setNode: function(id, object) {
addedNodes.push([id, object]);
}
};
addVertices(
{
v1: {
type: 'rect',
id: 'my-node-id',
classes: [],
styles: [],
text: 'Multi<br>Line'
}
},
mockG,
'svg-id'
);
expect(addedNodes).toHaveLength(1);
expect(addedNodes[0][0]).toEqual('my-node-id');
expect(addedNodes[0][1]).toHaveProperty('id', 'my-node-id');
expect(addedNodes[0][1]).toHaveProperty('labelType', 'svg');
expect(addedNodes[0][1].label).toBeDefined();
expect(addedNodes[0][1].label).toBeDefined(); // <text> node
expect(addedNodes[0][1].label.firstChild.innerHTML).toEqual('Multi'); // <tspan> node, line 1
expect(addedNodes[0][1].label.lastChild.innerHTML).toEqual('Line'); // <tspan> node, line 2
});
});
}); });
[ [
@ -109,9 +146,11 @@ describe('the flowchart renderer', function() {
{ text: 'Multi<br>Line' }, { text: 'Multi<br>Line' },
{ text: 'Multi<br/>Line' }, { text: 'Multi<br/>Line' },
{ text: 'Multi<br />Line' }, { text: 'Multi<br />Line' },
{ text: 'Multi<br\t/>Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br>Line' }, { style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br>Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br/>Line' }, { style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br/>Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br />Line' } { style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br />Line' },
{ style: ['stroke:DarkGray', 'stroke-width:2px'], text: 'Multi<br\t/>Line' }
], ],
mockG, mockG,
'svg-id' 'svg-id'

View File

@ -280,7 +280,7 @@ const drawForkJoinState = (g, stateDef) => {
export const drawText = function(elem, textData) { export const drawText = function(elem, textData) {
// Remove and ignore br:s // Remove and ignore br:s
const nText = textData.text.replace(/<br\/?>/gi, ' '); const nText = textData.text.replace(/<br\s*\/?>/gi, ' ');
const textElem = elem.append('text'); const textElem = elem.append('text');
textElem.attr('x', textData.x); textElem.attr('x', textData.x);
@ -308,7 +308,7 @@ const _drawLongText = (_text, x, y, g) => {
let text = _text.replace(/\r\n/g, '<br/>'); let text = _text.replace(/\r\n/g, '<br/>');
text = text.replace(/\n/g, '<br/>'); text = text.replace(/\n/g, '<br/>');
const lines = text.split(/<br\/?>/gi); const lines = text.split(/<br\s*\/?>/gi);
let tHeight = 1.25 * getConfig().state.noteMargin; let tHeight = 1.25 * getConfig().state.noteMargin;
for (const line of lines) { for (const line of lines) {
@ -392,7 +392,7 @@ export const drawState = function(elem, stateDef) {
}; };
const getRows = s => { const getRows = s => {
let str = s.replace(/<br\/?>/gi, '#br#'); let str = s.replace(/<br\s*\/?>/gi, '#br#');
str = str.replace(/\\n/g, '#br#'); str = str.replace(/\\n/g, '#br#');
return str.split('#br#'); return str.split('#br#');
}; };

View File

@ -261,6 +261,16 @@ describe('state diagram, ', function() {
parser.parse(str); parser.parse(str);
}); });
it('should handle multiline notes with different line breaks', function() {
const str = `stateDiagram
State1
note right of State1
Line1<br>Line2<br/>Line3<br />Line4<br />Line5
end note
`;
parser.parse(str);
});
it('should handle floating notes', function() { it('should handle floating notes', function() {
const str = `stateDiagram const str = `stateDiagram
foo: bar foo: bar

View File

@ -102,7 +102,7 @@ const getLabelWidth = text => {
/* TODO: REMOVE DUPLICATION, SEE SHAPES */ /* TODO: REMOVE DUPLICATION, SEE SHAPES */
const getRows = s => { const getRows = s => {
if (!s) return 1; if (!s) return 1;
let str = s.replace(/<br\/?>/gi, '#br#'); let str = s.replace(/<br\s*\/?>/gi, '#br#');
str = str.replace(/\\n/g, '#br#'); str = str.replace(/\\n/g, '#br#');
return str.split('#br#'); return str.split('#br#');
}; };

View File

@ -98,7 +98,7 @@ const init = function() {
txt = he txt = he
.decode(txt) .decode(txt)
.trim() .trim()
.replace(/<br>/gi, '<br/>'); .replace(/<br\s*\/?>/gi, '<br/>');
mermaidAPI.render( mermaidAPI.render(
id, id,

View File

@ -84,8 +84,7 @@ export const sanitize = (text, config) => {
htmlLabels = false; htmlLabels = false;
if (config.securityLevel !== 'loose' && htmlLabels) { // eslint-disable-line if (config.securityLevel !== 'loose' && htmlLabels) { // eslint-disable-line
txt = txt.replace(/<br>/g, '#br#'); txt = txt.replace(/<br\s*\/?>/gi, '#br#');
txt = txt.replace(/<br\S*?\/>/g, '#br#');
txt = txt.replace(/</g, '&lt;').replace(/>/g, '&gt;'); txt = txt.replace(/</g, '&lt;').replace(/>/g, '&gt;');
txt = txt.replace(/=/g, '&equals;'); txt = txt.replace(/=/g, '&equals;');
txt = txt.replace(/#br#/g, '<br/>'); txt = txt.replace(/#br#/g, '<br/>');