Files
WASasquatch-ComfyUI_Viewer/web/views/json.js
T

134 lines
4.5 KiB
JavaScript

/**
* JSON View - JSON tree viewer with collapsible nodes
*/
import { BaseView, escapeHtml } from "./base_view.js";
class JsonView extends BaseView {
static id = "json";
static displayName = "JSON";
static priority = 90;
static detect(content) {
const trimmed = content.trim();
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
try {
JSON.parse(trimmed);
return 100;
} catch {}
}
return 0;
}
static renderTree(data, depth = 0) {
const indent = " ".repeat(depth);
const childIndent = " ".repeat(depth + 1);
if (data === null) return `<span class="json-null">null</span>`;
if (typeof data === "boolean") return `<span class="json-boolean">${data}</span>`;
if (typeof data === "number") return `<span class="json-number">${data}</span>`;
if (typeof data === "string") return `<span class="json-string">"${escapeHtml(data)}"</span>`;
if (Array.isArray(data)) {
if (data.length === 0) return `<span class="json-bracket">[]</span>`;
const id = `json-${Math.random().toString(36).slice(2, 9)}`;
const items = data.map((item, i) => {
const comma = i < data.length - 1 ? "," : "";
return `${childIndent}${this.renderTree(item, depth + 1)}${comma}`;
}).join("\n");
return `<span class="json-node"><span class="json-toggle" onclick="toggleJson('${id}')"><span class="json-arrow">▼</span><span class="json-bracket">[</span><span class="json-collapsed-preview">${data.length} items</span></span><span id="${id}" class="json-collapsible">
${items}
${indent}<span class="json-bracket">]</span></span><span class="json-collapsed-bracket">]</span></span>`;
}
if (typeof data === "object") {
const keys = Object.keys(data);
if (keys.length === 0) return `<span class="json-bracket">{}</span>`;
const id = `json-${Math.random().toString(36).slice(2, 9)}`;
const items = keys.map((key, i) => {
const comma = i < keys.length - 1 ? "," : "";
return `${childIndent}<span class="json-key">"${escapeHtml(key)}"</span>: ${this.renderTree(data[key], depth + 1)}${comma}`;
}).join("\n");
return `<span class="json-node"><span class="json-toggle" onclick="toggleJson('${id}')"><span class="json-arrow">▼</span><span class="json-bracket">{</span><span class="json-collapsed-preview">${keys.length} keys</span></span><span id="${id}" class="json-collapsible">
${items}
${indent}<span class="json-bracket">}</span></span><span class="json-collapsed-bracket">}</span></span>`;
}
return escapeHtml(String(data));
}
static render(content, theme) {
try {
const parsed = JSON.parse(content);
return `<div class="json-tree"><pre>${this.renderTree(parsed)}</pre></div>`;
} catch {
return `<pre><code class="language-javascript">${escapeHtml(content)}</code></pre>`;
}
}
static getStyles(theme) {
return `
.json-tree pre {
margin: 0;
white-space: pre-wrap;
font-size: 13px;
line-height: 1.4;
}
.json-key { color: #9cdcfe; }
.json-string { color: #ce9178; }
.json-number { color: #b5cea8; }
.json-boolean { color: #569cd6; }
.json-null { color: #569cd6; }
.json-bracket { color: ${theme.fg}; }
.json-node { display: inline; }
.json-toggle {
cursor: pointer;
user-select: none;
}
.json-toggle:hover { opacity: 0.7; }
.json-arrow {
display: inline-block;
width: 1em;
font-size: 10px;
transition: transform 0.15s;
color: #888;
}
.json-collapsed-preview {
color: #6a9955;
font-size: 11px;
font-style: italic;
display: none;
}
.json-collapsed-bracket {
display: none;
}
.json-collapsible.collapsed {
display: none;
}
.json-collapsible.collapsed + .json-collapsed-bracket {
display: inline;
}
.json-node:has(> .json-collapsible.collapsed) .json-collapsed-preview {
display: inline;
margin-left: 4px;
}
.json-node:has(> .json-collapsible.collapsed) .json-arrow {
transform: rotate(-90deg);
}
`;
}
static getScripts() {
return `
<script>
function toggleJson(id) {
const el = document.getElementById(id);
if (el) el.classList.toggle('collapsed');
}
<\/script>
`;
}
}
export default JsonView;