62 lines
2.0 KiB
JavaScript
62 lines
2.0 KiB
JavaScript
function createFeatureLoader({ document, urls, timeoutMs = 10000 }) {
|
|
const pending = new Map();
|
|
const loaded = new Set();
|
|
|
|
function load(name) {
|
|
if (loaded.has(name)) return Promise.resolve();
|
|
if (pending.has(name)) return pending.get(name);
|
|
const url = urls[name];
|
|
if (!url) return Promise.reject(new Error('Unknown feature: ' + name));
|
|
|
|
const request = new Promise((resolve, reject) => {
|
|
const script = document.createElement('script');
|
|
let timeout;
|
|
const fail = () => {
|
|
clearTimeout(timeout);
|
|
script.remove();
|
|
pending.delete(name);
|
|
reject(new Error('Could not load ' + name.replace(/-/g, ' ') + '.'));
|
|
};
|
|
script.src = url;
|
|
script.async = true;
|
|
script.onload = () => {
|
|
clearTimeout(timeout);
|
|
pending.delete(name);
|
|
loaded.add(name);
|
|
resolve();
|
|
};
|
|
script.onerror = fail;
|
|
timeout = setTimeout(fail, timeoutMs);
|
|
document.head.appendChild(script);
|
|
});
|
|
pending.set(name, request);
|
|
return request;
|
|
}
|
|
|
|
async function run(name, elements, callback) {
|
|
const trigger = elements?.trigger;
|
|
const status = elements?.status;
|
|
const retryLabel = elements?.retryLabel || 'Tap New issue to retry.';
|
|
if (trigger) trigger.disabled = true;
|
|
if (status) status.textContent = 'Loading ' + name.replace(/-/g, ' ') + '…';
|
|
try {
|
|
await load(name);
|
|
callback();
|
|
if (status) status.textContent = '';
|
|
return true;
|
|
} catch (_error) {
|
|
if (status) {
|
|
const label = name === 'issue-capture' ? 'Issue capture' :
|
|
name === 'pull-workflow' ? 'Pull workspace' : name.replace(/-/g, ' ');
|
|
status.textContent = label + ' could not load. ' + retryLabel;
|
|
}
|
|
return false;
|
|
} finally {
|
|
if (trigger) trigger.disabled = false;
|
|
}
|
|
}
|
|
|
|
return { load, run, ready: name => loaded.has(name) };
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = createFeatureLoader; |