diff --git a/src/js/browser.ts b/src/js/browser.ts index aa30346..33ceeba 100644 --- a/src/js/browser.ts +++ b/src/js/browser.ts @@ -4,23 +4,31 @@ import { $, $$ } from "./dom" import { focusInput } from "./focus" +import { scrollback } from "./dom" +import { addInput } from "./scrollback" +import { randomId } from "../shared/utils" + +const HEIGHT = 540 +const WIDTH = 960 const controls = $("browser-controls") as HTMLDivElement const address = $("browser-address") as HTMLSpanElement let iframe: HTMLIFrameElement -let iframeWindow: Window +let realUrl = "" +let showInput = true export function isBrowsing(): boolean { return document.querySelector("iframe.browser.active") !== null } -export function openBrowser(url: string) { +export function openBrowser(url: string, openedVia: "click" | "command" = "click") { + showInput = openedVia === "click" + iframe = $$("iframe.browser.active") as HTMLIFrameElement - iframeWindow = iframe.contentWindow as Window iframe.src = url iframe.sandbox.add("allow-scripts", "allow-same-origin", "allow-forms") - iframe.height = "540" - iframe.width = "960" + iframe.height = String(HEIGHT) + iframe.width = String(WIDTH) iframe.tabIndex = 0 window.addEventListener("message", handleAppMessage) @@ -35,6 +43,28 @@ export function openBrowser(url: string) { setAddress(url) } +function closeBrowser() { + window.removeEventListener("keydown", handleBrowserKeydown) + window.removeEventListener("message", handleAppMessage) + controls.removeEventListener("click", handleClick) + iframe.removeEventListener("load", handlePageLoad) + + const id = randomId() + if (showInput) + addInput(id, "browse " + realUrl, "ok") + + iframe.height = String(HEIGHT / 2) + iframe.width = String(WIDTH / 2) + iframe.style.pointerEvents = "none" + iframe.tabIndex = -1 + iframe.classList.remove("fullscreen", "active") + iframe.style.border = "2px solid var(--c64-light-blue)" + scrollback.append(iframe) + + controls.style.display = "none" + focusInput() +} + function handleAppMessage(event: MessageEvent) { const origin = event.origin if (!origin.includes('localhost') && !origin.match(/\.local$/)) { @@ -74,20 +104,6 @@ function handleAppMessage(event: MessageEvent) { } } -function closeBrowser() { - window.removeEventListener("keydown", handleBrowserKeydown) - window.removeEventListener("message", handleAppMessage) - controls.removeEventListener("click", handleClick) - iframe.removeEventListener("load", handlePageLoad) - - iframe.src = 'about:blank' - setTimeout(() => { - iframe.remove() - controls.style.display = "none" - focusInput() - }, 0) -} - function handleBrowserKeydown(e: KeyboardEvent) { if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) { e.preventDefault() @@ -123,6 +139,7 @@ function handlePageLoad() { } function setAddress(url: string) { + realUrl = url address.textContent = url.replace(/https?:\/\//, "") } diff --git a/src/js/commands.ts b/src/js/commands.ts index 117ba49..1c55d37 100644 --- a/src/js/commands.ts +++ b/src/js/commands.ts @@ -2,16 +2,17 @@ // temporary hack for browser commands import type { CommandOutput } from "../shared/types" +import { openBrowser } from "./browser" import { scrollback, content } from "./dom" +import { focusInput } from "./focus" import { resize } from "./resize" -import { autoScroll } from "./scrollback" import { sessionId } from "./session" import { send } from "./websocket" -import { focusInput } from "./focus" export const commands: string[] = [] export const browserCommands: Record void | Promise | CommandOutput> = { + browse: (url: string) => openBrowser(url, "command"), "browser-session": () => sessionId, clear: () => scrollback.innerHTML = "", commands: () => { @@ -27,7 +28,6 @@ export const browserCommands: Record void | Promi content.style.display = "" document.body.dataset.mode = mode resize() - autoScroll() focusInput() }, reload: () => window.location.reload(), diff --git a/src/js/scrollback.ts b/src/js/scrollback.ts index 87c9853..d488375 100644 --- a/src/js/scrollback.ts +++ b/src/js/scrollback.ts @@ -7,25 +7,26 @@ import { scrollback, cmdInput, $$ } from "./dom" import { randomId } from "../shared/utils" type InputStatus = "waiting" | "streaming" | "ok" | "error" +const statusColors = { + waiting: "yellow", + streaming: "purple", + ok: "green", + error: "red" +} export function initScrollback() { window.addEventListener("click", handleInputClick) } -export function autoScroll() { - // requestAnimationFrame(() => scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight) - // scrollback.scrollTop = scrollback.scrollHeight - scrollback.clientHeight -} - export function insert(node: HTMLElement) { scrollback.append(node) } -export function addInput(id: string, input: string) { +export function addInput(id: string, input: string, status?: InputStatus) { const parent = $$("li.input") - const status = $$("span.status.yellow", "•") + const statusSpan = $$(`span.status.${statusColors[status || "waiting"]}`, "•") const content = $$("span.content", input) - parent.append(status, content) + parent.append(statusSpan, content) parent.dataset.id = id insert(parent) @@ -36,15 +37,8 @@ export function setStatus(id: string, status: InputStatus) { const statusEl = document.querySelector(`[data-id="${id}"].input .status`) if (!statusEl) return - const colors = { - waiting: "yellow", - streaming: "purple", - ok: "green", - error: "red" - } - - statusEl.classList.remove(...Object.values(colors)) - statusEl.classList.add(colors[status]) + statusEl.classList.remove(...Object.values(statusColors)) + statusEl.classList.add(statusColors[status]) } export function addOutput(id: string, output: CommandOutput) { @@ -65,8 +59,6 @@ export function addOutput(id: string, output: CommandOutput) { } else { insert(item) } - - autoScroll() } export function addErrorMessage(message: string) { @@ -87,8 +79,6 @@ export function appendOutput(id: string, output: CommandOutput) { item.innerHTML += content else item.textContent += content - - autoScroll() } export function replaceOutput(id: string, output: CommandOutput) { @@ -105,8 +95,6 @@ export function replaceOutput(id: string, output: CommandOutput) { item.innerHTML = content else item.textContent = content - - autoScroll() } function processOutput(output: CommandOutput): ["html" | "text", string] {