feat(link-support): show dialog when clicking on links to external websites

There are a few bugs. But I want to commit this now.
It might double replace the link, which means the <a> will be wrapped in another <a> and break the HTML.
This commit is contained in:
RealPacket 2024-08-01 10:50:42 -05:00 committed by GStudiosX
parent 329b44b4ce
commit a9fb44d00a

View File

@ -14,6 +14,7 @@
import Report from './Report.svelte';
import { createEventDispatcher } from 'svelte';
import DOMPurify from 'dompurify';
import { page } from '$app/stores';
function getTimeElapsed(date: Date | string) {
if (typeof date === 'string') date = new Date(date);
@ -84,7 +85,8 @@
let contentElement: HTMLSpanElement | null = null;
content = content!;
let clickingExternalLink = false;
let openExternalLink = false;
// I can just use this in the listener and that should work.
let externalLink: URL | null = null;
const formattedDate = formatDateTooltip(createdAt);
@ -121,22 +123,30 @@
$: if (contentElement) {
// this shouldn't have any XSS vulnerabilities. Or at least, hopefully...
const sanitizedContent: string = DOMPurify.sanitize(content);
const sanitizedContent: string = DOMPurify.sanitize(content, {
USE_PROFILES: {
html: true
},
});
const links = sanitizedContent.match(/[A-z|A-Z|a-z]+:\/\/[^\s]+/gm);
if (links)
for (const link of links) {
const linkHTML = `<a href="${link}" target="_blank">${link}</a>`;
console.log("link", link, "linkHTML", linkHTML);
// FIXME: it may "double replace" the link, which isn't good.
contentElement.innerHTML = contentElement.innerHTML.replace(
link,
`<a href="${link}" class="post-link" target="_blank">${link}</a>`
linkHTML
);
const a = contentElement.querySelector("a");
a?.addEventListener("click", async (e) => {
e.preventDefault();
if (new URL(a.href).host !== window.location.host) {
console.log("innerHTML after replace", contentElement.innerHTML)
const a = contentElement.querySelectorAll('a');
a.forEach(el => el.addEventListener("click", (e) => {
if (new URL(el.href).host !== $page.url.host) {
e.preventDefault();
externalLink = new URL(link);
clickingExternalLink = true;
}
return false;
})
}))
}
}
</script>
@ -149,7 +159,7 @@
{/if}
{#if clickingExternalLink}
<AlertDialog.Root>
<AlertDialog.Root open={clickingExternalLink}>
<AlertDialog.Content>
<AlertDialog.Header>
<AlertDialog.Title class="mb-2 text-2xl font-bold"
@ -157,11 +167,19 @@
>
<AlertDialog.Description>
This link leads to a external website.
Are you sure you want to open it?
</AlertDialog.Description>
</AlertDialog.Header>
<AlertDialog.Footer>
<AlertDialog.Action on:click={() => openExternalLink = true}>Open</AlertDialog.Action>
<AlertDialog.Action on:click={() => openExternalLink = false}>Return to Lyntr</AlertDialog.Action>
<AlertDialog.Action on:click={() => {
if (!externalLink)
return console.error("externalLink is null");
window.open(externalLink)
externalLink = null
}}>Open</AlertDialog.Action>
<AlertDialog.Action class="bg-primary" on:click={() => {
clickingExternalLink = false
}}>Return to Lyntr</AlertDialog.Action>
</AlertDialog.Footer>
</AlertDialog.Content>
</AlertDialog.Root>