UNPKG

browser-automator

Version:

Puppeteer alternative for Chrome extensions. A module for Chrome extensions that functions similarly to Puppeteer.

178 lines (177 loc) 6.72 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.syncPageIntegration = void 0; const page_1 = __importDefault(require("./page")); const self_1 = require("./self"); const syncPageIntegration = async (tabId) => { await chrome.scripting.executeScript({ target: { tabId }, func: self_1.selfIntegration }).catch(() => { }); }; exports.syncPageIntegration = syncPageIntegration; /** * Represents a Browser instance for interacting with Chrome browser pages. */ class Browser { /** * An array of available Page instances within the browser. */ availablePages = []; /** * Creates a new Browser instance. */ constructor() { onbeforeunload = (event) => { event.preventDefault(); this.close(); return false; }; this.syncListeners(); } /** * Returns an array of available Page instances. * @returns An array of available Page instances. */ pages() { return this.availablePages; } /** * Closes all associated pages in the Browser instance. */ async close() { try { onbeforeunload = null; await Promise.all(this.availablePages.map(async (page) => { const { tabId, originWindowId, activeInOrigin, onBeforeClose } = page; if (onBeforeClose) onBeforeClose(); if (!originWindowId) await page.close(); else { if (originWindowId !== (await chrome.tabs.get(tabId)).windowId) await chrome.tabs.move(tabId, { index: -1, windowId: originWindowId }); if (activeInOrigin) await chrome.tabs.update(tabId, { active: true }); } })); this.availablePages = []; this.syncListeners(); } catch (glitch) { throw glitch; } } /** * Creates a new Page instance and associates it with the browser. * @param tabId - The ID of the tab to use for creating the Page instance. If not supplied a tab will be created. * @param windowId - The ID of the window to open the page in. If not supplied a window will be created. * @param originWindowId - The ID of the tab's origin window. If supplied the tab will be moved in that window when closing the browser-automator instance instead of closing the tab. * @param activeInOrigin - Whether the page/tab should be active in the origin window when moved to the origin window. * @param windowOptions - Options for creating the window. * @param tabOptions - Options for creating or updating the tab. * @returns A Promise that resolves with the new Page instance. */ async newPage({ tabId, windowId, originWindowId, activeInOrigin, windowOptions, tabOptions } = {}) { try { if (windowId) { if (tabId) { if (tabOptions) await chrome.tabs.update(tabId, tabOptions); } else await chrome.tabs.create({ url: 'about:blank', ...tabOptions }).then(createdTab => { tabId = createdTab.id; }); } else { await chrome.windows.create({ type: 'popup', focused: true, width: 1000, left: Math.round((screen.availWidth - 1000) * 0.5), height: 650, top: Math.round((screen.availHeight - 650) * 0.5), ...(tabId ? { tabId } : { url: 'about:blank' }), ...(windowOptions || {}) }).then((createdWindow) => { tabId = createdWindow.tabs[0].id; windowId = createdWindow.id; }); if (tabOptions) await chrome.tabs.update(tabId, tabOptions); } const page = new page_1.default({ browser: this, tabId, windowId, ...(originWindowId ? { originWindowId, activeInOrigin: activeInOrigin || false } : {}) }); this.availablePages.push(page); this?.onPageAdded?.(page); this.syncListeners(); (0, exports.syncPageIntegration)(tabId); return page; } catch (glitch) { throw glitch; } } /** * A callback function that is invoked when a new page is added to the browser. */ onPageAdded; /** * A callback function that is invoked when a page is closed. */ onPageClose; /** * A callback function that is invoked when a page is updated. */ onPageUpdate; handleTabRemove = (tabId, removeInfo) => { const index = this.availablePages.findIndex(({ tabId: id }) => id === tabId); if (index !== -1) { this?.onPageClose?.(tabId, removeInfo); this.availablePages.splice(index, 1); } }; handleTabUpdate = (tabId, changeInfo, tab) => { const index = this.availablePages.findIndex(({ tabId: id }) => id === tabId); if (index !== -1) { this?.onPageUpdate?.(this.availablePages[index]); if (changeInfo.status === 'complete' && tab.url?.match(/^HTTP/i)) { (0, exports.syncPageIntegration)(tabId); } } }; syncListeners() { if (this.availablePages.length) { if (!chrome.tabs.onUpdated.hasListener(this.handleTabUpdate)) chrome.tabs.onUpdated.addListener(this.handleTabUpdate); if (!chrome.tabs.onRemoved.hasListener(this.handleTabRemove)) chrome.tabs.onRemoved.addListener(this.handleTabRemove); } else { if (chrome.tabs.onUpdated.hasListener(this.handleTabUpdate)) chrome.tabs.onUpdated.removeListener(this.handleTabUpdate); if (chrome.tabs.onRemoved.hasListener(this.handleTabRemove)) chrome.tabs.onRemoved.removeListener(this.handleTabRemove); } } } exports.default = Browser;