(function() { const import_cache = {}; function fetch_import(id) { return new Promise((fulfil, reject) => { curl([`https://bundle.run/${id}`]).then(module => { import_cache[id] = module; fulfil(module); }, err => { console.error(err.stack); reject(new Error(`Error loading ${id} from bundle.run`)); }); }); } function fetch_imports(imports, progress_func) { const missing_imports = imports.filter(x => !import_cache[x]); let pending_imports = missing_imports.length; if (missing_imports.length) { let promise = Promise.all( missing_imports.map(id => fetch_import(id).then(() => { pending_imports -= 1; if (progress_func) progress_func(pending_imports); })) ); return promise; } else { return Promise.resolve(); } } function handle_message(ev) { let { action, cmd_id } = ev.data; const send_message = (payload) => parent.postMessage( { ...payload }, ev.origin); const send_reply = (payload) => send_message({ ...payload, cmd_id }); const send_ok = () => send_reply({ action: 'cmd_ok' }); const send_error = (message, stack) => send_reply({ action: 'cmd_error', message, stack }); if (action === 'eval') { try { const { script } = ev.data.args; eval(script); send_ok(); } catch (e) { send_error(e.message, e.stack); } } if (action === 'catch_clicks') { try { const top_origin = ev.origin; document.body.addEventListener('click', event => { if (event.which !== 1) return; if (event.metaKey || event.ctrlKey || event.shiftKey) return; if (event.defaultPrevented) return; // ensure target is a link let el = event.target; while (el && el.nodeName !== 'A') el = el.parentNode; if (!el || el.nodeName !== 'A') return; if (el.hasAttribute('download') || el.getAttribute('rel') === 'external' || el.target) return; event.preventDefault(); if (el.href.startsWith(top_origin)) { const url = new URL(el.href); if (url.hash[0] === '#') { window.location.hash = url.hash; return; } } window.open(el.href, '_blank'); }); send_ok(); } catch(e) { send_error(e.message, e.stack); } } if (action === 'fetch_imports') { const { imports, import_map } = ev.data.args; fetch_imports(imports, (remaining) => { send_message({action: 'fetch_progress', args: { remaining }}); }) .then(() => { imports.forEach(x=> { const module = import_cache[x]; const name = import_map.get(x); window[name] = module; }); send_ok(); }) .catch(e => { send_error(e.message, e.stack); }); } } window.addEventListener('message', handle_message, false); })();