@@ -28,7 +28,9 @@ export class TabRulesService {
2828 } catch ( error ) {
2929 // Content script not loaded (likely a tab that was open before extension reload)
3030 // The content script will apply rules automatically when the tab loads
31- console . log ( `[TabRulesService] Content script not ready for tab ${ tab . id } , rule will be applied on next load` ) ;
31+ console . log (
32+ `[TabRulesService] Content script not ready for tab ${ tab . id } , rule will be applied on next load`
33+ ) ;
3234 }
3335 }
3436
@@ -42,14 +44,17 @@ export class TabRulesService {
4244 if ( ! currentTab . id || ! currentTab . url ) return ;
4345
4446 const rule = message . rule as Rule ;
47+ const urlFragment = message . url_fragment ;
4548
46- // Check if current tab URL matches the url_matcher pattern
49+ // Check if current tab URL matches the url_matcher pattern (if defined)
4750 // If not, skip unique tab logic (tab doesn't match the rule)
4851 if ( rule ?. tab ?. url_matcher ) {
4952 try {
5053 const regex = new RegExp ( rule . tab . url_matcher ) ;
5154 if ( ! regex . test ( currentTab . url ) ) {
52- console . log ( '[TabRulesService] Current tab URL does not match url_matcher, skipping unique check' ) ;
55+ console . log (
56+ '[TabRulesService] Current tab URL does not match url_matcher, skipping unique check'
57+ ) ;
5358 return ;
5459 }
5560 } catch ( error ) {
@@ -59,7 +64,7 @@ export class TabRulesService {
5964 }
6065
6166 const processedUrlFragment = _processUrlFragment (
62- message . url_fragment ,
67+ urlFragment ,
6368 currentTab . url ,
6469 rule ?. tab ?. url_matcher
6570 ) ;
@@ -69,27 +74,50 @@ export class TabRulesService {
6974 for ( const tab of tabs ) {
7075 if ( ! tab . url || ! tab . id ) continue ;
7176
77+ // CRITICAL FIX: When url_matcher is NOT defined, compare full URLs
78+ // This prevents closing unrelated tabs (e.g., Gmail when refreshing GitHub)
79+ if ( ! rule ?. tab ?. url_matcher ) {
80+ // Without url_matcher, we use exact URL comparison for safety
81+ // This ensures only true duplicates (same exact URL) are closed
82+ if ( tab . url === currentTab . url && tab . id !== currentTab . id ) {
83+ // Remove beforeunload handler from the duplicate tab before closing it
84+ try {
85+ await chrome . scripting . executeScript ( {
86+ target : { tabId : tab . id } ,
87+ func : ( ) => {
88+ window . onbeforeunload = null ;
89+ } ,
90+ } ) ;
91+ } catch ( error ) {
92+ // Ignore errors if we can't execute script (e.g., chrome:// pages)
93+ console . log (
94+ `[TabRulesService] Could not remove beforeunload from tab ${ tab . id } :` ,
95+ error
96+ ) ;
97+ }
98+
99+ // Close the duplicate tab (keep the current tab)
100+ await chrome . tabs . remove ( tab . id ) ;
101+ return ; // Exit after closing the first duplicate
102+ }
103+ continue ;
104+ }
105+
72106 // Skip tabs that don't match the url_matcher pattern
73107 // This prevents closing unrelated tabs that happen to have the same processed fragment
74- if ( rule ?. tab ?. url_matcher ) {
75- try {
76- const regex = new RegExp ( rule . tab . url_matcher ) ;
77- if ( ! regex . test ( tab . url ) ) {
78- // This tab doesn't match the rule, skip it
79- continue ;
80- }
81- } catch ( error ) {
82- console . error ( '[TabRulesService] Invalid url_matcher regex:' , error ) ;
108+ try {
109+ const regex = new RegExp ( rule . tab . url_matcher ) ;
110+ if ( ! regex . test ( tab . url ) ) {
111+ // This tab doesn't match the rule, skip it
83112 continue ;
84113 }
114+ } catch ( error ) {
115+ console . error ( '[TabRulesService] Invalid url_matcher regex:' , error ) ;
116+ continue ;
85117 }
86118
87119 // Process the fragment for each tab to compare
88- const tabProcessedFragment = _processUrlFragment (
89- message . url_fragment ,
90- tab . url ,
91- rule ?. tab ?. url_matcher
92- ) ;
120+ const tabProcessedFragment = _processUrlFragment ( urlFragment , tab . url , rule . tab . url_matcher ) ;
93121
94122 // Compare processed fragments instead of raw URL
95123 if ( tabProcessedFragment === processedUrlFragment && tab . id !== currentTab . id ) {
0 commit comments