UNPKG

webext-active-tab

Version:

WebExtension module: Track `activeTab` permission; automatically inject content scripts

46 lines (45 loc) 1.83 kB
import { injectContentScript } from 'webext-content-scripts'; import { onActiveTab, possiblyActiveTabs } from './on-active-tab.js'; const gotNavigation = typeof chrome === 'object' && 'webNavigation' in chrome; const scripts = []; async function injectAllFrames({ id: tabId, origin: url }) { if (tabId === undefined) { return; } if (!gotNavigation) { // Without it, we only inject it into the top frame return injectOneFrame({ frameId: 0, url, tabId }); } const frames = await chrome.webNavigation.getAllFrames({ tabId }); // .map() needed for async loop void frames?.map(async ({ frameId, url }) => injectOneFrame({ frameId, url, tabId })); } async function injectOneFrame({ tabId, frameId, url }) { const { origin } = new URL(url); const activeOrigin = await possiblyActiveTabs.get(String(tabId)); // Check origin because the request might be for a frame; cross-origin frames do not receive activeTab if (activeOrigin === origin) { console.debug('activeTab: will inject', { tabId, frameId, url }); await injectContentScript({ tabId, frameId }, scripts); } else { console.debug('activeTab: won’t inject', { tabId, frameId, url }, { activeTab: activeOrigin ?? 'no' }); } } async function tabListener(tabId, { status }, { url }) { // Only status updates are relevant // No URL = no permission if (status === 'loading' && url) { await injectOneFrame({ tabId, url, frameId: 0 }); } } export default function registerActiveTabScripts(...newScripts) { scripts.push(...newScripts); onActiveTab.addListener(injectAllFrames); if (gotNavigation) { chrome.webNavigation.onCommitted.addListener(injectOneFrame); } else { chrome.tabs.onUpdated.addListener(tabListener); } }