From c13b8266ddbbc0d5a077a34dae0caec2e84bb964 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 11 Apr 2024 17:05:10 +0100 Subject: [PATCH] Prevent subflow being added to itself --- .../@node-red/editor-client/src/js/ui/view.js | 225 +++++++++--------- 1 file changed, 119 insertions(+), 106 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index a71daaea1..a2571dc28 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -646,120 +646,128 @@ RED.view = (function() { } d3.event = event; var selected_tool = $(ui.draggable[0]).attr("data-palette-type"); - var result = createNode(selected_tool); - if (!result) { - return; - } - var historyEvent = result.historyEvent; - var nn = RED.nodes.add(result.node); - - var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label"); - if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) { - nn.l = showLabel; - } - - var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0)); - var helperWidth = ui.helper.width(); - var helperHeight = ui.helper.height(); - var mousePos = d3.touches(this)[0]||d3.mouse(this); - try { - var isLink = (nn.type === "link in" || nn.type === "link out") - var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink; - - var label = RED.utils.getNodeLabel(nn, nn.type); - var labelParts = getLabelParts(label, "red-ui-flow-node-label"); - if (hideLabel) { - nn.w = node_height; - nn.h = Math.max(node_height,(nn.outputs || 0) * 15); - } else { - nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) ); - nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30); + var result = createNode(selected_tool); + if (!result) { + return; } - } catch(err) { - } + var historyEvent = result.historyEvent; + var nn = RED.nodes.add(result.node); - mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]); - mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]); - mousePos[1] /= scaleFactor; - mousePos[0] /= scaleFactor; + var showLabel = RED.utils.getMessageProperty(RED.settings.get('editor'),"view.view-node-show-label"); + if (showLabel !== undefined && (nn._def.hasOwnProperty("showLabel")?nn._def.showLabel:true) && !nn._def.defaults.hasOwnProperty("l")) { + nn.l = showLabel; + } - nn.x = mousePos[0]; - nn.y = mousePos[1]; + var helperOffset = d3.touches(ui.helper.get(0))[0]||d3.mouse(ui.helper.get(0)); + var helperWidth = ui.helper.width(); + var helperHeight = ui.helper.height(); + var mousePos = d3.touches(this)[0]||d3.mouse(this); - var minX = nn.w/2 -5; - if (nn.x < minX) { - nn.x = minX; - } - var minY = nn.h/2 -5; - if (nn.y < minY) { - nn.y = minY; - } - var maxX = space_width -nn.w/2 +5; - if (nn.x > maxX) { - nn.x = maxX; - } - var maxY = space_height -nn.h +5; - if (nn.y > maxY) { - nn.y = maxY; - } + try { + var isLink = (nn.type === "link in" || nn.type === "link out") + var hideLabel = nn.hasOwnProperty('l')?!nn.l : isLink; - if (snapGrid) { - var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn); - nn.x -= gridOffset.x; - nn.y -= gridOffset.y; - } + var label = RED.utils.getNodeLabel(nn, nn.type); + var labelParts = getLabelParts(label, "red-ui-flow-node-label"); + if (hideLabel) { + nn.w = node_height; + nn.h = Math.max(node_height,(nn.outputs || 0) * 15); + } else { + nn.w = Math.max(node_width,20*(Math.ceil((labelParts.width+50+(nn._def.inputs>0?7:0))/20)) ); + nn.h = Math.max(6+24*labelParts.lines.length,(nn.outputs || 0) * 15, 30); + } + } catch(err) { + } - var linkToSplice = $(ui.helper).data("splice"); - if (linkToSplice) { - spliceLink(linkToSplice, nn, historyEvent) - } + mousePos[1] += this.scrollTop + ((helperHeight/2)-helperOffset[1]); + mousePos[0] += this.scrollLeft + ((helperWidth/2)-helperOffset[0]); + mousePos[1] /= scaleFactor; + mousePos[0] /= scaleFactor; + + nn.x = mousePos[0]; + nn.y = mousePos[1]; + + var minX = nn.w/2 -5; + if (nn.x < minX) { + nn.x = minX; + } + var minY = nn.h/2 -5; + if (nn.y < minY) { + nn.y = minY; + } + var maxX = space_width -nn.w/2 +5; + if (nn.x > maxX) { + nn.x = maxX; + } + var maxY = space_height -nn.h +5; + if (nn.y > maxY) { + nn.y = maxY; + } + + if (snapGrid) { + var gridOffset = RED.view.tools.calculateGridSnapOffsets(nn); + nn.x -= gridOffset.x; + nn.y -= gridOffset.y; + } + + var linkToSplice = $(ui.helper).data("splice"); + if (linkToSplice) { + spliceLink(linkToSplice, nn, historyEvent) + } + + var group = $(ui.helper).data("group"); + if (group) { + var oldX = group.x; + var oldY = group.y; + RED.group.addToGroup(group, nn); + var moveEvent = null; + if ((group.x !== oldX) || + (group.y !== oldY)) { + moveEvent = { + t: "move", + nodes: [{n: group, + ox: oldX, oy: oldY, + dx: group.x -oldX, + dy: group.y -oldY}], + dirty: true + }; + } + historyEvent = { + t: 'multi', + events: [historyEvent], - var group = $(ui.helper).data("group"); - if (group) { - var oldX = group.x; - var oldY = group.y; - RED.group.addToGroup(group, nn); - var moveEvent = null; - if ((group.x !== oldX) || - (group.y !== oldY)) { - moveEvent = { - t: "move", - nodes: [{n: group, - ox: oldX, oy: oldY, - dx: group.x -oldX, - dy: group.y -oldY}], - dirty: true }; + if (moveEvent) { + historyEvent.events.push(moveEvent) + } + historyEvent.events.push({ + t: "addToGroup", + group: group, + nodes: nn + }) } - historyEvent = { - t: 'multi', - events: [historyEvent], - }; - if (moveEvent) { - historyEvent.events.push(moveEvent) + RED.history.push(historyEvent); + RED.editor.validateNode(nn); + RED.nodes.dirty(true); + // auto select dropped node - so info shows (if visible) + clearSelection(); + nn.selected = true; + movingSet.add(nn); + updateActiveNodes(); + updateSelection(); + redraw(); + + if (nn._def.autoedit) { + RED.editor.edit(nn); + } + } catch (error) { + if (error.code != "NODE_RED") { + RED.notify(RED._("notification.error",{message:error.toString()}),"error"); + } else { + RED.notify(RED._("notification.error",{message:error.message}),"error"); } - historyEvent.events.push({ - t: "addToGroup", - group: group, - nodes: nn - }) - } - - RED.history.push(historyEvent); - RED.editor.validateNode(nn); - RED.nodes.dirty(true); - // auto select dropped node - so info shows (if visible) - clearSelection(); - nn.selected = true; - movingSet.add(nn); - updateActiveNodes(); - updateSelection(); - redraw(); - - if (nn._def.autoedit) { - RED.editor.edit(nn); } } }); @@ -6063,14 +6071,19 @@ RED.view = (function() { function createNode(type, x, y, z) { const wasDirty = RED.nodes.dirty() var m = /^subflow:(.+)$/.exec(type); - var activeSubflow = z ? RED.nodes.subflow(z) : null; + var activeSubflow = (z || RED.workspaces.active()) ? RED.nodes.subflow(z || RED.workspaces.active()) : null; + if (activeSubflow && m) { var subflowId = m[1]; + let err if (subflowId === activeSubflow.id) { - throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddSubflowToItself") })) + err = new Error(RED._("notification.errors.cannotAddSubflowToItself")) + } else if (RED.nodes.subflowContains(m[1], activeSubflow.id)) { + err = new Error(RED._("notification.errors.cannotAddCircularReference")) } - if (RED.nodes.subflowContains(m[1], activeSubflow.id)) { - throw new Error(RED._("notification.error", { message: RED._("notification.errors.cannotAddCircularReference") })) + if (err) { + err.code = 'NODE_RED' + throw err } }