mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-01 19:06:01 +00:00
fix(frontend): stop matching <header> as <head> in HTML preview base injection (#4625)
appendHtmlPreviewBaseHref detected the head tag with /<head[^>]*>/i, which also matches <header ...>. For a fragment with no <head> that opens with <header> - a common shape in agent-generated report pages - the <base> element was injected after the <header> opening tag instead of being prepended, so relative assets appearing before that point (e.g. a leading <img>) resolved without the base and failed to load in the sandboxed iframe. Use the word-boundary-safe /<head(?:\s[^>]*)?>/i that the sibling appendHtmlPreviewScrollRestoration already uses, keeping the two injectors consistent.
This commit is contained in:
parent
5bf3e3960d
commit
2f6cadb8b0
@ -175,8 +175,14 @@ export function appendHtmlPreviewBaseHref(
|
||||
|
||||
const baseHref = htmlBaseHref(url, currentHref);
|
||||
const baseElement = `<base href="${escapeHtmlAttribute(baseHref)}">`;
|
||||
if (/<head[^>]*>/i.exec(content)) {
|
||||
return content.replace(/<head([^>]*)>/i, `<head$1>${baseElement}`);
|
||||
// "(?:\s[^>]*)?" keeps the tag-name boundary so `<header>` (a common
|
||||
// leading tag in agent-generated fragments) is not mistaken for `<head>`;
|
||||
// mirrors appendHtmlPreviewScrollRestoration below.
|
||||
if (/<head(?:\s[^>]*)?>/i.test(content)) {
|
||||
return content.replace(
|
||||
/<head(?:\s[^>]*)?>/i,
|
||||
(headTag) => `${headTag}${baseElement}`,
|
||||
);
|
||||
}
|
||||
return `${baseElement}${content}`;
|
||||
}
|
||||
|
||||
@ -282,6 +282,39 @@ test("preserves existing head elements when injecting scroll restoration", () =>
|
||||
);
|
||||
});
|
||||
|
||||
test("does not mistake <header> for <head> when injecting the base href", () => {
|
||||
// Agent-generated fragments often have no <head> but open with <header>;
|
||||
// the base must then be prepended so assets before the tag resolve too.
|
||||
const html =
|
||||
'<img src="logo.png"><header class="top">Report</header><main>content</main>';
|
||||
|
||||
const result = appendHtmlPreviewBaseHref(
|
||||
html,
|
||||
"/demo/threads/thread-1/user-data/outputs/report.html",
|
||||
"http://localhost/workspace/chats/thread-1",
|
||||
);
|
||||
|
||||
expect(result).toBe(
|
||||
'<base href="http://localhost/demo/threads/thread-1/user-data/outputs/">' +
|
||||
html,
|
||||
);
|
||||
});
|
||||
|
||||
test("injects the base href inside an attributed <head> tag", () => {
|
||||
const html =
|
||||
'<!doctype html><html><head lang="en"><meta charset="utf-8"></head><body>x</body></html>';
|
||||
|
||||
const result = appendHtmlPreviewBaseHref(
|
||||
html,
|
||||
"/demo/threads/thread-1/user-data/outputs/report.html",
|
||||
"http://localhost/workspace/chats/thread-1",
|
||||
);
|
||||
|
||||
expect(result).toContain(
|
||||
'<head lang="en"><base href="http://localhost/demo/threads/thread-1/user-data/outputs/">',
|
||||
);
|
||||
});
|
||||
|
||||
test("does not duplicate HTML scroll restoration script", () => {
|
||||
const html = appendHtmlPreviewScrollRestoration(
|
||||
"<html><body>x</body></html>",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user