import { isFunction } from "../helpers"; import outputBuild from "../renderer/index"; import { SPACE, h } from "../renderer/dom"; import type { IOutputInterface } from "./interface"; const TAB_SIZE = 4; function parseOutput(data = ""): string { return ("" + data) .replace(/(\n)|(\n\r)|(\r\n)/g, "
") .replace(/\s{2}/g, SPACE.repeat(2)) .replace(/\t/g, SPACE.repeat(TAB_SIZE)); } /** * Escapes user input so it can be safely rendered as HTML text. * - preserves all characters by converting them to HTML entities where needed. */ export function escapeHTML(data = ""): string { const span = document.createElement("span"); span.textContent = data; return span.innerHTML; } /** * Output Component */ export default class XOutputComponent implements IOutputInterface { public el: HTMLDivElement; private console: HTMLSpanElement; private lastOutput?: HTMLSpanElement; public onoutput?: () => void; constructor(target: HTMLElement) { const { outputBox, consoleBox } = outputBuild(target); this.el = outputBox; this.console = consoleBox; } public write(data: string, callback?: () => void): void { this.lastOutput = h("span", { html: parseOutput(data) }); this.console.appendChild(this.lastOutput); if (isFunction(this.onoutput)) this.onoutput(); if (isFunction(callback)) callback(); } public writeSafe(data: string, callback?: () => void): void { this.write(escapeHTML(data), callback); } public clear(): void { if (this.console) { this.console.innerHTML = ""; } } public clearLast(): void { if (this.lastOutput) { this.lastOutput.parentNode?.removeChild(this.lastOutput); } this.lastOutput = undefined; } }