diff --git a/src/canvas/FloatingRenderLink.ts b/src/canvas/FloatingRenderLink.ts index 2b986fb70..780a2db37 100644 --- a/src/canvas/FloatingRenderLink.ts +++ b/src/canvas/FloatingRenderLink.ts @@ -96,6 +96,15 @@ export class FloatingRenderLink implements RenderLink { this.fromPos = fromReroute.pos } + canConnectToReroute(reroute: Reroute): boolean { + if (this.toType === "input") { + if (reroute.origin_id === this.inputNode?.id) return false + } else { + if (reroute.origin_id === this.outputNode?.id) return false + } + return true + } + connectToInput(node: LGraphNode, input: INodeInputSlot, _events?: LinkConnectorEventTarget): void { const floatingLink = this.link floatingLink.target_id = node.id diff --git a/src/canvas/LinkConnector.ts b/src/canvas/LinkConnector.ts index d38095a97..83a69d987 100644 --- a/src/canvas/LinkConnector.ts +++ b/src/canvas/LinkConnector.ts @@ -538,6 +538,7 @@ export class LinkConnector { for (const renderLink of this.renderLinks) { if (renderLink.toType !== "output") continue + if (!renderLink.canConnectToReroute(reroute)) continue if (isValidConnectionToOutput(renderLink, node, output)) return true } } diff --git a/src/canvas/MovingRenderLink.ts b/src/canvas/MovingRenderLink.ts index 5d779371c..834f6564f 100644 --- a/src/canvas/MovingRenderLink.ts +++ b/src/canvas/MovingRenderLink.ts @@ -86,6 +86,15 @@ export class MovingRenderLink implements RenderLink { this.fromSlotIndex = this.toType === "input" ? outputIndex : inputIndex } + canConnectToReroute(reroute: Reroute): boolean { + if (this.toType === "input") { + if (reroute.origin_id === this.inputNode.id) return false + } else { + if (reroute.origin_id === this.outputNode.id) return false + } + return true + } + connectToInput(inputNode: LGraphNode, input: INodeInputSlot, events: LinkConnectorEventTarget): LLink | null | undefined { if (input === this.inputSlot) return diff --git a/src/canvas/ToOutputRenderLink.ts b/src/canvas/ToOutputRenderLink.ts index f68eea391..585156aec 100644 --- a/src/canvas/ToOutputRenderLink.ts +++ b/src/canvas/ToOutputRenderLink.ts @@ -31,6 +31,11 @@ export class ToOutputRenderLink implements RenderLink { : this.node.getInputPos(inputIndex) } + canConnectToReroute(reroute: Reroute): boolean { + if (reroute.origin_id === this.node.id) return false + return true + } + connectToOutput(node: LGraphNode, output: INodeOutputSlot, events: LinkConnectorEventTarget) { const { node: inputNode, fromSlot, fromReroute } = this if (inputNode) return diff --git a/test/LinkConnector.integration.test.ts b/test/LinkConnector.integration.test.ts index aaca24148..bbda41c70 100644 --- a/test/LinkConnector.integration.test.ts +++ b/test/LinkConnector.integration.test.ts @@ -361,6 +361,37 @@ describe("LinkConnector Integration", () => { validateIntegrityFloatingRemoved() }) + + test("Should prevent dragging from an output to a child reroute", ({ graph, connector, floatingReroute }) => { + const manyOutputsNode = graph.getNodeById(4)! + + const reroute7 = graph.reroutes.get(7)! + const reroute10 = graph.reroutes.get(10)! + const reroute13 = graph.reroutes.get(13)! + + const canvasX = reroute7.pos[0] + const canvasY = reroute7.pos[1] + const reroute7Event = { canvasX, canvasY } as any + + const toSortedRerouteChain = (linkIds: number[]) => linkIds + .map(x => graph.links.get(x)!) + .map(x => LLink.getReroutes(graph, x)) + .sort((a, b) => a.at(-1)!.id - b.at(-1)!.id) + + const reroutesBefore = toSortedRerouteChain(manyOutputsNode.outputs[0].links!) + + connector.moveOutputLink(graph, manyOutputsNode.outputs[0]) + expect(connector.isRerouteValidDrop(reroute7)).toBe(false) + expect(connector.isRerouteValidDrop(reroute10)).toBe(false) + expect(connector.isRerouteValidDrop(reroute13)).toBe(false) + connector.dropLinks(graph, reroute7Event) + + const reroutesAfter = toSortedRerouteChain(manyOutputsNode.outputs[0].links!) + expect(reroutesAfter).toEqual(reroutesBefore) + + expect(graph.floatingLinks.size).toBe(1) + expect(floatingReroute.linkIds.size).toBe(0) + }) }) describe("Floating links", () => {