From 8f74951ac43ce09b9b2e22dddac6e34ca7337442 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Tue, 30 Apr 2024 20:20:41 +0100 Subject: [PATCH 1/3] Adds options auto-zoom and auto-scroll (enabled by default) Adds minified build and build script (no deps, uses npz terser) (was getting large!) Updates README and demo files for new options Updates package.json for v0.3.0 release --- README.md | 30 ++++-- demo-esm.html | 9 +- demo-vanilla.html | 7 +- demo-vue.html | 8 +- index.js | 256 ++++++++++++++++++++++++++++++++++++++-------- index.min.js | 1 + package-lock.json | 4 +- package.json | 5 +- 8 files changed, 256 insertions(+), 64 deletions(-) create mode 100644 index.min.js diff --git a/README.md b/README.md index e5c295c..3d9e452 100644 --- a/README.md +++ b/README.md @@ -15,21 +15,26 @@ All client-side code is in the `index.js` file for easy inclusion in a web page. Run `npm run demo` to test the flow renderer in a browser. +Run `npm run build` to build a minimised version of the flow renderer. This will output the file `index.min.js`. + +IMPORTANT: The minified version of the flow renderer should be built before committing changes to the repository. + ## Usage Add the following script tag to your HTML file: ```html - + ``` _or wherever the script is located in your project_ Next, add a container element to your HTML file and call the `flowRenderer` function with the flow data and options. NOTE: flow-renderer is an ES Module and requires a modern browser to run. Script tags must have the `type="module"` attribute. -By default, the flow renderer will render the flow with `gridlines`, `images`, `labels` and `zoom` options enabled. +By default, the flow renderer will render the flow with `gridlines`, `images`, `labels`, `zoom`, `autozoom`, and `autoscroll` enabled. +`linklines` are disabled by default. -To operate the zoom, use the mouse wheel + Ctrl key. +To operate the zoom, use the mouse wheel + Ctrl or key. To scroll the container vertically, use the mouse wheel without the Shift key. To scroll the container horizontally, use the mouse wheel + Shift key. @@ -50,10 +55,21 @@ renderer.renderFlows(flow, { container: container1 }) ### Inline Options example -Options can be set by data attributes `scope`, `grid-lines`, `zoom`, `images`, `link-lines`, `labels` +Options can be set by data attributes `scope`, `grid-lines`, `zoom`, `images`, `link-lines`, `labels`, `auto-zoom`, `auto-scroll`. + +NOTE: To SET and option, the data attribute can simply be present on the container element. To UNSET an option, the data attribute must be set to `false`. ```html -
+
``` ```javascript @@ -79,9 +95,11 @@ renderer.renderFlows(flow, { scope: 'my-scope', // scope for CSS gridlines: true, // show gridlines images: true, // show images - linkLines: false, // show link lines + linklines: false, // show link lines labels: true, // show labels zoom: true, // enable zoom within the container + autozoom: true, // auto zoom to fit the flow within the container upon rendering (best fit, limited to 20% min, 100% max zoom) + autoscroll: true, // auto scroll the leftmost node to the left of the container and the topmost node to the top of the container upon rendering flowId: undefined // Id of flow to display }) ``` diff --git a/demo-esm.html b/demo-esm.html index a263b1f..172eb66 100644 --- a/demo-esm.html +++ b/demo-esm.html @@ -21,7 +21,6 @@ margin-bottom: 4px; } - @@ -48,12 +47,12 @@

Render (no grid, no images, labels)

-

Render (no grid, images, no labels) using data-options

-
+

Render (no grid, images, no labels, no auto layout) using data-options

+
+ + @@ -48,8 +49,8 @@

Render (no grid, no images, labels)

-

Render (no grid, images, no labels) using data-options

-
+

Render (no grid, images, no labels, no auto layout) using data-options

+
+ @@ -49,8 +49,8 @@

Render (no grid, no images, labels)

-

Render (no grid, images, no labels) using data-options

-
+

Render (no grid, images, no labels, no auto layout) using data-options

+
@@ -59,7 +59,7 @@

Render (no grid, images, no labels) using data-options

diff --git a/demo-vanilla.html b/demo-vanilla.html index cf74247..669fee6 100644 --- a/demo-vanilla.html +++ b/demo-vanilla.html @@ -50,7 +50,7 @@

Render (no grid, no images, labels)

Render (no grid, images, no labels, no auto layout) using data-options

-
+
diff --git a/demo-vue.html b/demo-vue.html index 1aa7fb7..f4c8830 100644 --- a/demo-vue.html +++ b/demo-vue.html @@ -50,7 +50,7 @@

Render (no grid, no images, labels)

Render (no grid, images, no labels, no auto layout) using data-options

-
+
@@ -90,7 +90,7 @@

Render (no grid, images, no labels, no auto layout) using data-options

const data = flows || this.demoFlow || [] const dataObject = typeof data === 'string' ? JSON.parse(data) : data renderer.renderFlows(dataObject, { container: this.$refs.f1 }) - renderer.renderFlows(dataObject, { container: this.$refs.f2, gridlines: false, images: false }) + renderer.renderFlows(dataObject, { container: this.$refs.f2, gridLines: false, images: false }) renderer.renderFlows(dataObject, { container: this.$refs.f3, scope: 'nr-flow-3' }) }, clear() { diff --git a/index.js b/index.js index a55d213..78d6955 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,12 @@ /** * @typedef {Object} FlowRendererOptions - * @property {boolean} [gridlines=true] - Whether to display grid lines on the flow diagram. Defaults to true. + * @property {boolean} [gridLines=true] - Whether to display grid lines on the flow diagram. Defaults to true. * @property {boolean} [zoom=true] - Whether to enable zooming on the flow diagram. Defaults to true. * @property {boolean} [images=true] - Whether to display images on the flow diagram. Defaults to true. - * @property {boolean} [linklines=false] - Whether to display link lines on the flow diagram. Defaults to false. + * @property {boolean} [linkLines=false] - Whether to display link lines on the flow diagram. Defaults to false. * @property {boolean} [labels=true] - Whether to display labels on the flow diagram. Defaults to true. - * @property {boolean} [autozoom=true] - Whether to automatically zoom the diagram to fit the container. Depends on zoom option being true. Defaults to true. - * @property {boolean} [autoscroll=true] - Whether to automatically scroll the diagram to the top leftmost node. Defaults to true. + * @property {boolean} [autoZoom=true] - Whether to automatically zoom the diagram to fit the container. Depends on zoom option being true. Defaults to true. + * @property {boolean} [autoScroll=true] - Whether to automatically scroll the diagram to the top leftmost node. Defaults to true. * @property {Array} flowId - The specific flow(s) to render. If not provided, all flows will be rendered. * @property {HTMLElement} container - The container div where the SVG diagram and controls will be rendered. * @property {Document} document - The document object to use for creating SVG elements. Defaults to the global document object. @@ -48,13 +48,13 @@ const FlowRenderer = (function () { /** @type {FlowRendererOptions} */ const defaults = { arrows: false, - gridlines: true, + gridLines: true, zoom: true, images: true, - linklines: false, + linkLines: false, labels: true, - autozoom: true, - autoscroll: true, + autoZoom: true, + autoScroll: true, flowId: undefined, container: undefined, document: undefined @@ -646,13 +646,13 @@ const FlowRenderer = (function () { } function autoLayout(svg, flow, renderOpts) { - const computedAutoScaleAndScroll = (renderOpts.autozoom || renderOpts.autoscroll) ? computeAutoLayout(flow, renderOpts) : null + const computedAutoScaleAndScroll = (renderOpts.autoZoom || renderOpts.autoScroll) ? computeAutoLayout(flow, renderOpts) : null if (renderOpts.zoom) { - if (computedAutoScaleAndScroll && renderOpts.autozoom) { + if (computedAutoScaleAndScroll && renderOpts.autoZoom) { updateScale(svg.querySelector('g.outerContainer'), computedAutoScaleAndScroll.scale, true); } } - if (computedAutoScaleAndScroll && renderOpts.autoscroll) { + if (computedAutoScaleAndScroll && renderOpts.autoScroll) { updateScroll(svg.parentElement, computedAutoScaleAndScroll.scrollX, computedAutoScaleAndScroll.scrollY, true); } return computedAutoScaleAndScroll @@ -1929,10 +1929,10 @@ const FlowRenderer = (function () { if (options) { if (options.container) { const containerOptions = {} - const dataOptions = ['scope', 'grid-lines', 'arrows', 'zoom', 'images', 'link-lines', 'labels', 'auto-zoom', 'auto-scroll'] + const dataOptions = ['scope', 'gridLines', 'arrows', 'zoom', 'images', 'linkLines', 'labels', 'autoZoom', 'autoScroll', 'flowId'] dataOptions.forEach(function (opt) { - if (options.container.hasAttribute("data-" + opt)) { - const optionValue = options.container.getAttribute("data-" + opt) || "true" + if (typeof options.container.dataset[opt] === 'string') { + const optionValue = options.container.dataset[opt] || "true" containerOptions[opt.replace(/-/g, '')] = optionValue === "true" } }) @@ -2130,7 +2130,7 @@ const FlowRenderer = (function () { /** @type {SVGGElement} */ const flow_gridEl = svg.querySelector('.flow_grid'); - if (renderOpts.gridlines && flow_gridEl) { + if (renderOpts.gridLines && flow_gridEl) { for (var idx = 0; idx < 250; idx++) { flow_gridEl.append(createSvgElement('line', { x1: 0, @@ -2760,7 +2760,7 @@ const FlowRenderer = (function () { } /* draw the links between link nodes, i.e. link-in and link-out nodes */ - if (renderOpts.linklines) { + if (renderOpts.linkLines) { linkOutNodes.forEach(function (nde) { nde.links.forEach(function (ndeId) { var otherNode = nodes[ndeId]; diff --git a/index.min.js b/index.min.js index cba8db2..5b187d2 100644 --- a/index.min.js +++ b/index.min.js @@ -1 +1 @@ -const FlowRenderer=function(){let t=this||{};const e="flow-renderer-css",i=.75,M=30,A=100,n=13.5,g={view:{}};g.view.tools={},g.utils={},g.view.gridSize=function(){return 20},g.view.tools.calculateGridSnapOffsets=function(t,e){0;e=e||{align:"nearest"};const i={x:0,y:0},M=g.view.gridSize(),A=t.x-(M*Math.round((t.x-t.w/2)/M)+t.w/2),n=t.x-(M*Math.round((t.x+t.w/2)/M)-t.w/2);i.x=n,"right"===e.align||("left"===e.align||Math.abs(A)"tab"!==t.type&&"subflow"!==t.type&&t.z==I));if(0===l.length)return{scale:1,scrollX:0,scrollY:0};for(let t of l){if("tab"===t.type||"subflow"===t.type||"junction"===t.type)continue;const e=t.x||0,i=t.y||0,M=j(t),A=(M.width||100)/2,n=(M.height||30)/2,g=e-A,o=i-n,I=e+A,l=i+n;a=Math.min(a,g),u=Math.min(u,o),s=Math.max(s,I),r=Math.max(r,l)}let d=1;const N=s-a,c=r-u,L=g/N,y=o/c;(N>g||c>o)&&(d=Math.min(L,y),d*=.95);d=D(d,i,M,1);let b=a,w=u;b<50&&(b=0);w<40&&(w=0);b>0&&(b-=50);w>0&&(w-=40);return b=D(b*d,0,A.scrollWidth),w=D(w*d,0,A.scrollHeight),{scale:d,scrollX:b,scrollY:w,minX:a,minY:u,maxX:s,maxY:r}}(e,i):null;return i.zoom&&M&&i.autozoom&&w(t.querySelector("g.outerContainer"),M.scale,!0),M&&i.autoscroll&&x(t.parentElement,M.scrollX,M.scrollY,!0),M}function S(t,e,i){const M=t.parentElement,A=M.scrollLeft,n=M.scrollTop,g=b(t.querySelector("g.outerContainer")),o=i||e.flowId||"default";M.setAttribute(`_state_${o}_x`,A),M.setAttribute(`_state_${o}_y`,n),M.setAttribute(`_state_${o}_scale`,g)}function T(t){const e=c(t,this);if(!e)return null;let i=t.querySelector(".toolbar");return i||(i=e.createElement("div"),i.classList.add("toolbar"),t&&t.appendChild(i),i)}function m(t){const e=c(t,this),i=e.createElementNS("http://www.w3.org/2000/svg","svg"),M=e.createElementNS("http://www.w3.org/2000/svg","g");M.setAttribute("class","outerContainer"),i.setAttribute("style","width:8000px; height:8000px;"),i.appendChild(M);const A=["flow_grid","flow_group_elements","flow_group_select","flow_wires","flow_nodes"];for(let t of A){const i=e.createElementNS("http://www.w3.org/2000/svg","g");i.setAttribute("class",t),M.appendChild(i)}return t.appendChild(i),i}function z(t){t&&t.length&&"string"!=typeof t&&"string"==typeof t[0]&&(t=[...t].join(" "));return`\n :root {\n --red-ui-primary-background: #fff;\n --red-ui-secondary-text-color: #333;\n --red-ui-view-grid-color: #eee;\n --red-ui-view-border: 1px solid #bbbbbb;\n --red-ui-node-border: #999;\n --red-ui-node-background-default: #eee;\n --red-ui-node-icon-background-color-fill: black;\n --red-ui-node-icon-background-color-opacity: 0.1;\n --red-ui-node-label-color: #333;\n --red-ui-node-port-background: #d9d9d9;\n --red-ui-link-color: #999;\n --red-ui-workspace-button-color: #333;\n --red-ui-workspace-button-background: #f3f3f3;\n --red-ui-form-input-border-color: #ccc;\n }\n ${t=(t=t||".flow-renderer").split(" ").map((t=>`.${t}`)).join(" ").trim()} {\n position: relative;\n }\n ${t} .red-ui-workspace-chart {\n box-sizing: border-box;\n border: var(--red-ui-view-border);\n overflow: scroll;\n height: 100%;\n width: 100%;\n }\n ${t} .red-ui-workspace-chart.has-tabs {\n height: calc(100% - 34px); // 34px is the height of the tabs\n }\n ${t} svg {\n position: relative;\n width: 100%;\n height: 100%;\n min-height: 250px;\n margin: auto;\n display: block;\n border-radius: 2px;\n }\n ${t} svg {\n cursor: default;\n }\n ${t} svg .group-text-label {\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 14px;\n }\n ${t} svg .node-text-label {\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 14px;\n dominant-baseline: middle;\n }\n ${t} svg .subflow-node-text-label {\n color: rgb(85, 85, 85);\n dominant-baseline: middle;\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 10px;\n line-height: 20px;\n pointer-events: none;\n text-anchor: middle;\n user-select: none\n }\n ${t} svg .subflow-node-text-label-number {\n color: rgb(85, 85, 85);\n dominant-baseline: middle;\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 20px;\n pointer-events: none;\n text-anchor: middle;\n user-select: none\n }\n\n ${t} svg .node {\n fill-opacity: 1;\n stroke-width: 1px;\n }\n ${t} svg .link {\n stroke: #999;\n stroke-width: 3;\n fill: none;\n }\n ${t} svg .link-highlight, .node-highlight {\n stroke: rgb(255, 127, 14);\n }\n ${t} svg .node-highlight {\n stroke-width: 3px;\n }\n\n ${t} svg .node-disabled {\n stroke-dasharray: 8,3;\n fill-opacity: 0.5;\n }\n ${t} svg .group-highlight {\n stroke: rgb(255, 127, 14);\n stroke-width: 4px;\n fill: rgb(255, 127, 14);\n fill-opacity: 0.2;\n }\n ${t} svg .link-disabled {\n stroke-dasharray: 10,8 !important;\n stroke-width: 2 !important;\n stroke: rgb(204, 204, 204);\n }\n ${t} svg .grid-line {\n shape-rendering: crispedges;\n stroke: rgb(238, 238, 238);\n stroke-width: 1px;\n fill: none;\n }\n ${t} svg .red-ui-flow-port {\n stroke-width: 1px;\n stroke-miterlimit: 4;\n fill: var(--red-ui-node-port-background);\n }\n ${t} svg .red-ui-flow-port-input {\n stroke-width: 1px;\n stroke-miterlimit: 4;\n fill: var(--red-ui-node-port-background);\n }\n ${t} svg .flow-render-error {\n background-color: rgb(54, 52, 52); \n color: rgb(196, 59, 59); \n width: 100%;\n }\n ${t} svg text {\n user-select: none;\n }\n ${t} .red-ui-tabs {\n display: flex;\n }\n ${t} .red-ui-tab {\n padding: 6px 12px;\n box-sizing: border-box;\n display: block;\n border: 1px solid #bbbbbb;\n border-right: none;\n background-color: #f0f0f0;\n max-width: 200px;\n max-height: 34px; /* for calculating svg height */\n width: 14%;\n overflow: hidden;\n white-space: nowrap;\n position: relative;\n margin-top: -1px;\n transition: 0.2s background-color;\n user-select: none;\n position: relative;\n z-index: 1;\n top: 1px;\n }\n ${t} .red-ui-tab-subflow-icon {\n mask-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAsIDAsIDQwLCA2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjUgMjUuOTRoN2MuNTggMCAxLS40MiAxLTF2LTJjMC0uNTgtLjQyLTEtMS0xaC03Yy0uNTggMC0xIC40Mi0xIDF2MmMwIC41OC40MiAxIDEgMXptLTE3IDEyaDdjLjU4IDAgMS0uNDIgMS0xdi0yYzAtLjU4LS40Mi0xLTEtMUg4Yy0uNTggMC0xIC40Mi0xIDF2MmMwIC41OC40MiAxIDEgMXptLS40MTYgMTFDNS42MjQgNDguOTQgNCA0Ny4zMTUgNCA0NS4zNTZWMTQuNTIyYzAtMS45NiAxLjYyNS0zLjU4MiAzLjU4NC0zLjU4MmgyNC44MzJjMS45NiAwIDMuNTg0IDEuNjIzIDMuNTg0IDMuNTgydjMwLjgzNGMwIDEuOTYtMS42MjUgMy41ODQtMy41ODQgMy41ODR6TTMyIDM2Ljk0SDE5YzAgMi4xOS0xLjgxIDQtNCA0SDd2NC40MTZjMCAuMzUuMjM1LjU4NC41ODQuNTg0aDI0LjgzMmMuMzUgMCAuNTg0LS4yMzUuNTg0LS41ODR2LTguNDE3em0xLTJ2LTZoLThjLTIuMTkgMC00LTEuODEtNC00aC0xYy00LjMzMy0uMDAyLTguNjY3LjAwNC0xMyAwdjZoOGMyLjE5IDAgNCAxLjgxIDQgNGgxM3ptMC0xNnYtNC40MThjMC0uMzUtLjIzNS0uNTgyLS41ODQtLjU4Mkg3LjU4NGMtLjM1IDAtLjU4NC4yMzMtLjU4NC41ODJ2OC40MTdjNC4zMzMuMDAyIDguNjY3LjAwMSAxMyAuMDAxaDFjMC0yLjE5IDEuODEtNCA0LTRoOHoiIGNvbG9yPSIjMDAwIiBmaWxsPSIjZmZmIi8+PC9zdmc+Cg==);\n display: inline-block;\n background-color: grey;\n margin-left: -8px;\n margin-right: 3px;\n margin-top: -1px;\n margin-bottom: 1px;\n opacity: 1;\n width: 16px;\n height: 18px;\n vertical-align: middle;\n mask-size: contain;\n mask-position: center;\n mask-repeat: no-repeat;\n }\n ${t} .red-ui-tab-disabled-icon {\n mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 1536 1792' style='&%2310;'%3E%3Cscript xmlns=''/%3E%3Cpath d='M1312 893q0-161-87-295l-754 753q137 89 297 89 111 0 211.5-43.5t173.5-116.5 116-174.5 43-212.5zM313 1192l755-754q-135-91-300-91-148 0-273 73t-198 199-73 274q0 162 89 299zM1536 893q0 157-61 300t-163.5 246-245 164-298.5 61-298.5-61-245-164-163.5-246-61-300 61-299.5 163.5-245.5 245-164 298.5-61 298.5 61 245 164 163.5 245.5 61 299.5z' fill='currentColor'/%3E%3Cscript xmlns=''/%3E%3C/svg%3E");\n display: inline-block;\n background-color: grey;\n margin-left: -8px;\n margin-right: 3px;\n margin-top: 0px;\n margin-bottom: 0px;\n opacity: 1;\n width: 16px;\n height: 16px;\n vertical-align: middle;\n mask-size: contain;\n mask-position: center;\n mask-repeat: no-repeat;\n transform: translateY(-2px);\n }\n ${t} .red-ui-tab span {\n font-size: 0.875rem;\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n }\n ${t} .red-ui-tab.active {\n background-color: white;\n border-bottom-color: white;\n font-weight: bold;\n }\n ${t} .red-ui-tab.disabled {\n border-top-style: dashed;\n border-left-style: dashed;\n font-style: italic;\n }\n ${t} .red-ui-tab:last-child {\n border-right: 1px solid #bbbbbb;\n }\n ${t} .red-ui-tab:last-child.disabled {\n border-right-style: dashed;\n }\n ${t} .red-ui-tab:hover {\n cursor: pointer;\n background-color: white;\n }\n /* positioning of toolbar */\n ${t} .toolbar {\n display: flex;\n flex-direction: row;\n position: absolute;\n bottom: 5px;\n right: 5px;\n opacity: 0.7;\n }\n ${t} .toolbar:hover {\n opacity: 1;\n }\n ${t}.has-scrollbars .toolbar {\n bottom: 24px;\n right: 24px;\n }\n /* styles for button groups and buttons */\n ${t} .button-group {\n display: flex;\n flex-direction: row;\n }\n ${t} .button-group button {\n user-select: none;\n box-sizing: border-box;\n display: inline-block;\n text-align: center;\n cursor: pointer;\n line-height: 22px;\n height: 24px;\n color: var(--red-ui-workspace-button-color) !important;\n background: var(--red-ui-workspace-button-background);\n text-decoration: none;\n border: 1px solid var(--red-ui-form-input-border-color);\n margin: 0px;\n padding: 0px;\n }\n ${t} .button-group button:not(:first-child) {\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n border-left: none;\n }\n\n /* zoom controls */\n ${t} .zoom-controls.button-group button {\n font-size: 22px;\n width: 24px;\n }\n\n /* copy controls */\n ${t} .copy-controls.button-group {\n margin-right: 24px;\n }\n ${t} .copy-controls.button-group button {\n padding: 0px 4px;\n }\n `}function p(t){t&&["flow_grid","flow_group_elements","flow_group_select","flow_wires","flow_nodes"].forEach((e=>{const i=t.querySelector(`.${e}`)||L("g",{class:i});for(;i.firstChild;)i.removeChild(i.firstChild)}))}function h(t,e,n,g,o,a=!1){var u=g-e,s=n-t,r=Math.sqrt(u*u+s*s),I=i;if(s*o>0?r0){let i=[[t+o*(A*I),e+0*M],[n-o*I*A,g-0*M]];return`M ${t} ${e} C ${i[0][0]} ${i[0][1]} ${i[1][0]} ${i[1][1]} ${n} ${g}`}{let i,r,c,L,D,y=Math.floor(n-s/2),b=Math.floor(g-u/2);if(Math.abs(u)<10){L=Math.max(e,g)+(a?35:25);let i=L-e;return D=[[t+15*o,e],[t+25*o,e+5],[t+25*o,e+i/2],[t+25*o,e+i-5],[t+15*o,e+i],[t,e+i],[n-15*o,e+i],[n-25*o,e+i-5],[n-25*o,g+(L-g)/2],[n-25*o,g+5],[n-15*o,g],[n,g]],"M "+t+" "+e+" C "+D[0][0]+" "+D[0][1]+" "+D[1][0]+" "+D[1][1]+" "+D[2][0]+" "+D[2][1]+" C "+D[3][0]+" "+D[3][1]+" "+D[4][0]+" "+D[4][1]+" "+D[5][0]+" "+D[5][1]+" h "+s+" C "+D[6][0]+" "+D[6][1]+" "+D[7][0]+" "+D[7][1]+" "+D[8][0]+" "+D[8][1]+" C "+D[9][0]+" "+D[9][1]+" "+D[10][0]+" "+D[10][1]+" "+D[11][0]+" "+D[11][1]+" "}var l=M/2,d=(g+b)/2;i=t+o*A*I,r=u>0?Math.min(d-u/2,e+l):Math.max(d-u/2,e-l),c=n-o*A*I,L=u>0?Math.max(d,g-l):Math.min(d,g+l);var j=(t+i)/2,N=u>0?1:-1;return D=[[j,e],[i,u>0?Math.max(e,r-l):Math.min(e,r+l)],[j,u>0?Math.min(b,r+l):Math.max(b,r-l)],[c,u>0?Math.max(b,L-l):Math.min(b,L+l)],[(n+c)/2,g]],D[2][1]===r+N*l&&(Math.abs(u)<10*l&&(D[1][1]=r-N*l/2,D[3][1]=L-N*l/2),D[2][0]=i),"M "+t+" "+e+" C "+D[0][0]+" "+D[0][1]+" "+D[1][0]+" "+D[1][1]+" "+i+" "+r+" S "+D[2][0]+" "+D[2][1]+" "+y+" "+b+" S "+D[3][0]+" "+D[3][1]+" "+c+" "+L+" S "+D[4][0]+" "+D[4][1]+" "+n+" "+g}}function E(t,e){for(var i=function(t){var e=[],i=t.split(/\\n /);if(i.length>1){var M=0;for(M=0;M{switch(t){case"str":return"string";case"num":return"number";case"bool":return"boolean";case"json":return"json";case"date":return"timestamp";case"bin":return"binary";case"env":return"environment";case"flow":return"flow";case"global":return"global";default:return t}},Z=["inject","change","switch","function","template","delay","trigger","link in","link out","link call","watch","complete","catch","status","comment","debug","subflow","range","filter","rbe","mqtt in","mqtt out","http in","http response","http request","websocket in","websocket out","tcp in","tcp out","udp in","udp out","tcp request","split","join","sort","batch","csv","json","xml","yaml","html","file in","file","exec"];var B=(t,e,i)=>{let M=t.name||t.label||t.info||t.text||e.name||"",A="",n="",g="",o="";switch(t.type){case"file":g="write file";case"file in":return g=g||"read file",n=t.filename,"str"!=t.filenameType&&"env"!=t.filenameType&&(n=""),"env"===t.filenameType&&(n="env."+n),"write file"===g&&"delete"===t.overwriteFile?t.name||"delete "+n:t.name||n||g;case"html":A=t.tag;break;case"tcp in":case"tcp out":case"tcp request":g="tcp:";case"udp in":case"udp out":return g=g||"udp:",n=t.host||t.addr||t.server||"",g+(n?n+":":"")+(t.port||"");case"debug":return!0!==t.console&&"true"!==t.console||(o="\t⇲"),"jsonata"===t.targetType?(t.name||"JSONata")+o:!0===t.complete||"true"===t.complete?(t.name||"msg")+o:(t.name||"msg."+(t.complete&&"false"!==t.complete?this.complete:"payload"))+o}return t.type&&t.type.startsWith("ui-")?A=t.type.replace(/^ui-/,""):t.type&&t.type.startsWith("ui_")&&(A=t.type.replace(/^ui_/,"")),A&&A.length<=32?A:M||(t.topic&&t.topic.length<=32&&Z.includes(t.type)?t.topic:t.type)};var U=(t,e,i)=>(t.name||t.label||t.info||t.text||"").replace(/(.{40,60})([ \n\t])/g,"$1\\n$2")+(t.sumPass?" ⭄":"")+(t.sumPassPrio&&0!=parseInt(t.sumPassPrio)?" ("+t.sumPassPrio+")":""),Y={base64:void 0,batch:void 0,catch:(t,e,i)=>{var M="";return t.uncaught&&(M=": uncaught"),t.scope&&(M=": "+t.scope.length),t.scope||t.uncaught||(M=": all"),t.name||t.type+M},change:t=>{function e(t,e){return t+"."+g.utils.parseContextKey(e).key}return t.name?t.name:(t._=t._||function(t,e){let i=t;switch(t){case"change.label.set":i="set {{property}}";break;case"change.label.change":i="change {{property}}";break;case"change.label.move":i="move {{property}}";break;case"change.label.delete":i="delete {{property}}";break;case"change.label.changeCount":i="change {{count}} properties"}for(var M in e)t=i.replace(new RegExp("\\{\\{"+M+"\\}\\}","g"),e[M]);return t},t.rules?1==t.rules.length?"set"===t.rules[0].t?t._("change.label.set",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):"change"===t.rules[0].t?t._("change.label.change",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):"move"===t.rules[0].t?t._("change.label.move",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):t._("change.label.delete",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):t._("change.label.changeCount",{count:t.rules.length}):"replace"===t.action?t._("change.label.set",{property:"msg."+t.property}):"change"===t.action?t._("change.label.change",{property:"msg."+t.property}):"move"===t.action?t._("change.label.move",{property:"msg."+t.property}):t._("change.label.delete",{property:"msg."+t.property}))},comment:void 0,csv:void 0,debug:void 0,exec:void 0,file:void 0,"file in":void 0,function:void 0,html:void 0,"http response":(t,e,i)=>t.name||"http"+(t.statusCode?" ("+t.statusCode+")":""),"http in":(t,e,i)=>t.name||"["+t.method+"] "+t.url,"http request":void 0,inject:t=>{var e="";if(t.once&&(e=" ¹"),(t.repeat&&0!=t.repeat||t.crontab)&&(e="\t↻"),t.name)return t.name+e;var i,M="",A="str";const n=t.props;if(n)for(var o=0;o0&&M.length<24?M+e:"inject"+e:"date"===A||"bin"===A||"env"===A?""!==i&&i.length<=16?i+":"+v(A)+e:v(A)+e:"flow"===A||"global"===A?A+"."+g.utils.parseContextKey(M).key+e:"inject"+e},join:void 0,json:void 0,junction:void 0,"link in":void 0,"link out":void 0,"link call":(t,e,i)=>{if(!t.links||0==t.links.length)return t.name||t.type;var M=void 0;return i.forEach((function(A){M||A.id==t.links[0]&&(M=(Y[A.type]||B)(A,e,i))})),t.name||M||t.type},markdown:void 0,postgresql:void 0,range:void 0,sort:void 0,split:void 0,switch:void 0,yaml:void 0,xml:void 0,BlogPages:void 0,BlogDetails:void 0,BlogPageInfo:(t,e,i)=>{if(t.name)return t.name;var M=void 0;return i.forEach((function(e){M||"link in"==e.type&&e.name.startsWith("[blog] ")&&(e.wires[0]||[]).indexOf(t.id)>-1&&(M=e.name.substring(7))})),M||t.type},PubMedium:void 0,Topic:U,Observation:U,Question:U,Thought:U,Idea:U,Analogy:U,Aphorism:U,Poesie:U,Humour:U,Treasure:U,Consequence:U,Advantage:U,Disadvantage:U,Text:U,"Blog-Post":U,Comment:U,Codebase:U,Sketch:U,Inspiration:U,Quote:U,Definition:U,Book:U,Author:U,"nnb-input-node":void 0,"nnb-layer-node":(t,e,i)=>t.name||t.actfunct+": "+t.bias+", "+t.threshold,"nnb-output-node":void 0,"nnb-backprop":void 0,"nnb-trainer":void 0,Seeker:void 0,Sink:void 0,Screenshot:void 0,Orphans:void 0,IsMobile:void 0,Navigator:void 0,DrawSVG:void 0,GetFlows:void 0,_default:B};function Q(t){const e={};let i=1e4,M=0;for(let A of t)"subflow"===A.type?e[A.id]={id:A.id,label:A.name,type:"subflow",disabled:A.disabled,order:i++}:"tab"!==A.type&&A.z&&(e[A.z]||(e[A.z]={id:A.z,label:"Flow "+(M+1),type:"tab",disabled:!1,order:M++}));const A=t.filter((t=>"tab"===t.type));let n=0;for(let t of A)e[t.id]&&(e[t.id].label=t.label||e[t.id].label,e[t.id].disabled=!!t.disabled,e[t.id].order=n++);const g=Object.keys(e).map((t=>e[t]));return g.sort(((t,e)=>t.order-e.order)),g}function G(t){Array.isArray(t)||(t=[]);const e=[...t];for(let t=0;tt.id===w));T&&"tab"===T.type&&(S=T.disabled);let f=o&&o.querySelector("svg");f=f||m(o),p(f);const O=f.querySelector(".flow_grid");if(i.gridlines&&O){for(var k=0;k<250;k++)O.append(L("line",{x1:0,x2:8e3,y1:20*k,y2:20*k,class:"grid-line"}));for(k=0;k<250;k++)O.append(L("line",{x1:20*k,x2:20*k,y1:0,y2:8e3,class:"grid-line"}))}e.forEach((function(t){if("subflow"==t.type){l["subflow:"+t.id]=t;for(var e=0;e0&&t.wires.forEach((function(t){t.forEach((function(t){b[t]=!0}))}))}));const v=f.querySelector(".flow_nodes");e.forEach((function(t){if(t.z==w||t.id==w){var o=j(t);const w=function(t){let e=!0;return"link out"!==t.type&&"link in"!==t.type||(e=!1),"junction"===t.type||"tab"===t.type||"subflow"===t.type||(!1===t.l?e=!1:!0===t.l&&(e=!0)),e}(t),m=!i.labels;var c=d(t.type);switch(t.type){case"tab":case"ui_spacer":case"ui-spacer":break;case"group":N[t.id]=t;break;case"subflow":D[t.id]={...t};for(var y=0;y1?18:16)+")"});var T=0;N.lines.forEach((function(t){var e=L("text",{y:T,class:"node-text-label"});e.textContent=t,D.appendChild(e),T+=20}))}const y=L("g",{id:"g"+Math.random().toString().substring(2)});v.appendChild(y),w&&D&&y.appendChild(D);const C=w?D?.getBBox():{width:0,height:0},z=C.width,p=C.height+13.5;let h=w?o.width>z?o.width:z:o.width,f=w?o.height>p?o.height:p:o.height;const O={x:t.x,y:t.y,w:h,h:f,outputs:(t.wires||[]).length},k=!!b[t.id];try{w?(O.w=Math.max(A,20*Math.ceil((N.width+48+(k?7:0))/20)),O.h=Math.max(6+24*N.lines.length,15*(O.outputs||0),30)):(O.w=M,O.h=Math.max(M,15*(O.outputs||0)))}catch(t){}if(O.outputs>2&&w&&D&&O.h>p){const t=(O.h-p)/2;D.setAttributeNS(null,"transform","translate(38,"+((N.lines.length>1?16:14)+t)+")")}m&&D&&(D.style.display="none"),y.prepend(L("rect",{...c,rx:5,ry:5,fill:j.color||c.fill,width:O.w,height:O.h,class:"node node-"+t.id})),y.appendChild(L("path",{d:"M5 0 h25 v"+O.h+" h-25 a 5 5 0 0 1 -5 -5 v-"+(O.h-10)+" a 5 5 0 0 1 5 -5",fill:"rgb(0,0,0)","fill-opacity":.1,stroke:"none"})),w&&y.appendChild(L("path",{d:"M 29.5 0.5 l 0 "+(O.h-1),fill:"none",stroke:"rgb(0,0,0)","stroke-opacity":.1,"stroke-width":"1px"}));const Z=g.view.tools.calculateGridSnapOffsets(O),B=t.x-O.w/2-Z.x,U=t.y-O.h/2-Z.y;if(y.setAttribute("transform",`translate(${B}, ${U})`),t.bbox=y.getBBox(),t.bbox.x=B,t.bbox.y=U,i.images){const e={x:0,y:Math.max(O.h/2-15,0),width:30,height:30},i=function(t){let e=r[t];return e||(t.startsWith("subflow:")?e=r.subflow:t.startsWith("ui-")?e=r["ui-template"]:t.startsWith("ui_")&&(e=r.ui_template)),e&&I[e]||""}(t.type);if(i)y.appendChild(L("image",{href:i,...e}));else if(t.type.startsWith("subflow:")){const t=j.icon&&I[j.icon]||I["subflow.svg"];y.appendChild(L("image",{href:t,...e}))}}(j.in&&j.in.length>0||b[t.id])&&(i.arrows?y.appendChild(L("path",{...x,transform:"translate(-3,"+(t.bbox.height/2-5)+")",d:i.arrows?"M 0,10 9,5 0,0 Z":"M -1,9.5 8,9.5 8,0.5 -1,0.5 Z",class:"red-ui-flow-port-input input-arrows","stroke-linecap":"round","stroke-linejoin":"round"})):y.appendChild(L("rect",{...x,transform:"translate(-5,"+(t.bbox.height/2-5)+")",...a,...u,class:"red-ui-flow-port-input"})));const Q={...x,...a,...u,class:"red-ui-flow-port"};if(t.wires&&Array.isArray(t.wires)){const e=1==t.wires.length?t.bbox.height/2-5:t.wires.length%2==0?3.5:4.5;for(let i=0;i0;)for(var P in R-=1,N)if(!(B.indexOf(P)>-1)){var W=N[P],J=0,F=0,V=!1;if(W.nodes.forEach((function(t){var e=(s[t]||{}).bbox;e?(J=Math.max(J,e.x-W.x+e.width),F=Math.max(F,e.y-W.y+e.height)):V=!0})),!V){var X=L("g",{id:"grpRectId"+Math.random().toString().substring(2)});X.setAttribute("transform",`translate(${W.x}, ${W.y})`),X.appendChild(L("rect",{rx:5,ry:5,width:W.w,height:W.h,fill:"none","fill-opacity":0,"stroke-width":2,stroke:"grey",class:"group-"+W.id,...W.style})),Z.prepend(X);var q=s[P];q.bbox=X.getBBox(),q.bbox.x=W.x,q.bbox.y=W.y;var K=L("g",{});if(X.appendChild(K),W.style.label&&W.name){var _=W.style["label-position"]||"nw",$=E(W.name,"group-text-label"),tt=0,et=0,it="start";if(et="n"===_[0]?15:q.bbox.height-5-16*($.lines.length-1),"w"===_[1]?(tt=5,it="start"):"e"===_[1]?(tt=q.bbox.width-5,it="end"):(tt=q.bbox.width/2,it="middle"),K.setAttribute("transform",`translate(${tt}, ${et})`),K.setAttribute("text-anchor",it),$){let t=0;$.lines.forEach((function(e){const i=L("text",{class:"group-text-label",x:0,y:t,fill:W.style.color||"grey"});i.textContent=e,K.appendChild(i),t+=16}))}}B.push(P)}}const Mt=f.querySelector(".flow_wires");var At=[],nt=Object.keys(D);for(k=0;kt.clientWidth,hasVerticalScrollbar:t.scrollHeight>t.clientHeight}}(f.parentElement);Dt.hasHorizontalScrollbar||Dt.hasVerticalScrollbar?o.classList.add("has-scrollbars"):o.classList.remove("has-scrollbars"),i.zoom&&y(f,i.container);const yt=C(f,e,i);return{svg:f.innerHTML,flowId:i.flowId,css:z(i.scope),autoScaleAndScroll:yt}}return{renderFlows:function(i,M){i=G(i);const A=c((M=H(M)).document,t.document,M.container,this),n=M.container;for(;n.firstChild;)n.removeChild(n.firstChild);const g=A.createElement("div");g.classList.add("red-ui-tabs"),n.appendChild(g);const o=function(t){const e=c(t,this).createElement("div");return e.classList.add("red-ui-workspace-chart"),t?(t.appendChild(e),e):e}(n),a=function(t){const e=c(t,this);if(!e)return null;let i=t.querySelector(".toolbar");i||(i=T(t));let M=i.querySelector(".copy-controls");if(M)return{copy:i.querySelector(".copy-flow"),download:i.querySelector(".download-flow")};M=e.createElement("div"),M.classList.add("copy-controls"),M.classList.add("button-group");const A=e.createElement("button");A.classList.add("red-ui-footer-button","copy-flow"),A.innerHTML="Copy";const n=e.createElement("button");return n.classList.add("red-ui-footer-button","download-flow"),n.innerHTML="Download",M.appendChild(A),M.appendChild(n),i&&i.appendChild(M),{copy:A,download:n}}(n);a.copy.onclick=function(t){!function(t,e,i){i=i||function(){};let M=e||[];"object"==typeof M?M=JSON.stringify(M,null,0):"string"!=typeof M&&(M=M.toString());const A=c(t&&t.target&&t.target.ownerDocument,this);if("undefined"!=typeof navigator&&navigator.clipboard)return void navigator.clipboard.writeText(M).then((function(){i(null,!0)})).catch((function(t){i(t,!1)}));const n=A.createElement("textarea");n.value=M,n.style.position="fixed",n.style.top="0",n.style.left="0";try{A.body.appendChild(n),n.focus(),n.select();const t=A.execCommand("copy");i(null,t),console.log("failed to copy",t)}catch(t){console.error("failed to copy",t)}finally{A.body.removeChild(n)}}(t,i)},a.download.onclick=function(t){!function(t,e,i,M,A){A=A||function(){};let n=e||[];"object"==typeof n?n=JSON.stringify(n,null,2):"string"!=typeof n&&(n=n.toString());const g=c(t&&t.target&&t.target.ownerDocument,this),o=new Blob([n],{type:i}),a=URL.createObjectURL(o),u=g.createElement("a");u.style.display="none",u.href=a,u.download=M,u.style.position="fixed",u.style.top="0",u.style.left="0";try{g.body.appendChild(u),u.focus(),u.click(t),URL.revokeObjectURL(a),A(null,!0)}catch(t){A(t,!1),console.error("failed to download",t)}finally{g.body.removeChild(u)}}(t,i,"application/json","flows.json")};const u=m(o);if(p(u),function(t){const e=t.parentElement,i=e.attributes;for(let t=0;tt.classList.remove("active")));return g.querySelector(`[data-flow-id="${t}"]`).classList.add("active"),M.flowId=t,R(i,M)},r=function(t,e){const o=`red-ui-tab-${e}`,a=t.label;let r=n.querySelector(`.${o}`);if(r||(r=A.createElement("div"),g.appendChild(r),r.classList.add("red-ui-tab"),r.classList.add("red-ui-tab-"+t.type),r.setAttribute("data-flow-id",t.id)),t.disabled){r.classList.add("disabled");const t=A.createElement("i");t.classList.add("red-ui-tab-disabled-icon"),r.appendChild(t)}else if("subflow"===t.type){const t=A.createElement("i");t.classList.add("red-ui-tab-subflow-icon"),r.appendChild(t)}r.title=a;const I=A.createElement("span");I.textContent=a,r.appendChild(I),r.onclick=function(e){i&&i.length&&S(u,M,M.flowId),s(t.id),i&&i.length&&function(t,e,i){const M=t.parentElement,A=i||e.flowId||"default",n=M.getAttribute(`_state_${A}_x`),g=M.getAttribute(`_state_${A}_y`),o=M.getAttribute(`_state_${A}_scale`);"string"==typeof n&&"string"==typeof g&&x(M,n,g),"string"==typeof o&&w(t.querySelector("g.outerContainer"),o)}(u,M,t.id)}};!function(t,i){const M=e+(i?"--"+i.toString():"").replace(/[^a-z0-9]/gi,"-").toLowerCase();let A=t.getElementById(M);A||(A=t.createElement("style"),A.id=M,A.innerHTML=z(i),t.head.appendChild(A))}(A,M.scope);let I=n.querySelectorAll(".red-ui-tab");I&&I.forEach((t=>t.remove()));const l=Q(i);if(l.forEach(((t,e)=>{r(t,e)})),l.length&&o.classList.add("has-tabs"),!M.flowId){const t=l.find((t=>"tab"===t.type)),e=l.find((t=>"subflow"===t.type));M.flowId=t?t.id:e?e.id:null}let d=null;return d=l.length?s(M.flowId):R(i,M),S(u,M,M.flowId),d=d||{},d.tabs=l,d.flowId=M.flowId,d.css=d.css||z(M.scope),d},renderFlow:R,normaliseOptions:H,getStyles:z}};"object"==typeof module&&module.exports?module.exports=FlowRenderer:"object"==typeof window?window.FlowRenderer=FlowRenderer:global.FlowRenderer=FlowRenderer;export default FlowRenderer; \ No newline at end of file +const FlowRenderer=function(){let t=this||{};const e="flow-renderer-css",i=.75,M=30,A=100,n=13.5,g={view:{}};g.view.tools={},g.utils={},g.view.gridSize=function(){return 20},g.view.tools.calculateGridSnapOffsets=function(t,e){0;e=e||{align:"nearest"};const i={x:0,y:0},M=g.view.gridSize(),A=t.x-(M*Math.round((t.x-t.w/2)/M)+t.w/2),n=t.x-(M*Math.round((t.x+t.w/2)/M)-t.w/2);i.x=n,"right"===e.align||("left"===e.align||Math.abs(A)"tab"!==t.type&&"subflow"!==t.type&&t.z==I));if(0===l.length)return{scale:1,scrollX:0,scrollY:0};for(let t of l){if("tab"===t.type||"subflow"===t.type||"junction"===t.type)continue;const e=t.x||0,i=t.y||0,M=j(t),A=(M.width||100)/2,n=(M.height||30)/2,g=e-A,o=i-n,I=e+A,l=i+n;a=Math.min(a,g),u=Math.min(u,o),s=Math.max(s,I),r=Math.max(r,l)}let d=1;const N=s-a,c=r-u,L=g/N,y=o/c;(N>g||c>o)&&(d=Math.min(L,y),d*=.95);d=D(d,i,M,1);let b=a,w=u;b<50&&(b=0);w<40&&(w=0);b>0&&(b-=50);w>0&&(w-=40);return b=D(b*d,0,A.scrollWidth),w=D(w*d,0,A.scrollHeight),{scale:d,scrollX:b,scrollY:w,minX:a,minY:u,maxX:s,maxY:r}}(e,i):null;return i.zoom&&M&&i.autoZoom&&w(t.querySelector("g.outerContainer"),M.scale,!0),M&&i.autoScroll&&x(t.parentElement,M.scrollX,M.scrollY,!0),M}function C(t,e,i){const M=t.parentElement,A=M.scrollLeft,n=M.scrollTop,g=b(t.querySelector("g.outerContainer")),o=i||e.flowId||"default";M.setAttribute(`_state_${o}_x`,A),M.setAttribute(`_state_${o}_y`,n),M.setAttribute(`_state_${o}_scale`,g)}function T(t){const e=c(t,this);if(!e)return null;let i=t.querySelector(".toolbar");return i||(i=e.createElement("div"),i.classList.add("toolbar"),t&&t.appendChild(i),i)}function m(t){const e=c(t,this),i=e.createElementNS("http://www.w3.org/2000/svg","svg"),M=e.createElementNS("http://www.w3.org/2000/svg","g");M.setAttribute("class","outerContainer"),i.setAttribute("style","width:8000px; height:8000px;"),i.appendChild(M);const A=["flow_grid","flow_group_elements","flow_group_select","flow_wires","flow_nodes"];for(let t of A){const i=e.createElementNS("http://www.w3.org/2000/svg","g");i.setAttribute("class",t),M.appendChild(i)}return t.appendChild(i),i}function z(t){t&&t.length&&"string"!=typeof t&&"string"==typeof t[0]&&(t=[...t].join(" "));return`\n :root {\n --red-ui-primary-background: #fff;\n --red-ui-secondary-text-color: #333;\n --red-ui-view-grid-color: #eee;\n --red-ui-view-border: 1px solid #bbbbbb;\n --red-ui-node-border: #999;\n --red-ui-node-background-default: #eee;\n --red-ui-node-icon-background-color-fill: black;\n --red-ui-node-icon-background-color-opacity: 0.1;\n --red-ui-node-label-color: #333;\n --red-ui-node-port-background: #d9d9d9;\n --red-ui-link-color: #999;\n --red-ui-workspace-button-color: #333;\n --red-ui-workspace-button-background: #f3f3f3;\n --red-ui-form-input-border-color: #ccc;\n }\n ${t=(t=t||".flow-renderer").split(" ").map((t=>`.${t}`)).join(" ").trim()} {\n position: relative;\n }\n ${t} .red-ui-workspace-chart {\n box-sizing: border-box;\n border: var(--red-ui-view-border);\n overflow: scroll;\n height: 100%;\n width: 100%;\n }\n ${t} .red-ui-workspace-chart.has-tabs {\n height: calc(100% - 34px); // 34px is the height of the tabs\n }\n ${t} svg {\n position: relative;\n width: 100%;\n height: 100%;\n min-height: 250px;\n margin: auto;\n display: block;\n border-radius: 2px;\n }\n ${t} svg {\n cursor: default;\n }\n ${t} svg .group-text-label {\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 14px;\n }\n ${t} svg .node-text-label {\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 14px;\n dominant-baseline: middle;\n }\n ${t} svg .subflow-node-text-label {\n color: rgb(85, 85, 85);\n dominant-baseline: middle;\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 10px;\n line-height: 20px;\n pointer-events: none;\n text-anchor: middle;\n user-select: none\n }\n ${t} svg .subflow-node-text-label-number {\n color: rgb(85, 85, 85);\n dominant-baseline: middle;\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n font-size: 16px;\n line-height: 20px;\n pointer-events: none;\n text-anchor: middle;\n user-select: none\n }\n\n ${t} svg .node {\n fill-opacity: 1;\n stroke-width: 1px;\n }\n ${t} svg .link {\n stroke: #999;\n stroke-width: 3;\n fill: none;\n }\n ${t} svg .link-highlight, .node-highlight {\n stroke: rgb(255, 127, 14);\n }\n ${t} svg .node-highlight {\n stroke-width: 3px;\n }\n\n ${t} svg .node-disabled {\n stroke-dasharray: 8,3;\n fill-opacity: 0.5;\n }\n ${t} svg .group-highlight {\n stroke: rgb(255, 127, 14);\n stroke-width: 4px;\n fill: rgb(255, 127, 14);\n fill-opacity: 0.2;\n }\n ${t} svg .link-disabled {\n stroke-dasharray: 10,8 !important;\n stroke-width: 2 !important;\n stroke: rgb(204, 204, 204);\n }\n ${t} svg .grid-line {\n shape-rendering: crispedges;\n stroke: rgb(238, 238, 238);\n stroke-width: 1px;\n fill: none;\n }\n ${t} svg .red-ui-flow-port {\n stroke-width: 1px;\n stroke-miterlimit: 4;\n fill: var(--red-ui-node-port-background);\n }\n ${t} svg .red-ui-flow-port-input {\n stroke-width: 1px;\n stroke-miterlimit: 4;\n fill: var(--red-ui-node-port-background);\n }\n ${t} svg .flow-render-error {\n background-color: rgb(54, 52, 52); \n color: rgb(196, 59, 59); \n width: 100%;\n }\n ${t} svg text {\n user-select: none;\n }\n ${t} .red-ui-tabs {\n display: flex;\n }\n ${t} .red-ui-tab {\n padding: 6px 12px;\n box-sizing: border-box;\n display: block;\n border: 1px solid #bbbbbb;\n border-right: none;\n background-color: #f0f0f0;\n max-width: 200px;\n max-height: 34px; /* for calculating svg height */\n width: 14%;\n overflow: hidden;\n white-space: nowrap;\n position: relative;\n margin-top: -1px;\n transition: 0.2s background-color;\n user-select: none;\n position: relative;\n z-index: 1;\n top: 1px;\n }\n ${t} .red-ui-tab-subflow-icon {\n mask-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAsIDAsIDQwLCA2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjUgMjUuOTRoN2MuNTggMCAxLS40MiAxLTF2LTJjMC0uNTgtLjQyLTEtMS0xaC03Yy0uNTggMC0xIC40Mi0xIDF2MmMwIC41OC40MiAxIDEgMXptLTE3IDEyaDdjLjU4IDAgMS0uNDIgMS0xdi0yYzAtLjU4LS40Mi0xLTEtMUg4Yy0uNTggMC0xIC40Mi0xIDF2MmMwIC41OC40MiAxIDEgMXptLS40MTYgMTFDNS42MjQgNDguOTQgNCA0Ny4zMTUgNCA0NS4zNTZWMTQuNTIyYzAtMS45NiAxLjYyNS0zLjU4MiAzLjU4NC0zLjU4MmgyNC44MzJjMS45NiAwIDMuNTg0IDEuNjIzIDMuNTg0IDMuNTgydjMwLjgzNGMwIDEuOTYtMS42MjUgMy41ODQtMy41ODQgMy41ODR6TTMyIDM2Ljk0SDE5YzAgMi4xOS0xLjgxIDQtNCA0SDd2NC40MTZjMCAuMzUuMjM1LjU4NC41ODQuNTg0aDI0LjgzMmMuMzUgMCAuNTg0LS4yMzUuNTg0LS41ODR2LTguNDE3em0xLTJ2LTZoLThjLTIuMTkgMC00LTEuODEtNC00aC0xYy00LjMzMy0uMDAyLTguNjY3LjAwNC0xMyAwdjZoOGMyLjE5IDAgNCAxLjgxIDQgNGgxM3ptMC0xNnYtNC40MThjMC0uMzUtLjIzNS0uNTgyLS41ODQtLjU4Mkg3LjU4NGMtLjM1IDAtLjU4NC4yMzMtLjU4NC41ODJ2OC40MTdjNC4zMzMuMDAyIDguNjY3LjAwMSAxMyAuMDAxaDFjMC0yLjE5IDEuODEtNCA0LTRoOHoiIGNvbG9yPSIjMDAwIiBmaWxsPSIjZmZmIi8+PC9zdmc+Cg==);\n display: inline-block;\n background-color: grey;\n margin-left: -8px;\n margin-right: 3px;\n margin-top: -1px;\n margin-bottom: 1px;\n opacity: 1;\n width: 16px;\n height: 18px;\n vertical-align: middle;\n mask-size: contain;\n mask-position: center;\n mask-repeat: no-repeat;\n }\n ${t} .red-ui-tab-disabled-icon {\n mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 1536 1792' style='&%2310;'%3E%3Cscript xmlns=''/%3E%3Cpath d='M1312 893q0-161-87-295l-754 753q137 89 297 89 111 0 211.5-43.5t173.5-116.5 116-174.5 43-212.5zM313 1192l755-754q-135-91-300-91-148 0-273 73t-198 199-73 274q0 162 89 299zM1536 893q0 157-61 300t-163.5 246-245 164-298.5 61-298.5-61-245-164-163.5-246-61-300 61-299.5 163.5-245.5 245-164 298.5-61 298.5 61 245 164 163.5 245.5 61 299.5z' fill='currentColor'/%3E%3Cscript xmlns=''/%3E%3C/svg%3E");\n display: inline-block;\n background-color: grey;\n margin-left: -8px;\n margin-right: 3px;\n margin-top: 0px;\n margin-bottom: 0px;\n opacity: 1;\n width: 16px;\n height: 16px;\n vertical-align: middle;\n mask-size: contain;\n mask-position: center;\n mask-repeat: no-repeat;\n transform: translateY(-2px);\n }\n ${t} .red-ui-tab span {\n font-size: 0.875rem;\n font-family: Helvetica Neue, Arial, Helvetica, sans-serif;\n }\n ${t} .red-ui-tab.active {\n background-color: white;\n border-bottom-color: white;\n font-weight: bold;\n }\n ${t} .red-ui-tab.disabled {\n border-top-style: dashed;\n border-left-style: dashed;\n font-style: italic;\n }\n ${t} .red-ui-tab:last-child {\n border-right: 1px solid #bbbbbb;\n }\n ${t} .red-ui-tab:last-child.disabled {\n border-right-style: dashed;\n }\n ${t} .red-ui-tab:hover {\n cursor: pointer;\n background-color: white;\n }\n /* positioning of toolbar */\n ${t} .toolbar {\n display: flex;\n flex-direction: row;\n position: absolute;\n bottom: 5px;\n right: 5px;\n opacity: 0.7;\n }\n ${t} .toolbar:hover {\n opacity: 1;\n }\n ${t}.has-scrollbars .toolbar {\n bottom: 24px;\n right: 24px;\n }\n /* styles for button groups and buttons */\n ${t} .button-group {\n display: flex;\n flex-direction: row;\n }\n ${t} .button-group button {\n user-select: none;\n box-sizing: border-box;\n display: inline-block;\n text-align: center;\n cursor: pointer;\n line-height: 22px;\n height: 24px;\n color: var(--red-ui-workspace-button-color) !important;\n background: var(--red-ui-workspace-button-background);\n text-decoration: none;\n border: 1px solid var(--red-ui-form-input-border-color);\n margin: 0px;\n padding: 0px;\n }\n ${t} .button-group button:not(:first-child) {\n border-top-left-radius: 0px;\n border-bottom-left-radius: 0px;\n border-left: none;\n }\n\n /* zoom controls */\n ${t} .zoom-controls.button-group button {\n font-size: 22px;\n width: 24px;\n }\n\n /* copy controls */\n ${t} .copy-controls.button-group {\n margin-right: 24px;\n }\n ${t} .copy-controls.button-group button {\n padding: 0px 4px;\n }\n `}function p(t){t&&["flow_grid","flow_group_elements","flow_group_select","flow_wires","flow_nodes"].forEach((e=>{const i=t.querySelector(`.${e}`)||L("g",{class:i});for(;i.firstChild;)i.removeChild(i.firstChild)}))}function h(t,e,n,g,o,a=!1){var u=g-e,s=n-t,r=Math.sqrt(u*u+s*s),I=i;if(s*o>0?r0){let i=[[t+o*(A*I),e+0*M],[n-o*I*A,g-0*M]];return`M ${t} ${e} C ${i[0][0]} ${i[0][1]} ${i[1][0]} ${i[1][1]} ${n} ${g}`}{let i,r,c,L,D,y=Math.floor(n-s/2),b=Math.floor(g-u/2);if(Math.abs(u)<10){L=Math.max(e,g)+(a?35:25);let i=L-e;return D=[[t+15*o,e],[t+25*o,e+5],[t+25*o,e+i/2],[t+25*o,e+i-5],[t+15*o,e+i],[t,e+i],[n-15*o,e+i],[n-25*o,e+i-5],[n-25*o,g+(L-g)/2],[n-25*o,g+5],[n-15*o,g],[n,g]],"M "+t+" "+e+" C "+D[0][0]+" "+D[0][1]+" "+D[1][0]+" "+D[1][1]+" "+D[2][0]+" "+D[2][1]+" C "+D[3][0]+" "+D[3][1]+" "+D[4][0]+" "+D[4][1]+" "+D[5][0]+" "+D[5][1]+" h "+s+" C "+D[6][0]+" "+D[6][1]+" "+D[7][0]+" "+D[7][1]+" "+D[8][0]+" "+D[8][1]+" C "+D[9][0]+" "+D[9][1]+" "+D[10][0]+" "+D[10][1]+" "+D[11][0]+" "+D[11][1]+" "}var l=M/2,d=(g+b)/2;i=t+o*A*I,r=u>0?Math.min(d-u/2,e+l):Math.max(d-u/2,e-l),c=n-o*A*I,L=u>0?Math.max(d,g-l):Math.min(d,g+l);var j=(t+i)/2,N=u>0?1:-1;return D=[[j,e],[i,u>0?Math.max(e,r-l):Math.min(e,r+l)],[j,u>0?Math.min(b,r+l):Math.max(b,r-l)],[c,u>0?Math.max(b,L-l):Math.min(b,L+l)],[(n+c)/2,g]],D[2][1]===r+N*l&&(Math.abs(u)<10*l&&(D[1][1]=r-N*l/2,D[3][1]=L-N*l/2),D[2][0]=i),"M "+t+" "+e+" C "+D[0][0]+" "+D[0][1]+" "+D[1][0]+" "+D[1][1]+" "+i+" "+r+" S "+D[2][0]+" "+D[2][1]+" "+y+" "+b+" S "+D[3][0]+" "+D[3][1]+" "+c+" "+L+" S "+D[4][0]+" "+D[4][1]+" "+n+" "+g}}function E(t,e){for(var i=function(t){var e=[],i=t.split(/\\n /);if(i.length>1){var M=0;for(M=0;M{switch(t){case"str":return"string";case"num":return"number";case"bool":return"boolean";case"json":return"json";case"date":return"timestamp";case"bin":return"binary";case"env":return"environment";case"flow":return"flow";case"global":return"global";default:return t}},Z=["inject","change","switch","function","template","delay","trigger","link in","link out","link call","watch","complete","catch","status","comment","debug","subflow","range","filter","rbe","mqtt in","mqtt out","http in","http response","http request","websocket in","websocket out","tcp in","tcp out","udp in","udp out","tcp request","split","join","sort","batch","csv","json","xml","yaml","html","file in","file","exec"];var B=(t,e,i)=>{let M=t.name||t.label||t.info||t.text||e.name||"",A="",n="",g="",o="";switch(t.type){case"file":g="write file";case"file in":return g=g||"read file",n=t.filename,"str"!=t.filenameType&&"env"!=t.filenameType&&(n=""),"env"===t.filenameType&&(n="env."+n),"write file"===g&&"delete"===t.overwriteFile?t.name||"delete "+n:t.name||n||g;case"html":A=t.tag;break;case"tcp in":case"tcp out":case"tcp request":g="tcp:";case"udp in":case"udp out":return g=g||"udp:",n=t.host||t.addr||t.server||"",g+(n?n+":":"")+(t.port||"");case"debug":return!0!==t.console&&"true"!==t.console||(o="\t⇲"),"jsonata"===t.targetType?(t.name||"JSONata")+o:!0===t.complete||"true"===t.complete?(t.name||"msg")+o:(t.name||"msg."+(t.complete&&"false"!==t.complete?this.complete:"payload"))+o}return t.type&&t.type.startsWith("ui-")?A=t.type.replace(/^ui-/,""):t.type&&t.type.startsWith("ui_")&&(A=t.type.replace(/^ui_/,"")),A&&A.length<=32?A:M||(t.topic&&t.topic.length<=32&&Z.includes(t.type)?t.topic:t.type)};var U=(t,e,i)=>(t.name||t.label||t.info||t.text||"").replace(/(.{40,60})([ \n\t])/g,"$1\\n$2")+(t.sumPass?" ⭄":"")+(t.sumPassPrio&&0!=parseInt(t.sumPassPrio)?" ("+t.sumPassPrio+")":""),Y={base64:void 0,batch:void 0,catch:(t,e,i)=>{var M="";return t.uncaught&&(M=": uncaught"),t.scope&&(M=": "+t.scope.length),t.scope||t.uncaught||(M=": all"),t.name||t.type+M},change:t=>{function e(t,e){return t+"."+g.utils.parseContextKey(e).key}return t.name?t.name:(t._=t._||function(t,e){let i=t;switch(t){case"change.label.set":i="set {{property}}";break;case"change.label.change":i="change {{property}}";break;case"change.label.move":i="move {{property}}";break;case"change.label.delete":i="delete {{property}}";break;case"change.label.changeCount":i="change {{count}} properties"}for(var M in e)t=i.replace(new RegExp("\\{\\{"+M+"\\}\\}","g"),e[M]);return t},t.rules?1==t.rules.length?"set"===t.rules[0].t?t._("change.label.set",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):"change"===t.rules[0].t?t._("change.label.change",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):"move"===t.rules[0].t?t._("change.label.move",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):t._("change.label.delete",{property:e(t.rules[0].pt||"msg",t.rules[0].p)}):t._("change.label.changeCount",{count:t.rules.length}):"replace"===t.action?t._("change.label.set",{property:"msg."+t.property}):"change"===t.action?t._("change.label.change",{property:"msg."+t.property}):"move"===t.action?t._("change.label.move",{property:"msg."+t.property}):t._("change.label.delete",{property:"msg."+t.property}))},comment:void 0,csv:void 0,debug:void 0,exec:void 0,file:void 0,"file in":void 0,function:void 0,html:void 0,"http response":(t,e,i)=>t.name||"http"+(t.statusCode?" ("+t.statusCode+")":""),"http in":(t,e,i)=>t.name||"["+t.method+"] "+t.url,"http request":void 0,inject:t=>{var e="";if(t.once&&(e=" ¹"),(t.repeat&&0!=t.repeat||t.crontab)&&(e="\t↻"),t.name)return t.name+e;var i,M="",A="str";const n=t.props;if(n)for(var o=0;o0&&M.length<24?M+e:"inject"+e:"date"===A||"bin"===A||"env"===A?""!==i&&i.length<=16?i+":"+v(A)+e:v(A)+e:"flow"===A||"global"===A?A+"."+g.utils.parseContextKey(M).key+e:"inject"+e},join:void 0,json:void 0,junction:void 0,"link in":void 0,"link out":void 0,"link call":(t,e,i)=>{if(!t.links||0==t.links.length)return t.name||t.type;var M=void 0;return i.forEach((function(A){M||A.id==t.links[0]&&(M=(Y[A.type]||B)(A,e,i))})),t.name||M||t.type},markdown:void 0,postgresql:void 0,range:void 0,sort:void 0,split:void 0,switch:void 0,yaml:void 0,xml:void 0,BlogPages:void 0,BlogDetails:void 0,BlogPageInfo:(t,e,i)=>{if(t.name)return t.name;var M=void 0;return i.forEach((function(e){M||"link in"==e.type&&e.name.startsWith("[blog] ")&&(e.wires[0]||[]).indexOf(t.id)>-1&&(M=e.name.substring(7))})),M||t.type},PubMedium:void 0,Topic:U,Observation:U,Question:U,Thought:U,Idea:U,Analogy:U,Aphorism:U,Poesie:U,Humour:U,Treasure:U,Consequence:U,Advantage:U,Disadvantage:U,Text:U,"Blog-Post":U,Comment:U,Codebase:U,Sketch:U,Inspiration:U,Quote:U,Definition:U,Book:U,Author:U,"nnb-input-node":void 0,"nnb-layer-node":(t,e,i)=>t.name||t.actfunct+": "+t.bias+", "+t.threshold,"nnb-output-node":void 0,"nnb-backprop":void 0,"nnb-trainer":void 0,Seeker:void 0,Sink:void 0,Screenshot:void 0,Orphans:void 0,IsMobile:void 0,Navigator:void 0,DrawSVG:void 0,GetFlows:void 0,_default:B};function Q(t){const e={};let i=1e4,M=0;for(let A of t)"subflow"===A.type?e[A.id]={id:A.id,label:A.name,type:"subflow",disabled:A.disabled,order:i++}:"tab"!==A.type&&A.z&&(e[A.z]||(e[A.z]={id:A.z,label:"Flow "+(M+1),type:"tab",disabled:!1,order:M++}));const A=t.filter((t=>"tab"===t.type));let n=0;for(let t of A)e[t.id]&&(e[t.id].label=t.label||e[t.id].label,e[t.id].disabled=!!t.disabled,e[t.id].order=n++);const g=Object.keys(e).map((t=>e[t]));return g.sort(((t,e)=>t.order-e.order)),g}function G(t){Array.isArray(t)||(t=[]);const e=[...t];for(let t=0;tt.id===w));T&&"tab"===T.type&&(C=T.disabled);let f=o&&o.querySelector("svg");f=f||m(o),p(f);const O=f.querySelector(".flow_grid");if(i.gridLines&&O){for(var k=0;k<250;k++)O.append(L("line",{x1:0,x2:8e3,y1:20*k,y2:20*k,class:"grid-line"}));for(k=0;k<250;k++)O.append(L("line",{x1:20*k,x2:20*k,y1:0,y2:8e3,class:"grid-line"}))}e.forEach((function(t){if("subflow"==t.type){l["subflow:"+t.id]=t;for(var e=0;e0&&t.wires.forEach((function(t){t.forEach((function(t){b[t]=!0}))}))}));const v=f.querySelector(".flow_nodes");e.forEach((function(t){if(t.z==w||t.id==w){var o=j(t);const w=function(t){let e=!0;return"link out"!==t.type&&"link in"!==t.type||(e=!1),"junction"===t.type||"tab"===t.type||"subflow"===t.type||(!1===t.l?e=!1:!0===t.l&&(e=!0)),e}(t),m=!i.labels;var c=d(t.type);switch(t.type){case"tab":case"ui_spacer":case"ui-spacer":break;case"group":N[t.id]=t;break;case"subflow":D[t.id]={...t};for(var y=0;y1?18:16)+")"});var T=0;N.lines.forEach((function(t){var e=L("text",{y:T,class:"node-text-label"});e.textContent=t,D.appendChild(e),T+=20}))}const y=L("g",{id:"g"+Math.random().toString().substring(2)});v.appendChild(y),w&&D&&y.appendChild(D);const S=w?D?.getBBox():{width:0,height:0},z=S.width,p=S.height+13.5;let h=w?o.width>z?o.width:z:o.width,f=w?o.height>p?o.height:p:o.height;const O={x:t.x,y:t.y,w:h,h:f,outputs:(t.wires||[]).length},k=!!b[t.id];try{w?(O.w=Math.max(A,20*Math.ceil((N.width+48+(k?7:0))/20)),O.h=Math.max(6+24*N.lines.length,15*(O.outputs||0),30)):(O.w=M,O.h=Math.max(M,15*(O.outputs||0)))}catch(t){}if(O.outputs>2&&w&&D&&O.h>p){const t=(O.h-p)/2;D.setAttributeNS(null,"transform","translate(38,"+((N.lines.length>1?16:14)+t)+")")}m&&D&&(D.style.display="none"),y.prepend(L("rect",{...c,rx:5,ry:5,fill:j.color||c.fill,width:O.w,height:O.h,class:"node node-"+t.id})),y.appendChild(L("path",{d:"M5 0 h25 v"+O.h+" h-25 a 5 5 0 0 1 -5 -5 v-"+(O.h-10)+" a 5 5 0 0 1 5 -5",fill:"rgb(0,0,0)","fill-opacity":.1,stroke:"none"})),w&&y.appendChild(L("path",{d:"M 29.5 0.5 l 0 "+(O.h-1),fill:"none",stroke:"rgb(0,0,0)","stroke-opacity":.1,"stroke-width":"1px"}));const Z=g.view.tools.calculateGridSnapOffsets(O),B=t.x-O.w/2-Z.x,U=t.y-O.h/2-Z.y;if(y.setAttribute("transform",`translate(${B}, ${U})`),t.bbox=y.getBBox(),t.bbox.x=B,t.bbox.y=U,i.images){const e={x:0,y:Math.max(O.h/2-15,0),width:30,height:30},i=function(t){let e=r[t];return e||(t.startsWith("subflow:")?e=r.subflow:t.startsWith("ui-")?e=r["ui-template"]:t.startsWith("ui_")&&(e=r.ui_template)),e&&I[e]||""}(t.type);if(i)y.appendChild(L("image",{href:i,...e}));else if(t.type.startsWith("subflow:")){const t=j.icon&&I[j.icon]||I["subflow.svg"];y.appendChild(L("image",{href:t,...e}))}}(j.in&&j.in.length>0||b[t.id])&&(i.arrows?y.appendChild(L("path",{...x,transform:"translate(-3,"+(t.bbox.height/2-5)+")",d:i.arrows?"M 0,10 9,5 0,0 Z":"M -1,9.5 8,9.5 8,0.5 -1,0.5 Z",class:"red-ui-flow-port-input input-arrows","stroke-linecap":"round","stroke-linejoin":"round"})):y.appendChild(L("rect",{...x,transform:"translate(-5,"+(t.bbox.height/2-5)+")",...a,...u,class:"red-ui-flow-port-input"})));const Q={...x,...a,...u,class:"red-ui-flow-port"};if(t.wires&&Array.isArray(t.wires)){const e=1==t.wires.length?t.bbox.height/2-5:t.wires.length%2==0?3.5:4.5;for(let i=0;i0;)for(var P in R-=1,N)if(!(B.indexOf(P)>-1)){var W=N[P],J=0,F=0,V=!1;if(W.nodes.forEach((function(t){var e=(s[t]||{}).bbox;e?(J=Math.max(J,e.x-W.x+e.width),F=Math.max(F,e.y-W.y+e.height)):V=!0})),!V){var X=L("g",{id:"grpRectId"+Math.random().toString().substring(2)});X.setAttribute("transform",`translate(${W.x}, ${W.y})`),X.appendChild(L("rect",{rx:5,ry:5,width:W.w,height:W.h,fill:"none","fill-opacity":0,"stroke-width":2,stroke:"grey",class:"group-"+W.id,...W.style})),Z.prepend(X);var q=s[P];q.bbox=X.getBBox(),q.bbox.x=W.x,q.bbox.y=W.y;var K=L("g",{});if(X.appendChild(K),W.style.label&&W.name){var _=W.style["label-position"]||"nw",$=E(W.name,"group-text-label"),tt=0,et=0,it="start";if(et="n"===_[0]?15:q.bbox.height-5-16*($.lines.length-1),"w"===_[1]?(tt=5,it="start"):"e"===_[1]?(tt=q.bbox.width-5,it="end"):(tt=q.bbox.width/2,it="middle"),K.setAttribute("transform",`translate(${tt}, ${et})`),K.setAttribute("text-anchor",it),$){let t=0;$.lines.forEach((function(e){const i=L("text",{class:"group-text-label",x:0,y:t,fill:W.style.color||"grey"});i.textContent=e,K.appendChild(i),t+=16}))}}B.push(P)}}const Mt=f.querySelector(".flow_wires");var At=[],nt=Object.keys(D);for(k=0;kt.clientWidth,hasVerticalScrollbar:t.scrollHeight>t.clientHeight}}(f.parentElement);Dt.hasHorizontalScrollbar||Dt.hasVerticalScrollbar?o.classList.add("has-scrollbars"):o.classList.remove("has-scrollbars"),i.zoom&&y(f,i.container);const yt=S(f,e,i);return{svg:f.innerHTML,flowId:i.flowId,css:z(i.scope),autoScaleAndScroll:yt}}return{renderFlows:function(i,M){i=G(i);const A=c((M=H(M)).document,t.document,M.container,this),n=M.container;for(;n.firstChild;)n.removeChild(n.firstChild);const g=A.createElement("div");g.classList.add("red-ui-tabs"),n.appendChild(g);const o=function(t){const e=c(t,this).createElement("div");return e.classList.add("red-ui-workspace-chart"),t?(t.appendChild(e),e):e}(n),a=function(t){const e=c(t,this);if(!e)return null;let i=t.querySelector(".toolbar");i||(i=T(t));let M=i.querySelector(".copy-controls");if(M)return{copy:i.querySelector(".copy-flow"),download:i.querySelector(".download-flow")};M=e.createElement("div"),M.classList.add("copy-controls"),M.classList.add("button-group");const A=e.createElement("button");A.classList.add("red-ui-footer-button","copy-flow"),A.innerHTML="Copy";const n=e.createElement("button");return n.classList.add("red-ui-footer-button","download-flow"),n.innerHTML="Download",M.appendChild(A),M.appendChild(n),i&&i.appendChild(M),{copy:A,download:n}}(n);a.copy.onclick=function(t){!function(t,e,i){i=i||function(){};let M=e||[];"object"==typeof M?M=JSON.stringify(M,null,0):"string"!=typeof M&&(M=M.toString());const A=c(t&&t.target&&t.target.ownerDocument,this);if("undefined"!=typeof navigator&&navigator.clipboard)return void navigator.clipboard.writeText(M).then((function(){i(null,!0)})).catch((function(t){i(t,!1)}));const n=A.createElement("textarea");n.value=M,n.style.position="fixed",n.style.top="0",n.style.left="0";try{A.body.appendChild(n),n.focus(),n.select();const t=A.execCommand("copy");i(null,t),console.log("failed to copy",t)}catch(t){console.error("failed to copy",t)}finally{A.body.removeChild(n)}}(t,i)},a.download.onclick=function(t){!function(t,e,i,M,A){A=A||function(){};let n=e||[];"object"==typeof n?n=JSON.stringify(n,null,2):"string"!=typeof n&&(n=n.toString());const g=c(t&&t.target&&t.target.ownerDocument,this),o=new Blob([n],{type:i}),a=URL.createObjectURL(o),u=g.createElement("a");u.style.display="none",u.href=a,u.download=M,u.style.position="fixed",u.style.top="0",u.style.left="0";try{g.body.appendChild(u),u.focus(),u.click(t),URL.revokeObjectURL(a),A(null,!0)}catch(t){A(t,!1),console.error("failed to download",t)}finally{g.body.removeChild(u)}}(t,i,"application/json","flows.json")};const u=m(o);if(p(u),function(t){const e=t.parentElement,i=e.attributes;for(let t=0;tt.classList.remove("active")));return g.querySelector(`[data-flow-id="${t}"]`).classList.add("active"),M.flowId=t,R(i,M)},r=function(t,e){const o=`red-ui-tab-${e}`,a=t.label;let r=n.querySelector(`.${o}`);if(r||(r=A.createElement("div"),g.appendChild(r),r.classList.add("red-ui-tab"),r.classList.add("red-ui-tab-"+t.type),r.setAttribute("data-flow-id",t.id)),t.disabled){r.classList.add("disabled");const t=A.createElement("i");t.classList.add("red-ui-tab-disabled-icon"),r.appendChild(t)}else if("subflow"===t.type){const t=A.createElement("i");t.classList.add("red-ui-tab-subflow-icon"),r.appendChild(t)}r.title=a;const I=A.createElement("span");I.textContent=a,r.appendChild(I),r.onclick=function(e){i&&i.length&&C(u,M,M.flowId),s(t.id),i&&i.length&&function(t,e,i){const M=t.parentElement,A=i||e.flowId||"default",n=M.getAttribute(`_state_${A}_x`),g=M.getAttribute(`_state_${A}_y`),o=M.getAttribute(`_state_${A}_scale`);"string"==typeof n&&"string"==typeof g&&x(M,n,g),"string"==typeof o&&w(t.querySelector("g.outerContainer"),o)}(u,M,t.id)}};!function(t,i){const M=e+(i?"--"+i.toString():"").replace(/[^a-z0-9]/gi,"-").toLowerCase();let A=t.getElementById(M);A||(A=t.createElement("style"),A.id=M,A.innerHTML=z(i),t.head.appendChild(A))}(A,M.scope);let I=n.querySelectorAll(".red-ui-tab");I&&I.forEach((t=>t.remove()));const l=Q(i);if(l.forEach(((t,e)=>{r(t,e)})),l.length&&o.classList.add("has-tabs"),!M.flowId){const t=l.find((t=>"tab"===t.type)),e=l.find((t=>"subflow"===t.type));M.flowId=t?t.id:e?e.id:null}let d=null;return d=l.length?s(M.flowId):R(i,M),C(u,M,M.flowId),d=d||{},d.tabs=l,d.flowId=M.flowId,d.css=d.css||z(M.scope),d},renderFlow:R,normaliseOptions:H,getStyles:z}};"object"==typeof module&&module.exports?module.exports=FlowRenderer:"object"==typeof window?window.FlowRenderer=FlowRenderer:global.FlowRenderer=FlowRenderer;export default FlowRenderer; \ No newline at end of file From 1b0c6341cf880c287a8b3926d813cb237cdd9847 Mon Sep 17 00:00:00 2001 From: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com> Date: Tue, 30 Apr 2024 21:01:43 +0100 Subject: [PATCH 3/3] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6741206..85f1322 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ const container3 = document.getElementById('nr-flow-3'); const flow = [{"id": "1001", "type": "inject", "x": 100, "y": 40, "wires": [["1002"]]}, {"id": "1002", "type": "debug", "x":300, "y": 40}] renderer.renderFlows(flow, { container: container3, - scope: 'my-scope', // scope for CSS + scope: 'custom-css-scope', // scope for CSS gridLines: true, // show gridLines images: true, // show images linkLines: false, // show link lines