diff --git a/src/background/background.js b/src/background/background.js index ae8134b..172386f 100644 --- a/src/background/background.js +++ b/src/background/background.js @@ -23,21 +23,23 @@ browser.runtime.onInstalled.addListener(({ reason }) => { }); // Setup "Send Tab to..." -browser.contextMenus.onClicked.addListener((info, tab) => { +browser.contextMenus.onClicked.addListener(async (info, tab) => { if (info.menuItemId.startsWith("tabby-send-tab-to-")) { let moveTo = info.menuItemId.replace("tabby-send-tab-to-", ""); + let highlightedTabIds = (await browser.tabs.query({ highlighted: true })).map(tab => tab.id); + let tabIds = [tab.id]; + if (highlightedTabIds.includes(tab.id)) { + tabIds = highlightedTabIds; + } switch (moveTo) { case "": break; case "-": case "new": - browser.windows.create({ - tabId: tab.id, - incognito: tab.incognito - }); + await moveTabsToANewWindow(tabIds, tab.id); break; default: - browser.tabs.move(tab.id, { + await browser.tabs.move(tabIds, { windowId: parseInt(moveTo), index: -1 }); @@ -102,20 +104,22 @@ browser.runtime.onMessage.addListener((message) => { }); }); +async function moveTabsToANewWindow(tabIds, anchorId) { + if (tabIds.length > 0) { + let anchorTab = await browser.tabs.get(anchorId) + let window = await browser.windows.create({ incognito: anchorTab.incognito }); + await new TTabActions(...tabIds).moveTo(window.id, -1); + if (window.tabs.length > 0) { + await new TTabActions(window.tabs[0].id).remove(); + } + } +} + // Mechanism for taking over from the popup when it needs to move tabs to a new window // Note: async onMessage listeners always return a Promise, thus, if the listener is async, it will always take over and sendResponse before the correct one can, ruining every single piece of code that needs to return something after browser.runtime.onMessage.addListener(message => { if (message["_"] !== "menuMoveTabsToANewWindow") return; - return (async () => { - if (message.tabIds.length > 0) { - let firstTab = await browser.tabs.get(message.tabIds[0]) - let window = await browser.windows.create({ incognito: firstTab.incognito }); - await new TTabActions(...message.tabIds).moveTo(window.id, -1); - if (window.tabs.length > 0) { - await new TTabActions(window.tabs[0].id).remove(); - } - } - })(); + return moveTabsToANewWindow(message.tabIds, message.anchorId); }); // Mechanism for updating the menu when the window name is changed from the popup diff --git a/src/popup/popup.js b/src/popup/popup.js index 4e9444e..d872e81 100644 --- a/src/popup/popup.js +++ b/src/popup/popup.js @@ -1571,7 +1571,8 @@ class TUITabsList extends TUIListDataInterpret { // Creating windows, along with other window related operations, tends to have a habit of closing the popup, so the work must be passed to the background script to complete. browser.runtime.sendMessage({ _: "menuMoveTabsToANewWindow", - tabIds: actions.ids + tabIds: actions.ids, + anchorId: tabId }); } }, [...this.sess._rel.getWindowIds().map((windowId, _) => { @@ -1971,8 +1972,17 @@ class TUITabsList extends TUIListDataInterpret { tabsList.kb = true; } else if (evt.key === 'a' || evt.key === 'A') { tabsList.modifySelected((processSelectCB) => { - for (let child of tabsList.children(tabsList.root, true)) { - if (TUIList.isElementVisible(child)) { + let windowEntries = tabsList.children(tabsList.root, false); + let count = windowEntries.length; + for (let windowEntry of windowEntries) { + let countPart = windowEntry.getAttribute("data-selected-children-count"); + if (countPart !== null) { + count += parseInt(countPart); + } + } + let allChildren = tabsList.children(tabsList.root, true); + for (let child of allChildren) { + if (allChildren.length > count && TUIList.isElementVisible(child)) { processSelectCB(child, evt, "selecting", true); } else { processSelectCB(child, evt, "unselecting", true);