29 lines
1.2 KiB
TypeScript
29 lines
1.2 KiB
TypeScript
import { sanitizeHtml } from "../parse/html.ts";
|
|
import { elementFactory, requireFile, setButtonLabel } from "./dom.ts";
|
|
import { sandboxFrame } from "./frame.ts";
|
|
import type { ViewerMount } from "../types.ts";
|
|
|
|
export const mountHtml: ViewerMount = async ({ parent, file, source, button, signal }) => {
|
|
const text = await requireFile(file).text();
|
|
if (signal.aborted) return;
|
|
const view = parent.ownerDocument.defaultView;
|
|
if (!view) throw new Error("HTML preview requires a document");
|
|
const frame = sandboxFrame(parent, {
|
|
title: source.name || "HTML preview",
|
|
policy:
|
|
"default-src 'none'; base-uri 'none'; form-action 'none'; style-src 'unsafe-inline'; img-src data:",
|
|
body: sanitizeHtml(text, view),
|
|
css: "body{padding:1rem;box-sizing:border-box;font:16px/1.5 system-ui}img{max-width:100%}",
|
|
});
|
|
const raw = elementFactory(parent.ownerDocument)("pre", text);
|
|
let sourceView = false;
|
|
const toggle = button("Source", () => {
|
|
sourceView = !sourceView;
|
|
setButtonLabel(toggle, sourceView ? "Preview" : "Source");
|
|
toggle.setAttribute("aria-pressed", String(sourceView));
|
|
parent.replaceChildren(sourceView ? raw : frame);
|
|
});
|
|
toggle.setAttribute("aria-pressed", "false");
|
|
parent.append(frame);
|
|
};
|