fix: drag & drop corrigé — 3 bugs critiques résolus
CI / lint (push) Failing after 9s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Successful in 15s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled
CI / lint (push) Failing after 9s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Successful in 15s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled
1. types.includes → Array.from(types).includes (DOMStringList n'a pas .includes) 2. dragleave: compteur _dragCounter empêche clear sur child enter/leave 3. drag-to-split: zone recalculée dans drop handler (plus de closure corrompue) 4. drop: stopPropagation + skip same-paneId dans container handler 5. dragenter: appel preventDefault pour accepter le drop dès l'entrée
This commit is contained in:
+37
-27
@@ -734,11 +734,18 @@ const PaneManager = {
|
||||
|
||||
/** Add dragover/drop on a pane container for cross-pane transfers + drag-to-split */
|
||||
_setupPaneDropZone(container, paneId) {
|
||||
let _edgeZone = null; // 'right' | 'bottom' | null
|
||||
let _dragCounter = 0;
|
||||
|
||||
container.addEventListener('dragenter', (e) => {
|
||||
const types = Array.from(e.dataTransfer.types || []);
|
||||
if (!types.includes('application/obsigate-tab')) return;
|
||||
_dragCounter++;
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
container.addEventListener('dragover', (e) => {
|
||||
const raw = e.dataTransfer.types.includes('application/obsigate-tab');
|
||||
if (!raw) return;
|
||||
const types = Array.from(e.dataTransfer.types || []);
|
||||
if (!types.includes('application/obsigate-tab')) return;
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
|
||||
@@ -750,37 +757,35 @@ const PaneManager = {
|
||||
|
||||
// Clean up previous indicators
|
||||
container.querySelectorAll('.pane-drop-zone-indicator').forEach(d => d.remove());
|
||||
_edgeZone = null;
|
||||
const tabBar = container.querySelector('.tab-bar');
|
||||
if (tabBar) tabBar.classList.remove('drop-target');
|
||||
|
||||
if (isSingle) {
|
||||
if (relX > rect.width * 0.75) {
|
||||
_edgeZone = 'right';
|
||||
} else if (relY > rect.height * 0.75) {
|
||||
_edgeZone = 'bottom';
|
||||
}
|
||||
}
|
||||
|
||||
if (_edgeZone) {
|
||||
// Show edge zone indicator
|
||||
if (isSingle && relX > rect.width * 0.72) {
|
||||
const indicator = document.createElement('div');
|
||||
indicator.className = 'pane-drop-zone-indicator pane-drop-zone-' + _edgeZone;
|
||||
indicator.className = 'pane-drop-zone-indicator pane-drop-zone-right';
|
||||
container.appendChild(indicator);
|
||||
} else if (isSingle && relY > rect.height * 0.72) {
|
||||
const indicator = document.createElement('div');
|
||||
indicator.className = 'pane-drop-zone-indicator pane-drop-zone-bottom';
|
||||
container.appendChild(indicator);
|
||||
} else {
|
||||
// Show tab-bar highlight for cross-pane transfer
|
||||
const tabBar = container.querySelector('.tab-bar');
|
||||
if (tabBar) tabBar.classList.add('drop-target');
|
||||
}
|
||||
});
|
||||
|
||||
container.addEventListener('dragleave', (e) => {
|
||||
_dragCounter--;
|
||||
if (_dragCounter > 0) return; // Still inside container (entered a child)
|
||||
container.querySelectorAll('.pane-drop-zone-indicator').forEach(d => d.remove());
|
||||
const tabBar = container.querySelector('.tab-bar');
|
||||
if (tabBar) tabBar.classList.remove('drop-target');
|
||||
_edgeZone = null;
|
||||
});
|
||||
|
||||
container.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
_dragCounter = 0;
|
||||
container.querySelectorAll('.pane-drop-zone-indicator').forEach(d => d.remove());
|
||||
const tabBar = container.querySelector('.tab-bar');
|
||||
if (tabBar) tabBar.classList.remove('drop-target');
|
||||
@@ -789,28 +794,33 @@ const PaneManager = {
|
||||
if (!raw) return;
|
||||
try {
|
||||
const dragData = JSON.parse(raw);
|
||||
if (dragData.paneId === paneId) return; // Same pane, let tab handler deal with it
|
||||
|
||||
if (_edgeZone === 'right') {
|
||||
// Drag to right edge → split right with this tab
|
||||
// Recalculate edge zone from drop coordinates
|
||||
const rect = container.getBoundingClientRect();
|
||||
const relX = e.clientX - rect.left;
|
||||
const relY = e.clientY - rect.top;
|
||||
const isSingle = !this.isSplit();
|
||||
|
||||
if (isSingle && relX > rect.width * 0.72) {
|
||||
// Dropped on right edge → split right with this tab
|
||||
this.splitRight();
|
||||
// Transfer the dragged tab to the new pane
|
||||
setTimeout(() => {
|
||||
const newPaneId = this.panes.length - 1;
|
||||
this.transferTab(dragData.paneId, dragData.tabId, newPaneId);
|
||||
}, 100);
|
||||
} else if (_edgeZone === 'bottom') {
|
||||
// Drag to bottom edge → split down with this tab
|
||||
}, 150);
|
||||
} else if (isSingle && relY > rect.height * 0.72) {
|
||||
// Dropped on bottom edge → split down with this tab
|
||||
this.splitDown();
|
||||
setTimeout(() => {
|
||||
const newPaneId = this.panes.length - 1;
|
||||
this.transferTab(dragData.paneId, dragData.tabId, newPaneId);
|
||||
}, 100);
|
||||
} else if (dragData.paneId !== paneId) {
|
||||
// Cross-pane transfer (dropped on tab bar or content area of another pane)
|
||||
}, 150);
|
||||
} else {
|
||||
// Cross-pane transfer (dropped on tab bar or empty area of another pane)
|
||||
this.transferTab(dragData.paneId, dragData.tabId, paneId);
|
||||
}
|
||||
} catch (e2) { /* ignore */ }
|
||||
_edgeZone = null;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user