fix: split view — plus de panneaux vides, transfert auto de l'onglet
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 14s
Desktop Build / build-windows (push) Has been cancelled
Desktop Build / build-linux (push) Has been cancelled

- _hasAnyTab(): empêche split si aucun onglet ouvert (tous les points d'entrée)
- _copyActiveTabToNewPane(): copie l'onglet actif dans le nouveau panneau
- Menu contextuel: l'onglet cliqué-droit est transféré dans le nouveau panneau
- Raccourci clavier Ctrl+Alt+\: transfert l'onglet actif dans le nouveau panneau
- Boutons split: vérifient _hasAnyTab() avant d'agir
- Singleton ui.js: même comportement (split + transfert de l'onglet)
This commit is contained in:
2026-07-28 13:10:57 -04:00
parent ffefe4eb16
commit 298ea082c0
2 changed files with 93 additions and 12 deletions
+77 -10
View File
@@ -69,11 +69,11 @@ function createPaneTabManager(paneId) {
`;
btns.querySelector('[data-action="split-right"]').addEventListener('click', (e) => {
e.stopPropagation();
if (window.PaneManager) window.PaneManager.splitRight();
if (window.PaneManager && window.PaneManager._hasAnyTab()) window.PaneManager.splitRight();
});
btns.querySelector('[data-action="split-down"]').addEventListener('click', (e) => {
e.stopPropagation();
if (window.PaneManager) window.PaneManager.splitDown();
if (window.PaneManager && window.PaneManager._hasAnyTab()) window.PaneManager.splitDown();
});
this._tabBar.appendChild(btns);
if (typeof safeCreateIcons === 'function') safeCreateIcons();
@@ -539,8 +539,23 @@ function createPaneTabManager(paneId) {
menu.addEventListener('click', (e) => {
const action = e.target.closest('.context-menu-item')?.dataset.action;
if (action === 'moveTo') return; // handled by hover
if (action === 'splitRight') { if (pm) { pm.splitRight(); menu.remove(); return; } }
else if (action === 'splitDown') { if (pm) { pm.splitDown(); menu.remove(); return; } }
if (action === 'splitRight') {
if (pm && pm._hasAnyTab()) {
pm.splitRight();
// Transfer this specific tab to the new pane
const newPaneId = pm.panes.length - 1;
pm.transferTab(this.paneId, tabId, newPaneId);
menu.remove(); return;
}
}
else if (action === 'splitDown') {
if (pm && pm._hasAnyTab()) {
pm.splitDown();
const newPaneId = pm.panes.length - 1;
pm.transferTab(this.paneId, tabId, newPaneId);
menu.remove(); return;
}
}
else if (action === 'closePane') { if (pm) { pm.closeActivePane(); menu.remove(); return; } }
else if (action === 'close') this.close(tabId);
else if (action === 'closeOthers') this.closeOthers(tabId);
@@ -660,20 +675,60 @@ const PaneManager = {
// ------------------------------------------------------------------
splitRight() {
if (this.panes.length >= PANE_MAX) return;
// Don't split if no tab is open anywhere
if (!this._hasAnyTab()) return;
this.layout = 'horizontal';
if (this.panes.length === 0) this._buildGrid(2);
else this._addPane();
if (this.panes.length === 0) {
this._buildGrid(2);
// Copy active tab to the new pane
this._copyActiveTabToNewPane();
} else {
this._addPane();
}
this._persist();
},
splitDown() {
if (this.panes.length >= PANE_MAX) return;
if (!this._hasAnyTab()) return;
this.layout = 'vertical';
if (this.panes.length === 0) this._buildGrid(2);
else this._addPane();
if (this.panes.length === 0) {
this._buildGrid(2);
this._copyActiveTabToNewPane();
} else {
this._addPane();
}
this._persist();
},
/** Check if any pane has at least one tab */
_hasAnyTab() {
if (!this.isSplit()) {
// Check singleton in single-pane mode
if (window._singletonTabManager && window._singletonTabManager._tabs.length > 0)
return true;
return false;
}
for (const tm of Object.values(this.tabManagers)) {
if (tm._tabs && tm._tabs.length > 0) return true;
}
return false;
},
/** Copy the active tab to the newly created last pane */
_copyActiveTabToNewPane() {
const newPaneId = this.panes.length - 1;
const srcTm = this.tabManagers[this.activePaneId];
const dstTm = this.tabManagers[newPaneId];
if (!srcTm || !dstTm || !srcTm._activeTabId) return;
const cache = srcTm._tabCache[srcTm._activeTabId];
if (cache) {
setTimeout(() => {
dstTm.open(cache.vault, cache.path);
}, 150);
}
},
// ------------------------------------------------------------------
// Close pane
// ------------------------------------------------------------------
@@ -1268,11 +1323,23 @@ if (typeof window !== 'undefined') {
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.altKey && !e.shiftKey && e.key === '\\') {
e.preventDefault();
PaneManager.splitRight();
if (PaneManager._hasAnyTab()) {
PaneManager.splitRight();
// Transfer active tab to new pane
const tm = PaneManager.getActiveTabManager();
if (tm && tm._activeTabId) {
setTimeout(() => {
const newPaneId = PaneManager.panes.length - 1;
PaneManager.transferTab(PaneManager.activePaneId === newPaneId ? 0 : PaneManager.activePaneId, tm._activeTabId, newPaneId);
}, 200);
}
}
}
if (e.ctrlKey && e.altKey && e.shiftKey && e.key === '\\') {
e.preventDefault();
PaneManager.splitDown();
if (PaneManager._hasAnyTab()) {
PaneManager.splitDown();
}
}
// Close active pane
if (e.ctrlKey && e.altKey && !e.shiftKey && (e.key === 'w' || e.key === 'W') && PaneManager.isSplit()) {
+16 -2
View File
@@ -2351,8 +2351,22 @@ export const TabManager = {
menu.addEventListener("click", (e) => {
const action = e.target.closest(".context-menu-item")?.dataset.action;
if (action === "splitRight") { if (window.PaneManager) { window.PaneManager.splitRight(); menu.remove(); return; } }
else if (action === "splitDown") { if (window.PaneManager) { window.PaneManager.splitDown(); menu.remove(); return; } }
if (action === "splitRight") {
if (window.PaneManager && window.PaneManager._hasAnyTab && window.PaneManager._hasAnyTab()) {
window.PaneManager.splitRight();
const newPaneId = window.PaneManager.panes.length - 1;
window.PaneManager.transferTab(0, tabId, newPaneId);
menu.remove(); return;
}
}
else if (action === "splitDown") {
if (window.PaneManager && window.PaneManager._hasAnyTab && window.PaneManager._hasAnyTab()) {
window.PaneManager.splitDown();
const newPaneId = window.PaneManager.panes.length - 1;
window.PaneManager.transferTab(0, tabId, newPaneId);
menu.remove(); return;
}
}
else if (action === "closePane") { if (window.PaneManager) { window.PaneManager.closeActivePane(); menu.remove(); return; } }
else if (action === "close") this.close(tabId);
else if (action === "closeOthers") this.closeOthers(tabId);