From 793af85244204e265e50a5342cf386a3c5c54617 Mon Sep 17 00:00:00 2001 From: Prajna Date: Sun, 17 Dec 2023 23:54:59 +0800 Subject: [PATCH 1/2] feat: Add tabGroupMap to track manual and setting tab groups --- src/background.ts | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/background.ts b/src/background.ts index 7735d23..92cab9b 100644 --- a/src/background.ts +++ b/src/background.ts @@ -28,6 +28,12 @@ const windowGroupMaps: { [key: number]: Map } = {}; // tab map: { tabId: tabInformation } const tabMap: { [key: number]: chrome.tabs.Tab } = {}; +const tabGroupMap: { + [key: number]: { + type: "manual" | "setting"; + title: string; + }; +} = {}; chrome.runtime.onMessage.addListener((message) => { chrome.storage.local.get("types", (resultStorage) => { @@ -55,13 +61,51 @@ chrome.runtime.onMessage.addListener((message) => { }); }); -chrome.tabGroups.onUpdated.addListener((group) => { +const createdManualType = (group: chrome.tabGroups.TabGroup) => { + if (!group.title) return; + const hasCreatedType = types.find((type, index) => { + if (type === group.title) { + types[index] = group.title; + return true; + } + return false; + }); + if (!hasCreatedType) { + types.push(group.title); + tabGroupMap[group.id] = { type: "manual", title: group.title }; + setStorage("types", types); + } +}; + +const updatedManualType = (group: chrome.tabGroups.TabGroup) => { + if (!group.title) return; + const existType = types.findIndex( + (type) => type === tabGroupMap[group.id].title + ); + if (existType) { + types.splice(existType, 1, group.title); + tabGroupMap[group.id] = { type: "manual", title: group.title }; + setStorage("types", types); + } +}; + +chrome.tabGroups.onUpdated.addListener(async (group) => { if (!windowGroupMaps.hasOwnProperty(group.windowId)) { windowGroupMaps[group.windowId] = new Map(); } if (group.title) { windowGroupMaps[group.windowId].set(group.title, group.id); } + + const types = await getStorage("types"); + // 更新types中的群组条目 + if (types && types.length > 0) { + if (!tabGroupMap[group.id]) { + createdManualType(group); + } else { + updatedManualType(group); + } + } }); async function groupOneType(type: string, tabIds: number[]) { From f60a06b98f23ba7d55197e2820acd7cdc7d22afc Mon Sep 17 00:00:00 2001 From: Prajna Date: Mon, 18 Dec 2023 00:27:20 +0800 Subject: [PATCH 2/2] feat: add filter for manual groups Groups created manually will not be placed in "Group Existing Tabs" button. --- src/background.ts | 49 ++++++++------------------------- src/utils.ts | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 38 deletions(-) diff --git a/src/background.ts b/src/background.ts index 92cab9b..7b4dae8 100644 --- a/src/background.ts +++ b/src/background.ts @@ -5,6 +5,10 @@ import { getRootDomain, getStorage, setStorage, + tabGroupMap, + createdManualType, + updatedManualType, + curryFilterManualGroups, } from "./utils"; chrome.runtime.onInstalled.addListener((details) => { @@ -28,23 +32,20 @@ const windowGroupMaps: { [key: number]: Map } = {}; // tab map: { tabId: tabInformation } const tabMap: { [key: number]: chrome.tabs.Tab } = {}; -const tabGroupMap: { - [key: number]: { - type: "manual" | "setting"; - title: string; - }; -} = {}; chrome.runtime.onMessage.addListener((message) => { - chrome.storage.local.get("types", (resultStorage) => { + chrome.storage.local.get("types", async (resultStorage) => { if (resultStorage.types) { types = resultStorage.types; const result = message.result; + + const filterTabs = await curryFilterManualGroups(); + types.forEach((_, i) => { // Check if result[i] exists before accessing the 'type' property if (result[i]) { - groupOneType(result[i].type, result[i].tabIds); + groupOneType(result[i].type, result[i].tabIds.filter(filterTabs)); result[i].tabIds.forEach((tabId: number) => { if (tabId) { chrome.tabs.get(tabId, (tab) => { @@ -61,34 +62,6 @@ chrome.runtime.onMessage.addListener((message) => { }); }); -const createdManualType = (group: chrome.tabGroups.TabGroup) => { - if (!group.title) return; - const hasCreatedType = types.find((type, index) => { - if (type === group.title) { - types[index] = group.title; - return true; - } - return false; - }); - if (!hasCreatedType) { - types.push(group.title); - tabGroupMap[group.id] = { type: "manual", title: group.title }; - setStorage("types", types); - } -}; - -const updatedManualType = (group: chrome.tabGroups.TabGroup) => { - if (!group.title) return; - const existType = types.findIndex( - (type) => type === tabGroupMap[group.id].title - ); - if (existType) { - types.splice(existType, 1, group.title); - tabGroupMap[group.id] = { type: "manual", title: group.title }; - setStorage("types", types); - } -}; - chrome.tabGroups.onUpdated.addListener(async (group) => { if (!windowGroupMaps.hasOwnProperty(group.windowId)) { windowGroupMaps[group.windowId] = new Map(); @@ -101,9 +74,9 @@ chrome.tabGroups.onUpdated.addListener(async (group) => { // 更新types中的群组条目 if (types && types.length > 0) { if (!tabGroupMap[group.id]) { - createdManualType(group); + createdManualType(types, group); } else { - updatedManualType(group); + updatedManualType(types, group); } } }); diff --git a/src/utils.ts b/src/utils.ts index afd5584..e802dde 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -71,3 +71,73 @@ export function getRootDomain(url: URL) { } return parts.slice(1).join("."); } + +export const getTabsFromGroup = async ( + groupId: number +): Promise => { + return new Promise((resolve) => { + chrome.tabs.query({ groupId }, (tabs) => { + resolve(tabs); + }); + }); +}; + +export const tabGroupMap: { + [key: number]: { + type: "manual" | "setting"; + title: string; + }; +} = {}; + +export const createdManualType = ( + types: string[], + group: chrome.tabGroups.TabGroup +) => { + if (!group.title) return; + const hasCreatedType = types.find((type, index) => { + if (type === group.title) { + types[index] = group.title; + return true; + } + return false; + }); + if (!hasCreatedType) { + types.push(group.title); + tabGroupMap[group.id] = { type: "manual", title: group.title }; + setStorage("types", types); + } +}; + +export const updatedManualType = ( + types: string[], + group: chrome.tabGroups.TabGroup +) => { + if (!group.title) return; + const existType = types.findIndex( + (type) => type === tabGroupMap[group.id].title + ); + if (existType) { + types.splice(existType, 1, group.title); + tabGroupMap[group.id] = { type: "manual", title: group.title }; + setStorage("types", types); + } +}; + +export const curryFilterManualGroups = async () => { + const manualGroups = Object.entries(tabGroupMap).filter( + ([_groupId, group]) => group.type === "manual" + ); + const manualGroupsTabs = ( + await Promise.all( + manualGroups.map(async ([groupId, _group]) => { + const groupTabs = getTabsFromGroup(parseInt(groupId)); + return groupTabs; + }) + ) + ).flat(); + + // filter out tabs that are in manual groups + return (tabId: number) => { + return !manualGroupsTabs.map((tab) => tab.id).includes(tabId); + }; +};