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 });
};