| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- 'use strict';
- // loadScript(script: Array<Promise|string>|string): Promise
- // eslint-disable-next-line no-var
- var loadScript = (() => {
- const cache = new Map();
- function inject(file) {
- if (!cache.has(file)) {
- cache.set(file, doInject(file));
- }
- return cache.get(file);
- }
- function doInject(file) {
- return new Promise((resolve, reject) => {
- let el;
- if (file.endsWith('.js')) {
- el = document.createElement('script');
- el.src = file;
- } else {
- el = document.createElement('link');
- el.rel = 'stylesheet';
- el.href = file;
- }
- el.onload = () => {
- el.onload = null;
- el.onerror = null;
- resolve();
- };
- el.onerror = () => {
- el.onload = null;
- el.onerror = null;
- reject(new Error(`Failed to load script: ${file}`));
- };
- document.head.appendChild(el);
- });
- }
- return files => {
- if (!Array.isArray(files)) {
- files = [files];
- }
- return Promise.all(files.map(f => (typeof f === 'string' ? inject(f) : f)));
- };
- })();
- (() => {
- 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(), 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;
- }
- }
- })();
|