UNPKG

webext-active-tab

Version:

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

48 lines (47 loc) 1.99 kB
import { injectContentScript } from 'webext-content-scripts'; import { addActiveTabListener, possiblyActiveTabs } from './tracker.js'; import { isContentScriptRegistered } from './utils.js'; const gotNavigation = typeof chrome === 'object' && 'webNavigation' in chrome; const scripts = chrome.runtime.getManifest().content_scripts; async function injectToTabUnlessRegistered({ id: tabId, origin }) { if (tabId === undefined) { return; } const frames = gotNavigation // Only with `webNavigation` we can inject into the frames ? await chrome.webNavigation.getAllFrames({ tabId }) // Without it, we only inject it into the top frame : [{ frameId: 0, url: origin }]; // .map() needed for async loop void frames?.map(async ({ frameId, url }) => injectIfActive({ frameId, url, tabId })); } async function injectIfActive({ tabId, frameId, url }) { const { origin } = new URL(url); if ( // Check origin because the request might be for a frame; cross-origin frames do not receive activeTab possiblyActiveTabs.get(tabId) === origin // Don't inject if already registered && !(await isContentScriptRegistered(url))) { console.debug('activeTab: will inject', { tabId, frameId, url }); await injectContentScript({ tabId, frameId }, scripts); } else { console.debug('activeTab: won’t inject', { tabId, frameId, url }, { activeTab: possiblyActiveTabs.get(tabId) ?? 'no' }); } } async function tabListener(tabId, { status }, { url }) { // Only status updates are relevant // No URL = no permission if (status === 'loading' && url) { await injectIfActive({ tabId, url, frameId: 0 }); } } export default function register() { addActiveTabListener(injectToTabUnlessRegistered); if (gotNavigation) { chrome.webNavigation.onCommitted.addListener(injectIfActive); } else { chrome.tabs.onUpdated.addListener(tabListener); } }