Revert "fix: safely extract notebook summaries"
This reverts commit fa3d0375c5.
This commit is contained in:
1 parent
38a710efe3
commit
84b334abab
3 files changed
+13
-53
No files matched your search
@@ -1,38 +1,33 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
|
|
||||||
import { WidgetMobileSummary } from "../common/mobile-summary";
|
import { WidgetMobileSummary } from "../common/mobile-summary";
|
||||||
import type { WidgetComponentProps } from "../definition";
|
import type { WidgetComponentProps } from "../definition";
|
||||||
import { extractNotebookExcerpt } from "./mobile-summary";
|
|
||||||
|
|
||||||
const Notebook = dynamic(() => import("./notebook").then((module) => module.Notebook), {
|
const Notebook = dynamic(() => import("./notebook").then((module) => module.Notebook), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
interface NotebookMobileSummaryProps {
|
|
||||||
content: string;
|
|
||||||
label: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NotebookMobileSummary = ({ content, label }: NotebookMobileSummaryProps) => {
|
|
||||||
const [excerpt, setExcerpt] = useState("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setExcerpt(extractNotebookExcerpt(content));
|
|
||||||
}, [content]);
|
|
||||||
|
|
||||||
return <WidgetMobileSummary value={excerpt || "—"} label={label} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function NotebookWidget(props: WidgetComponentProps<"notebook">) {
|
export default function NotebookWidget(props: WidgetComponentProps<"notebook">) {
|
||||||
const t = useScopedI18n("widget.notebook");
|
const t = useScopedI18n("widget.notebook");
|
||||||
|
|
||||||
if (props.displayMode === "mobileSummary") {
|
if (props.displayMode === "mobileSummary") {
|
||||||
return <NotebookMobileSummary content={props.options.content} label={t("name")} />;
|
const excerpt = props.options.content
|
||||||
|
.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, " ")
|
||||||
|
.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, " ")
|
||||||
|
.replace(/<[^>]+>/g, " ")
|
||||||
|
.replace(/&(?:nbsp|#160);/gi, " ")
|
||||||
|
.replace(/&(?:amp|#38);/gi, "&")
|
||||||
|
.replace(/&(?:lt|#60);/gi, "<")
|
||||||
|
.replace(/&(?:gt|#62);/gi, ">")
|
||||||
|
.replace(/&(?:quot|#34);/gi, '"')
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
return <WidgetMobileSummary value={excerpt || "—"} label={t("name")} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Notebook {...props} />;
|
return <Notebook {...props} />;
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
|
||||||
|
|
||||||
import { extractNotebookExcerpt } from "./mobile-summary";
|
|
||||||
|
|
||||||
describe("extractNotebookExcerpt", () => {
|
|
||||||
test("returns decoded plain text from notebook HTML", () => {
|
|
||||||
expect(extractNotebookExcerpt("<h1>Hello world</h1><p>Fish & chips</p>")).toBe("Hello world Fish & chips");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("removes script and style content including whitespace before closing brackets", () => {
|
|
||||||
const content =
|
|
||||||
'<p>Visible</p><script>alert("hidden")</script ><style>body { display: none; }</style ><p>Still visible</p>';
|
|
||||||
|
|
||||||
expect(extractNotebookExcerpt(content)).toBe("Visible Still visible");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("returns an empty excerpt when there is no visible content", () => {
|
|
||||||
expect(extractNotebookExcerpt("<script>hidden()</script><style>.hidden {}</style>")).toBe("");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
export const extractNotebookExcerpt = (content: string) => {
|
|
||||||
const parsedDocument = new DOMParser().parseFromString(content, "text/html");
|
|
||||||
parsedDocument.querySelectorAll("script, style").forEach((element) => {
|
|
||||||
element.remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
const textWalker = parsedDocument.createTreeWalker(parsedDocument.body, NodeFilter.SHOW_TEXT);
|
|
||||||
const textParts: string[] = [];
|
|
||||||
|
|
||||||
while (textWalker.nextNode()) {
|
|
||||||
textParts.push(textWalker.currentNode.textContent ?? "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return textParts.join(" ").replace(/\s+/g, " ").trim();
|
|
||||||
};
|
|
||||||
Reference in new issue
Block a user