import browser, {Menus} from 'webextension-polyfill'; import {debug, error} from './utilities/log'; import {getManifest, updateBadge} from './utilities/browser'; import {versionAsNumber} from './utilities/version'; import Settings from './utilities/settings'; import {migrate} from './utilities/migrations'; import {Queue} from './types.d'; let timeoutID: number | null = null; browser.runtime.onStartup.addListener(async () => { debug('Removing history from local storage'); await browser.storage.local.remove('history'); }); browser.browserAction.onClicked.addListener(async () => { const settings = await Settings.get(); // When the extension icon is initially clicked, create a timeout for 500ms // that will open the next queue item when it expires. // If the icon is clicked again in those 500ms, open the options page instead. if (timeoutID === null) { timeoutID = window.setTimeout(async () => { timeoutID = null; const nextItem = settings.nextItem(); if (nextItem === undefined) { await openOptionsPage(); } else { const tabs = await browser.tabs.query({ currentWindow: true, active: true, }); const message: Queue.Message = { action: 'queue open url', data: nextItem, }; try { await browser.tabs.sendMessage(tabs[0].id!, message); } catch { await browser.tabs.create({active: true, url: nextItem.url}); } await settings.removeItem(nextItem.id); } }, 500); } else { window.clearTimeout(timeoutID); timeoutID = null; await openOptionsPage(); } }); browser.runtime.onMessage.addListener( async (request: Queue.Message) => { if (request.action === 'queue update badge') { await updateBadge(await Settings.get()); } }, ); browser.runtime.onInstalled.addListener(async () => { const manifest = getManifest(); const settings = await Settings.get(); const versionGotUpdated = versionAsNumber(manifest.version) > versionAsNumber(settings.latestVersion); if (versionGotUpdated) { // Set the previous sync storage data in the local storage as a backup. const previous = await browser.storage.sync.get(); await browser.storage.local.clear(); await browser.storage.local.set(previous); // Then migrate the sync storage data and update it. const next = migrate(settings.latestVersion, previous); next.latestVersion = manifest.version; next.versionGotUpdated = versionGotUpdated; await browser.storage.sync.clear(); await browser.storage.sync.set(next); } // Open the options page when: // * The extension is first installed or is updated. // * In development, for convenience. if (versionGotUpdated || manifest.nodeEnv === 'development') { await openOptionsPage(); } }); async function openOptionsPage() { return browser.runtime.openOptionsPage(); } /** The callback function for custom context menu entries. */ function contextCreated() { if ( browser.runtime.lastError !== null && browser.runtime.lastError !== undefined ) { error(browser.runtime.lastError); } } const contextMenus: Menus.CreateCreatePropertiesType[] = [ { id: 'queue-add-new-link', title: 'Add to Queue', contexts: ['link'], }, { id: 'queue-add-new-link-tab', title: 'Add to Queue', contexts: ['tab'], }, { id: 'queue-open-next-link-in-new-tab', title: 'Open next link in new tab', contexts: ['browser_action'], }, { id: 'queue-open-options-page', title: 'Open the extension page', contexts: ['browser_action'], }, ]; const contextMenuIDs: Set = new Set( contextMenus.map((value) => value.id!), ); for (const menu of contextMenus) { browser.contextMenus.create(menu, contextCreated); } browser.contextMenus.onClicked.addListener(async (info, tab) => { const id = info.menuItemId.toString(); if (!contextMenuIDs.has(id)) { return; } const settings = await Settings.get(); if (id.includes('queue-add-new-link')) { let text: string | undefined; let url: string; if (info.menuItemId === 'queue-add-new-link') { text = info.linkText; url = info.linkUrl!; } else if (info.menuItemId === 'queue-add-new-link-tab') { text = tab?.title; url = info.pageUrl!; } else { error(`Unknown menuItemId: ${info.menuItemId}`); return; } settings.queue.push({ added: new Date(), id: settings.newItemId(), text: text ?? url, url, }); await settings.save(); await updateBadge(settings); } else if (id === 'queue-open-next-link-in-new-tab') { const nextItem = settings.nextItem(); if (nextItem === undefined) { await openOptionsPage(); } else { await browser.tabs.create({active: true, url: nextItem.url}); await settings.removeItem(nextItem.id); } } else if (id === 'queue-open-options-page') { await openOptionsPage(); } });