From a8390965825b9fdc90960849c213abe1ac1fedcf Mon Sep 17 00:00:00 2001 From: Sven Carstensen Date: Tue, 10 Nov 2026 17:03:12 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20Canvas-Verschieben=20stabilisiert=20und?= =?UTF-8?q?=20Version=20auf=200.9.5=20erh=C3=B6ht?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- src/main/frontend/node-editor/node-editor.js | 67 ++++++++++++++------ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index b7e49bb..f66424c 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ de.assecutor workflow-editor - 0.9.3 + 0.9.5 Workflow Editor n8n-inspired editor for task list workflows diff --git a/src/main/frontend/node-editor/node-editor.js b/src/main/frontend/node-editor/node-editor.js index 3e304d6..6eb8aad 100644 --- a/src/main/frontend/node-editor/node-editor.js +++ b/src/main/frontend/node-editor/node-editor.js @@ -329,7 +329,9 @@ function attach(host) { host.classList.add('task-list-editor'); host.innerHTML = ''; const container = document.createElement('div'); - container.className = 'task-list-editor-container'; + // Drawflow prüft beim Drag-Start nur classList[0]. Nach dem Verschieben + // liegt der freie Hintergrund oft außerhalb des transformierten .drawflow. + container.className = 'parent-drawflow task-list-editor-container'; container.style.width = '100%'; container.style.height = '100%'; host.appendChild(container); @@ -476,11 +478,18 @@ function attach(host) { selectConnection(state, path); }, true); - // Rechte Maustaste: auf einem Knoten wird der Knoten verschoben (Drawflow - // zieht Knoten nur mit links), auf dem freien Canvas wird die gesamte - // Ansicht verschoben (Panning). + // Panning mit links und rechts über dieselben dokumentweiten Handler: + // Drawflow hört selbst nur am Container und verliert beim Verlassen des + // Canvas insbesondere das mouseup. Seine Auswahl-Logik bleibt erhalten. let rightDrag = null; - let rightPan = null; + let canvasPan = null; + editor.on('clickEnd', e => { + if (e.type !== 'mousedown' || e.button !== 0 || !editor.editor_selected) return; + editor.editor_selected = false; + canvasPan = { lastX: e.clientX, lastY: e.clientY, button: 0 }; + }); + + // Rechte Maustaste: Knoten verschieben oder auf freiem Canvas pannen. container.addEventListener('mousedown', e => { if (e.button !== 2) return; e.preventDefault(); @@ -494,18 +503,30 @@ function attach(host) { lastY: e.clientY }; } else { - rightPan = { lastX: e.clientX, lastY: e.clientY }; + canvasPan = { lastX: e.clientX, lastY: e.clientY, button: 2 }; } }, true); - const onRightMove = e => { - if (rightPan) { - editor.canvas_x += e.clientX - rightPan.lastX; - editor.canvas_y += e.clientY - rightPan.lastY; - rightPan.lastX = e.clientX; - rightPan.lastY = e.clientY; - editor.precanvas.style.transform = - 'translate(' + editor.canvas_x + 'px, ' + editor.canvas_y + 'px) scale(' + editor.zoom + ')'; + const moveCanvas = e => { + editor.canvas_x += e.clientX - canvasPan.lastX; + editor.canvas_y += e.clientY - canvasPan.lastY; + canvasPan.lastX = e.clientX; + canvasPan.lastY = e.clientY; + editor.precanvas.style.transform = + 'translate(' + editor.canvas_x + 'px, ' + editor.canvas_y + 'px) scale(' + editor.zoom + ')'; + editor.dispatch('translate', { x: editor.canvas_x, y: editor.canvas_y }); + }; + const onDragMove = e => { + if (!canvasPan && !rightDrag) return; + // Auch ein außerhalb des Browserfensters verlorenes mouseup abfangen. + const buttonMask = canvasPan?.button === 0 ? 1 : 2; + if (!(e.buttons & buttonMask)) { + onDragEnd(); + return; + } + if (canvasPan) { + e.preventDefault(); + moveCanvas(e); return; } if (!rightDrag) return; @@ -521,15 +542,20 @@ function attach(host) { if (data) { data.pos_x = newLeft; data.pos_y = newTop; } editor.updateConnectionNodes('node-' + rightDrag.id); }; - const onRightUp = () => { + const onDragEnd = e => { + if (e?.type === 'mouseup') { + if (e.button !== (canvasPan?.button ?? 2)) return; + if (canvasPan) moveCanvas(e); + } // Ein per Rechts-Drag verschobener Knoten löst Drawflows nodeMoved // nicht aus -> Undo-Schnappschuss hier ablegen. if (rightDrag && rightDrag.moved) recordHistory(state); rightDrag = null; - rightPan = null; + canvasPan = null; }; - document.addEventListener('mousemove', onRightMove); - document.addEventListener('mouseup', onRightUp); + document.addEventListener('mousemove', onDragMove, true); + document.addEventListener('mouseup', onDragEnd, true); + window.addEventListener('blur', onDragEnd); // Rechts dient nur zum Verschieben: Browser-Kontextmenü unterdrücken und // das Event in der Capture-Phase stoppen, bevor Drawflows eigener @@ -598,8 +624,9 @@ function attach(host) { } document.removeEventListener('keydown', deleteSelectedConnection); document.removeEventListener('keydown', undoKeyHandler); - document.removeEventListener('mousemove', onRightMove); - document.removeEventListener('mouseup', onRightUp); + document.removeEventListener('mousemove', onDragMove, true); + document.removeEventListener('mouseup', onDragEnd, true); + window.removeEventListener('blur', onDragEnd); container.removeEventListener('wheel', onWheelZoom, { capture: true }); };