diff --git a/docs/assets/js/common.js b/docs/assets/js/common.js index 3621591ce..d092642b4 100644 --- a/docs/assets/js/common.js +++ b/docs/assets/js/common.js @@ -1,3 +1,4 @@ +/* global Artplayer, monaco */ (function () { Artplayer.DEBUG = true @@ -5,22 +6,22 @@ window.location.href = `./mobile.html${location.search}` } - let $codeMirror = document.querySelector('.codeMirrorWrap') - let $lib = document.querySelector('.libsInput') - let $run = document.querySelector('.run') - let $popups = document.querySelector('.popups') - let $console = document.querySelector('.console') - let $prod = document.querySelector('#prod') - let $ts = document.querySelector('#ts') - let $code = document.querySelector('#code') - let $log = document.querySelector('#log') - let $file = document.querySelector('#file') - let $editor = document.querySelector('#editor') + const $codeMirror = document.querySelector('.codeMirrorWrap') + const $lib = document.querySelector('.libsInput') + const $run = document.querySelector('.run') + const $popups = document.querySelector('.popups') + const $console = document.querySelector('.console') + const $prod = document.querySelector('#prod') + const $ts = document.querySelector('#ts') + const $code = document.querySelector('#code') + const $log = document.querySelector('#log') + const $file = document.querySelector('#file') + const $editor = document.querySelector('#editor') window.consoleLog($console) // Helper functions for localStorage - const getStorageBoolean = (key) => localStorage.getItem(key) === 'true' + const getStorageBoolean = key => localStorage.getItem(key) === 'true' const setStorageBoolean = (key, value) => localStorage.setItem(key, value ? 'true' : 'false') $prod.checked = getStorageBoolean('prod') @@ -37,7 +38,7 @@ } let editor = null - let loadedLibs = [] + let initialization = 0 require.config({ paths: { vs: './assets/js/vs' } }) require(['vs/editor/editor.main'], async () => { monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({ @@ -50,7 +51,7 @@ allowNonTsExtensions: true, }) - let libUris = [ + const libUris = [ './assets/ts/artplayer-plugin-ads.d.ts', './assets/ts/artplayer-plugin-ambilight.d.ts', './assets/ts/artplayer-plugin-asr.d.ts', @@ -76,8 +77,8 @@ ] for (let index = 0; index < libUris.length; index++) { - let libUri = libUris[index] - let libSource = await (await fetch(libUri)).text() + const libUri = libUris[index] + const libSource = await (await fetch(libUri)).text() monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri) monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri)) } @@ -108,122 +109,51 @@ }) }) - function getURLParameters(url) { - return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce((params, pair) => { - const index = pair.indexOf('=') - params[pair.slice(0, index)] = pair.slice(index + 1) - return params - }, {}) + async function loadLib(libs) { + $lib.value = decodeURIComponent(libs || '') + return window.ArtplayerDocsLoader.loadLibraries(libs) } - function getExt(url) { - if (url.includes('?')) { - return getExt(url.split('?')[0]) - } - - if (url.includes('#')) { - return getExt(url.split('#')[0]) - } - - return url.trim().toLowerCase().split('.').pop() + async function runExample(name, current) { + const text = await window.ArtplayerDocsLoader.exampleSource(name) + if (current !== initialization) + return + editor.setValue(text) + runCode() } - function loadScript(url) { - return new Promise((resolve, reject) => { - const originalDefine = window.define - window.define = undefined - const script = document.createElement('script') - script.type = 'text/javascript' - script.src = url - script.onload = () => { - window.define = originalDefine - resolve(url) - } - script.onerror = () => { - window.define = originalDefine - reject(new Error(`Loading script failed: ${url}`)) - } - document.head.appendChild(script) - }) - } - - function loadStyle(url) { - return new Promise((resolve, reject) => { - const link = document.createElement('link') - link.rel = 'stylesheet' - link.href = url - link.onload = () => resolve(url) - link.onerror = () => reject(new Error(`Loading style failed: ${url}`)) - document.head.appendChild(link) - }) - } - - function loadLib(libs) { - const libPromises = [] - const libsDecoded = decodeURIComponent(libs || '') - const urls = libsDecoded - .split(/\r?\n/) - .filter((url) => url.trim() && !loadedLibs.includes(url)) - - urls.forEach((url) => { - const ext = getExt(url) - if (ext === 'js') { - libPromises.push(loadScript(url)) - } else if (ext === 'css') { - libPromises.push(loadStyle(url)) - } - }) - - $lib.value = libsDecoded - return Promise.all(libPromises) - } - - function runExample(name) { - fetch(`./assets/example/${name}.js`) - .then((response) => { - return response.text() - }) - .then((text) => { - editor.setValue(text) - runCode() - }) - .catch((err) => { - console.error(err) - }) - } - - function loadCode(code, example) { - if (example) { - runExample(example) - } - else if (code) { + function loadCode(code, example, current) { + if (current !== initialization) + return + if (example) + return runExample(example, current) + if (code) { editor.setValue(decodeURIComponent(code).trim()) runCode() } else { - runExample('index') + return runExample('index', current) } } function runCode() { window.dispatchEvent(new Event('artplayer:example:cleanup')) // Destroy all existing instances - Artplayer.instances.slice().forEach((art) => art.destroy(true)) - + Artplayer.instances.slice().forEach(art => art.destroy(true)) + const value = editor.getValue() + // eslint-disable-next-line no-eval -- Preserve the editor's classic-script Run scope for user-provided examples. eval(value) window.art = Artplayer.instances[0] } function initApp() { - const urlParams = getURLParameters(window.location.href) + const current = ++initialization + const urlParams = window.ArtplayerDocsLoader.parameters(window.location.href) const { code, libs, example } = urlParams loadLib(libs) - .then((result) => { - loadedLibs.push(...result) - loadCode(code, example) - }) + .then(() => loadCode(code, example, current)) .catch((err) => { console.error('Failed to initialize app:', err) }) diff --git a/docs/assets/js/loader.js b/docs/assets/js/loader.js new file mode 100644 index 000000000..1488abd38 --- /dev/null +++ b/docs/assets/js/loader.js @@ -0,0 +1,135 @@ +// Generated by yarn build:site-assets. Do not edit. +"use strict"; +(() => { + // packages/artplayer-vitepress/browser/loader.ts + function parameters(url) { + const result = {}; + for (const part of new URL(url).search.slice(1).split("&")) { + const index = part.indexOf("="); + if (index >= 0) + result[part.slice(0, index)] = part.slice(index + 1); + } + return result; + } + function suspendDefine(host) { + const descriptor = Object.getOwnPropertyDescriptor(host, "define"); + if (descriptor?.configurable === false) { + if (!("value" in descriptor) || !descriptor.writable) + throw new Error("Cannot temporarily suspend the AMD loader"); + Object.defineProperty(host, "define", { value: void 0 }); + } else { + Object.defineProperty(host, "define", { value: void 0, configurable: true, writable: true, enumerable: descriptor?.enumerable ?? true }); + } + return () => { + if (descriptor) + Object.defineProperty(host, "define", descriptor); + else Reflect.deleteProperty(host, "define"); + }; + } + function createLibraryLoader(host = window) { + const loaded = /* @__PURE__ */ new Set(); + let queue = Promise.resolve(); + let cancel; + let disposed = false; + const ensureActive = () => { + if (disposed) + throw new Error("Documentation loader was disposed"); + }; + function load(url, script) { + return new Promise((resolve, reject) => { + const element = host.document.createElement(script ? "script" : "link"); + let restore; + let settled = false; + function finish(error) { + if (settled) + return; + settled = true; + element.removeEventListener("load", success); + element.removeEventListener("error", failure); + cancel = void 0; + try { + restore?.(); + } catch (cause) { + error = new Error(`Failed to restore AMD loader: ${String(cause)}`); + } + if (error) { + element.remove(); + reject(error); + } else { + resolve(); + } + } + function success() { + finish(); + } + function failure() { + finish(new Error(`Loading ${script ? "script" : "style"} failed: ${url}`)); + } + element.addEventListener("load", success); + element.addEventListener("error", failure); + cancel = () => finish(new Error(`Cancelled documentation dependency: ${url}`)); + try { + ensureActive(); + if (script) { + restore = suspendDefine(host); + const node = element; + node.type = "text/javascript"; + node.src = url; + node.async = false; + } else { + const node = element; + node.rel = "stylesheet"; + node.href = url; + } + host.document.head.appendChild(element); + } catch (cause) { + finish(cause instanceof Error ? cause : new Error(String(cause))); + } + }); + } + return { + loadLibraries(encoded = "") { + const work = queue.then(async () => { + ensureActive(); + const urls = decodeURIComponent(encoded).split(/\r?\n/).map((url) => url.trim()).filter(Boolean); + const result = []; + for (const url of urls) { + ensureActive(); + const absolute = new URL(url, host.location.href); + const extension = absolute.pathname.toLowerCase().split(".").pop(); + if (extension !== "js" && extension !== "css") + continue; + if (!loaded.has(absolute.href)) { + await load(absolute.href, extension === "js"); + loaded.add(absolute.href); + } + result.push(url); + } + return result; + }); + queue = work.catch(() => { + }); + return work; + }, + dispose() { + disposed = true; + cancel?.(); + loaded.clear(); + } + }; + } + async function exampleSource(name, request = fetch) { + const response = await request(`./assets/example/${name}.js`); + if (!response.ok) + throw new Error(`Loading example failed: ${name} (${response.status})`); + return response.text(); + } + + // packages/artplayer-vitepress/browser/editor-loader.ts + var loader = createLibraryLoader(); + Object.assign(window, { ArtplayerDocsLoader: { ...loader, exampleSource, parameters } }); + window.addEventListener("pagehide", (event) => { + if (!event.persisted) + loader.dispose(); + }); +})(); diff --git a/docs/assets/js/mobile.js b/docs/assets/js/mobile.js index 79f847404..83fc8979e 100644 --- a/docs/assets/js/mobile.js +++ b/docs/assets/js/mobile.js @@ -1,100 +1,142 @@ -(function () { - Artplayer.DEBUG = true; - - function getURLParameters(url) { - return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(function (a, v) { - return (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a; - }, {}); +// Generated by yarn build:site-assets. Do not edit. +"use strict"; +(() => { + // packages/artplayer-vitepress/browser/loader.ts + function parameters(url) { + const result = {}; + for (const part of new URL(url).search.slice(1).split("&")) { + const index = part.indexOf("="); + if (index >= 0) + result[part.slice(0, index)] = part.slice(index + 1); } - - function getExt(url) { - if (url.includes('?')) { - return getExt(url.split('?')[0]); - } - - if (url.includes('#')) { - return getExt(url.split('#')[0]); - } - - return url.trim().toLowerCase().split('.').pop(); + return result; + } + function suspendDefine(host) { + const descriptor = Object.getOwnPropertyDescriptor(host, "define"); + if (descriptor?.configurable === false) { + if (!("value" in descriptor) || !descriptor.writable) + throw new Error("Cannot temporarily suspend the AMD loader"); + Object.defineProperty(host, "define", { value: void 0 }); + } else { + Object.defineProperty(host, "define", { value: void 0, configurable: true, writable: true, enumerable: descriptor?.enumerable ?? true }); } - - function loadScript(url) { - return new Promise(function (resolve, reject) { - var define2 = window.define; - window.define = undefined; - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = url; - script.onload = function () { - window.define = define2; - resolve(url); - }; - script.onerror = function () { - reject(new Error('Loading script failed:' + url)); - }; - document.querySelector('head').appendChild(script); + return () => { + if (descriptor) + Object.defineProperty(host, "define", descriptor); + else Reflect.deleteProperty(host, "define"); + }; + } + function createLibraryLoader(host = window) { + const loaded = /* @__PURE__ */ new Set(); + let queue = Promise.resolve(); + let cancel; + let disposed = false; + const ensureActive = () => { + if (disposed) + throw new Error("Documentation loader was disposed"); + }; + function load(url, script) { + return new Promise((resolve, reject) => { + const element = host.document.createElement(script ? "script" : "link"); + let restore; + let settled = false; + function finish(error) { + if (settled) + return; + settled = true; + element.removeEventListener("load", success); + element.removeEventListener("error", failure); + cancel = void 0; + try { + restore?.(); + } catch (cause) { + error = new Error(`Failed to restore AMD loader: ${String(cause)}`); + } + if (error) { + element.remove(); + reject(error); + } else { + resolve(); + } + } + function success() { + finish(); + } + function failure() { + finish(new Error(`Loading ${script ? "script" : "style"} failed: ${url}`)); + } + element.addEventListener("load", success); + element.addEventListener("error", failure); + cancel = () => finish(new Error(`Cancelled documentation dependency: ${url}`)); + try { + ensureActive(); + if (script) { + restore = suspendDefine(host); + const node = element; + node.type = "text/javascript"; + node.src = url; + node.async = false; + } else { + const node = element; + node.rel = "stylesheet"; + node.href = url; + } + host.document.head.appendChild(element); + } catch (cause) { + finish(cause instanceof Error ? cause : new Error(String(cause))); + } + }); + } + return { + loadLibraries(encoded = "") { + const work = queue.then(async () => { + ensureActive(); + const urls = decodeURIComponent(encoded).split(/\r?\n/).map((url) => url.trim()).filter(Boolean); + const result = []; + for (const url of urls) { + ensureActive(); + const absolute = new URL(url, host.location.href); + const extension = absolute.pathname.toLowerCase().split(".").pop(); + if (extension !== "js" && extension !== "css") + continue; + if (!loaded.has(absolute.href)) { + await load(absolute.href, extension === "js"); + loaded.add(absolute.href); + } + result.push(url); + } + return result; }); - } - - function loadStyle(url) { - return new Promise(function (resolve, reject) { - var link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = url; - link.onload = function () { - resolve(url); - }; - link.onerror = function () { - reject(new Error('Loading style failed:' + url)); - }; - document.querySelector('head').appendChild(link); + queue = work.catch(() => { }); - } + return work; + }, + dispose() { + disposed = true; + cancel?.(); + loaded.clear(); + } + }; + } + async function exampleSource(name, request = fetch) { + const response = await request(`./assets/example/${name}.js`); + if (!response.ok) + throw new Error(`Loading example failed: ${name} (${response.status})`); + return response.text(); + } - function loadLib(libs) { - var libPromise = []; - var libsDecode = decodeURIComponent(libs || ''); - libsDecode - .split(/\r?\n/) - .forEach(function (url) { - var ext = getExt(url); - if (ext === 'js') { - libPromise.push(loadScript(url)); - } else if (ext === 'css') { - libPromise.push(loadStyle(url)); - } - }); - return Promise.all(libPromise); - } - - function runExample(name) { - fetch('./assets/example/' + name + '.js') - .then(function (response) { - return response.text(); - }) - .then(function (text) { - eval(text); - }) - } - - function loadCode(code, example) { - if (example) { - runExample(example); - } else if (code) { - eval(decodeURIComponent(code).trim()); - } else { - runExample('mobile'); - } - } - - var _getURLParameters = getURLParameters(window.location.href), - code = _getURLParameters.code, - libs = _getURLParameters.libs; - example = _getURLParameters.example; - - loadLib(libs) - .then(function () { - loadCode(code, example); - }) -})(); \ No newline at end of file + // packages/artplayer-vitepress/browser/mobile.ts + window.Artplayer.DEBUG = true; + var loader = createLibraryLoader(); + window.addEventListener("pagehide", (event) => { + if (!event.persisted) + loader.dispose(); + }); + async function start() { + const { code, libs, example } = parameters(location.href); + await loader.loadLibraries(libs); + const source = example ? await exampleSource(example) : code ? decodeURIComponent(code).trim() : await exampleSource("mobile"); + new Function(source)(); + } + start().catch((error) => console.error("Failed to initialize mobile example:", error)); +})(); diff --git a/docs/index.html b/docs/index.html index 9b9b72ba5..84f291249 100644 --- a/docs/index.html +++ b/docs/index.html @@ -229,6 +229,7 @@
+