| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- 'use strict';
- (() => {
- /* Chrome reinjects content script when documentElement is replaced so we ignore it
- by checking against a literal `1`, not just `if (truthy)`, because <html id="INJECTED">
- is exposed per HTML spec as a global `window.INJECTED` */
- if (window.INJECTED === 1) return;
- //#region for content scripts and our extension pages
- if (!((window.browser || {}).runtime || {}).sendMessage) {
- /* Auto-promisifier with a fallback to direct call on signature error.
- The fallback isn't used now since we call all synchronous methods via `chrome` */
- const directEvents = ['addListener', 'removeListener', 'hasListener', 'hasListeners'];
- // generated by tools/chrome-api-no-cb.js
- const directMethods = {
- alarms: ['create'],
- extension: ['getBackgroundPage', 'getExtensionTabs', 'getURL', 'getViews', 'setUpdateUrlData'],
- i18n: ['getMessage', 'getUILanguage'],
- identity: ['getRedirectURL'],
- runtime: ['connect', 'connectNative', 'getManifest', 'getURL', 'reload', 'restart'],
- tabs: ['connect'],
- };
- const promisify = function (fn, ...args) {
- let res;
- try {
- let resolve, reject;
- /* Some callbacks have 2 parameters so we're resolving as an array in that case.
- For example, chrome.runtime.requestUpdateCheck and chrome.webRequest.onAuthRequired */
- args.push((...results) =>
- chrome.runtime.lastError ?
- reject(new Error(chrome.runtime.lastError.message)) :
- resolve(results.length <= 1 ? results[0] : results));
- fn.apply(this, args);
- res = new Promise((...rr) => ([resolve, reject] = rr));
- } catch (err) {
- if (!err.message.includes('No matching signature')) {
- throw err;
- }
- args.pop();
- res = fn.apply(this, args);
- }
- return res;
- };
- const proxify = (src, srcName, target, key) => {
- let res = src[key];
- if (res && typeof res === 'object') {
- res = createProxy(res, key); // eslint-disable-line no-use-before-define
- } else if (typeof res === 'function') {
- res = (directMethods[srcName] || directEvents).includes(key)
- ? res.bind(src)
- : promisify.bind(src, res);
- }
- target[key] = res;
- return res;
- };
- const createProxy = (src, srcName) =>
- new Proxy({}, {
- get(target, key) {
- return target[key] || proxify(src, srcName, target, key);
- },
- });
- window.browser = createProxy(chrome);
- }
- //#endregion
- if (!chrome.tabs) return;
- //#region for our extension pages
- const reqPromise = {};
- window.require = async function require(urls, cb) {
- const promises = [];
- const all = [];
- const toLoad = [];
- for (let url of Array.isArray(urls) ? urls : [urls]) {
- const isCss = url.endsWith('.css');
- const tag = isCss ? 'link' : 'script';
- const attr = isCss ? 'href' : 'src';
- if (!isCss && !url.endsWith('.js')) url += '.js';
- if (url.startsWith('/')) url = url.slice(1);
- let el = document.head.querySelector(`${tag}[${attr}$="${url}"]`);
- if (!el) {
- el = document.createElement(tag);
- toLoad.push(el);
- reqPromise[url] = new Promise((resolve, reject) => {
- el.onload = resolve;
- el.onerror = reject;
- el[attr] = url;
- if (isCss) el.rel = 'stylesheet';
- }).catch(console.warn);
- }
- promises.push(reqPromise[url]);
- all.push(el);
- }
- if (toLoad.length) document.head.append(...toLoad);
- if (promises.length) await Promise.all(promises);
- if (cb) cb(...all);
- return all[0];
- };
- if (!(new URLSearchParams({foo: 1})).get('foo')) {
- // TODO: remove when minimum_chrome_version >= 61
- window.URLSearchParams = class extends URLSearchParams {
- constructor(init) {
- if (init && typeof init === 'object') {
- super();
- for (const [key, val] of Object.entries(init)) {
- this.set(key, val);
- }
- } else {
- super(...arguments);
- }
- }
- };
- }
- //#endregion
- })();
|