/* Helper to manage the visibility and icon of a pageAction button. * Each callback is evaluated whenever the tab has changed. * Callbacks may be async (i.e. return a Promise). * * Arguments: * - options.visible: Tab => boolean; whether to show the pageAction button * - options.icon: Tab => either a string (the icon path), or null (to get the * default icon from the manifest), or an object (with path or imageData, see * docs of browser.pageAction.setIcon). * - options.title: Tab => string (to use as button tooltip), or null (to use * default title from the manifest) * - options.onClicked: Tab => void; executed on click, after which the button * state is automatically updated on all tabs. * * Returns an object with the following methods: * - update(tab?): update visibility, icons, etcetera of a given tab, or of * all tabs if the tab argument is omitted. * * Example usage: * const pageActionButton = PageActionButton({ * visible: tab => tab.url.startsWith('https'), * icon: tab => isEnabled(tab.url) ? '/icon_enabled.svg' : '/icon_disabled.svg', * title: tab => isEnabled(tab.url) ? 'Disable' : 'Enable', * onClicked: tab => toggleEnabled(tab.url), * }) * // Manually trigger an update of a tab. * pageActionButton.update(tab) */ import browser from 'webextension-polyfill' export default function PageActionButton({ visible = tab => true, icon = tab => null, title = tab => null, onClicked = tab => {}, }) { async function setIcon(tab) { let iconSetting = await icon(tab) if (typeof iconSetting === 'string' || iconSetting === null) { iconSetting = { path: iconSetting } } browser.pageAction.setIcon({ ...iconSetting, tabId: tab.id, }) } async function setTitle(tab) { browser.pageAction.setTitle({ title: await title(tab), tabId: tab.id, }) } async function checkTab(tab) { if (await visible(tab)) { setIcon(tab) setTitle(tab) browser.pageAction.show(tab.id) } else { browser.pageAction.hide(tab.id) } } async function checkAllTabs() { const tabs = await browser.tabs.query({}) for (const tab of tabs) { await checkTab(tab) } } // Show/hide the button on current tabs (XXX not awaiting it's completion) checkAllTabs() // Show/hide the button whenever a tab changes. browser.tabs.onUpdated.addListener((id, changeInfo, tab) => { checkTab(tab) }); // Handle button clicks browser.pageAction.onClicked.addListener(async tab => { await onClicked(tab) await checkAllTabs(tab) }) return { update: tab => tab ? checkTab(tab) : checkAllTabs() } }