stylus/js/polyfill.js

96 lines
3.1 KiB
JavaScript

'use strict';
// eslint-disable-next-line no-unused-expressions
self.INJECTED !== 1 && (() => {
//#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
for (const storage of ['localStorage', 'sessionStorage']) {
try {
window[storage]._access_check = 1;
delete window[storage]._access_check;
} catch (err) {
Object.defineProperty(window, storage, {value: {}});
}
}
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
})();