Skip to content

Instantly share code, notes, and snippets.

@disco0
Last active October 5, 2020 07:12
Show Gist options
  • Save disco0/6bb36689412f8fcd064d1537de106fdc to your computer and use it in GitHub Desktop.
Save disco0/6bb36689412f8fcd064d1537de106fdc to your computer and use it in GitHub Desktop.
Browser Extension window.onload workaround
(() => {
let subscribers, observer;
// natively declared <script> elements in html can't have onload= attribute
// due to the default extension CSP that forbids inline code (and we don't want to relax it),
// so we're using MutationObserver to add onload event listener to the script element to be loaded
window.onDOMscriptReady = (srcSuffix, timeout = 1000) =>
{
if (!subscribers)
{
subscribers = new Map();
observer = new MutationObserver(observe);
observer.observe(document.head, { childList: true });
}
return new Promise((resolve, reject) =>
{
const listeners = subscribers.get(srcSuffix);
if (listeners)
listeners.push(resolve);
else
subscribers.set(srcSuffix, [resolve]);
// a resolved Promise won't reject anymore
setTimeout(() => {
emptyAfterCleanup(srcSuffix);
reject(new Error('Timeout'));
}, timeout);
});
};
return;
function observe(mutations) {
for (const { addedNodes } of mutations) {
for (const n of addedNodes) {
if (n.src && getSubscribersForSrc(n.src)) {
n.addEventListener('load', notifySubscribers);
}
}
}
}
function getSubscribersForSrc(src) {
for (const [suffix, listeners] of subscribers.entries()) {
if (src.endsWith(suffix)) {
return { suffix, listeners };
}
}
}
function notifySubscribers(event) {
this.removeEventListener('load', notifySubscribers);
for (let data; (data = getSubscribersForSrc(this.src));) {
data.listeners.forEach(fn => fn(event));
if (emptyAfterCleanup(data.suffix)) {
return;
}
}
}
function emptyAfterCleanup(suffix) {
if (!subscribers) {
return true;
}
subscribers.delete(suffix);
if (!subscribers.size) {
observer.disconnect();
observer = null;
subscribers = null;
return true;
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment