(function() { // eslint-disable-line strict 'use strict'; // eslint-disable-line strict function dirname(path) { const ndx = path.lastIndexOf('/'); return path.substring(0, ndx + 1); } function getPrefix(url) { const u = new URL(url, window.location.href); const prefix = u.origin + dirname(u.pathname); return prefix; } function getRootPrefix(url) { const u = new URL(url, window.location.href); return u.origin; } function removeDotDotSlash(url) { // assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. const parts = url.split('/'); for (;;) { const dotDotNdx = parts.indexOf('..'); if (dotDotNdx < 0) { break; } parts.splice(dotDotNdx - 1, 2); } const newUrl = parts.join('/'); return newUrl; } /** * Fix any local URLs into fully qualified urls. * * Examples: * resources/image.jpg -> https://domain.org/webgl/resouces/image.jpg * /3rdparty/lib.js -> https://domain.org/3rdparty/lib.js * * The reason is (a) we're running the code as via blobUrl and nothing is relative to a blob. * (b) we can upload to jsfiddle/codepen and so need to link back to the files. * * This is all kind of hacky in that it's just a bunch of regular expressions looking * for matches. * * @param {string} url The URL of the file source. * @param {string} source An HTML file or JavaScript file * @returns {string} the source after having urls fixed. */ function fixSourceLinks(url, source) { const srcRE = /(src=)(")(.*?)(")()/g; const linkRE = /(href=)(")(.*?)(")()/g; const imageSrcRE = /((?:image|img)\.src = )(")(.*?)(")()/g; const loaderLoadRE = /(loader\.load[a-z]*\s*\(\s*)('|")(.*?)('|")/ig; const loaderArrayLoadRE = /(loader\.load[a-z]*\(\[)([\s\S]*?)(\])/ig; const loadFileRE = /(loadFile\s*\(\s*)('|")(.*?)('|")/ig; const threejsUrlRE = /(.*?)('|")([^"']*?)('|")([^'"]*?)(\/\*\s+threejs.org:\s+url\s+\*\/)/ig; const arrayLineRE = /^(\s*["|'])([\s\S]*?)(["|']*$)/; const urlPropRE = /(url:\s*)('|")(.*?)('|")/g; const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g; const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g; const moduleRE = /(import.*?)('|")(.*?)('|")/g; const prefix = getPrefix(url); const rootPrefix = getRootPrefix(url); function addCorrectPrefix(url) { return (url.startsWith('/')) ? `${rootPrefix}${url}` : removeDotDotSlash((prefix + url).replace(/\/.\//g, '/')); } function addPrefix(url) { return url.indexOf('://') < 0 && !url.startsWith('data:') && url[0] !== '?' ? removeDotDotSlash(addCorrectPrefix(url)) : url; } function makeLinkFDedQuotes(match, fn, q1, url, q2) { return fn + q1 + addPrefix(url) + q2; } function makeTaggedFDedQuotes(match, start, q1, url, q2, suffix) { return start + q1 + addPrefix(url) + q2 + suffix; } function makeFDedQuotesModule(match, start, q1, url, q2) { // modules require relative paths or fully qualified, otherwise they are module names return `${start}${q1}${url.startsWith('.') ? addPrefix(url) : url}${q2}`; } function makeArrayLinksFDed(match, prefix, arrayStr, suffix) { const lines = arrayStr.split(',').map((line) => { const m = arrayLineRE.exec(line); return m ? `${m[1]}${addPrefix(m[2])}${m[3]}` : line; }); return `${prefix}${lines.join(',')}${suffix}`; } source = source.replace(srcRE, makeTaggedFDedQuotes); source = source.replace(linkRE, makeTaggedFDedQuotes); source = source.replace(imageSrcRE, makeTaggedFDedQuotes); source = source.replace(urlPropRE, makeLinkFDedQuotes); source = source.replace(loadFileRE, makeLinkFDedQuotes); source = source.replace(loaderLoadRE, makeLinkFDedQuotes); source = source.replace(workerRE, makeLinkFDedQuotes); source = source.replace(importScriptsRE, makeLinkFDedQuotes); source = source.replace(loaderArrayLoadRE, makeArrayLinksFDed); source = source.replace(threejsUrlRE, makeTaggedFDedQuotes); source = source.replace(moduleRE, makeFDedQuotesModule); return source; } /** * Called after parsing to give a change to update htmlParts * @param {string} html The main page html turned into a template with the