diff --git a/cypress/platform/click_security_loose.html b/cypress/platform/click_security_loose.html index dab82f983..8d7b7f244 100644 --- a/cypress/platform/click_security_loose.html +++ b/cypress/platform/click_security_loose.html @@ -5,6 +5,11 @@ Mermaid Quick Test Page +
@@ -16,7 +21,19 @@
graph TB - 1Function-->2URL + 1Function--->2URL + click 1Function clickByFlow "Add a div" + click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" +
+
+ flowchart TB + Function-->URL + click Function clickByFlow "Add a div" + click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs" +
+
+ flowchart TB + 1Function--->2URL click 1Function clickByFlow "Add a div" click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs"
diff --git a/src/dagre-wrapper/nodes.js b/src/dagre-wrapper/nodes.js index 086919241..485b56abf 100644 --- a/src/dagre-wrapper/nodes.js +++ b/src/dagre-wrapper/nodes.js @@ -552,19 +552,11 @@ const class_box = (parent, node) => { classes = 'node ' + node.classes; } // Add outer g element - const shapeSvgG = parent + const shapeSvg = parent .insert('g') .attr('class', classes) .attr('id', node.domId || node.id); - // Add link - const shapeSvg = node.link - ? shapeSvgG - .append('svg:a') - .attr('xlink:href', node.link) - .attr('target', node.linkTarget || '_blank') - : shapeSvgG; - // Create the title label and insert it after the rect const rect = shapeSvg.insert('rect', ':first-child'); const topLine = shapeSvg.insert('line'); @@ -830,7 +822,26 @@ const shapes = { let nodeElems = {}; export const insertNode = (elem, node, dir) => { - nodeElems[node.id] = shapes[node.shape](elem, node, dir); + let newEl; + let el; + + // Add link when appropriate + if (node.link) { + newEl = elem + .insert('svg:a') + .attr('xlink:href', node.link) + .attr('target', node.linkTarget || '_blank'); + el = shapes[node.shape](newEl, node, dir); + } else { + el = shapes[node.shape](elem, node, dir); + newEl = el; + } + if (node.tooltip) { + el.attr('title', node.tooltip); + } + + nodeElems[node.id] = newEl; + if (node.haveCallback) { nodeElems[node.id].attr('class', nodeElems[node.id].attr('class') + ' clickable'); } diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js index 6be1f2c18..d70d56433 100644 --- a/src/diagrams/flowchart/flowDb.js +++ b/src/diagrams/flowchart/flowDb.js @@ -5,8 +5,8 @@ import common from '../common/common'; import mermaidAPI from '../../mermaidAPI'; // const MERMAID_DOM_ID_PREFIX = 'mermaid-dom-id-'; -const MERMAID_DOM_ID_PREFIX = ''; - +const MERMAID_DOM_ID_PREFIX = 'flowchart-'; +let vertexCounter = 0; let config = configApi.getConfig(); let vertices = {}; let edges = []; @@ -24,6 +24,20 @@ export const parseDirective = function(statement, context, type) { mermaidAPI.parseDirective(this, statement, context, type); }; +/** + * Function to lookup domId from id in the graph definition. + * @param id + * @public + */ +export const lookUpDomId = function(id) { + const veritceKeys = Object.keys(vertices); + for (let i = 0; i < veritceKeys.length; i++) { + if (vertices[veritceKeys[i]].id === id) { + return vertices[veritceKeys[i]].domId; + } + } +}; + /** * Function called by parser when a node definition has been found * @param id @@ -42,11 +56,17 @@ export const addVertex = function(_id, text, type, style, classes) { return; } - if (id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; + // if (id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; if (typeof vertices[id] === 'undefined') { - vertices[id] = { id: id, styles: [], classes: [] }; + vertices[id] = { + id: id, + domId: MERMAID_DOM_ID_PREFIX + id + '-' + vertexCounter, + styles: [], + classes: [] + }; } + vertexCounter++; if (typeof text !== 'undefined') { config = configApi.getConfig(); txt = common.sanitizeText(text.trim(), config); @@ -91,8 +111,8 @@ export const addVertex = function(_id, text, type, style, classes) { export const addSingleLink = function(_start, _end, type, linktext) { let start = _start; let end = _end; - if (start[0].match(/\d/)) start = MERMAID_DOM_ID_PREFIX + start; - if (end[0].match(/\d/)) end = MERMAID_DOM_ID_PREFIX + end; + // if (start[0].match(/\d/)) start = MERMAID_DOM_ID_PREFIX + start; + // if (end[0].match(/\d/)) end = MERMAID_DOM_ID_PREFIX + end; // logger.info('Got edge...', start, end); const edge = { start: start, end: end, type: undefined, text: '' }; @@ -203,7 +223,7 @@ export const setDirection = function(dir) { export const setClass = function(ids, className) { ids.split(',').forEach(function(_id) { let id = _id; - if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; + // if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; if (typeof vertices[id] !== 'undefined') { vertices[id].classes.push(className); } @@ -222,9 +242,9 @@ const setTooltip = function(ids, tooltip) { }); }; -const setClickFun = function(_id, functionName) { - let id = _id; - if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; +const setClickFun = function(id, functionName) { + let domId = lookUpDomId(id); + // if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; if (configApi.getConfig().securityLevel !== 'loose') { return; } @@ -232,8 +252,9 @@ const setClickFun = function(_id, functionName) { return; } if (typeof vertices[id] !== 'undefined') { + vertices[id].haveCallback = true; funs.push(function() { - const elem = document.querySelector(`[id="${id}"]`); + const elem = document.querySelector(`[id="${domId}"]`); if (elem !== null) { elem.addEventListener( 'click', @@ -254,9 +275,9 @@ const setClickFun = function(_id, functionName) { * @param tooltip Tooltip for the clickable element */ export const setLink = function(ids, linkStr, tooltip, target) { - ids.split(',').forEach(function(_id) { - let id = _id; - if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; + ids.split(',').forEach(function(id) { + // let domId = lookUpDomId(id); + // if (_id[0].match(/\d/)) id = MERMAID_DOM_ID_PREFIX + id; if (typeof vertices[id] !== 'undefined') { vertices[id].link = utils.formatUrl(linkStr, config); vertices[id].linkTarget = target; @@ -638,6 +659,7 @@ export default { parseDirective, defaultConfig: () => configApi.defaultConfig.flowchart, addVertex, + lookUpDomId, addLink, updateLinkInterpolate, updateLink, diff --git a/src/diagrams/flowchart/flowRenderer-v2.js b/src/diagrams/flowchart/flowRenderer-v2.js index e9548b5b5..a3b9472ab 100644 --- a/src/diagrams/flowchart/flowRenderer-v2.js +++ b/src/diagrams/flowchart/flowRenderer-v2.js @@ -144,7 +144,9 @@ export const addVertices = function(vert, g, svgId) { id: vertex.id, link: vertex.link, linkTarget: vertex.linkTarget, - domId: 'flow-' + vertex.id + '-' + cnt, + tooltip: flowDb.getTooltip(vertex.id) || '', + domId: flowDb.lookUpDomId(vertex.id), + haveCallback: vertex.haveCallback, width: vertex.type === 'group' ? 500 : undefined, type: vertex.type, padding: getConfig().flowchart.padding @@ -159,7 +161,7 @@ export const addVertices = function(vert, g, svgId) { class: classStr, style: styles.style, id: vertex.id, - domId: 'flow-' + vertex.id + '-' + cnt, + domId: flowDb.lookUpDomId(vertex.id), width: vertex.type === 'group' ? 500 : undefined, type: vertex.type, padding: getConfig().flowchart.padding @@ -411,11 +413,6 @@ export const draw = function(text, id) { // Run the renderer. This is what draws the final graph. const element = select('#' + id + ' g'); render(element, g, ['point', 'circle', 'cross'], 'flowchart', id); - // dagre.layout(g); - - element.selectAll('g.node').attr('title', function() { - return flowDb.getTooltip(this.id); - }); const padding = conf.diagramPadding; const svgBounds = svg.node().getBBox(); @@ -436,28 +433,6 @@ export const draw = function(text, id) { // Index nodes flowDb.indexNodes('subGraph' + i); - // // reposition labels - // for (i = 0; i < subGraphs.length; i++) { - // subG = subGraphs[i]; - - // if (subG.title !== 'undefined') { - // const clusterRects = document.querySelectorAll('#' + id + ' [id="' + subG.id + '"] rect'); - // const clusterEl = document.querySelectorAll('#' + id + ' [id="' + subG.id + '"]'); - - // const xPos = clusterRects[0].x.baseVal.value; - // const yPos = clusterRects[0].y.baseVal.value; - // const width = clusterRects[0].width.baseVal.value; - // const cluster = d3.select(clusterEl[0]); - // const te = cluster.select('.label'); - // te.attr('transform', `translate(${xPos + width / 2}, ${yPos + 14})`); - // te.attr('id', id + 'Text'); - - // for (let j = 0; j < subG.classes.length; j++) { - // clusterEl[0].classList.add(subG.classes[j]); - // } - // } - // } - // Add label rects for non html labels if (!conf.htmlLabels) { const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');