mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-06-14 12:21:22 +00:00
162 lines
4.0 KiB
TypeScript
162 lines
4.0 KiB
TypeScript
import React, { useEffect } from "react";
|
|
import DOMPurify from "dompurify";
|
|
import "./styles.css";
|
|
import { executeEvent } from "../../utils/events";
|
|
|
|
const extractComponents = (url) => {
|
|
if (!url || !url.startsWith("qortal://")) {
|
|
// Check if url exists and starts with "qortal://"
|
|
return null;
|
|
}
|
|
|
|
url = url.replace(/^(qortal\:\/\/)/, ""); // Safe to use replace now
|
|
if (url.includes("/")) {
|
|
let parts = url.split("/");
|
|
const service = parts[0].toUpperCase();
|
|
parts.shift();
|
|
const name = parts[0];
|
|
parts.shift();
|
|
let identifier;
|
|
const path = parts.join("/");
|
|
return { service, name, identifier, path };
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
function processText(input) {
|
|
const linkRegex = /(qortal:\/\/\S+)/g;
|
|
function processNode(node) {
|
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
const parts = node.textContent.split(linkRegex);
|
|
if (parts.length > 0) {
|
|
const fragment = document.createDocumentFragment();
|
|
parts.forEach((part) => {
|
|
if (part.startsWith("qortal://")) {
|
|
const link = document.createElement("span");
|
|
link.setAttribute("data-url", part);
|
|
link.textContent = part;
|
|
link.style.color = "var(--code-block-text-color)";
|
|
link.style.textDecoration = "underline";
|
|
link.style.cursor = "pointer";
|
|
fragment.appendChild(link);
|
|
} else {
|
|
fragment.appendChild(document.createTextNode(part));
|
|
}
|
|
});
|
|
node.replaceWith(fragment);
|
|
}
|
|
} else {
|
|
Array.from(node.childNodes).forEach(processNode);
|
|
}
|
|
}
|
|
|
|
const wrapper = document.createElement("div");
|
|
wrapper.innerHTML = input;
|
|
processNode(wrapper);
|
|
return wrapper.innerHTML;
|
|
}
|
|
|
|
export const MessageDisplay = ({ htmlContent, isReply }) => {
|
|
const linkify = (text) => {
|
|
if (!text) return ""; // Return an empty string if text is null or undefined
|
|
|
|
let textFormatted = text;
|
|
const urlPattern = /(\bhttps?:\/\/[^\s<]+|\bwww\.[^\s<]+)/g;
|
|
textFormatted = text.replace(urlPattern, (url) => {
|
|
const href = url.startsWith("http") ? url : `https://${url}`;
|
|
return `<a href="${DOMPurify.sanitize(
|
|
href
|
|
)}" class="auto-link">${DOMPurify.sanitize(url)}</a>`;
|
|
});
|
|
return processText(textFormatted);
|
|
};
|
|
|
|
const sanitizedContent = DOMPurify.sanitize(linkify(htmlContent), {
|
|
ALLOWED_TAGS: [
|
|
"a",
|
|
"b",
|
|
"i",
|
|
"em",
|
|
"strong",
|
|
"p",
|
|
"br",
|
|
"div",
|
|
"span",
|
|
"img",
|
|
"ul",
|
|
"ol",
|
|
"li",
|
|
"h1",
|
|
"h2",
|
|
"h3",
|
|
"h4",
|
|
"h5",
|
|
"h6",
|
|
"blockquote",
|
|
"code",
|
|
"pre",
|
|
"table",
|
|
"thead",
|
|
"tbody",
|
|
"tr",
|
|
"th",
|
|
"td",
|
|
],
|
|
ALLOWED_ATTR: [
|
|
"href",
|
|
"target",
|
|
"rel",
|
|
"class",
|
|
"src",
|
|
"alt",
|
|
"title",
|
|
"width",
|
|
"height",
|
|
"style",
|
|
"align",
|
|
"valign",
|
|
"colspan",
|
|
"rowspan",
|
|
"border",
|
|
"cellpadding",
|
|
"cellspacing",
|
|
"data-url",
|
|
],
|
|
});
|
|
|
|
const handleClick = async (e) => {
|
|
e.preventDefault();
|
|
|
|
const target = e.target;
|
|
if (target.tagName === "A") {
|
|
const href = target.getAttribute("href");
|
|
if (chrome && chrome.tabs) {
|
|
chrome.tabs.create({ url: href }, (tab) => {
|
|
if (chrome.runtime.lastError) {
|
|
console.error("Error opening tab:", chrome.runtime.lastError);
|
|
} else {
|
|
console.log("Tab opened successfully:", tab);
|
|
}
|
|
});
|
|
}
|
|
} else if (target.getAttribute("data-url")) {
|
|
const url = target.getAttribute("data-url");
|
|
const res = extractComponents(url);
|
|
if (res) {
|
|
const { service, name, identifier, path } = res;
|
|
executeEvent("addTab", { data: { service, name, identifier, path } });
|
|
executeEvent("open-apps-mode", {});
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={`tiptap ${isReply ? "isReply" : ""}`}
|
|
dangerouslySetInnerHTML={{ __html: sanitizedContent }}
|
|
onClick={handleClick}
|
|
/>
|
|
);
|
|
};
|