/** * Module-window bridge. Exposes the public Module API as `window.chjModule` and, for * backwards compatibility, under the 0.1.0 name `window.chjPlugin` (same object, same * method names). Also injects the shared Core window chrome (title + "Collapse"). */ import { moduleApi } from "../index"; import { subscribe } from "../transport"; import { bootInfo } from "./boot"; import { installWindowChrome } from "./windowChrome"; import { installActivityReporter } from "./activity"; const boot = bootInfo(); const api = Object.freeze({ apiVersion: moduleApi.version, getInfo: moduleApi.getInfo, ui: moduleApi.ui, close: moduleApi.close, sessions: moduleApi.sessions, system: moduleApi.system, disks: moduleApi.disks, keys: moduleApi.keys, logs: moduleApi.logs, users: moduleApi.users, nginx: moduleApi.nginx, files: moduleApi.files, hashing: moduleApi.hashing }); for (const name of ["chjModule", "chjPlugin"]) { Object.defineProperty(window, name, { value: api, writable: false, configurable: false, enumerable: true }); } // "Collapse" texts come from the core catalogs (i18n/core/.json), injected by the Core. declare global { var __CHJ_I18N__: { catalogs?: { chrome?: Record> } } | undefined } function chromeCopy(language: string): [string, string] { const catalogs = globalThis.__CHJ_I18N__?.catalogs?.chrome || {}; const entry = catalogs[language] || catalogs.en || {}; return [entry["chrome.collapse"] || "Collapse", entry["chrome.collapseDescription"] || "Collapse into the application's bottom bar"]; } let chromeRoot: ShadowRoot | null = null; window.addEventListener("DOMContentLoaded", () => { const styleUrl = new URL("/__chj_core__/window-chrome.css", window.location.href).href; const host = document.createElement("chj-plugin-chrome"); host.id = "chj-plugin-window-chrome"; const shadow = host.attachShadow({ mode: "open" }); chromeRoot = shadow; let loaded = 0; const stylesheet = () => { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = styleUrl; link.addEventListener("load", () => { if (++loaded === 2) host.dataset.ready = "true"; }); return link; }; document.head.append(stylesheet()); const header = document.createElement("header"); header.id = "chj-chrome-header"; if (boot.platform === "win32" || boot.platform === "linux") header.className = "native-controls"; const mark = document.createElement("span"); mark.id = "chj-chrome-mark"; mark.textContent = "CH-J"; const title = document.createElement("span"); title.id = "chj-chrome-title"; title.textContent = document.title || "CH-J Server Manager"; const collapse = document.createElement("button"); collapse.type = "button"; collapse.id = "chj-chrome-collapse"; const translate = (language: string) => { const [label, description] = chromeCopy(language); collapse.textContent = label; collapse.title = description; collapse.setAttribute("aria-label", description); }; translate("en"); collapse.addEventListener("click", () => { void moduleApi.minimize().catch((error) => console.error("Module collapse failed.", error)); }); subscribe("module:ui:languageChanged", translate); void moduleApi.ui.getLanguage().then(translate).catch(() => {}); void moduleApi.getInfo().then((manifest) => { title.textContent = manifest.name; }).catch(() => {}); header.append(mark, title, collapse); shadow.append(stylesheet(), header); document.body.prepend(host); }); installWindowChrome(boot.platform, ["#chj-chrome-header"], () => (chromeRoot ? [document, chromeRoot] : [document])); installActivityReporter();