Skip to content

Commit a338356

Browse files
committed
Add multiple tabs to existing session #45
1 parent 6971432 commit a338356

File tree

4 files changed

+92
-40
lines changed

4 files changed

+92
-40
lines changed

src/_locales/en/messages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,10 @@
450450
"message": "&add this tab to a session"
451451
},
452452

453+
"tab_contextmenu_add_multiple": {
454+
"message": "&add tabs to a session"
455+
},
456+
453457
"tab_contextmenu_add_and_set_aside": {
454458
"message": "add to a session && &set aside",
455459
"description": "a single ampersand (&) marks the next character as an access key for this item"

src/_locales/fr/messages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,10 @@
450450
"message": "&Ajouter cet onglet à une session"
451451
},
452452

453+
"tab_contextmenu_add_multiple": {
454+
"message": "&Ajouter des onglets à une session"
455+
},
456+
453457
"tab_contextmenu_add_and_set_aside": {
454458
"message": "Ajouter à une session && &mettre de côté",
455459
"description": "a single ampersand (&) marks the next character as an access key for this item"

src/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 2,
33
"name": "Tabs Aside",
4-
"version": "3.3.4",
4+
"version": "3.4.0",
55
"description": "__MSG_extension_description__",
66
"author": "Tim Weißenfels",
77

src/ts/background/BrowserTabContextMenu.ts

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,24 @@ const parentOptions = {
2222
export async function init() {
2323
browser.menus.create(parentOptions);
2424

25-
browser.menus.onShown.addListener((info, tab) => {
25+
browser.menus.onShown.addListener(async (info, tab) => {
2626
if(info.contexts.includes("tab")) {
2727
shown = true;
28-
createMenuForTab(tab);
28+
29+
// get selected/highlighted tabs
30+
let selection = await browser.tabs.query({
31+
currentWindow: true,
32+
highlighted: true
33+
});
34+
35+
console.assert(selection.length >= 1);
36+
37+
if(!selection.find(t => t.id === tab.id)) {
38+
console.error(`[TA] Unexpected tab selection`, selection);
39+
return;
40+
}
41+
42+
createMenuForTabs(selection);
2943
}
3044
});
3145

@@ -39,44 +53,67 @@ export async function init() {
3953
});
4054
}
4155

42-
async function createMenuForTab(tab:Tab) {
43-
let currentSession:ActiveSession = ActiveSessionManager.getSessionFromTab(tab);
44-
let currentSessionId:SessionId = currentSession ? currentSession.bookmarkId : null;
56+
async function createMenuForTabs(tabs:Tab[]) {
57+
// collect active sessions of selected tabs
58+
let currentSessions = new Set<ActiveSession>();
59+
let currentSessionIds = new Set<SessionId>();
60+
tabs.forEach(tab => {
61+
let activeSession = ActiveSessionManager.getSessionFromTab(tab);
62+
if(activeSession) {
63+
currentSessions.add(activeSession);
64+
currentSessionIds.add(activeSession.bookmarkId);
65+
}
66+
});
67+
68+
// get list of sessions (active + non-active)
4569
let sessions:Bookmark[] = await SessionManager.getSessionBookmarks();
4670
let activeSessions:Set<SessionId> = new Set(
4771
ActiveSessionManager.getActiveSessions().map(data => data.bookmarkId)
4872
);
73+
74+
addToSessionMenu(sessions, currentSessionIds, activeSessions, tabs);
4975

50-
addToSessionMenu(sessions, currentSessionId, activeSessions, tab);
51-
52-
if(currentSession) {
76+
if(currentSessions.size === 1) {
5377
dynamicMenus.push(browser.menus.create({
5478
parentId: "parent",
5579
id: "set-aside",
5680
title: browser.i18n.getMessage("tab_contextmenu_set_aside"),
57-
onclick: info => {
58-
currentSession.setTabAside(tab.id);
81+
onclick: async (info) => {
82+
let currentSession:ActiveSession = currentSessions.values().next().value;
83+
84+
// set aside all selected/highlighted tabs
85+
for(let tab of tabs) {
86+
await currentSession.setTabAside(tab.id);
87+
}
5988
}
6089
}));
61-
} else {
62-
addAndSetAsideMenu(sessions, activeSessions, tab);
90+
} else if(currentSessions.size === 0) {
91+
addAndSetAsideMenu(sessions, activeSessions, tabs);
6392
}
6493

65-
browser.menus.refresh();
94+
if(shown) {
95+
// rebuilding a shown menu is an expensive operation, only invoke this method when necessary
96+
browser.menus.refresh();
97+
}
6698
}
6799

68100
async function addToSessionMenu(
69101
sessions:Bookmark[],
70-
currentSessionId:SessionId|null,
102+
currentSessionIds:Set<SessionId>,
71103
activeSessions:Set<SessionId>,
72-
tab:Tab
104+
tabs:Tab[]
73105
) {
106+
console.assert(tabs.length > 0);
107+
74108
if(sessions.length > 0) {
75109
dynamicMenus.push(
76110
browser.menus.create({
77111
parentId: "parent",
78112
id: "add",
79-
title: browser.i18n.getMessage("tab_contextmenu_add"),
113+
title: browser.i18n.getMessage(tabs.length > 1 ?
114+
"tab_contextmenu_add_multiple" :
115+
"tab_contextmenu_add"
116+
),
80117
icons: {
81118
"16": "img/browserMenu/add.svg",
82119
"32": "img/browserMenu/add.svg"
@@ -91,39 +128,44 @@ async function addToSessionMenu(
91128
"16": "img/browserMenu/active.svg",
92129
"32": "img/browserMenu/active.svg"
93130
} : undefined,
94-
enabled: session.id !== currentSessionId,
131+
enabled: !currentSessionIds.has(session.id),
95132
onclick: async (info) => {
96-
const data = TabData.createFromTab(tab);
97133
let added = false;
98134

99-
// move tab to active session
135+
// move tabs to active session
100136
if(activeSessions.has(session.id)) {
101137
let as = ActiveSessionManager.getActiveSession(session.id);
102138
console.assert(as);
103139

104140
// only if the target session has its own window
105141
if(as.getWindowId() !== null) {
106-
// move or copy tab to new session
107-
if(currentSessionId === null) {
108-
await browser.tabs.move(tab.id, {
109-
windowId: as.getWindowId(),
110-
index: tab.pinned ? 0 : -1
111-
});
142+
// move or copy tabs to new session
143+
if(currentSessionIds.size === 0) {
144+
for(let tab of tabs) {
145+
await browser.tabs.move(tab.id, {
146+
windowId: as.getWindowId(),
147+
index: tab.pinned ? 0 : -1
148+
});
149+
}
112150
} else {
113-
// duplicate tab
114-
let details = data.getTabCreateProperties(true);
115-
details.windowId = as.getWindowId();
116-
await createTab(details);
151+
// duplicate tabs
152+
for(let tab of tabs) {
153+
let details = TabData.createFromTab(tab).getTabCreateProperties(true);
154+
details.windowId = as.getWindowId();
155+
await createTab(details);
156+
}
117157
}
118158
added = true;
119159
}
120160
}
121161

122162
// otherwise just create the bookmark
123163
if(!added) {
124-
await browser.bookmarks.create(
125-
data.getBookmarkCreateDetails(session.id)
126-
);
164+
for(let tab of tabs) {
165+
await browser.bookmarks.create(
166+
TabData.createFromTab(tab).getBookmarkCreateDetails(session.id)
167+
);
168+
}
127169
}
128170

129171
// update sidebar
@@ -136,7 +178,7 @@ async function addToSessionMenu(
136178
async function addAndSetAsideMenu(
137179
sessions:Bookmark[],
138180
activeSessions:Set<SessionId>,
139-
tab:Tab
181+
tabs:Tab[]
140182
) {
141183
if(sessions.length > 0) {
142184
dynamicMenus.push(
@@ -155,13 +197,15 @@ async function addAndSetAsideMenu(
155197
parentId: "add-n-close",
156198
title: "&" + session.title.replace(/&/ig, "&&").trim(),
157199
onclick: async (info) => {
158-
const data = TabData.createFromTab(tab);
159-
await browser.bookmarks.create(
160-
data.getBookmarkCreateDetails(session.id)
161-
);
162-
163-
browser.tabs.remove(tab.id);
200+
for(let tab of tabs) {
201+
const data = TabData.createFromTab(tab);
202+
await browser.bookmarks.create(
203+
data.getBookmarkCreateDetails(session.id)
204+
);
164205

206+
browser.tabs.remove(tab.id);
207+
}
208+
165209
// update sidebar
166210
SessionContentUpdate.send(session.id);
167211
}

0 commit comments

Comments
 (0)