adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
42 lines
1.1 KiB
TypeScript
42 lines
1.1 KiB
TypeScript
import Amuchina from "amuchina";
|
|
|
|
const should_open_link_in_new_tab = (link: string | null): boolean => {
|
|
const href = link?.trim();
|
|
return !!href && !href.startsWith("#");
|
|
};
|
|
|
|
export function sanitize(source: string): string {
|
|
const amuchina = new Amuchina();
|
|
const node = new DOMParser().parseFromString(source, "text/html");
|
|
const sanitized_node = amuchina.sanitize(node);
|
|
walk_nodes(sanitized_node.body, "A", (node) => {
|
|
if (node instanceof HTMLElement && "target" in node) {
|
|
if (should_open_link_in_new_tab(node.getAttribute("href"))) {
|
|
node.setAttribute("target", "_blank");
|
|
node.setAttribute("rel", "noopener noreferrer");
|
|
}
|
|
}
|
|
});
|
|
|
|
return sanitized_node.body.innerHTML;
|
|
}
|
|
|
|
function walk_nodes(
|
|
node: Node | null | HTMLElement,
|
|
test: string | ((node: Node | HTMLElement) => boolean),
|
|
callback: (node: Node | HTMLElement) => void
|
|
): void {
|
|
if (
|
|
node &&
|
|
((typeof test === "string" && node.nodeName === test) ||
|
|
(typeof test === "function" && test(node)))
|
|
) {
|
|
callback(node);
|
|
}
|
|
const children = node?.childNodes || [];
|
|
for (let i = 0; i < children.length; i++) {
|
|
// @ts-ignore
|
|
walk_nodes(children[i], test, callback);
|
|
}
|
|
}
|