11import { canInjectScript } from '../background/utils/extension-api' ;
22import { createFileLoader } from './utils/network' ;
33import type { FetchRequestParameters } from './utils/network' ;
4- import type { MessageBGtoCS , MessageCStoBG , MessageUItoBG } from '../definitions' ;
4+ import type { MessageBGtoCS , MessageCStoBG , MessageUItoBG , documentId , frameId , tabId } from '../definitions' ;
55import { isFirefox } from '../utils/platform' ;
66import { MessageTypeCStoBG , MessageTypeBGtoCS , MessageTypeUItoBG } from '../utils/message' ;
77import { ASSERT , logInfo , logWarn } from './utils/log' ;
88import { StateManager } from '../utils/state-manager' ;
99import { getURLHostOrProtocol } from '../utils/url' ;
1010import { isPanel } from './utils/tab' ;
1111import { makeFirefoxHappy } from './make-firefox-happy' ;
12+ import { getActiveTab , queryTabs } from '../utils/tabs' ;
1213
1314declare const __CHROMIUM_MV2__ : boolean ;
1415declare const __CHROMIUM_MV3__ : boolean ;
1516declare const __FIREFOX_MV2__ : boolean ;
1617declare const __THUNDERBIRD__ : boolean ;
1718
18- // ContextId is a number on Firefox and documentId is a string in Chromium,
19- // let's use string for simplicity
20- type documentId = string ;
21- type tabId = number ;
22- type frameId = number ;
23-
2419interface TabManagerOptions {
2520 getConnectionMessage : ( tabURl : string , url : string , isTopFrame : boolean ) => Promise < MessageBGtoCS > ;
2621 getTabMessage : ( tabURL : string , url : string , isTopFrame : boolean ) => MessageBGtoCS ;
@@ -55,12 +50,12 @@ enum DocumentState {
5550}
5651
5752export default class TabManager {
58- private static tabs : { [ tabId : tabId ] : { [ frameId : frameId ] : DocumentInfo } } ;
53+ private static tabs : TabManagerState [ 'tabs' ] ;
5954 private static stateManager : StateManager < TabManagerState > ;
6055 private static fileLoader : { get : ( params : FetchRequestParameters ) => Promise < string | null > } | null = null ;
6156 private static onColorSchemeChange : TabManagerOptions [ 'onColorSchemeChange' ] ;
6257 private static getTabMessage : TabManagerOptions [ 'getTabMessage' ] ;
63- private static timestamp = 0 ;
58+ private static timestamp : TabManagerState [ 'timestamp' ] ;
6459 private static readonly LOCAL_STORAGE_KEY = 'TabManager-state' ;
6560
6661 public static init ( { getConnectionMessage, onColorSchemeChange, getTabMessage} : TabManagerOptions ) : void {
@@ -208,12 +203,6 @@ export default class TabManager {
208203 break ;
209204 }
210205
211- case MessageTypeUItoBG . REQUEST_EXPORT_CSS : {
212- const activeTab = await TabManager . getActiveTab ( ) ;
213- chrome . tabs . sendMessage < MessageBGtoCS > ( activeTab . id ! , { type : MessageTypeBGtoCS . EXPORT_CSS } , { frameId : 0 } ) ;
214- break ;
215- }
216-
217206 default :
218207 break ;
219208 }
@@ -234,12 +223,6 @@ export default class TabManager {
234223 }
235224 }
236225
237- private static async queryTabs ( query : chrome . tabs . QueryInfo = { } ) {
238- return new Promise < chrome . tabs . Tab [ ] > ( ( resolve ) =>
239- chrome . tabs . query ( query , resolve )
240- ) ;
241- }
242-
243226 private static addFrame ( tabId : tabId , frameId : frameId , documentId : documentId , url : string , timestamp : number ) {
244227 let frames : { [ frameId : frameId ] : DocumentInfo } ;
245228 if ( TabManager . tabs [ tabId ] ) {
@@ -273,8 +256,11 @@ export default class TabManager {
273256 TabManager . stateManager . saveState ( ) ;
274257 }
275258
276- private static async getTabURL ( tab : chrome . tabs . Tab ) : Promise < string > {
259+ private static async getTabURL ( tab : chrome . tabs . Tab | null ) : Promise < string > {
277260 if ( __CHROMIUM_MV3__ ) {
261+ if ( ! tab ) {
262+ return 'abou:blank' ;
263+ }
278264 try {
279265 if ( TabManager . tabs [ tab . id ! ] && TabManager . tabs [ tab . id ! ] [ 0 ] ) {
280266 return TabManager . tabs [ tab . id ! ] [ 0 ] . url || 'about:blank' ;
@@ -298,7 +284,7 @@ export default class TabManager {
298284 }
299285
300286 public static async updateContentScript ( options : { runOnProtectedPages : boolean } ) : Promise < void > {
301- ( await TabManager . queryTabs ( ) )
287+ ( await queryTabs ( ) )
302288 . filter ( ( tab ) => __CHROMIUM_MV3__ || options . runOnProtectedPages || canInjectScript ( tab . url ) )
303289 . filter ( ( tab ) => ! Boolean ( TabManager . tabs [ tab . id ! ] ) )
304290 . forEach ( ( tab ) => {
@@ -343,7 +329,7 @@ export default class TabManager {
343329
344330 const activeTabHostname = onlyUpdateActiveTab ? getURLHostOrProtocol ( await TabManager . getActiveTabURL ( ) ) : null ;
345331
346- ( await TabManager . queryTabs ( ) )
332+ ( await queryTabs ( ) )
347333 . filter ( ( tab ) => Boolean ( TabManager . tabs [ tab . id ! ] ) )
348334 . forEach ( ( tab ) => {
349335 const frames = TabManager . tabs [ tab . id ! ] ;
@@ -373,48 +359,19 @@ export default class TabManager {
373359 }
374360
375361 public static async canAccessActiveTab ( ) : Promise < boolean > {
376- const tab = await TabManager . getActiveTab ( ) ;
377- return Boolean ( TabManager . tabs [ tab . id ! ] ) ;
362+ const tab = await getActiveTab ( ) ;
363+ return tab && Boolean ( TabManager . tabs [ tab . id ! ] ) || false ;
378364 }
379365
380366 public static async isActiveTabDarkThemeDetected ( ) : Promise < boolean | null > {
381- const tab = await TabManager . getActiveTab ( ) ;
367+ const tab = await getActiveTab ( ) ;
368+ if ( ! tab ) {
369+ return null ;
370+ }
382371 return TabManager . tabs [ tab . id ! ] && TabManager . tabs [ tab . id ! ] [ 0 ] && TabManager . tabs [ tab . id ! ] [ 0 ] . darkThemeDetected || null ;
383372 }
384373
385374 public static async getActiveTabURL ( ) : Promise < string > {
386- return TabManager . getTabURL ( await TabManager . getActiveTab ( ) ) ;
387- }
388-
389- public static async getActiveTab ( ) : Promise < chrome . tabs . Tab > {
390- let tab = ( await TabManager . queryTabs ( {
391- active : true ,
392- lastFocusedWindow : true ,
393- // Explicitly exclude Dark Reader's Dev Tools and other special windows from the query
394- windowType : 'normal' ,
395- } ) ) [ 0 ] ;
396- if ( ! tab ) {
397- tab = ( await TabManager . queryTabs ( {
398- active : true ,
399- lastFocusedWindow : true ,
400- windowType : 'app' ,
401- } ) ) [ 0 ] ;
402- }
403- if ( ! tab ) {
404- // When Dark Reader's DevTools are open, last focused window might be the DevTools window
405- // so we lift this restriction and try again (with the best guess)
406- tab = ( await TabManager . queryTabs ( {
407- active : true ,
408- windowType : 'normal' ,
409- } ) ) [ 0 ] ;
410- if ( ! tab ) {
411- tab = ( await TabManager . queryTabs ( {
412- active : true ,
413- windowType : 'app' ,
414- } ) ) [ 0 ] ;
415- }
416- logWarn ( 'TabManager.getActiveTab() could not reliably find the active tab, picking the best guess' , tab ) ;
417- }
418- return tab ;
375+ return TabManager . getTabURL ( await getActiveTab ( ) ) ;
419376 }
420377}
0 commit comments