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
JavaScript
;
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;