From ed40b6027a987a7454fef6767052a190ad3ae667 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Sat, 20 Mar 2021 17:18:25 +0100 Subject: [PATCH 01/12] Allow global and local configuration, and from & to native mermaid conversion --- drawio_desktop/src/mermaid-plugin.js | 211 +++++++- drawio_desktop/src/shapes/shapeMermaid.js | 602 ++++++++++++---------- 2 files changed, 542 insertions(+), 271 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index 7008318..d3581ff 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -1,4 +1,4 @@ -import "./shapes/shapeMermaid"; +import { mermaid_plugin_defaults, isObject, mergeDeep, diffDeep, mxShapeMermaid } from "./shapes/shapeMermaid"; import "./palettes/mermaid/paletteMermaid"; import mermaid from 'mermaid' @@ -14,6 +14,9 @@ var DialogMermaid = function (editorUi, shape) { var graph = editorUi.editor.graph; graph.getModel().beginUpdate(); graph.labelChanged(shape.state.cell,text); + // To replace valueChanged in mxShapeMermaid.prototype.paintVertexShape + shape.updateImage(); + shape.redraw(); graph.getModel().endUpdate(); editorUi.spinner.stop(); @@ -35,8 +38,11 @@ var DialogMermaid = function (editorUi, shape) {

       
-

- [ Syntax ] +

| + HTML | + + PNG | + Syntax |


@@ -119,6 +125,52 @@ var DialogMermaid = function (editorUi, shape) { textarea.addEventListener('input', handleInput, false); } + // Handle copy + + div.querySelector('#plugin_mermaid_button_png').onclick = async function() { + var clipboard = navigator.clipboard; + var svg = div.querySelector('#graph-div'); + + // https://stackoverflow.com/questions/60551658/saving-offscreencanvas-content-to-disk-as-png-in-electron + // https://stackoverflow.com/questions/32230894/convert-very-large-svg-to-png-using-canvas + var svg_xml = (new XMLSerializer()).serializeToString(svg); + var blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}); + var url = window.URL.createObjectURL(blob); + + var scale = 3; + var img = new Image(); + img.width = svg.getBBox().width * scale ; + img.height = svg.getBBox().height * scale ; + img.onload = () => { + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + canvas.width = svg.getBBox().width * scale; + canvas.height = svg.getBBox().height * scale; + context.drawImage(img, svg.getBBox().x * scale, svg.getBBox().y * scale, svg.getBBox().width * scale, svg.getBBox().height * scale); + window.URL.revokeObjectURL(url); + canvas.toBlob(function(imgBlob) { + clipboard.write( [ new ClipboardItem({[imgBlob.type]: imgBlob }) ] ); + }, 'image/png'); + } + img.src = url; + } + + /* + div.querySelector('#plugin_mermaid_button_svg').onclick = async function() { + var svg_xml = (new XMLSerializer()).serializeToString(div.querySelector('#graph-div')); + var svg_blob = new Blob([svg_xml], {type : 'image/svg+xml;charset=utf-8'}); + var clip_item = new ClipboardItem( {'image/svg+xml': svg_blob } ); + navigator.clipboard.write( [ clip_item ] ); + } + */ + + div.querySelector('#plugin_mermaid_button_html').onclick = async function() { + navigator.clipboard.write( [ new ClipboardItem( + { 'text/html' : new Blob([""], {type : 'text/html'}) }) ] + ); + } + var cancelBtn = mxUtils.button(mxResources.get('close'), function () { win.destroy(); }); @@ -147,23 +199,160 @@ var DialogMermaid = function (editorUi, shape) { }; Draw.loadPlugin(function (ui) { + + // Build mermaid settings : by least order + // - mermaid_plugin_defaults : this plugin defaults + // - EditorUi.defaultMermaidConfig : drawio defaults mermaid + // - Editor.config.defaultMermaidConfig : drawio config (from PreConfig and local configuration) + + let mermaid_settings = {}; + mermaid_settings = mergeDeep(mermaid_settings, mermaid_plugin_defaults); + mermaid_settings = mergeDeep(mermaid_settings, window.EditorUi.defaultMermaidConfig); + mermaid_settings = mergeDeep(mermaid_settings, window.Editor.config.defaultMermaidConfig); + + // Result is updated back in EditorUi.defaultMermaidConfig to have consistent settings with native mermaid + // Note that the result will not be consistent if the diagram is updated in native mermaid without the plugin, + // but no solution would be perfect until native mermaid allow some configuration... + // As mermaid version are not the same between native mermaid and the plugin one, render may be different. + window.EditorUi.defaultMermaidConfig = mermaid_settings; + + // Handle defaults + Object.assign(mermaid_plugin_defaults, mermaid_settings); + mxShapeMermaid.prototype.customProperties = mxShapeMermaid.prototype.buildCustomProperties(mermaid_settings); + // Adds custom sidebar entry ui.sidebar.addMermaidPalette(); - ui.editor.graph.addListener(mxEvent.DOUBLE_CLICK, function (sender, evt) { - var cell = evt.getProperty("cell"); + function isCellPluginMermaid(cell) { if (!cell) { - return; + return false; } if (cell.style.indexOf("shape=mxgraph.mermaid.abstract.mermaid") < 0) { - return; + return false; } + return true; + } + + function isCellNativeMermaid(cell) { + if (!cell) { return false; } + if (mxUtils.isNode(cell.value)) { + if (cell.getAttribute('mermaidData', '') != '') { + return true; + } + } + return false; + } - var shape = ui.editor.graph.view.states["map"][cell.mxObjectId].shape; + ui.editor.graph.addListener(mxEvent.DOUBLE_CLICK, function (sender, evt) { + var cell = evt.getProperty("cell"); + if (isCellPluginMermaid(cell)) { + var shape = ui.editor.graph.view.states["map"][cell.mxObjectId].shape; - if (shape) { - var dlg = new DialogMermaid(ui,shape); + if (shape) { + var dlg = new DialogMermaid(ui,shape); + } + evt.consume(); } - evt.consume(); }); + + // Add convert menus + mxResources.parse('mermaidconvertfrom=Convert to Mermaid plugin shape...'); + mxResources.parse('mermaidconvertto=Convert to native Mermaid shape...'); + + var uiCreatePopupMenu = ui.menus.createPopupMenu; + ui.menus.createPopupMenu = function(menu, cell, evt) + { + uiCreatePopupMenu.apply(this, arguments); + + var graph = ui.editor.graph; + var cell = graph.getSelectionCell(); + + if (isCellPluginMermaid(cell)) { + this.addMenuItems(menu, ['-', 'mermaidconvertto'], null, evt); + } + + if (isCellNativeMermaid(cell)) { + this.addMenuItems(menu, ['-', 'mermaidconvertfrom'], null, evt); + } + + }; + + ui.actions.addAction('mermaidconvertto', function() + { + let graph =ui.editor.graph ; + let cell = graph.getSelectionCell(); + if (!isCellPluginMermaid(cell)) return; + + graph.getModel().beginUpdate(); + try + { + let state = graph.view.getState(cell, true); + let mermaidData = JSON.stringify({data: graph.convertValueToString(cell), config: state.shape.getRenderOptions() /*getStyleOptions()*/}, null, 2) + state.shape.redraw(); + let image = state.shape.image.replace(";base64",""); // ;base64 breaks the style + graph.setCellStyle('shape=image;noLabel=1;verticalAlign=top;imageAspect=1;' + 'image=' + image + ';', [cell]); + graph.setAttributeForCell(cell, 'mermaidData', mermaidData ); + + graph.view.getState(cell, true).destroy(); + graph.view.getState(cell, true); + } + finally + { + graph.getModel().endUpdate(); + } + + }); + + + ui.actions.addAction('mermaidconvertfrom', function() + { + let graph = ui.editor.graph; + let cell = graph.getSelectionCell(); + if (!isCellNativeMermaid(cell)) return; + + var data = JSON.parse(cell.getAttribute('mermaidData', '')); + + graph.getModel().beginUpdate(); + try { + // Default style from paletteMermaid + let style = 'shadow=0;dashed=0;align=left;strokeWidth=1;shape=mxgraph.mermaid.abstract.mermaid;labelBackgroundColor=#ffffff;noLabel=1;'; + + function addToStyle(basestyle, value) { + if (isObject(value)) { + for(let key in value) { + addToStyle( (basestyle == '') ? key : basestyle + "_" + key , value[key] ); + } + } else { + style += encodeURI(basestyle) + "=" + encodeURI(value) + ";"; + } + } + + let configDiff = diffDeep(data.config, mermaid_plugin_defaults); + addToStyle('', configDiff); + + // cell.value = data.data; + graph.setAttributeForCell(cell, 'mermaidData', "" ); + graph.labelChanged(cell,data.data); + + + graph.setCellStyle(style, [cell]); + + graph.view.getState(cell, true).destroy(); + graph.view.getState(cell, true); + } + finally + { + graph.getModel().endUpdate(); + } + + }); + + + + + }); + + + + diff --git a/drawio_desktop/src/shapes/shapeMermaid.js b/drawio_desktop/src/shapes/shapeMermaid.js index 04b6d92..78671a3 100644 --- a/drawio_desktop/src/shapes/shapeMermaid.js +++ b/drawio_desktop/src/shapes/shapeMermaid.js @@ -1,9 +1,177 @@ import mermaid from 'mermaid' +export const mermaid_plugin_defaults_original = { + startOnLoad: false, + themeCSS: "", + theme: 'default', + arrowMarkerAbsolute: false, + flowchart: { + diagramPadding: 8, + htmlLabels: true, + nodeSpacing: 50, + rankSpacing: 50, + curve: 'linear', + padding: 15, + useMaxWidth: true + }, + sequence: { + activationWidth: 10, + diagramMarginX: 50, + diagramMarginY: 10, + actorMargin: 50, + width: 150, + height: 65, + boxMargin: 10, + boxTextMargin: 5, + noteMargin: 10, + messageMargin: 35, + messageAlign: 'center', + mirrorActors: true, + bottomMarginAdj: 1, + useMaxWidth: true, + rightAngles: false, + showSequenceNumbers: false, + actorFontSize: 14, + actorFontFamily: '"Open-Sans", "sans-serif"', + actorFontWeight: 400, + noteFontSize: 14, + noteFontFamily: '"trebuchet ms", verdana, arial', + noteFontWeight: 400, + noteAlign: 'center', + messageFontSize: 16, + messageFontFamily: '"trebuchet ms", verdana, arial', + messageFontWeight: 400, + wrap: false, + wrapPadding: 10, + labelBoxWidth: 50, + labelBoxHeight: 20, + }, + gantt: { + titleTopMargin: 25, + barHeight: 20, + barGap: 4, + topPadding: 50, + leftPadding: 75, + gridLineStartPadding: 35, + fontSize: 11, + fontFamily: '"Open-Sans", "sans-serif"', + numberSectionStyles: 4, + axisFormat: "%Y-%m-%d", + useMaxWidth: true, + }, + journey: { + diagramMarginX: 50, + diagramMarginY: 10, + actorMargin: 50, + width: 150, + height: 65, + boxMargin: 10, + boxTextMargin: 5, + noteMargin: 10, + messageMargin: 35, + messageAlign: 'center', + bottomMarginAdj: 1, + useMaxWidth: true, + rightAngles: false, + }, + class: { + arrowMarkerAbsolute: false, + useMaxWidth: true, + }, + git: { + arrowMarkerAbsolute: false, + useMaxWidth: true, + }, + state: { + dividerMargin: 10, + sizeUnit: 5, + padding: 8, + textHeight: 10, + titleShift: -15, + noteMargin: 10, + forkWidth: 70, + forkHeight: 7, + miniPadding: 2, + fontSizeFactor: 5.02, + fontSize: 24, + labelHeight: 16, + edgeLengthFactor: '20', + compositTitleSize: 35, + radius: 5, + }, + er: { + diagramPadding: 20, + layoutDirection: 'TB', + minEntityWidth: 100, + minEntityHeight: 75, + entityPadding: 15, + stroke: 'grey', + fill: 'honeydew', + fontSize: 12, + useMaxWidth: true, + + }, + pie: { + useMaxWidth: true, + } +}; + +// From https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge/34749873#34749873 +export function isObject(item) { + return (item && typeof item === 'object' && !Array.isArray(item)); + } + +export function mergeDeep(target, source) { + let output = Object.assign({}, target); + if (isObject(target) && isObject(source)) { + Object.keys(source).forEach(key => { + if (isObject(source[key])) { + if (!(key in target)) + Object.assign(output, { [key]: source[key] }); + else + output[key] = mergeDeep(target[key], source[key]); + } else { + Object.assign(output, { [key]: source[key] }); + } + }); + } + return output; + } +// --- + +// Adapted from https://stackoverflow.com/questions/8572826/generic-deep-diff-between-two-objects +export function diffDeep(target, source) { + let diff = Object.keys(target).reduce((diff, key) => { + // If object, deep + if (isObject(target[key]) && (key in source)) { + let diffkey = diffDeep(target[key], source[key]); + if (Object.keys(diffkey).length == 0) { + return diff + } else { + return { + ...diff, + [key]: diffkey + } + } + } + // If identical ignore + if ((key in source) && (target[key] === source[key])) return diff + // If different, add value to the result + return { + ...diff, + [key]: target[key] + } + }, {}) + return diff; +} +// --- + +export var mermaid_plugin_defaults = mergeDeep({}, mermaid_plugin_defaults_original); + /** * Extends mxShape. */ -function mxShapeMermaid(bounds, fill, stroke, strokewidth) { +export function mxShapeMermaid(bounds, fill, stroke, strokewidth) { mxShape.call(this); this.bounds = bounds; this.image = ''; @@ -13,6 +181,8 @@ function mxShapeMermaid(bounds, fill, stroke, strokewidth) { this.stroke = stroke; this.strokewidth = (strokewidth != null) ? strokewidth : 1; this.shadow = false; + + this.defaults = mermaid_plugin_defaults; }; /** * Extends mxShape. @@ -23,275 +193,186 @@ mxShapeMermaid.prototype.cst = { SHAPE_MERMAID: 'mxgraph.mermaid.abstract.mermaid' }; -mxShapeMermaid.prototype.customProperties = [ - // { name: 'theme_css', dispName: 'theme_css', type: 'string', defVal: "" }, - { - name: 'theme', dispName: 'theme', type: 'enum', defVal: 'default', - enumList: [ - { val: 'default', dispName: 'default' }, - { val: 'forest', dispName: 'forest' }, - { val: 'dark', dispName: 'dark' }, - { val: 'neutral', dispName: 'neutral' }, - { val: 'null', dispName: 'null' } - ] - }, - { name: 'arrowMarkerAbsolute', dispName: 'arrowMarkerAbsolute', type: 'bool', defVal: false }, - - { name: 'flowchart_diagramPadding', dispName: 'flowchart_diagramPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: 8 }, - { name: 'flowchart_htmlLabels', dispName: 'flowchart_htmlLabels', type: 'bool', defVal: true }, - { name: 'flowchart_nodeSpacing', dispName: 'flowchart_nodeSpacing', type: 'int', minVal: 1, maxVal: 1000, defVal: 50 }, - { name: 'flowchart_rankSpacing', dispName: 'flowchart_rankSpacing', type: 'int', minVal: 1, maxVal: 1000, defVal: 50 }, - { - name: 'flowchart_curve', dispName: 'flowchart_curve', type: 'enum', defVal: 'linear', - enumList: [ - { val: 'linear', dispName: 'linear' }, - { val: 'basis', dispName: 'basis' }, - { val: 'cardinal', dispName: 'cardinal' } - ] - }, - { name: 'flowchart_padding', dispName: 'flowchart_padding', type: 'int', minVal: 1, maxVal: 1000, defVal: 15 }, - { name: 'flowchart_useMaxWidth', dispName: 'flowchart_useMaxWidth', type: 'bool', defVal: true }, - - { name: 'sequence_activationWidth', dispName: 'sequence_activationWidth', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'sequence_diagramMarginX', dispName: 'sequence_diagramMarginX', type: 'int', min: 1, max: 1000, defVal: 50 }, - { name: 'sequence_diagramMarginY', dispName: 'sequence_diagramMarginY', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'sequence_actorMargin', dispName: 'sequence_actorMargin', type: 'int', min: 1, max: 1000, defVal: 50 }, - { name: 'sequence_width', dispName: 'sequence_width', type: 'int', min: 1, max: 1000, defVal: 150 }, - { name: 'sequence_height', dispName: 'sequence_height', type: 'int', min: 1, max: 1000, defVal: 65 }, - { name: 'sequence_boxMargin', dispName: 'sequence_boxMargin', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'sequence_boxTextMargin', dispName: 'sequence_boxTextMargin', type: 'int', min: 1, max: 1000, defVal: 5 }, - { name: 'sequence_noteMargin', dispName: 'sequence_noteMargin', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'sequence_messageMargin', dispName: 'sequence_messageMargin', type: 'int', min: 1, max: 1000, defVal: 35 }, - { - name: 'sequence_messageAlign', dispName: 'sequence_messageAlign', type: 'enum', defVal: 'center', - enumList: [ - { val: 'center', dispName: 'center' }, - { val: 'left', dispName: 'left' }, - { val: 'right', dispName: 'right' } - ] - }, - { name: 'sequence_mirrorActors', dispName: 'sequence_mirrorActors', type: 'bool', defVal: true }, - { name: 'sequence_bottomMarginAdj', dispName: 'sequence_bottomMarginAdj', type: 'int', min: 1, max: 1000, defVal: 1 }, - { name: 'sequence_useMaxWidth', dispName: 'sequence_useMaxWidth', type: 'bool', defVal: true }, - { name: 'sequence_rightAngles', dispName: 'sequence_rightAngles', type: 'bool', defVal: false }, - { name: 'sequence_showSequenceNumbers', dispName: 'sequence_showSequenceNumbers', type: 'bool', defVal: false }, - { name: 'sequence_actorFontSize', dispName: 'sequence_actorFontSize', type: 'int', min: 1, max: 1000, defVal: 14 }, - { name: 'sequence_actorFontFamily', dispName: 'sequence_actorFontFamily', type: 'string', defVal: '"Open-Sans", "sans-serif"' }, - { name: 'sequence_actorFontWeight', dispName: 'sequence_actorFontWeight', type: 'int', min: 1, max: 1000, defVal: 400 }, - { name: 'sequence_noteFontSize', dispName: 'sequence_noteFontSize', type: 'int', min: 1, max: 1000, defVal: 14 }, - { name: 'sequence_noteFontFamily', dispName: 'sequence_noteFontFamily', type: 'string', defVal: '"trebuchet ms", verdana, arial' }, - { name: 'sequence_noteFontWeight', dispName: 'sequence_noteFontWeight', type: 'int', min: 1, max: 1000, defVal: 400 }, - { - name: 'sequence_noteAlign', dispName: 'sequence_noteAlign', type: 'enum', defVal: 'center', - enumList: [ - { val: 'center', dispName: 'center' }, - { val: 'left', dispName: 'left' }, - { val: 'right', dispName: 'right' } - ] - }, - { name: 'sequence_messageFontSize', dispName: 'sequence_messageFontSize', type: 'int', min: 1, max: 1000, defVal: 16 }, - { name: 'sequence_messageFontFamily', dispName: 'sequence_messageFontFamily', type: 'string', defVal: '"trebuchet ms", verdana, arial' }, - { name: 'sequence_messageFontWeight', dispName: 'sequence_messageFontWeight', type: 'int', min: 1, max: 1000, defVal: 400 }, - { name: 'sequence_wrap', dispName: 'sequence_wrap', type: 'bool', defVal: false }, - { name: 'sequence_wrapPadding', dispName: 'sequence_wrapPadding', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'sequence_labelBoxWidth', dispName: 'sequence_labelBoxWidth', type: 'int', min: 1, max: 1000, defVal: 50 }, - { name: 'sequence_labelBoxHeight', dispName: 'sequence_labelBoxHeight', type: 'int', min: 1, max: 1000, defVal: 20 }, - - { name: 'gantt_titleTopMargin', dispName: 'gantt_titleTopMargin', type: 'int', min: 1, max: 1000, defVal: 25 }, - { name: 'gantt_barHeight', dispName: 'gantt_barHeight', type: 'int', min: 1, max: 1000, defVal: 20 }, - { name: 'gantt_barGap', dispName: 'gantt_barGap', type: 'int', min: 1, max: 1000, defVal: 4 }, - { name: 'gantt_topPadding', dispName: 'gantt_topPadding', type: 'int', min: 1, max: 1000, defVal: 50 }, - { name: 'gantt_leftPadding', dispName: 'gantt_leftPadding', type: 'int', min: 1, max: 1000, defVal: 75 }, - { name: 'gantt_gridLineStartPadding', dispName: 'gantt_gridLineStartPadding', type: 'int', min: 1, max: 1000, defVal: 35 }, - { name: 'gantt_fontSize', dispName: 'gantt_fontSize', type: 'int', min: 1, max: 1000, defVal: 11 }, - { name: 'gantt_fontFamily', dispName: 'gantt_fontFamily', type: 'string', defVal: '"Open-Sans", "sans-serif"' }, - { name: 'gantt_numberSectionStyles', dispName: 'gantt_numberSectionStyles', type: 'int', min: 1, max: 1000, defVal: 4 }, - { name: 'gantt_axisFormat', dispName: 'gantt_axisFormat', type: 'string', defVal: "%Y-%m-%d" }, - { name: 'gantt_useMaxWidth', dispName: 'gantt_useMaxWidth', type: 'bool', defVal: true }, - - { name: 'journey_diagramMarginX', dispName: 'journey_diagramMarginX', type: 'int', min: 1, max: 1000, defVal: 50 }, - { name: 'journey_diagramMarginY', dispName: 'journey_diagramMarginY', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'journey_actorMargin', dispName: 'journey_actorMargin', type: 'int', min: 1, max: 1000, defVal: 50 }, - { name: 'journey_width', dispName: 'journey_width', type: 'int', min: 1, max: 1000, defVal: 150 }, - { name: 'journey_height', dispName: 'journey_height', type: 'int', min: 1, max: 1000, defVal: 65 }, - { name: 'journey_boxMargin', dispName: 'journey_boxMargin', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'journey_boxTextMargin', dispName: 'journey_boxTextMargin', type: 'int', min: 1, max: 1000, defVal: 5 }, - { name: 'journey_noteMargin', dispName: 'journey_noteMargin', type: 'int', min: 1, max: 1000, defVal: 10 }, - { name: 'journey_messageMargin', dispName: 'journey_messageMargin', type: 'int', min: 1, max: 1000, defVal: 35 }, - { - name: 'journey_messageAlign', dispName: 'journey_messageAlign', type: 'enum', defVal: 'center', - enumList: [ - { val: 'center', dispName: 'center' }, - { val: 'left', dispName: 'left' }, - { val: 'right', dispName: 'right' } - ] - }, - { name: 'journey_bottomMarginAdj', dispName: 'journey_bottomMarginAdj', type: 'int', minVal: 1, maxVal: 1000, defVal: 1 }, - { name: 'journey_useMaxWidth', dispName: 'journey_useMaxWidth', type: 'bool', defVal: true }, - { name: 'journey_rightAngles', dispName: 'journey_rightAngles', type: 'bool', defVal: false }, - - { name: 'class_arrowMarkerAbsolute', dispName: 'class_arrowMarkerAbsolute', type: 'boolean', defVal: false }, - { name: 'class_useMaxWidth', dispName: 'class_useMaxWidth', type: 'boolean', defVal: true }, - - { name: 'git_arrowMarkerAbsolute', dispName: 'git_arrowMarkerAbsolute', type: 'boolean', defVal: false }, - { name: 'git_useMaxWidth', dispName: 'git_useMaxWidth', type: 'boolean', defVal: true }, - - { name: 'state_dividerMargin', dispName: 'state_dividerMargin', type: 'int', minVal: 1, maxVal: 1000, defVal: 10 }, - { name: 'state_sizeUnit', dispName: 'state_sizeUnit', type: 'int', minVal: 1, maxVal: 1000, defVal: 5 }, - { name: 'state_padding', dispName: 'state_padding', type: 'int', minVal: 1, maxVal: 1000, defVal: 8 }, - { name: 'state_textHeight', dispName: 'state_textHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: 10 }, - { name: 'state_titleShift', dispName: 'state_titleShift', type: 'int', minVal: -1000, maxVal: 1000, defVal: -15 }, - { name: 'state_noteMargin', dispName: 'state_noteMargin', type: 'int', minVal: 1, maxVal: 1000, defVal: 10 }, - { name: 'state_forkWidth', dispName: 'state_forkWidth', type: 'int', minVal: 1, maxVal: 1000, defVal: 70 }, - { name: 'state_forkHeight', dispName: 'state_forkHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: 7 }, - { name: 'state_miniPadding', dispName: 'state_miniPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: 2 }, - { name: 'state_fontSizeFactor', dispName: 'state_fontSizeFactor', type: 'float', minVal: 1, maxVal: 1000, defVal: 5.02 }, - { name: 'state_fontSize', dispName: 'state_fontSize', type: 'int', minVal: 1, maxVal: 1000, defVal: 24 }, - { name: 'state_labelHeight', dispName: 'state_labelHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: 16 }, - { name: 'state_edgeLengthFactor', dispName: 'state_edgeLengthFactor', type: 'string', defVal: '20' }, - { name: 'state_compositTitleSize', dispName: 'state_compositTitleSize', type: 'int', minVal: 1, maxVal: 1000, defVal: 35 }, - { name: 'state_radius', dispName: 'state_radius', type: 'int', minVal: 1, maxVal: 1000, defVal: 5 }, - - { name: 'er_diagramPadding', dispName: 'er_diagramPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: 20 }, - { - name: 'er_layoutDirection', dispName: 'er_layoutDirection', type: 'enum', defVal: 'TB', - enumList: [ - { val: 'TB', dispName: 'top to bottom' }, - { val: 'BT', dispName: 'bottom to top' }, - { val: 'RL', dispName: 'right to left' }, - { val: 'LR', dispName: 'left to right' } - ] - }, - { name: 'er_minEntityWidth', dispName: 'er_minEntityWidth', type: 'int', minVal: 1, maxVal: 1000, defVal: 100 }, - { name: 'er_minEntityHeight', dispName: 'er_minEntityHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: 75 }, - { name: 'er_entityPadding', dispName: 'er_entityPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: 15 }, - { name: 'er_stroke', dispName: 'er_stroke', type: 'string', defVal: 'gray' }, - { name: 'er_fill', dispName: 'er_fill', type: 'string', defVal: 'honeydew' }, - { name: 'er_fontSize', dispName: 'er_fontSize', type: 'int', minVal: 1, maxVal: 1000, defVal: 12 }, - { name: 'er_useMaxWidth', dispName: 'er_useMaxWidth', type: 'bool', defVal: true }, - - { name: 'pie_useMaxWidth', dispName: 'pie_useMaxWidth', type: 'bool', defVal: true }, -]; - -mxShapeMermaid.prototype.getRenderOptions = function () { - var config = { - startOnLoad: false, - themeCSS: mxUtils.getValue(this.style, 'theme_css', ""), - theme: mxUtils.getValue(this.style, 'theme', 'default'), - arrowMarkerAbsolute: mxUtils.getValue(this.style, 'arrowMarkerAbsolute', false), - flowchart: { - diagramPadding: mxUtils.getValue(this.style, 'flowchart_diagramPadding', 8), - htmlLabels: mxUtils.getValue(this.style, 'flowchart_htmlLabels', true), - nodeSpacing: mxUtils.getValue(this.style, 'flowchart_nodeSpacing', 50), - rankSpacing: mxUtils.getValue(this.style, 'flowchart_rankSpacing', 50), - curve: mxUtils.getValue(this.style, 'flowchart_curve', 'linear'), - padding: mxUtils.getValue(this.style, 'flowchart_padding', 15), - useMaxWidth: mxUtils.getValue(this.style, 'flowchart_useMaxWidth', true) +mxShapeMermaid.prototype.buildCustomProperties = function (defaults) { + return [ + // { name: 'theme_css', dispName: 'theme_css', type: 'string', defVal: "" }, + { + name: 'theme', dispName: 'theme', type: 'enum', defVal: defaults.theme, + enumList: [ + { val: 'default', dispName: 'default' }, + { val: 'forest', dispName: 'forest' }, + { val: 'dark', dispName: 'dark' }, + { val: 'neutral', dispName: 'neutral' }, + { val: 'null', dispName: 'null' } + ] }, - sequence: { - activationWidth: mxUtils.getValue(this.style, 'sequence_activationWidth', 10), - diagramMarginX: mxUtils.getValue(this.style, 'sequence_diagramMarginX', 50), - diagramMarginY: mxUtils.getValue(this.style, 'sequence_diagramMarginY', 10), - actorMargin: mxUtils.getValue(this.style, 'sequence_actorMargin', 50), - width: mxUtils.getValue(this.style, 'sequence_width', 150), - height: mxUtils.getValue(this.style, 'sequence_height', 65), - boxMargin: mxUtils.getValue(this.style, 'sequence_boxMargin', 10), - boxTextMargin: mxUtils.getValue(this.style, 'sequence_boxTextMargin', 5), - noteMargin: mxUtils.getValue(this.style, 'sequence_noteMargin', 10), - messageMargin: mxUtils.getValue(this.style, 'sequence_messageMargin', 35), - messageAlign: mxUtils.getValue(this.style, 'sequence_messageAlign', 'center'), - mirrorActors: mxUtils.getValue(this.style, 'sequence_mirrorActors', true), - bottomMarginAdj: mxUtils.getValue(this.style, 'sequence_bottomMarginAdj', 1), - useMaxWidth: mxUtils.getValue(this.style, 'sequence_useMaxWidth', true), - rightAngles: mxUtils.getValue(this.style, 'sequence_rightAngles', false), - showSequenceNumbers: mxUtils.getValue(this.style, 'sequence_showSequenceNumbers', false), - actorFontSize: mxUtils.getValue(this.style, 'sequence_actorFontSize', 14), - actorFontFamily: mxUtils.getValue(this.style, 'sequence_actorFontFamily', '"Open-Sans", "sans-serif"'), - actorFontWeight: mxUtils.getValue(this.style, 'sequence_actorFontWeight', 400), - noteFontSize: mxUtils.getValue(this.style, 'sequence_noteFontSize', 14), - noteFontFamily: mxUtils.getValue(this.style, 'sequence_noteFontFamily', '"trebuchet ms", verdana, arial'), - noteFontWeight: mxUtils.getValue(this.style, 'sequence_noteFontWeight', 400), - noteAlign: mxUtils.getValue(this.style, 'sequence_noteAlign', 'center'), - messageFontSize: mxUtils.getValue(this.style, 'sequence_messageFontSize', 16), - messageFontFamily: mxUtils.getValue(this.style, 'sequence_messageFontFamily', '"trebuchet ms", verdana, arial'), - messageFontWeight: mxUtils.getValue(this.style, 'sequence_messageFontWeight', 400), - wrap: mxUtils.getValue(this.style, 'sequence_wrap', false), - wrapPadding: mxUtils.getValue(this.style, 'sequence_wrapPadding', 10), - labelBoxWidth: mxUtils.getValue(this.style, 'sequence_labelBoxWidth', 50), - labelBoxHeight: mxUtils.getValue(this.style, 'sequence_labelBoxHeight', 20), + { name: 'arrowMarkerAbsolute', dispName: 'arrowMarkerAbsolute', type: 'bool', defVal: defaults.arrowMarkerAbsolute }, + + { name: 'flowchart_diagramPadding', dispName: 'flowchart_diagramPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.flowchart.diagramPadding }, + { name: 'flowchart_htmlLabels', dispName: 'flowchart_htmlLabels', type: 'bool', defVal: defaults.flowchart.htmlLabels }, + { name: 'flowchart_nodeSpacing', dispName: 'flowchart_nodeSpacing', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.flowchart.nodeSpacing }, + { name: 'flowchart_rankSpacing', dispName: 'flowchart_rankSpacing', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.flowchart.rankSpacing }, + { + name: 'flowchart_curve', dispName: 'flowchart_curve', type: 'enum', defVal: defaults.flowchart.curve, + enumList: [ + { val: 'linear', dispName: 'linear' }, + { val: 'basis', dispName: 'basis' }, + { val: 'cardinal', dispName: 'cardinal' } + ] }, - gantt: { - titleTopMargin: mxUtils.getValue(this.style, 'gantt_titleTopMargin', 25), - barHeight: mxUtils.getValue(this.style, 'gantt_barHeight', 20), - barGap: mxUtils.getValue(this.style, 'gantt_barGap', 4), - topPadding: mxUtils.getValue(this.style, 'gantt_topPadding', 50), - leftPadding: mxUtils.getValue(this.style, 'gantt_leftPadding', 75), - gridLineStartPadding: mxUtils.getValue(this.style, 'gantt_gridLineStartPadding', 35), - fontSize: mxUtils.getValue(this.style, 'gantt_fontSize', 11), - fontFamily: mxUtils.getValue(this.style, 'gantt_fontFamily', '"Open-Sans", "sans-serif"'), - numberSectionStyles: mxUtils.getValue(this.style, 'gantt_numberSectionStyles', 4), - axisFormat: mxUtils.getValue(this.style, 'gantt_axisFormat', "%Y-%m-%d"), - useMaxWidth: mxUtils.getValue(this.style, 'gantt_useMaxWidth', true), + { name: 'flowchart_padding', dispName: 'flowchart_padding', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.flowchart.padding }, + { name: 'flowchart_useMaxWidth', dispName: 'flowchart_useMaxWidth', type: 'bool', defVal: defaults.flowchart.useMaxWidth }, + + { name: 'sequence_activationWidth', dispName: 'sequence_activationWidth', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.activationWidth }, + { name: 'sequence_diagramMarginX', dispName: 'sequence_diagramMarginX', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.diagramMarginX }, + { name: 'sequence_diagramMarginY', dispName: 'sequence_diagramMarginY', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.diagramMarginY }, + { name: 'sequence_actorMargin', dispName: 'sequence_actorMargin', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.actorMargin }, + { name: 'sequence_width', dispName: 'sequence_width', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.width }, + { name: 'sequence_height', dispName: 'sequence_height', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.height }, + { name: 'sequence_boxMargin', dispName: 'sequence_boxMargin', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.boxMargin }, + { name: 'sequence_boxTextMargin', dispName: 'sequence_boxTextMargin', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.boxTextMargin }, + { name: 'sequence_noteMargin', dispName: 'sequence_noteMargin', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.noteMargin }, + { name: 'sequence_messageMargin', dispName: 'sequence_messageMargin', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.messageMargin }, + { + name: 'sequence_messageAlign', dispName: 'sequence_messageAlign', type: 'enum', defVal: defaults.sequence.messageAlign, + enumList: [ + { val: 'center', dispName: 'center' }, + { val: 'left', dispName: 'left' }, + { val: 'right', dispName: 'right' } + ] }, - journey: { - diagramMarginX: mxUtils.getValue(this.style, 'journey_diagramMarginX', 50), - diagramMarginY: mxUtils.getValue(this.style, 'journey_diagramMarginY', 10), - actorMargin: mxUtils.getValue(this.style, 'journey_actorMargin', 50), - width: mxUtils.getValue(this.style, 'journey_width', 150), - height: mxUtils.getValue(this.style, 'journey_height', 65), - boxMargin: mxUtils.getValue(this.style, 'journey_boxMargin', 10), - boxTextMargin: mxUtils.getValue(this.style, 'journey_boxTextMargin', 5), - noteMargin: mxUtils.getValue(this.style, 'journey_noteMargin', 10), - messageMargin: mxUtils.getValue(this.style, 'journey_messageMargin', 35), - messageAlign: mxUtils.getValue(this.style, 'journey_messageAlign', 'center'), - bottomMarginAdj: mxUtils.getValue(this.style, 'journey_bottomMarginAdj', 1), - useMaxWidth: mxUtils.getValue(this.style, 'journey_useMaxWidth', true), - rightAngles: mxUtils.getValue(this.style, 'journey_rightAngles', false), + { name: 'sequence_mirrorActors', dispName: 'sequence_mirrorActors', type: 'bool', defVal: defaults.sequence.mirrorActors }, + { name: 'sequence_bottomMarginAdj', dispName: 'sequence_bottomMarginAdj', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.bottomMarginAdj }, + { name: 'sequence_useMaxWidth', dispName: 'sequence_useMaxWidth', type: 'bool', defVal: defaults.sequence.useMaxWidth }, + { name: 'sequence_rightAngles', dispName: 'sequence_rightAngles', type: 'bool', defVal: defaults.sequence.rightAngles }, + { name: 'sequence_showSequenceNumbers', dispName: 'sequence_showSequenceNumbers', type: 'bool', defVal: defaults.sequence.showSequenceNumbers }, + { name: 'sequence_actorFontSize', dispName: 'sequence_actorFontSize', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.actorFontSize }, + { name: 'sequence_actorFontFamily', dispName: 'sequence_actorFontFamily', type: 'string', defVal: defaults.sequence.actorFontFamily }, + { name: 'sequence_actorFontWeight', dispName: 'sequence_actorFontWeight', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.actorFontWeight }, + { name: 'sequence_noteFontSize', dispName: 'sequence_noteFontSize', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.actorFontSize }, + { name: 'sequence_noteFontFamily', dispName: 'sequence_noteFontFamily', type: 'string', defVal: defaults.sequence.noteFontFamily }, + { name: 'sequence_noteFontWeight', dispName: 'sequence_noteFontWeight', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.noteFontWeight }, + { + name: 'sequence_noteAlign', dispName: 'sequence_noteAlign', type: 'enum', defVal: defaults.sequence.noteAlign, + enumList: [ + { val: 'center', dispName: 'center' }, + { val: 'left', dispName: 'left' }, + { val: 'right', dispName: 'right' } + ] }, - class: { - arrowMarkerAbsolute: mxUtils.getValue(this.style, 'class_arrowMarkerAbsolute', false), - useMaxWidth: mxUtils.getValue(this.style, 'class_useMaxWidth', true), + { name: 'sequence_messageFontSize', dispName: 'sequence_messageFontSize', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.messageFontSize }, + { name: 'sequence_messageFontFamily', dispName: 'sequence_messageFontFamily', type: 'string', defVal: defaults.sequence.messageFontFamily }, + { name: 'sequence_messageFontWeight', dispName: 'sequence_messageFontWeight', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.messageFontWeight }, + { name: 'sequence_wrap', dispName: 'sequence_wrap', type: 'bool', defVal: defaults.sequence.wrap }, + { name: 'sequence_wrapPadding', dispName: 'sequence_wrapPadding', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.wrapPadding }, + { name: 'sequence_labelBoxWidth', dispName: 'sequence_labelBoxWidth', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.labelBoxWidth }, + { name: 'sequence_labelBoxHeight', dispName: 'sequence_labelBoxHeight', type: 'int', min: 1, max: 1000, defVal: defaults.sequence.labelBoxHeight }, + + { name: 'gantt_titleTopMargin', dispName: 'gantt_titleTopMargin', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.titleTopMargin }, + { name: 'gantt_barHeight', dispName: 'gantt_barHeight', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.barHeight }, + { name: 'gantt_barGap', dispName: 'gantt_barGap', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.barGap }, + { name: 'gantt_topPadding', dispName: 'gantt_topPadding', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.topPadding }, + { name: 'gantt_leftPadding', dispName: 'gantt_leftPadding', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.leftPadding }, + { name: 'gantt_gridLineStartPadding', dispName: 'gantt_gridLineStartPadding', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.gridLineStartPadding }, + { name: 'gantt_fontSize', dispName: 'gantt_fontSize', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.fontSize }, + { name: 'gantt_fontFamily', dispName: 'gantt_fontFamily', type: 'string', defVal: defaults.gantt.fontFamily }, + { name: 'gantt_numberSectionStyles', dispName: 'gantt_numberSectionStyles', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.numberSectionStyles }, + { name: 'gantt_axisFormat', dispName: 'gantt_axisFormat', type: 'string', defVal: defaults.gantt.axisFormat }, + { name: 'gantt_useMaxWidth', dispName: 'gantt_useMaxWidth', type: 'bool', defVal: defaults.gantt.useMaxWidth }, + + { name: 'journey_diagramMarginX', dispName: 'journey_diagramMarginX', type: 'int', min: 1, max: 1000, defVal: defaults.journey.diagramMarginX }, + { name: 'journey_diagramMarginY', dispName: 'journey_diagramMarginY', type: 'int', min: 1, max: 1000, defVal: defaults.journey.diagramMarginY }, + { name: 'journey_actorMargin', dispName: 'journey_actorMargin', type: 'int', min: 1, max: 1000, defVal: defaults.journey.actorMargin }, + { name: 'journey_width', dispName: 'journey_width', type: 'int', min: 1, max: 1000, defVal: defaults.journey.width }, + { name: 'journey_height', dispName: 'journey_height', type: 'int', min: 1, max: 1000, defVal: defaults.journey.height }, + { name: 'journey_boxMargin', dispName: 'journey_boxMargin', type: 'int', min: 1, max: 1000, defVal: defaults.journey.boxMargin }, + { name: 'journey_boxTextMargin', dispName: 'journey_boxTextMargin', type: 'int', min: 1, max: 1000, defVal: defaults.journey.boxTextMargin }, + { name: 'journey_noteMargin', dispName: 'journey_noteMargin', type: 'int', min: 1, max: 1000, defVal: defaults.journey.noteMargin }, + { name: 'journey_messageMargin', dispName: 'journey_messageMargin', type: 'int', min: 1, max: 1000, defVal: defaults.journey.messageMargin }, + { + name: 'journey_messageAlign', dispName: 'journey_messageAlign', type: 'enum', defVal: defaults.journey.messageAlign, + enumList: [ + { val: 'center', dispName: 'center' }, + { val: 'left', dispName: 'left' }, + { val: 'right', dispName: 'right' } + ] }, - git: { - arrowMarkerAbsolute: mxUtils.getValue(this.style, 'git_arrowMarkerAbsolute', false), - useMaxWidth: mxUtils.getValue(this.style, 'git_useMaxWidth', true), + { name: 'journey_bottomMarginAdj', dispName: 'journey_bottomMarginAdj', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.journey.bottomMarginAdj }, + { name: 'journey_useMaxWidth', dispName: 'journey_useMaxWidth', type: 'bool', defVal: defaults.journey.useMaxWidth }, + { name: 'journey_rightAngles', dispName: 'journey_rightAngles', type: 'bool', defVal: defaults.journey.rightAngles }, + + { name: 'class_arrowMarkerAbsolute', dispName: 'class_arrowMarkerAbsolute', type: 'boolean', defVal: defaults.class.arrowMarkerAbsolute }, + { name: 'class_useMaxWidth', dispName: 'class_useMaxWidth', type: 'boolean', defVal: defaults.class.useMaxWidth }, + + { name: 'git_arrowMarkerAbsolute', dispName: 'git_arrowMarkerAbsolute', type: 'boolean', defVal: defaults.git.arrowMarkerAbsolute }, + { name: 'git_useMaxWidth', dispName: 'git_useMaxWidth', type: 'boolean', defVal: defaults.git.useMaxWidth }, + + { name: 'state_dividerMargin', dispName: 'state_dividerMargin', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.dividerMargin }, + { name: 'state_sizeUnit', dispName: 'state_sizeUnit', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.sizeUnit }, + { name: 'state_padding', dispName: 'state_padding', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.padding }, + { name: 'state_textHeight', dispName: 'state_textHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.textHeight }, + { name: 'state_titleShift', dispName: 'state_titleShift', type: 'int', minVal: -1000, maxVal: 1000, defVal: defaults.state.titleShift }, + { name: 'state_noteMargin', dispName: 'state_noteMargin', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.noteMargin }, + { name: 'state_forkWidth', dispName: 'state_forkWidth', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.fontFamily }, + { name: 'state_forkHeight', dispName: 'state_forkHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.forkHeight }, + { name: 'state_miniPadding', dispName: 'state_miniPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.miniPadding }, + { name: 'state_fontSizeFactor', dispName: 'state_fontSizeFactor', type: 'float', minVal: 1, maxVal: 1000, defVal: defaults.state.fontSizeFactor }, + { name: 'state_fontSize', dispName: 'state_fontSize', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.fontSize }, + { name: 'state_labelHeight', dispName: 'state_labelHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.labelHeight }, + { name: 'state_edgeLengthFactor', dispName: 'state_edgeLengthFactor', type: 'string', defVal: defaults.state.edgeLengthFactor }, + { name: 'state_compositTitleSize', dispName: 'state_compositTitleSize', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.compositTitleSize }, + { name: 'state_radius', dispName: 'state_radius', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.state.radius }, + + { name: 'er_diagramPadding', dispName: 'er_diagramPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.er.diagramPadding }, + { + name: 'er_layoutDirection', dispName: 'er_layoutDirection', type: 'enum', defVal: defaults.er.layoutDirection, + enumList: [ + { val: 'TB', dispName: 'top to bottom' }, + { val: 'BT', dispName: 'bottom to top' }, + { val: 'RL', dispName: 'right to left' }, + { val: 'LR', dispName: 'left to right' } + ] }, - state: { - dividerMargin: mxUtils.getValue(this.style, 'state_dividerMargin', 10), - sizeUnit: mxUtils.getValue(this.style, 'state_sizeUnit', 5), - padding: mxUtils.getValue(this.style, 'state_padding', 8), - textHeight: mxUtils.getValue(this.style, 'state_textHeight', 10), - titleShift: mxUtils.getValue(this.style, 'state_titleShift', -15), - noteMargin: mxUtils.getValue(this.style, 'state_noteMargin', 10), - forkWidth: mxUtils.getValue(this.style, 'state_forkWidth', 70), - forkHeight: mxUtils.getValue(this.style, 'state_forkHeight', 7), - miniPadding: mxUtils.getValue(this.style, 'state_miniPadding', 2), - fontSizeFactor: mxUtils.getValue(this.style, 'state_fontSizeFactor', 5.02), - fontSize: mxUtils.getValue(this.style, 'state_fontSize', 24), - labelHeight: mxUtils.getValue(this.style, 'state_labelHeight', 16), - edgeLengthFactor: mxUtils.getValue(this.style, 'state_edgeLengthFactor', '20'), - compositTitleSize: mxUtils.getValue(this.style, 'state_compositTitleSize', 35), - radius: mxUtils.getValue(this.style, 'state_radius', 5), - }, - er: { - diagramPadding: mxUtils.getValue(this.style, 'er_diagramPadding', 20), - layoutDirection: mxUtils.getValue(this.style, 'er_layoutDirection', 'TB'), - minEntityWidth: mxUtils.getValue(this.style, 'er_minEntityWidth', 100), - minEntityHeight: mxUtils.getValue(this.style, 'er_minEntityHeight', 75), - entityPadding: mxUtils.getValue(this.style, 'er_entityPadding', 15), - stroke: mxUtils.getValue(this.style, 'er_stroke', 'grey'), - fill: mxUtils.getValue(this.style, 'er_fill', 'honeydew'), - fontSize: mxUtils.getValue(this.style, 'er_fontSize', 12), - useMaxWidth: mxUtils.getValue(this.style, 'er_useMaxWidth', true), + { name: 'er_minEntityWidth', dispName: 'er_minEntityWidth', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.er.minEntityWidth }, + { name: 'er_minEntityHeight', dispName: 'er_minEntityHeight', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.er.minEntityHeight }, + { name: 'er_entityPadding', dispName: 'er_entityPadding', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.er.entityPadding }, + { name: 'er_stroke', dispName: 'er_stroke', type: 'string', defVal: defaults.er.stroke }, + { name: 'er_fill', dispName: 'er_fill', type: 'string', defVal: defaults.er.fill }, + { name: 'er_fontSize', dispName: 'er_fontSize', type: 'int', minVal: 1, maxVal: 1000, defVal: defaults.er.fontSize }, + { name: 'er_useMaxWidth', dispName: 'er_useMaxWidth', type: 'bool', defVal: defaults.er.useMaxWidth }, + + { name: 'pie_useMaxWidth', dispName: 'pie_useMaxWidth', type: 'bool', defVal: defaults.pie.useMaxWidth }, + ]; +} - }, - pie: { - useMaxWidth: mxUtils.getValue(this.style, 'pie_useMaxWidth', true), +mxShapeMermaid.prototype.customProperties = mxShapeMermaid.prototype.buildCustomProperties(mermaid_plugin_defaults); + +mxShapeMermaid.prototype.getStyleOptions = function () { + let config = {}; + // Iterate through Mermaid custom properties + for(let prop of this.buildCustomProperties(mermaid_plugin_defaults)) { + // Test if we have it in the style + if (prop.name in this.style) { + // If yes, we build the config structure + if (prop.name == "theme_css") { config["theme_css"] = mxUtils.getValue(this.style, 'theme_css', this.defaults.themeCSS); } + else { + let prop_items = prop.name.split('_'); + if (prop_items.length == 1) { + config[prop_items[0]] = mxUtils.getValue(this.style, prop.name, this.defaults[prop_items[0]]); + } else if (prop_items.length == 2) { + if (! (config[prop_items[0]])) { config[prop_items[0]] = {}; } + config[prop_items[0]][prop_items[1]] = mxUtils.getValue(this.style, prop.name, this.defaults[prop_items[0]][prop_items[1]]); + } + } } - }; + } return config; } +mxShapeMermaid.prototype.getRenderOptions = function () { + return mergeDeep(this.defaults, this.getStyleOptions()); +} + mxShapeMermaid.prototype.updateImage = function (w, h) { try { var container = document.querySelector("#cmermaid-" + this.state.cell.id) @@ -343,7 +424,8 @@ mxShapeMermaid.prototype.paintVertexShape = function (c, x, y, w, h) { c.text(x, y + h / 2, 0, 0, '
' + this.error + '
', mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, false, 'html', 0, 0, 0); c.stroke(); } - this.state.cell.valueChanged = (value) => { var lastValue = mxCell.prototype.valueChanged.call(this.state.cell, value); this.updateImage(); this.redraw(); return lastValue; } + // Changing cell valueChanged will be kept even after changing shape -> moving the update to parse function (not seen any use case we miss) + //this.state.cell.valueChanged = (value) => { var lastValue = mxCell.prototype.valueChanged.call(this.state.cell, value); this.updateImage(); this.redraw(); return lastValue; } } mxCellRenderer.registerShape(mxShapeMermaid.prototype.cst.SHAPE_MERMAID, mxShapeMermaid); From 2686e02cd8a0ab67b06e5917af8a99b9dbf3ac77 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Sat, 20 Mar 2021 19:18:47 +0100 Subject: [PATCH 02/12] Copy and download functions --- drawio_desktop/src/mermaid-plugin.js | 95 +++++++++++++++++++--------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index d3581ff..bb1a6e3 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -38,10 +38,15 @@ var DialogMermaid = function (editorUi, shape) {

       
-

| - HTML | - +

+
Download as | + SVG | + PNG | +
Copy as | + HTML | + SVG | PNG | +
Help | Syntax |


@@ -126,48 +131,76 @@ var DialogMermaid = function (editorUi, shape) { } // Handle copy + function generateCanvas(callback, background=null) { + var svg = div.querySelector('#graph-div'); + + // https://stackoverflow.com/questions/60551658/saving-offscreencanvas-content-to-disk-as-png-in-electron + // https://stackoverflow.com/questions/32230894/convert-very-large-svg-to-png-using-canvas + var svg_xml = (new XMLSerializer()).serializeToString(svg); + var blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}); + var url = window.URL.createObjectURL(blob); + + var scale = 3; + var img = new Image(); + img.width = svg.getBBox().width * scale ; + img.height = svg.getBBox().height * scale ; + img.onload = () => { + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + canvas.width = svg.getBBox().width * scale; + canvas.height = svg.getBBox().height * scale; + + // Add a white background to cope with the transparent image problem getting black on windows... + if (background) { + context.fillStyle = background; + context.fillRect(0, 0, canvas.width, canvas.height); + } + + context.drawImage(img, svg.getBBox().x * scale, svg.getBBox().y * scale, svg.getBBox().width * scale, svg.getBBox().height * scale); + window.URL.revokeObjectURL(url); + + callback(canvas); + } + img.src = url; + } + + div.querySelector('#plugin_mermaid_button_dl_svg').onclick = async function() { + var aDownloadLink = document.createElement('a'); + aDownloadLink.download = 'image.svg'; + aDownloadLink.href = "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(div.querySelector('#graph-div').outerHTML))); + aDownloadLink.click(); + } - div.querySelector('#plugin_mermaid_button_png').onclick = async function() { - var clipboard = navigator.clipboard; - var svg = div.querySelector('#graph-div'); - - // https://stackoverflow.com/questions/60551658/saving-offscreencanvas-content-to-disk-as-png-in-electron - // https://stackoverflow.com/questions/32230894/convert-very-large-svg-to-png-using-canvas - var svg_xml = (new XMLSerializer()).serializeToString(svg); - var blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}); - var url = window.URL.createObjectURL(blob); + div.querySelector('#plugin_mermaid_button_dl_png').onclick = async function() { + generateCanvas(function(canvas) { + var aDownloadLink = document.createElement('a'); + aDownloadLink.download = 'image.png'; + aDownloadLink.href = canvas.toDataURL(); + aDownloadLink.click(); + }); + } - var scale = 3; - var img = new Image(); - img.width = svg.getBBox().width * scale ; - img.height = svg.getBBox().height * scale ; - img.onload = () => { - var canvas = document.createElement('canvas'); - var context = canvas.getContext('2d'); - canvas.width = svg.getBBox().width * scale; - canvas.height = svg.getBBox().height * scale; - context.drawImage(img, svg.getBBox().x * scale, svg.getBBox().y * scale, svg.getBBox().width * scale, svg.getBBox().height * scale); - window.URL.revokeObjectURL(url); - canvas.toBlob(function(imgBlob) { - clipboard.write( [ new ClipboardItem({[imgBlob.type]: imgBlob }) ] ); - }, 'image/png'); - } - img.src = url; + div.querySelector('#plugin_mermaid_button_png').onclick = async function() { + generateCanvas(function(canvas) { + canvas.toBlob(function(imgBlob) { + navigator.clipboard.write( [ new ClipboardItem({[imgBlob.type]: imgBlob }) ] ); + }, 'image/png'); + }, 'white'); } - /* + // (hidden) Buggy - Oddly makes the whole electron stop working... div.querySelector('#plugin_mermaid_button_svg').onclick = async function() { var svg_xml = (new XMLSerializer()).serializeToString(div.querySelector('#graph-div')); var svg_blob = new Blob([svg_xml], {type : 'image/svg+xml;charset=utf-8'}); var clip_item = new ClipboardItem( {'image/svg+xml': svg_blob } ); navigator.clipboard.write( [ clip_item ] ); } - */ + // (hidden) Tested, but not very usefull as not much destination applications support it... (Libreoffice Writer, with poor SVG render) div.querySelector('#plugin_mermaid_button_html').onclick = async function() { navigator.clipboard.write( [ new ClipboardItem( { 'text/html' : new Blob([""], {type : 'text/html'}) }) ] + btoa(unescape(encodeURIComponent(div.querySelector('#graph-div').outerHTML))) + "'>"], {type : 'text/html'}) }) ] ); } From d61866a9518327bf77a2bcc3267b24f23dac5638 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Sat, 27 Mar 2021 20:36:41 +0100 Subject: [PATCH 03/12] Removed blob: dependancy to allow use with default drawio-desktop --- drawio_desktop/src/mermaid-plugin.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index bb1a6e3..1414d16 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -136,9 +136,10 @@ var DialogMermaid = function (editorUi, shape) { // https://stackoverflow.com/questions/60551658/saving-offscreencanvas-content-to-disk-as-png-in-electron // https://stackoverflow.com/questions/32230894/convert-very-large-svg-to-png-using-canvas - var svg_xml = (new XMLSerializer()).serializeToString(svg); - var blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}); - var url = window.URL.createObjectURL(blob); + //var svg_xml = (new XMLSerializer()).serializeToString(svg); + //var blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}); + //var url = window.URL.createObjectURL(blob); + var url = "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(div.querySelector('#graph-div').outerHTML))); var scale = 3; var img = new Image(); From cd49b46661c9df8cb64156dc3b3feb8faecaee69 Mon Sep 17 00:00:00 2001 From: Remi Peyronnet Date: Tue, 30 Mar 2021 21:42:03 +0200 Subject: [PATCH 04/12] Update drawio_desktop/src/mermaid-plugin.js Co-authored-by: nopeslide --- drawio_desktop/src/mermaid-plugin.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index 1414d16..133590d 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -241,8 +241,20 @@ Draw.loadPlugin(function (ui) { let mermaid_settings = {}; mermaid_settings = mergeDeep(mermaid_settings, mermaid_plugin_defaults); - mermaid_settings = mergeDeep(mermaid_settings, window.EditorUi.defaultMermaidConfig); - mermaid_settings = mergeDeep(mermaid_settings, window.Editor.config.defaultMermaidConfig); + try { + mermaid_settings = mergeDeep(mermaid_settings, window.EditorUi.defaultMermaidConfig); + } catch (e) { + if (!e instanceof TypeError) { + throw e; + } + } + try { + mermaid_settings = mergeDeep(mermaid_settings, window.Editor.config.defaultMermaidConfig); + } catch (e) { + if (!e instanceof TypeError) { + throw e; + } + } // Result is updated back in EditorUi.defaultMermaidConfig to have consistent settings with native mermaid // Note that the result will not be consistent if the diagram is updated in native mermaid without the plugin, @@ -389,4 +401,3 @@ Draw.loadPlugin(function (ui) { - From fdb28c4895635cd2ca6415ba403b43e18b0fb738 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Fri, 2 Apr 2021 21:12:37 +0200 Subject: [PATCH 05/12] Added deepmerge and deep-object-diff packages --- drawio_desktop/package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drawio_desktop/package.json b/drawio_desktop/package.json index 2cc086f..c8becc5 100644 --- a/drawio_desktop/package.json +++ b/drawio_desktop/package.json @@ -18,5 +18,9 @@ "raw-loader": "^4.0.2", "webpack": "^5.1.3", "webpack-cli": "^4.0.0" + }, + "dependencies": { + "deep-object-diff": "^1.1.0", + "deepmerge": "^4.2.2" } } From 35a8cb0a9ace6256da6391253c207051066b329a Mon Sep 17 00:00:00 2001 From: rpeyron Date: Fri, 2 Apr 2021 21:28:22 +0200 Subject: [PATCH 06/12] Replaced merge & diff --- drawio_desktop/package.json | 9 ++-- drawio_desktop/src/mermaid-plugin.js | 32 ++++++++----- drawio_desktop/src/shapes/shapeMermaid.js | 55 ++--------------------- drawio_desktop/webpack.config.js | 5 ++- 4 files changed, 34 insertions(+), 67 deletions(-) diff --git a/drawio_desktop/package.json b/drawio_desktop/package.json index c8becc5..4886f5b 100644 --- a/drawio_desktop/package.json +++ b/drawio_desktop/package.json @@ -11,16 +11,19 @@ "webpack:production": "webpack --mode production", "webpack:development": "webpack --mode development", "build": "npm run webpack:production", - "dev": "npm run webpack:development" + "dev": "npm run webpack:development", + "dev-win": "set DRAWIO_ENV=dev&& npm run dev && copy /Y dist\\mermaid-plugin.webpack.js %AppData%\\draw.io\\plugins && cd ..\\..\\drawio\\src\\main\\webapp && .\\node_modules\\.bin\\electron .", + "release-win": "set DRAWIO_ENV=dev&& npm run build && copy /Y dist\\mermaid-plugin.webpack.js %AppData%\\draw.io\\plugins && cd ..\\..\\drawio\\src\\main\\webapp && .\\node_modules\\.bin\\electron ." }, "devDependencies": { - "mermaid": "^8.8.1", + "mermaid": "^8.9.1", "raw-loader": "^4.0.2", "webpack": "^5.1.3", "webpack-cli": "^4.0.0" }, "dependencies": { "deep-object-diff": "^1.1.0", - "deepmerge": "^4.2.2" + "deepmerge": "^4.2.2", + "is-object": "^1.0.2" } } diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index 1414d16..1b8787d 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -1,7 +1,11 @@ -import { mermaid_plugin_defaults, isObject, mergeDeep, diffDeep, mxShapeMermaid } from "./shapes/shapeMermaid"; +import { mermaid_plugin_defaults, mxShapeMermaid } from "./shapes/shapeMermaid"; import "./palettes/mermaid/paletteMermaid"; import mermaid from 'mermaid' +import merge from 'deepmerge' +import { diff, addedDiff, deletedDiff, updatedDiff, detailedDiff } from 'deep-object-diff' +import isObject from 'is-object' + /** * Constructs a new parse dialog. */ @@ -240,9 +244,9 @@ Draw.loadPlugin(function (ui) { // - Editor.config.defaultMermaidConfig : drawio config (from PreConfig and local configuration) let mermaid_settings = {}; - mermaid_settings = mergeDeep(mermaid_settings, mermaid_plugin_defaults); - mermaid_settings = mergeDeep(mermaid_settings, window.EditorUi.defaultMermaidConfig); - mermaid_settings = mergeDeep(mermaid_settings, window.Editor.config.defaultMermaidConfig); + mermaid_settings = merge(mermaid_settings, mermaid_plugin_defaults); + mermaid_settings = merge(mermaid_settings, window.EditorUi.defaultMermaidConfig); + mermaid_settings = merge(mermaid_settings, window.Editor.config.defaultMermaidConfig); // Result is updated back in EditorUi.defaultMermaidConfig to have consistent settings with native mermaid // Note that the result will not be consistent if the diagram is updated in native mermaid without the plugin, @@ -344,10 +348,11 @@ Draw.loadPlugin(function (ui) { let cell = graph.getSelectionCell(); if (!isCellNativeMermaid(cell)) return; - var data = JSON.parse(cell.getAttribute('mermaidData', '')); - - graph.getModel().beginUpdate(); try { + + var data = JSON.parse(cell.getAttribute('mermaidData', '')); + + graph.getModel().beginUpdate(); // Default style from paletteMermaid let style = 'shadow=0;dashed=0;align=left;strokeWidth=1;shape=mxgraph.mermaid.abstract.mermaid;labelBackgroundColor=#ffffff;noLabel=1;'; @@ -359,9 +364,9 @@ Draw.loadPlugin(function (ui) { } else { style += encodeURI(basestyle) + "=" + encodeURI(value) + ";"; } - } + } - let configDiff = diffDeep(data.config, mermaid_plugin_defaults); + let configDiff = diff(mermaid_plugin_defaults, data.config); addToStyle('', configDiff); // cell.value = data.data; @@ -373,8 +378,13 @@ Draw.loadPlugin(function (ui) { graph.view.getState(cell, true).destroy(); graph.view.getState(cell, true); - } - finally + + } + catch (error) + { + console.error(error); + } + finally { graph.getModel().endUpdate(); } diff --git a/drawio_desktop/src/shapes/shapeMermaid.js b/drawio_desktop/src/shapes/shapeMermaid.js index 78671a3..7456725 100644 --- a/drawio_desktop/src/shapes/shapeMermaid.js +++ b/drawio_desktop/src/shapes/shapeMermaid.js @@ -1,4 +1,5 @@ import mermaid from 'mermaid' +import merge from 'deepmerge' export const mermaid_plugin_defaults_original = { startOnLoad: false, @@ -116,57 +117,7 @@ export const mermaid_plugin_defaults_original = { } }; -// From https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge/34749873#34749873 -export function isObject(item) { - return (item && typeof item === 'object' && !Array.isArray(item)); - } - -export function mergeDeep(target, source) { - let output = Object.assign({}, target); - if (isObject(target) && isObject(source)) { - Object.keys(source).forEach(key => { - if (isObject(source[key])) { - if (!(key in target)) - Object.assign(output, { [key]: source[key] }); - else - output[key] = mergeDeep(target[key], source[key]); - } else { - Object.assign(output, { [key]: source[key] }); - } - }); - } - return output; - } -// --- - -// Adapted from https://stackoverflow.com/questions/8572826/generic-deep-diff-between-two-objects -export function diffDeep(target, source) { - let diff = Object.keys(target).reduce((diff, key) => { - // If object, deep - if (isObject(target[key]) && (key in source)) { - let diffkey = diffDeep(target[key], source[key]); - if (Object.keys(diffkey).length == 0) { - return diff - } else { - return { - ...diff, - [key]: diffkey - } - } - } - // If identical ignore - if ((key in source) && (target[key] === source[key])) return diff - // If different, add value to the result - return { - ...diff, - [key]: target[key] - } - }, {}) - return diff; -} -// --- - -export var mermaid_plugin_defaults = mergeDeep({}, mermaid_plugin_defaults_original); +export var mermaid_plugin_defaults = merge({}, mermaid_plugin_defaults_original); /** * Extends mxShape. @@ -370,7 +321,7 @@ mxShapeMermaid.prototype.getStyleOptions = function () { } mxShapeMermaid.prototype.getRenderOptions = function () { - return mergeDeep(this.defaults, this.getStyleOptions()); + return merge(this.defaults, this.getStyleOptions()); } mxShapeMermaid.prototype.updateImage = function (w, h) { diff --git a/drawio_desktop/webpack.config.js b/drawio_desktop/webpack.config.js index fe22b32..b59217e 100644 --- a/drawio_desktop/webpack.config.js +++ b/drawio_desktop/webpack.config.js @@ -6,5 +6,8 @@ module.exports = { filename: 'mermaid-plugin.webpack.js', path: path.resolve(__dirname, 'dist'), }, - devtool: 'source-map' + devtool: 'source-map', + externalsPresets: { + 'electron': true, + }, }; From 8a1f0548c7eb90a186277eacffa22dbf0e6209b1 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Fri, 2 Apr 2021 21:47:37 +0200 Subject: [PATCH 07/12] Clean local dev stuff --- drawio_desktop/package.json | 4 +--- drawio_desktop/webpack.config.js | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drawio_desktop/package.json b/drawio_desktop/package.json index 4886f5b..b3ad6a4 100644 --- a/drawio_desktop/package.json +++ b/drawio_desktop/package.json @@ -11,9 +11,7 @@ "webpack:production": "webpack --mode production", "webpack:development": "webpack --mode development", "build": "npm run webpack:production", - "dev": "npm run webpack:development", - "dev-win": "set DRAWIO_ENV=dev&& npm run dev && copy /Y dist\\mermaid-plugin.webpack.js %AppData%\\draw.io\\plugins && cd ..\\..\\drawio\\src\\main\\webapp && .\\node_modules\\.bin\\electron .", - "release-win": "set DRAWIO_ENV=dev&& npm run build && copy /Y dist\\mermaid-plugin.webpack.js %AppData%\\draw.io\\plugins && cd ..\\..\\drawio\\src\\main\\webapp && .\\node_modules\\.bin\\electron ." + "dev": "npm run webpack:development" }, "devDependencies": { "mermaid": "^8.9.1", diff --git a/drawio_desktop/webpack.config.js b/drawio_desktop/webpack.config.js index b59217e..fe22b32 100644 --- a/drawio_desktop/webpack.config.js +++ b/drawio_desktop/webpack.config.js @@ -6,8 +6,5 @@ module.exports = { filename: 'mermaid-plugin.webpack.js', path: path.resolve(__dirname, 'dist'), }, - devtool: 'source-map', - externalsPresets: { - 'electron': true, - }, + devtool: 'source-map' }; From 5e1c54ee25393efdb2a5a2c7a1247f64e7ee10dc Mon Sep 17 00:00:00 2001 From: rpeyron Date: Fri, 2 Apr 2021 21:57:46 +0200 Subject: [PATCH 08/12] Ensure beginUpdate --- drawio_desktop/src/mermaid-plugin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index 363d71b..e0cf21c 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -362,9 +362,10 @@ Draw.loadPlugin(function (ui) { try { + graph.getModel().beginUpdate(); + var data = JSON.parse(cell.getAttribute('mermaidData', '')); - graph.getModel().beginUpdate(); // Default style from paletteMermaid let style = 'shadow=0;dashed=0;align=left;strokeWidth=1;shape=mxgraph.mermaid.abstract.mermaid;labelBackgroundColor=#ffffff;noLabel=1;'; @@ -385,7 +386,6 @@ Draw.loadPlugin(function (ui) { graph.setAttributeForCell(cell, 'mermaidData', "" ); graph.labelChanged(cell,data.data); - graph.setCellStyle(style, [cell]); graph.view.getState(cell, true).destroy(); From cd416bc8c090560405e829ec67973b7c4a26d025 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Sat, 7 May 2022 20:56:29 +0200 Subject: [PATCH 09/12] Added global options possibility --- drawio_desktop/src/mermaid-plugin.js | 29 ++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index e0cf21c..0abc6ab 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -209,8 +209,10 @@ var DialogMermaid = function (editorUi, shape) { ); } - var cancelBtn = mxUtils.button(mxResources.get('close'), function () { - win.destroy(); + var cancelBtn = mxUtils.button(mxResources.get('cancel'), function () { + if (mxUtils.confirm(mxResources.get('changesNotSaved')+"\n"+mxResources.get('areYouSure'))) { + win.destroy(); + } }); cancelBtn.className = 'geBtn'; @@ -219,7 +221,15 @@ var DialogMermaid = function (editorUi, shape) { buttons.appendChild(cancelBtn); } - var okBtn = mxUtils.button(mxResources.get('apply'), function (evt) { + var saveBtn = mxUtils.button(mxResources.get('save'), function (evt) { + parse(textarea.value, evt); + win.destroy(); + }); + buttons.appendChild(saveBtn); + + saveBtn.className = 'geBtn'; + + var okBtn = mxUtils.button(mxResources.get('saveAndExit'), function (evt) { parse(textarea.value, evt); win.destroy(); }); @@ -241,7 +251,8 @@ Draw.loadPlugin(function (ui) { // Build mermaid settings : by least order // - mermaid_plugin_defaults : this plugin defaults // - EditorUi.defaultMermaidConfig : drawio defaults mermaid - // - Editor.config.defaultMermaidConfig : drawio config (from PreConfig and local configuration) + // - window.defaultMermaidConfig : drawio config from PreConfig + // - Editor.config.defaultMermaidConfig : drawio config (from PreConfig or local configuration) let mermaid_settings = {}; mermaid_settings = merge(mermaid_settings, mermaid_plugin_defaults); @@ -252,6 +263,13 @@ Draw.loadPlugin(function (ui) { throw e; } } + try { + mermaid_settings = merge(mermaid_settings, window.defaultMermaidConfig); + } catch (e) { + if (!e instanceof TypeError) { + throw e; + } + } try { mermaid_settings = merge(mermaid_settings, window.Editor.config.defaultMermaidConfig); } catch (e) { @@ -404,10 +422,9 @@ Draw.loadPlugin(function (ui) { }); +}); -}); - From 9ef7352594f032a07650e31348d1d6ca40d7d8e6 Mon Sep 17 00:00:00 2001 From: rpeyron Date: Sat, 7 May 2022 21:19:23 +0200 Subject: [PATCH 10/12] Added save button and check before cancelling --- drawio_desktop/src/mermaid-plugin.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index 0abc6ab..6e533d8 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -210,7 +210,14 @@ var DialogMermaid = function (editorUi, shape) { } var cancelBtn = mxUtils.button(mxResources.get('cancel'), function () { - if (mxUtils.confirm(mxResources.get('changesNotSaved')+"\n"+mxResources.get('areYouSure'))) { + // Check if modified or ask to save + let cellValue = editorUi.editor.graph.convertValueToString(shape.state.cell).replace(/(\r\n|\n\r)/g,"\n") + let formValue = textarea.value.replace(/(\r\n|\n\r)/g,"\n") + console.log(cellValue, formValue, cellValue == formValue, cellValue === formValue) + if ( + (cellValue == formValue) || + (mxUtils.confirm(mxResources.get('changesNotSaved')+"\n"+mxResources.get('areYouSure'))) + ) { win.destroy(); } }); @@ -223,7 +230,6 @@ var DialogMermaid = function (editorUi, shape) { var saveBtn = mxUtils.button(mxResources.get('save'), function (evt) { parse(textarea.value, evt); - win.destroy(); }); buttons.appendChild(saveBtn); From 0bdc2710c326c36f592a22541ab27460863ae321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Peyronnet?= Date: Mon, 26 Sep 2022 23:25:50 +0200 Subject: [PATCH 11/12] Fixed decodeURIComponent exception with recent drawio versions --- drawio_desktop/package.json | 5 ++++- drawio_desktop/src/shapes/shapeMermaid.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drawio_desktop/package.json b/drawio_desktop/package.json index 2f6c569..bc93212 100644 --- a/drawio_desktop/package.json +++ b/drawio_desktop/package.json @@ -11,7 +11,10 @@ "webpack:production": "webpack --mode production", "webpack:development": "webpack --mode development", "build": "npm run webpack:production", - "dev": "npm run webpack:development" + "dev": "npm run webpack:development", + "copy-plugin": "copy /y dist\\mermaid-plugin.webpack.js %appdata%\\draw.io\\plugins\\", + "run-drawio": "..\\..\\draw.io-20.3.0-windows-no-installer.exe --args --enable-plugins", + "maj-dev": "npm run dev && npm run copy-plugin && npm run run-drawio" }, "devDependencies": { "mermaid": "^8.13.3", diff --git a/drawio_desktop/src/shapes/shapeMermaid.js b/drawio_desktop/src/shapes/shapeMermaid.js index 7456725..862ca24 100644 --- a/drawio_desktop/src/shapes/shapeMermaid.js +++ b/drawio_desktop/src/shapes/shapeMermaid.js @@ -228,7 +228,7 @@ mxShapeMermaid.prototype.buildCustomProperties = function (defaults) { { name: 'gantt_fontSize', dispName: 'gantt_fontSize', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.fontSize }, { name: 'gantt_fontFamily', dispName: 'gantt_fontFamily', type: 'string', defVal: defaults.gantt.fontFamily }, { name: 'gantt_numberSectionStyles', dispName: 'gantt_numberSectionStyles', type: 'int', min: 1, max: 1000, defVal: defaults.gantt.numberSectionStyles }, - { name: 'gantt_axisFormat', dispName: 'gantt_axisFormat', type: 'string', defVal: defaults.gantt.axisFormat }, + { name: 'gantt_axisFormat', dispName: 'gantt_axisFormat', type: 'string', defVal: encodeURIComponent(defaults.gantt.axisFormat) }, { name: 'gantt_useMaxWidth', dispName: 'gantt_useMaxWidth', type: 'bool', defVal: defaults.gantt.useMaxWidth }, { name: 'journey_diagramMarginX', dispName: 'journey_diagramMarginX', type: 'int', min: 1, max: 1000, defVal: defaults.journey.diagramMarginX }, From b0baf88a53b3523c05eb6bfe00a75e2286fac93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Peyronnet?= Date: Tue, 6 Jun 2023 23:38:23 +0200 Subject: [PATCH 12/12] Update doc URL --- drawio_desktop/src/mermaid-plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drawio_desktop/src/mermaid-plugin.js b/drawio_desktop/src/mermaid-plugin.js index 6e533d8..971c391 100644 --- a/drawio_desktop/src/mermaid-plugin.js +++ b/drawio_desktop/src/mermaid-plugin.js @@ -51,7 +51,7 @@ var DialogMermaid = function (editorUi, shape) { SVG | PNG |
Help | - Syntax | + Syntax |