diff --git a/frontend/js/pane-manager.js b/frontend/js/pane-manager.js index 3a70153..561a5fc 100644 --- a/frontend/js/pane-manager.js +++ b/frontend/js/pane-manager.js @@ -366,11 +366,14 @@ function createPaneTabManager(paneId) { this._showTabContextMenu(e.clientX, e.clientY, tab.id); }); - // Drag within same pane + // Drag within same pane (+ cross-pane via container drop zone) el.addEventListener('dragstart', (e) => { - e.dataTransfer.setData('application/obsigate-tab', JSON.stringify({ + const payload = JSON.stringify({ paneId: this.paneId, tabId: tab.id, index: idx - })); + }); + e.dataTransfer.setData('application/obsigate-tab', payload); + e.dataTransfer.setData('text/plain', payload); // fallback for browser compat + e.dataTransfer.effectAllowed = 'move'; el.classList.add('dragging'); }); el.addEventListener('dragend', () => { @@ -737,16 +740,12 @@ const PaneManager = { let _dragCounter = 0; container.addEventListener('dragenter', (e) => { - const types = Array.from(e.dataTransfer.types || []); - if (!types.includes('application/obsigate-tab')) return; _dragCounter++; - e.preventDefault(); + e.preventDefault(); // Accept the drop unconditionally }); container.addEventListener('dragover', (e) => { - const types = Array.from(e.dataTransfer.types || []); - if (!types.includes('application/obsigate-tab')) return; - e.preventDefault(); + e.preventDefault(); // Required for drop to work e.dataTransfer.dropEffect = 'move'; // Detect edge zones for drag-to-split (only in single-pane mode) @@ -776,7 +775,7 @@ const PaneManager = { container.addEventListener('dragleave', (e) => { _dragCounter--; - if (_dragCounter > 0) return; // Still inside container (entered a child) + if (_dragCounter > 0) return; container.querySelectorAll('.pane-drop-zone-indicator').forEach(d => d.remove()); const tabBar = container.querySelector('.tab-bar'); if (tabBar) tabBar.classList.remove('drop-target'); @@ -790,11 +789,15 @@ const PaneManager = { const tabBar = container.querySelector('.tab-bar'); if (tabBar) tabBar.classList.remove('drop-target'); - const raw = e.dataTransfer.getData('application/obsigate-tab'); + // Try both data formats + let raw = e.dataTransfer.getData('application/obsigate-tab'); + if (!raw) raw = e.dataTransfer.getData('text/plain'); if (!raw) return; + try { const dragData = JSON.parse(raw); - if (dragData.paneId === paneId) return; // Same pane, let tab handler deal with it + if (dragData.paneId == null || dragData.tabId == null) return; + if (dragData.paneId === paneId) return; // Same pane, tab handler deals with it // Recalculate edge zone from drop coordinates const rect = container.getBoundingClientRect(); @@ -803,24 +806,21 @@ const PaneManager = { const isSingle = !this.isSplit(); if (isSingle && relX > rect.width * 0.72) { - // Dropped on right edge → split right with this tab this.splitRight(); setTimeout(() => { const newPaneId = this.panes.length - 1; this.transferTab(dragData.paneId, dragData.tabId, newPaneId); - }, 150); + }, 200); } 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); - }, 150); + }, 200); } else { - // Cross-pane transfer (dropped on tab bar or empty area of another pane) this.transferTab(dragData.paneId, dragData.tabId, paneId); } - } catch (e2) { /* ignore */ } + } catch (e2) { console.debug('PaneManager drop error:', e2); } }); },