Theseus: move a tab to a new window
Right-click a tab and pick Move to new window, or drag it out of the tab bar and let go off the window or over the page. The tab's own page moves over, so sign-ins, scroll position and typed text stay as they were. Each window has its own toolbar and tabs. The quick links, side panels and sidebar stay in the first window and pass to another one if it closes; the shared pop-ups (site info, downloads, password fill, page dialogs, approvals) open in whichever window asks. Messages from a window and events from its tabs run in that window's state, so the existing single-window code keeps working. Closing a window's last tab closes that window. The session file keeps every window with its place on screen, and still opens in older builds as the first window.
This commit is contained in:
parent
a29eaae876
commit
f803491844
3 changed files with 543 additions and 175 deletions
13
chrome.html
13
chrome.html
|
|
@ -1642,8 +1642,17 @@
|
|||
// chrome view taller and opened a gap under the toolbar).
|
||||
el.addEventListener("contextmenu", (e) => { e.preventDefault(); if (T.tabContextMenuPopup) T.tabContextMenuPopup(id, { x: e.clientX, y: e.clientY }); });
|
||||
// Drag-reorder — drop side chosen by pointer half (matches Chrome UX).
|
||||
el.addEventListener("dragstart", (e) => { dragId = id; try { e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/plain", String(id)); } catch {} el.classList.add("dragging"); });
|
||||
el.addEventListener("dragend", () => { el.classList.remove("dragging"); el.parentElement?.querySelectorAll(".tab").forEach((r) => r.classList.remove("dropbefore", "dropafter")); dragId = null; });
|
||||
// Its own data type, not text/plain: let go over a page, a plain-text tab
|
||||
// id would have been typed into whatever field was under the pointer.
|
||||
el.addEventListener("dragstart", (e) => { dragId = id; try { e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("application/x-theseus-tab", String(id)); } catch {} el.classList.add("dragging"); });
|
||||
el.addEventListener("dragend", (e) => {
|
||||
el.classList.remove("dragging"); el.parentElement?.querySelectorAll(".tab").forEach((r) => r.classList.remove("dropbefore", "dropafter"));
|
||||
// Dropped where nothing took it (off the window, or over the page): a
|
||||
// new window. Esc reports (0,0) on Windows; that is a cancel, not a drop.
|
||||
const dropped = e.dataTransfer && e.dataTransfer.dropEffect === "none" && (e.screenX || e.screenY);
|
||||
if (dropped && dragId === id && T.detachTab) T.detachTab(id, e.screenX, e.screenY);
|
||||
dragId = null;
|
||||
});
|
||||
el.addEventListener("dragover", (e) => {
|
||||
if (dragId == null || id === dragId) return;
|
||||
e.preventDefault(); e.dataTransfer.dropEffect = "move";
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ contextBridge.exposeInMainWorld("theseus", {
|
|||
closeTab: (id) => ipcRenderer.invoke("close-tab", id),
|
||||
switchTab: (id) => ipcRenderer.invoke("switch-tab", id),
|
||||
moveTab: (id, targetId, place) => ipcRenderer.invoke("move-tab", id, targetId, place),
|
||||
// A tab dragged out of the bar and dropped where nothing took it: main opens
|
||||
// it in a new window if the point (screen coordinates) is off the toolbar.
|
||||
detachTab: (id, x, y) => ipcRenderer.invoke("tab-detach", id, x, y),
|
||||
suggestAddress: (query, rect) => ipcRenderer.invoke("suggest-address", query, rect),
|
||||
closeAddressPicker: () => ipcRenderer.invoke("close-address-picker"),
|
||||
addressCursor: (dir) => ipcRenderer.invoke("address-cursor", dir),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue