diff --git a/src/components/InlineMarkdown.svelte b/src/components/InlineMarkdown.svelte index 5ea4b5b0b..878bd005b 100644 --- a/src/components/InlineMarkdown.svelte +++ b/src/components/InlineMarkdown.svelte @@ -3,7 +3,6 @@ import markdown from "@app/lib/markdown"; import { twemoji } from "@app/lib/utils"; - import { activeUnloadedRouteStore } from "@app/lib/router"; import { Renderer } from "@app/lib/markdown"; export let content: string; @@ -14,9 +13,7 @@ const render = (content: string): string => dompurify.sanitize( markdown.parseInline(content, { - renderer: new Renderer($activeUnloadedRouteStore, { - stripEmphasizedStyling, - }), + renderer: new Renderer(undefined, stripEmphasizedStyling), }) as string, ); diff --git a/src/components/Markdown.svelte b/src/components/Markdown.svelte index 8383f8d5e..3e1920339 100644 --- a/src/components/Markdown.svelte +++ b/src/components/Markdown.svelte @@ -11,7 +11,6 @@ import ErrorModal from "@app/modals/ErrorModal.svelte"; import markdown from "@app/lib/markdown"; import { Renderer } from "@app/lib/markdown"; - import { activeUnloadedRouteStore } from "@app/lib/router"; import { highlight } from "@app/lib/syntax"; import { isUrl, @@ -23,6 +22,8 @@ import { mimes } from "@app/lib/file"; export let content: string; + // If present, resolve all relative links with respect to this URL + export let linkBaseUrl: string | undefined = undefined; export let path: string = "/"; export let rawPath: string; // If present, means we are in a preview context, @@ -62,7 +63,7 @@ } /** - * Do internal navigation for clicks on anchor elements if possible + * Do internal navigation on for clicks on anchor elements if possible */ function navigateInternalOnAnchor(event: MouseEvent) { if (router.useDefaultNavigation(event)) { @@ -93,9 +94,7 @@ function render(content: string): string { return dompurify.sanitize( markdown.parse(content, { - renderer: new Renderer($activeUnloadedRouteStore, { - stripEmphasizedStyling: false, - }), + renderer: new Renderer(linkBaseUrl, false), breaks, }) as string, ); diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index 371ee581b..a7c13b103 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -1,5 +1,4 @@ import type { Tokens } from "marked"; -import type { Route } from "@app/lib/router"; import dompurify from "dompurify"; import katexMarkedExtension from "marked-katex-extension"; @@ -7,8 +6,6 @@ import markedLinkifyIt from "marked-linkify-it"; import { Marked, Renderer as BaseRenderer } from "marked"; import emojis from "@app/lib/emojis"; -import { routeToPath } from "@app/lib/router"; -import { canonicalize, isUrl } from "@app/lib/utils"; dompurify.setConfig({ // eslint-disable-next-line @typescript-eslint/naming-convention @@ -104,19 +101,16 @@ const anchorMarkedExtension = { }; export class Renderer extends BaseRenderer { - #route: Route; + #baseUrl: string | undefined; #stripEmphasizedStyling: boolean | undefined; /** * If `baseUrl` is provided, all hrefs attributes in anchor tags, except those * starting with `#`, are resolved with respect to `baseUrl` */ - constructor( - activeUnloadedRoute: Route, - { stripEmphasizedStyling }: { stripEmphasizedStyling: boolean }, - ) { + constructor(baseUrl: string | undefined, stripEmphasizedStyling: boolean) { super(); - this.#route = activeUnloadedRoute; + this.#baseUrl = baseUrl; this.#stripEmphasizedStyling = stripEmphasizedStyling; } // Overwrites the rendering of heading tokens. @@ -145,17 +139,15 @@ export class Renderer extends BaseRenderer { if (href.startsWith("#")) { // By lowercasing we avoid casing mismatches, between headings and links. return `${text}`; - } + } else { + try { + href = new URL(href, this.#baseUrl).href; + } catch { + // Use original href value + } - if ("path" in this.#route && this.#route.path && !isUrl(href)) { - href = routeToPath({ - ...this.#route, - path: canonicalize(href, this.#route.path), - route: undefined, - }); + return `${text}`; } - - return `${text}`; } } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 8ed5d8bd1..e77fdda98 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -115,23 +115,19 @@ export function formatPublicExplorer( .replace("$path", fullPath.replace(`/nodes/${host}/${rid}`, "")); } -// Takes a path, eg. "../images/image.png", and a base from where to start -// resolving, e.g. "static/images/index.html". Returns the resolved path. +// Takes a path, eg. "../images/image.png", and a base from where to start resolving, e.g. "static/images/index.html". +// Returns the resolved path. export function canonicalize( path: string, base: string, origin = document.location.origin, ): string { - let finalPath: string | undefined; - if (path.startsWith("/")) { - finalPath = new URL(path, origin).pathname; - } else { - finalPath = base - .split("/") - .slice(0, -1) // Remove file name. - .concat([path]) // Add image file path. - .join("/"); - } + path = path.replace(/^\//, ""); // Remove leading slash + const finalPath = base + .split("/") + .slice(0, -1) // Remove file name. + .concat([path]) // Add image file path. + .join("/"); // URL is used to resolve relative paths, eg. `../../assets/image.png`. const url = new URL(finalPath, origin); diff --git a/src/views/projects/Source.svelte b/src/views/projects/Source.svelte index 750a2fd21..810d4909d 100644 --- a/src/views/projects/Source.svelte +++ b/src/views/projects/Source.svelte @@ -179,9 +179,11 @@