mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-23 17:29:54 +02:00
#4220 Handling paragraphs and html labels with classes in mindmaps.
This commit is contained in:
@@ -66,21 +66,24 @@ h --3i -->a
|
||||
b --> d(The dog in the hog)
|
||||
c --> d
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid">
|
||||
<pre id="diagram" class="mermaid2">
|
||||
mindmap
|
||||
id1["`Start`"]
|
||||
id1["`**Start2**
|
||||
second line 😎 with long text that is wrapping to the next line`"]
|
||||
id2["`Child **with bold** text`"]
|
||||
id3["`Children of which some
|
||||
is using *italic type of* text`"]
|
||||
id4[Child]
|
||||
id5["`Child
|
||||
Row
|
||||
and another
|
||||
`"]
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram" class="mermaid">
|
||||
mindmap
|
||||
id1["`Start
|
||||
second line 😎`"]
|
||||
id2[Child]
|
||||
id3[Child]
|
||||
id4[Child]
|
||||
id1["`**Start** with
|
||||
|
||||
a second line 😎`"]
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
|
@@ -70,5 +70,12 @@ const getStyles = (options) =>
|
||||
.edge {
|
||||
fill: none;
|
||||
}
|
||||
.mindmap-node-label {
|
||||
dy: 1em;
|
||||
alignment-baseline: middle;
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
text-align: center;
|
||||
}
|
||||
`;
|
||||
export default getStyles;
|
||||
|
@@ -204,7 +204,7 @@ const roundedRectBkg = function (elem, node) {
|
||||
* @returns {number} The height nodes dom element
|
||||
*/
|
||||
export const drawNode = function (elem, node, fullSection, conf) {
|
||||
const htmlLabels = false;
|
||||
const htmlLabels = conf.htmlLabels;
|
||||
const section = fullSection % (MAX_SECTIONS - 1);
|
||||
const nodeElem = elem.append('g');
|
||||
node.section = section;
|
||||
@@ -217,19 +217,12 @@ export const drawNode = function (elem, node, fullSection, conf) {
|
||||
|
||||
// Create the wrapped text element
|
||||
const textElem = nodeElem.append('g');
|
||||
const newEl = createText(textElem, node.descr, { useHtmlLabels: htmlLabels, width: node.width });
|
||||
// const txt = textElem.node().appendChild(newEl);
|
||||
// const txt = textElem.append(newEl);
|
||||
// const txt = textElem
|
||||
// .append('text')
|
||||
// .text(node.descr)
|
||||
// .attr('dy', '1em')
|
||||
// .attr('alignment-baseline', 'middle')
|
||||
// .attr('dominant-baseline', 'middle')
|
||||
// .attr('text-anchor', 'middle')
|
||||
// .call(wrap, node.width);
|
||||
// const newerEl = textElem.node().appendChild(newEl);
|
||||
// setSize(textElem);
|
||||
const newEl = createText(textElem, node.descr, {
|
||||
useHtmlLabels: htmlLabels,
|
||||
width: node.width,
|
||||
classes: 'mindmap-node-label',
|
||||
});
|
||||
|
||||
if (!htmlLabels) {
|
||||
textElem
|
||||
.attr('dy', '1em')
|
||||
|
@@ -17,19 +17,22 @@ function applyStyle(dom, styleFn) {
|
||||
/**
|
||||
* @param element
|
||||
* @param {any} node
|
||||
* @param width
|
||||
* @param classes
|
||||
* @returns {SVGForeignObjectElement} Node
|
||||
*/
|
||||
function addHtmlSpan(element, node) {
|
||||
function addHtmlSpan(element, node, width, classes) {
|
||||
const fo = element.append('foreignObject');
|
||||
const newEl = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
|
||||
// const newEl = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
|
||||
// const newEl = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
|
||||
const div = fo.append('xhtml:div');
|
||||
// const div = body.append('div');
|
||||
// const div = fo.append('div');
|
||||
|
||||
const label = node.label;
|
||||
const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
|
||||
div.html(
|
||||
'<span class="' +
|
||||
labelClass +
|
||||
'" ' +
|
||||
`<span class="${labelClass} ${classes}" ` +
|
||||
(node.labelStyle ? 'style="' + node.labelStyle + '"' : '') +
|
||||
'>' +
|
||||
label +
|
||||
@@ -37,16 +40,22 @@ function addHtmlSpan(element, node) {
|
||||
);
|
||||
|
||||
applyStyle(div, node.labelStyle);
|
||||
div.style('display', 'inline-block');
|
||||
const bbox = div.node().getBoundingClientRect();
|
||||
div.style('display', 'table-cell');
|
||||
div.style('white-space', 'nowrap');
|
||||
div.style('max-width', width + 'px');
|
||||
div.attr('xmlns', 'http://www.w3.org/1999/xhtml');
|
||||
|
||||
let bbox = div.node().getBoundingClientRect();
|
||||
if (bbox.width === width) {
|
||||
div.style('display', 'table');
|
||||
div.style('white-space', 'break-spaces');
|
||||
div.style('width', '200px');
|
||||
bbox = div.node().getBoundingClientRect();
|
||||
}
|
||||
|
||||
fo.style('width', bbox.width);
|
||||
fo.style('height', bbox.height);
|
||||
|
||||
const divNode = div.node();
|
||||
window.divNode = divNode;
|
||||
// Fix for firefox
|
||||
div.style('white-space', 'nowrap');
|
||||
div.attr('xmlns', 'http://www.w3.org/1999/xhtml');
|
||||
return fo.node();
|
||||
}
|
||||
|
||||
@@ -158,7 +167,7 @@ export const createText = (
|
||||
),
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
};
|
||||
let vertexNode = addHtmlSpan(el, node);
|
||||
let vertexNode = addHtmlSpan(el, node, width, classes);
|
||||
return vertexNode;
|
||||
} else {
|
||||
const structuredText = markdownToLines(text);
|
||||
|
@@ -1,12 +1,25 @@
|
||||
import SimpleMarkdown from '@khanacademy/simple-markdown';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param markdown
|
||||
*/
|
||||
function preprocessMarkdown(markdown) {
|
||||
// Replace multiple newlines with a single newline
|
||||
const withoutMultipleNewlines = markdown.replace(/\n{2,}/g, '\n');
|
||||
// Remove extra spaces at the beginning of each line
|
||||
const withoutExtraSpaces = withoutMultipleNewlines.replace(/^\s+/gm, '');
|
||||
return withoutExtraSpaces;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param markdown
|
||||
*/
|
||||
export function markdownToLines(markdown) {
|
||||
const preprocessedMarkdown = preprocessMarkdown(markdown);
|
||||
const mdParse = SimpleMarkdown.defaultBlockParse;
|
||||
const syntaxTree = mdParse(markdown);
|
||||
const syntaxTree = mdParse(preprocessedMarkdown);
|
||||
|
||||
let lines = [[]];
|
||||
let currentLine = 0;
|
||||
@@ -19,6 +32,7 @@ export function markdownToLines(markdown) {
|
||||
function processNode(node, parentType) {
|
||||
if (node.type === 'text') {
|
||||
const textLines = node.content.split('\n');
|
||||
|
||||
textLines.forEach((textLine, index) => {
|
||||
if (index !== 0) {
|
||||
currentLine++;
|
||||
@@ -62,7 +76,7 @@ export function markdownToHTML(markdown) {
|
||||
*/
|
||||
function output(node) {
|
||||
if (node.type === 'text') {
|
||||
return node.content.replace(/\n/g, '<br>');
|
||||
return node.content.replace(/\n/g, '<br/>');
|
||||
} else if (node.type === 'strong') {
|
||||
return `<strong>${node.content.map(output).join('')}</strong>`;
|
||||
} else if (node.type === 'em') {
|
||||
|
@@ -95,6 +95,47 @@ test('markdownToLines - Only bold formatting', () => {
|
||||
expect(output).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
test('markdownToLines - paragraph 1', () => {
|
||||
const input = `**Start** with
|
||||
a second line`;
|
||||
|
||||
const expectedOutput = [
|
||||
[
|
||||
{ content: 'Start', type: 'strong' },
|
||||
{ content: 'with', type: 'normal' },
|
||||
],
|
||||
[
|
||||
{ content: 'a', type: 'normal' },
|
||||
{ content: 'second', type: 'normal' },
|
||||
{ content: 'line', type: 'normal' },
|
||||
],
|
||||
];
|
||||
|
||||
const output = markdownToLines(input);
|
||||
expect(output).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
test('markdownToLines - paragraph', () => {
|
||||
const input = `**Start** with
|
||||
|
||||
a second line`;
|
||||
|
||||
const expectedOutput = [
|
||||
[
|
||||
{ content: 'Start', type: 'strong' },
|
||||
{ content: 'with', type: 'normal' },
|
||||
],
|
||||
[
|
||||
{ content: 'a', type: 'normal' },
|
||||
{ content: 'second', type: 'normal' },
|
||||
{ content: 'line', type: 'normal' },
|
||||
],
|
||||
];
|
||||
|
||||
const output = markdownToLines(input);
|
||||
expect(output).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
test('markdownToLines - Only italic formatting', () => {
|
||||
const input = `This is an *italic* test`;
|
||||
|
||||
@@ -134,7 +175,7 @@ Here is a new line
|
||||
There is some words **with a bold** section
|
||||
Here is a line *with an italic* section`;
|
||||
|
||||
const expectedOutput = `<p>This is regular text<br>Here is a new line<br>There is some words <strong>with a bold</strong> section<br>Here is a line <em>with an italic</em> section</p>`;
|
||||
const expectedOutput = `<p>This is regular text<br/>Here is a new line<br/>There is some words <strong>with a bold</strong> section<br/>Here is a line <em>with an italic</em> section</p>`;
|
||||
|
||||
const output = markdownToHTML(input);
|
||||
expect(output).toEqual(expectedOutput);
|
||||
@@ -151,7 +192,7 @@ test('markdownToHTML - No formatting', () => {
|
||||
const input = `This is a simple test
|
||||
with no formatting`;
|
||||
|
||||
const expectedOutput = `<p>This is a simple test<br>with no formatting</p>`;
|
||||
const expectedOutput = `<p>This is a simple test<br/>with no formatting</p>`;
|
||||
const output = markdownToHTML(input);
|
||||
expect(output).toEqual(expectedOutput);
|
||||
});
|
||||
|
Reference in New Issue
Block a user