@@ -210,11 +210,18 @@ chrome.contextMenus.create({
210210 contexts : [ 'all' ] ,
211211} ) ;
212212
213- chrome . contextMenus . onClicked . addListener ( async function ( info , tab ) {
214- if ( ! tab ?. id ) return ;
213+ chrome . contextMenus . create ( {
214+ id : 'merge-windows' ,
215+ title : 'Merge All Windows' ,
216+ contexts : [ 'all' ] ,
217+ } ) ;
215218
219+ chrome . contextMenus . onClicked . addListener ( async function ( info , tab ) {
216220 if ( info . menuItemId === 'rename-tab' ) {
221+ if ( ! tab ?. id ) return ;
217222 await chrome . tabs . sendMessage ( tab . id , { action : 'openPrompt' } ) ;
223+ } else if ( info . menuItemId === 'merge-windows' ) {
224+ await mergeAllWindows ( ) ;
218225 }
219226} ) ;
220227
@@ -341,4 +348,75 @@ async function updateTabGroup(groupId: number, tmGroup: Group) {
341348 execute ( ) ;
342349}
343350
351+ // Merge Windows Command Handler
352+ chrome . commands . onCommand . addListener ( async ( command ) => {
353+ if ( command === 'merge-windows' ) {
354+ await mergeAllWindows ( ) ;
355+ }
356+ } ) ;
357+
358+ /**
359+ * Merge all browser windows into the current window
360+ */
361+ async function mergeAllWindows ( ) {
362+ try {
363+ // Get all windows
364+ const windows = await chrome . windows . getAll ( { populate : true } ) ;
365+
366+ if ( windows . length <= 1 ) {
367+ console . log ( '[Tabee] Only one window open, nothing to merge' ) ;
368+ return ;
369+ }
370+
371+ // Find the currently focused window or use the first normal window
372+ let targetWindow = windows . find ( ( w ) => w . focused ) ;
373+ if ( ! targetWindow ) {
374+ targetWindow = windows . find ( ( w ) => w . type === 'normal' ) ;
375+ }
376+
377+ if ( ! targetWindow || ! targetWindow . id ) {
378+ console . error ( '[Tabee] Could not find target window for merging' ) ;
379+ return ;
380+ }
381+
382+ console . log ( `[Tabee] Merging ${ windows . length - 1 } windows into window ${ targetWindow . id } ` ) ;
383+
384+ // Move all tabs from other windows to the target window
385+ for ( const window of windows ) {
386+ // Skip the target window itself
387+ if ( window . id === targetWindow . id ) continue ;
388+
389+ // Skip non-normal windows (popup, devtools, etc.)
390+ if ( window . type !== 'normal' ) continue ;
391+
392+ if ( window . tabs && window . tabs . length > 0 ) {
393+ const tabIds = window . tabs
394+ . map ( ( tab ) => tab . id )
395+ . filter ( ( id ) : id is number => id !== undefined ) ;
396+
397+ if ( tabIds . length > 0 ) {
398+ try {
399+ // Move tabs to target window
400+ await chrome . tabs . move ( tabIds , {
401+ windowId : targetWindow . id ,
402+ index : - 1 , // Append at the end
403+ } ) ;
404+
405+ console . log ( `[Tabee] Moved ${ tabIds . length } tabs from window ${ window . id } ` ) ;
406+ } catch ( error ) {
407+ console . error ( `[Tabee] Error moving tabs from window ${ window . id } :` , error ) ;
408+ }
409+ }
410+ }
411+ }
412+
413+ // Focus the target window
414+ await chrome . windows . update ( targetWindow . id , { focused : true } ) ;
415+
416+ console . log ( '[Tabee] Windows merged successfully' ) ;
417+ } catch ( error ) {
418+ console . error ( '[Tabee] Error merging windows:' , error ) ;
419+ }
420+ }
421+
344422export { } ;
0 commit comments