Files
2025-01-08 00:43:40 +08:00

215 lines
7.6 KiB
JavaScript

import { app } from "../../scripts/app.js";
import { addColorSchemeReactiveStylesheets } from "./ColorScheming.js";
import { addScriptAddedHandler } from "./RunOnScriptAvailable.js";
/**
* A small chip.
*/
function CHIP(node, name, opts, app) {
const element = document.createElement("div");
element.classList.add("gremlation", "chip", ...opts[1].extraClasses ?? [])
element.append(opts[1].default)
const widget = node.addDOMWidget(name, 'chip', element, {
getHeight: () => LiteGraph.NODE_SLOT_HEIGHT,
getValue: () => element.innerText,
setValue: (newValue) => element.innerText = newValue,
})
return { widget }
}
/**
* A multi-line read-only text field that performs syntax highlighting.
*/
function SYNTAXHIGHLIGHTED(node, name, opts, app) {
const wrapper = document.createElement("div")
wrapper.classList.add("gremlation-syntax-highlighted")
const preElement = document.createElement("pre")
wrapper.appendChild(preElement)
const codeElement = document.createElement("code")
codeElement.textContent = opts[1].default
preElement.appendChild(codeElement)
const widget = node.addDOMWidget(name, 'SYNTAXHIGHLIGHTED', wrapper, {
getValue: () => codeElement.textContent,
setValue: (newValue) => codeElement.textContent = newValue,
setLanguage: function (newLanguage) {
const index = [...codeElement.classList].findIndex(className => className.startsWith("language-"))
if (index !== -1) codeElement.classList.remove(codeElement.classList[index])
codeElement.classList.add(`language-${newLanguage}`)
},
})
widget.element = wrapper;
widget.preElement = preElement;
widget.codeElement = codeElement;
return { widget }
}
class ViewDataExtension extends LGraphNode {
name = "gremlation:ComfyUI-ViewData";
settings = [
{
id: "gremlation:ComfyUI-ViewData:ViewData.Indentation",
name: "Indentation size",
type: "number",
defaultValue: 2,
tooltip: "How many spaces should be used for indentation?",
category: ["View Data ~🅖", "Formatting"],
},
];
configureStylesheets() {
addColorSchemeReactiveStylesheets({
light: 'extensions/comfyui-viewdata/prism/light.css',
dark: 'extensions/comfyui-viewdata/prism/dark.css',
})
const extensionStylesheet = document.createElement('link');
extensionStylesheet.rel = 'stylesheet';
extensionStylesheet.href = 'extensions/comfyui-viewdata/ViewData.css';
document.head.appendChild(extensionStylesheet);
}
configurePrism() {
Prism.hooks.add('before-sanity-check', function (env) {
env.element.innerHTML = env.element.innerHTML.replace(/<br>/g, '\n');
env.code = env.element.textContent;
});
}
async init() {
this.configureStylesheets();
this.configurePrism();
}
async getCustomWidgets(app) {
return {
CHIP,
SYNTAXHIGHLIGHTED,
}
}
nodeCreated(node) {
if (node.comfyClass !== "gremlation:ComfyUI-ViewData:ViewData") { return }
node.typeWidget = CHIP(node, "type", ["chip", { default: "None", extraClasses: ["code"] }], app).widget
node.valueWidget = SYNTAXHIGHLIGHTED(node, "value", ["SYNTAXHIGHLIGHTED", {}], app).widget;
}
async onConfigure(nodeData) {
const valueType = this.widgets_values?.length > 0 ? this.widgets_values[0] : "None"
this.typeWidget.value = valueType;
let language
switch (valueType) {
case "dict":
language = "json"
break
case "Tensor":
language = "python"
break
}
this.valueWidget.options.setLanguage(language);
const value = this.widgets_values[1]
if (valueType === "dict") {
const indentSize = app.extensionManager.setting.get("gremlation:ComfyUI-ViewData:ViewData.Indentation");
const formattedSource = await prettier.format(value, {
parser: "json",
plugins: prettierPlugins,
tabWidth: indentSize,
})
this.valueWidget.value = formattedSource;
Prism.highlightElement(this.valueWidget.codeElement);
} else if (valueType == "None") {
this.valueWidget.value = "";
} else {
this.valueWidget.value = value;
Prism.highlightElement(this.valueWidget.codeElement);
}
}
async onExecuted(message, nodeData) {
const valueType = message.type[0]
const value = message.value[0]
this.typeWidget.value = valueType
let language
switch (valueType) {
case "dict":
language = "json"
break
case "Tensor":
language = "python"
break
}
this.valueWidget.options.setLanguage(language);
if (valueType === "dict") {
const indentSize = app.extensionManager.setting.get("gremlation:ComfyUI-ViewData:ViewData.Indentation");
const rawSource = JSON.stringify(value, null, indentSize);
const formattedSource = await prettier.format(rawSource, {
parser: "json",
plugins: prettierPlugins,
tabWidth: indentSize,
})
this.valueWidget.value = formattedSource;
Prism.highlightElement(this.valueWidget.codeElement);
} else if (valueType == "None") {
this.valueWidget.value = value;
} else {
this.valueWidget.value = value;
Prism.highlightElement(this.valueWidget.codeElement);
}
onDrawBackgroundOnce.apply(this, [function () {
const itemHeights = [
LiteGraph.NODE_TITLE_HEIGHT,
LiteGraph.NODE_SLOT_HEIGHT * (this.inputs.length),
this.typeWidget.element.clientHeight,
this.valueWidget.preElement.clientHeight,
]
const height = Math.ceil(itemHeights.reduce((a, b) => a + b, 0) / 10) * 10
this.setSize([Math.max(this.width, this.valueWidget.codeElement.clientWidth + (LiteGraph.NODE_SLOT_HEIGHT * 2)), Math.max(this.height, height)])
this.graph.setDirtyCanvas(true, false)
}])
}
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeType.comfyClass !== "gremlation:ComfyUI-ViewData:ViewData") { return }
const outerThis = this;
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function (nodeData) {
onConfigure?.apply(this, [nodeData]);
outerThis.onConfigure.apply(this, [nodeData, nodeType]);
}
const onExecuted = nodeType.prototype.onExecuted;
nodeType.prototype.onExecuted = function (message) {
onExecuted?.apply(this, [message])
outerThis.onExecuted.apply(this, [message, ...arguments]);
}
}
}
const viewDataExtension = new ViewDataExtension();
function onDrawBackgroundOnce(handler, ...args) {
const originalOnDrawBackground = this.onDrawBackground;
this.onDrawBackground = function (...onDrawBackgroundArgs) {
originalOnDrawBackground?.apply(this, ...onDrawBackgroundArgs);
handler.apply(this, ...args);
this.onDrawBackground = originalOnDrawBackground;
}
}
async function main() {
app.registerExtension(viewDataExtension);
}
function isPrismLoaded() {
return typeof Prism !== 'undefined';
}
addScriptAddedHandler(main, isPrismLoaded);