import MemoryStorage from "../infrastructures/MemoryStorage"; const CURRENT_SELECTED_KEY = "tabs.current.selected"; const LAST_SELECTED_KEY = "tabs.last.selected"; type Tab = browser.tabs.Tab; export default interface TabPresenter { open(url: string, tabId?: number): Promise; create( url: string, opts?: { active?: boolean; cookieStoreId?: string; index?: number; openerTabId?: number; pinned?: boolean; windowId?: number; } ): Promise; getCurrent(): Promise; getAll(): Promise; getLastSelectedId(): Promise; getByKeyword(keyword: string, excludePinned: boolean): Promise; select(tabId: number): Promise; remove(ids: number[]): Promise; reopen(): Promise; reload(tabId: number, cache: boolean): Promise; setPinned(tabId: number, pinned: boolean): Promise; duplicate(id: number): Promise; getZoom(tabId: number): Promise; setZoom(tabId: number, factor: number): Promise; onSelected( listener: (arg: { tabId: number; windowId: number }) => void ): void; toggleReaderMode(tabId: number): Promise; } export class TabPresenterImpl implements TabPresenter { open(url: string, tabId?: number): Promise { return browser.tabs.update(tabId, { url }); } create( url: string, opts?: { active?: boolean; cookieStoreId?: string; index?: number; openerTabId?: number; pinned?: boolean; windowId?: number; } ): Promise { return browser.tabs.create({ url, ...opts }); } async getCurrent(): Promise { const tabs = await browser.tabs.query({ active: true, currentWindow: true, }); return tabs[0]; } getAll(): Promise { return browser.tabs.query({ currentWindow: true }); } async getLastSelectedId(): Promise { const cache = new MemoryStorage(); const tabId = await cache.get(LAST_SELECTED_KEY); if (tabId === null || typeof tabId === "undefined") { return; } return tabId; } async getByKeyword(keyword: string, excludePinned = false): Promise { const tabs = await browser.tabs.query({ currentWindow: true }); return tabs .filter((t) => { return ( (t.url && t.url.toLowerCase().includes(keyword.toLowerCase())) || (t.title && t.title.toLowerCase().includes(keyword.toLowerCase())) ); }) .filter((t) => { return !(excludePinned && t.pinned); }); } async select(tabId: number): Promise { await browser.tabs.update(tabId, { active: true }); } async remove(ids: number[]): Promise { await browser.tabs.remove(ids); } async reopen(): Promise { const window = await browser.windows.getCurrent(); const sessions = await browser.sessions.getRecentlyClosed(); const session = sessions.find((s) => { return s.tab && s.tab.windowId === window.id; }); if (!session) { return; } if (session.tab && session.tab.sessionId) { await browser.sessions.restore(session.tab.sessionId); } else if (session.window && session.window.sessionId) { await browser.sessions.restore(session.window.sessionId); } } async reload(tabId: number, cache: boolean): Promise { await browser.tabs.reload(tabId, { bypassCache: cache }); } async setPinned(tabId: number, pinned: boolean): Promise { await browser.tabs.update(tabId, { pinned }); } duplicate(id: number): Promise { return browser.tabs.duplicate(id); } getZoom(tabId: number): Promise { return browser.tabs.getZoom(tabId); } setZoom(tabId: number, factor: number): Promise { return browser.tabs.setZoom(tabId, factor); } onSelected( listener: (arg: { tabId: number; windowId: number }) => void ): void { browser.tabs.onActivated.addListener(listener); } toggleReaderMode(tabId: number): Promise { return browser.tabs.toggleReaderMode(tabId); } } const tabPresenter = new TabPresenterImpl(); tabPresenter.onSelected((tab: any) => { const cache = new MemoryStorage(); const lastId = cache.get(CURRENT_SELECTED_KEY); if (lastId) { cache.set(LAST_SELECTED_KEY, lastId); } cache.set(CURRENT_SELECTED_KEY, tab.tabId); });