/** * @typedef {object} IncludeFile * * @prop {boolean} ok * @prop {number} status * @prop {string} html */ /** @type {Map>} */ const includeFiles = new Map(); /** * * @param {string} src * @param {'cors' | 'no-cors' | 'same-origin'} [mode='cors'] * * @returns {Promise} */ export function requestInclude(src, mode = 'cors'){ const prev = includeFiles.get(src); if (prev !== undefined) { return Promise.resolve(prev); } const fileDataPromise = fetch(src, { mode: mode }).then(async response => { const res = { ok: response.ok, status: response.status, html: await response.text() }; includeFiles.set(src, res); return res; }); includeFiles.set(src, fileDataPromise); return fileDataPromise; } class HtmlImport extends HTMLElement { constructor () { super(); } static get observedAttributes () { return ['src', 'mode', 'allow-scripts']; } get src() { return this.getAttribute('src') || ''; } set src(value) { this.setAttribute('src', value); } get mode() { return this.getAttribute('mode') || 'cors'; } set mode(value) { this.setAttribute('mode', value); } get allowScripts() { return this.hasAttribute('allow-scripts'); } set allowScripts(value) { this.toggleAttribute('allow-scripts', value); } /** * 执行 innerHTML 中的 * @param {HTMLScriptElement} scripts */ async executeScript(scripts) { const execQueue = function (script) { const newScript = document.createElement('script'); [...script.attributes].forEach(attr => newScript.setAttribute(attr.name, attr.value)); newScript.textContent = script.textContent; script.parentNode && script.parentNode.replaceChild(newScript, script); return script.src ? new Promise((resolve) => { newScript.async = false; newScript.addEventListener('load', e => resolve(e)); newScript.addEventListener('error', e => resolve(e)); }) : Promise.resolve(); }; // 按