diff --git a/frontend/app/player/web/messages/rewriter/urlResolve.ts b/frontend/app/player/web/messages/rewriter/urlResolve.ts index 47f74b36b..ff9af1046 100644 --- a/frontend/app/player/web/messages/rewriter/urlResolve.ts +++ b/frontend/app/player/web/messages/rewriter/urlResolve.ts @@ -1,64 +1,46 @@ export function resolveURL(baseURL: string, relURL: string): string { - if (relURL.startsWith('#') || relURL === "") { + if (relURL.startsWith('#') || relURL === '') { return relURL; } return new URL(relURL, baseURL).toString(); } -// url("url") or url('url') or url(url) -const re1 = /url\(("[^"]*"|'[^']*'|[^)]*)\)/g -// @import "url" or @import 'url' -const re2 = /@import (["'])(.*?)\1/g -function cssUrlsIndex(css: string): Array<[number, number]> { - const idxs: Array<[number, number]> = []; - const i1 = css.matchAll(re1); - // @ts-ignore - for (let m of i1) { - // @ts-ignore - const s: number = m.index + m[0].indexOf(m[1]); - const e: number = s + m[1].length; - idxs.push([s, e]); - } - const i2 = css.matchAll(re2); - // @ts-ignore - for (let m of i2) { - // @ts-ignore - const s = m.index + m[0].indexOf(m[1]); - const e = s + m[1].length; - idxs.push([s, e]) - } - return idxs.reverse() -} -function unquote(str: string): [string, string] { - if (str.length <= 2) { - return [str, ""] - } - if (str[0] == '"' && str[str.length-1] == '"') { - return [ str.substring(1, str.length-1), "\""]; - } - if (str[0] == '\'' && str[str.length-1] == '\'') { - return [ str.substring(1, str.length-1), "'" ]; - } - return [str, ""] -} -function rewriteCSSLinks(css: string, rewriter: (rawurl: string) => string): string { - for (let idx of cssUrlsIndex(css)) { - const f = idx[0] - const t = idx[1] - const [ rawurl, q ] = unquote(css.substring(f, t)); - css = css.substring(0,f) + q + rewriter(rawurl) + q + css.substring(t); - } - return css +function rewriteCSSLinks( + css: string, + rewriter: (rawurl: string) => string +): string { + // Replace url() functions + css = css.replace(/url\(\s*(['"]?)(.*?)\1\s*\)/gs, (match, quote, url) => { + let newurl = rewriter(url.trim()); + return `url(${quote}${newurl}${quote})`; + }); + + // Replace @import statements + css = css.replace( + /@import\s+(url\(\s*(['"]?)(.*?)\2\s*\)|(['"])(.*?)\4)([^;]*);?/gs, + (match, _, quote1, url1, quote2, url2, media) => { + let url = url1 || url2; + let newurl = rewriter(url.trim()); + let quote = quote1 || quote2 || ''; + return `@import ${ + quote ? `url(${quote}${newurl}${quote})` : `"${newurl}"` + }${media};`; + } + ); + + // Ensure the CSS ends with a semicolon + const hasSemi = css.trim().endsWith(';'); + return hasSemi ? css : css + ';'; } function rewritePseudoclasses(css: string): string { return css - .replace(/:hover/g, ".-openreplay-hover") - .replace(/:focus/g, ".-openreplay-focus") + .replace(/:hover/g, '.-openreplay-hover') + .replace(/:focus/g, '.-openreplay-focus'); } export function resolveCSS(baseURL: string, css: string): string { return rewritePseudoclasses( - rewriteCSSLinks(css, rawurl => resolveURL(baseURL, rawurl)) + rewriteCSSLinks(css, (rawurl) => resolveURL(baseURL, rawurl)) ); -} \ No newline at end of file +}