// client.js // UI: Buttons, Anzeige von Result als JSON + Baum, Fallback für Commands function appendLog(line) { const el = document.getElementById("log"); if (!el) return; const now = new Date().toISOString(); el.value += `[${now}] ${line}\n`; el.scrollTop = el.scrollHeight; } function clearTextarea(id) { const el = document.getElementById(id); if (el) el.value = ""; } function clearElement(id) { const el = document.getElementById(id); if (el) el.innerHTML = ""; } function formatScalar(value) { if (value === null) return "null"; if (value === undefined) return "undefined"; if (typeof value === "string") return JSON.stringify(value); if (typeof value === "number" && Number.isFinite(value)) return String(value); if (typeof value === "boolean") return String(value); return String(value); } function renderTree(container, value, key = "result", open = true) { if (!container) return; container.innerHTML = ""; container.appendChild(renderNode(key, value, open)); } function renderNode(key, value, open = false) { const isObject = value !== null && typeof value === "object"; if (!isObject) { const leaf = document.createElement("div"); leaf.className = "tree-leaf"; leaf.textContent = `${key}: ${formatScalar(value)}`; return leaf; } const details = document.createElement("details"); details.open = open; const summary = document.createElement("summary"); summary.textContent = Array.isArray(value) ? `${key} [${value.length}]` : key; details.appendChild(summary); const body = document.createElement("div"); body.style.marginLeft = "16px"; if (Array.isArray(value)) { value.forEach((item, idx) => { body.appendChild(renderNode(String(idx), item, false)); }); } else { Object.entries(value).forEach(([childKey, childVal]) => { body.appendChild(renderNode(childKey, childVal, false)); }); } details.appendChild(body); return details; } function renderResult(result) { const jsonEl = document.getElementById("result-json"); const treeEl = document.getElementById("result-tree"); if (jsonEl) { jsonEl.value = JSON.stringify(result, null, 2); } renderTree(treeEl, result, "result", true); } async function onCalculateClick() { clearTextarea("analysis-log"); clearTextarea("result-json"); clearElement("result-tree"); appendLog("Starte Berechnung..."); try { const result = await window.calculate(); renderResult(result); appendLog("Result angezeigt."); } catch (err) { appendLog(`Fehler: ${err.message}`); } } async function onCommandClick(btn) { const cmd = btn.dataset.cmd; const payloadSelector = btn.dataset.payload; const payload = payloadSelector ? document.querySelector(payloadSelector)?.value ?? "" : ""; if (typeof window.sendCommand === "function") { try { await window.sendCommand(cmd, payload); appendLog(`Command gesendet: ${cmd}${payload ? " " + payload : ""}`); } catch (err) { appendLog(`Command-Fehler: ${err.message}`); } return; } appendLog(`Command (kein Transport definiert): ${cmd}${payload ? " " + payload : ""}`); } function setupUi() { const calculateBtn = document.getElementById("btn-calculate"); if (calculateBtn) { calculateBtn.addEventListener("click", onCalculateClick); } document.querySelectorAll("button[data-cmd]").forEach(btn => { if (btn.id === "btn-calculate") return; btn.addEventListener("click", () => onCommandClick(btn)); }); } window.addEventListener("DOMContentLoaded", setupUi);