初始化

This commit is contained in:
2026-06-15 09:59:00 +08:00
commit c131f5e7c3
6 changed files with 938 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
__pycache__/
+21
View File
@@ -0,0 +1,21 @@
# ComfyUI 参考图管理器
一个轻量的 ComfyUI 自定义节点,用一个节点管理多张参考图,避免堆很多 `Load Image` 节点。
![参考图管理器预览](https://sywb.top/Staticfiles/pic/yscy1.png)
## 功能
- 标准 `IMAGE` 输出。
- 原生图片下拉和上传控件会隐藏,只显示自定义中文管理面板。
- 图片列表默认为空,只保存你主动添加到管理器里的图片。
- 支持多选添加、替换当前、点击缩略图切换输出。
- 支持编辑显示名称、原始路径、文件夹。
- 支持搜索、同文件夹筛选、收藏筛选、删除单张、清空列表。
- 不移动、不删除 ComfyUI input 缓存文件,只管理工作流里的图片引用和元数据。
## 使用
重启 ComfyUI 后添加:
`image/reference -> 参考图管理器`
+17
View File
@@ -0,0 +1,17 @@
"""
Reference Image Manager for ComfyUI.
"""
from .nodes import ReferenceImageManager
NODE_CLASS_MAPPINGS = {
"Reference Image Manager": ReferenceImageManager,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Reference Image Manager": "参考图管理器",
}
WEB_DIRECTORY = "./web"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
+97
View File
@@ -0,0 +1,97 @@
import hashlib
import os
import numpy as np
import torch
from PIL import Image, ImageOps, ImageSequence
import folder_paths
import node_helpers
class ReferenceImageManager:
@classmethod
def INPUT_TYPES(cls):
input_dir = folder_paths.get_input_directory()
files = []
if os.path.isdir(input_dir):
files = [
f
for f in os.listdir(input_dir)
if os.path.isfile(os.path.join(input_dir, f))
]
files = folder_paths.filter_files_content_types(files, ["image"])
return {
"required": {
"image": ([""] + sorted(files), {"image_upload": True}),
"managed_images": ("STRING", {"default": "[]", "multiline": True}),
}
}
CATEGORY = "image/reference"
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "load_image"
SEARCH_ALIASES = [
"reference image",
"image manager",
"image switcher",
"load image",
"managed image",
]
def load_image(self, image, managed_images="[]"):
if not image:
raise ValueError("参考图管理器未选择图片。")
image_path = folder_paths.get_annotated_filepath(image)
img = node_helpers.pillow(Image.open, image_path)
output_images = []
width, height = None, None
for frame in ImageSequence.Iterator(img):
frame = node_helpers.pillow(ImageOps.exif_transpose, frame)
if frame.mode == "I":
frame = frame.point(lambda i: i * (1 / 255))
image_rgb = frame.convert("RGB")
if not output_images:
width, height = image_rgb.size
if image_rgb.size != (width, height):
continue
image_np = np.array(image_rgb).astype(np.float32) / 255.0
output_images.append(torch.from_numpy(image_np)[None,])
if img.format == "MPO":
break
if len(output_images) > 1:
return (torch.cat(output_images, dim=0),)
return (output_images[0],)
@classmethod
def IS_CHANGED(cls, image, managed_images="[]"):
if not image:
return ""
image_path = folder_paths.get_annotated_filepath(image)
hasher = hashlib.sha256()
with open(image_path, "rb") as image_file:
hasher.update(image_file.read())
return hasher.digest().hex()
@classmethod
def VALIDATE_INPUTS(cls, image, managed_images="[]"):
if not image:
return "参考图管理器未选择图片。"
if not folder_paths.exists_annotated_filepath(image):
return "Invalid image file: {}".format(image)
return True
+214
View File
@@ -0,0 +1,214 @@
.rim-panel {
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
min-width: 320px;
height: 100%;
padding: 8px;
overflow: hidden;
color: #e8edf2;
background: #171b20;
border: 1px solid #2c333b;
border-radius: 6px;
font-family: Arial, Helvetica, sans-serif;
}
.rim-toolbar,
.rim-path-row,
.rim-editor,
.rim-tabs,
.rim-card-actions {
display: flex;
align-items: center;
gap: 6px;
}
.rim-toolbar {
justify-content: space-between;
flex-wrap: wrap;
}
.rim-title {
min-width: 0;
overflow: hidden;
font-size: 12px;
font-weight: 700;
text-overflow: ellipsis;
white-space: nowrap;
}
.rim-btn,
.rim-tab {
height: 26px;
padding: 0 8px;
color: #dfe8f0;
background: #222932;
border: 1px solid #3b4652;
border-radius: 5px;
cursor: pointer;
font-size: 12px;
white-space: nowrap;
}
.rim-btn:hover,
.rim-tab:hover {
background: #2d3742;
}
.rim-btn-primary {
color: #0d141b;
background: #8fd0ff;
border-color: #8fd0ff;
font-weight: 700;
}
.rim-btn-danger {
color: #ffd9d9;
border-color: #704040;
}
.rim-preview {
position: relative;
flex: 0 0 180px;
min-height: 150px;
overflow: hidden;
background:
linear-gradient(45deg, #20262d 25%, transparent 25%),
linear-gradient(-45deg, #20262d 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #20262d 75%),
linear-gradient(-45deg, transparent 75%, #20262d 75%);
background-color: #11151a;
background-position: 0 0, 0 8px, 8px -8px, -8px 0;
background-size: 16px 16px;
border: 1px solid #323b45;
border-radius: 6px;
}
.rim-preview img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}
.rim-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
padding: 12px;
color: #92a0ad;
font-size: 12px;
text-align: center;
}
.rim-path-row input,
.rim-editor input,
.rim-search {
box-sizing: border-box;
width: 100%;
height: 26px;
min-width: 0;
padding: 0 8px;
color: #e8edf2;
background: #11151a;
border: 1px solid #333d48;
border-radius: 5px;
font-size: 12px;
}
.rim-editor {
flex-direction: column;
align-items: stretch;
}
.rim-tabs {
flex-wrap: wrap;
}
.rim-tab-active {
color: #0d141b;
background: #b7dfb0;
border-color: #b7dfb0;
font-weight: 700;
}
.rim-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
gap: 8px;
min-height: 0;
padding-right: 2px;
overflow: auto;
}
.rim-card {
display: flex;
flex-direction: column;
gap: 5px;
min-width: 0;
padding: 5px;
background: #20262e;
border: 1px solid #303a44;
border-radius: 6px;
cursor: pointer;
}
.rim-card-active {
border-color: #8fd0ff;
box-shadow: 0 0 0 1px #8fd0ff inset;
}
.rim-thumb {
width: 100%;
aspect-ratio: 1 / 1;
overflow: hidden;
background: #101418;
border-radius: 4px;
}
.rim-thumb img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.rim-name,
.rim-meta {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rim-name {
color: #edf3f8;
font-size: 11px;
font-weight: 700;
}
.rim-meta {
color: #9ba8b4;
font-size: 10px;
}
.rim-star {
color: #f3d27a;
}
.rim-card-actions {
justify-content: space-between;
}
.rim-mini {
width: 24px;
height: 22px;
padding: 0;
}
.rim-hidden {
display: none !important;
}
+588
View File
@@ -0,0 +1,588 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
const NODE_NAME = "Reference Image Manager";
const MAX_ITEMS = 120;
const CONFIG_VALUES = "__rim_config_widgets_values";
function isItemsJson(value) {
return typeof value === "string" && value.trim().startsWith("[");
}
function ensureStyles() {
const id = "reference-image-manager-css";
if (document.getElementById(id)) return;
const link = document.createElement("link");
link.id = id;
link.rel = "stylesheet";
link.href = "extensions/ComfyUI-ReferenceImageManager/reference_image_manager.css";
document.head.append(link);
}
function makeEl(tag, className, text) {
const el = document.createElement(tag);
if (className) el.className = className;
if (text != null) el.textContent = text;
return el;
}
function basename(path) {
return (path || "").split(/[\\/]/).filter(Boolean).pop() || "";
}
function dirname(path) {
const slash = (path || "").includes("\\") ? "\\" : "/";
const parts = (path || "").split(/[\\/]/).filter(Boolean);
parts.pop();
return parts.join(slash);
}
function parseItems(value) {
try {
const items = JSON.parse(value || "[]");
return Array.isArray(items) ? items : [];
} catch {
return [];
}
}
function cleanItems(items) {
const seen = new Set();
return items
.filter((item) => item?.image)
.filter((item) => {
const key = item.id || `${item.image}|${item.original_path || ""}`;
if (seen.has(key)) return false;
seen.add(key);
return true;
})
.slice(0, MAX_ITEMS);
}
function annotatedImageName(upload) {
const prefix = upload.subfolder ? `${upload.subfolder}/` : "";
const type = upload.type && upload.type !== "input" ? ` [${upload.type}]` : "";
return `${prefix}${upload.name}${type}`;
}
function viewUrl(item) {
if (!item?.image) return "";
const filename = item.subfolder ? `${item.subfolder}/${item.name}` : item.name || item.image;
const params = new URLSearchParams({
filename,
type: item.type || "input",
});
return api.apiURL(`/view?${params.toString()}${app.getPreviewFormatParam?.() || ""}`);
}
function getWidget(node, name) {
return node.widgets?.find((w) => w.name === name);
}
function getWidgetValue(node, name) {
return getWidget(node, name)?.value || "";
}
function readConfiguredItems(node, fallbackValues) {
const values = fallbackValues || node?.[CONFIG_VALUES] || node?.widgets_values || [];
return values.find(isItemsJson) || "";
}
function readManagedJson(node, fallbackValues) {
const configuredItems = readConfiguredItems(node, fallbackValues);
if (node?.__rim_config_dirty) {
return configuredItems || getWidgetValue(node, "managed_images") || node?.properties?.rim_items || node?.__rim_state_json || "[]";
}
return (
node?.__rim_state_json ||
getWidgetValue(node, "managed_images") ||
configuredItems ||
node?.properties?.rim_items ||
"[]"
);
}
function readSelectedImage(node, fallbackValues) {
const values = fallbackValues || node?.[CONFIG_VALUES] || node?.widgets_values || [];
if (node?.__rim_config_dirty) {
return values[0] || getWidgetValue(node, "image") || "";
}
return getWidgetValue(node, "image") || values[0] || "";
}
function writeSerializableState(node, workflowNode) {
const existingValues = workflowNode?.widgets_values || node?.[CONFIG_VALUES] || node?.widgets_values || [];
if (!node?.__rim_config_dirty) {
node?.__rim_persist?.();
}
const image = readSelectedImage(node, existingValues);
const json = readManagedJson(node, existingValues);
const selectedId = node?.properties?.rim_selected_id || "";
if (workflowNode) {
workflowNode.widgets_values = [image, json];
if (!workflowNode.properties) workflowNode.properties = {};
workflowNode.properties.rim_items = json;
workflowNode.properties.rim_selected_id = selectedId;
}
if (node) {
node.__rim_state_json = json;
node[CONFIG_VALUES] = [image, json];
if (!node.properties) node.properties = {};
node.properties.rim_items = json;
node.properties.rim_selected_id = selectedId;
}
}
function setNodeProperty(node, name, value) {
if (!node.properties) node.properties = {};
if (typeof node.setProperty === "function") {
node.setProperty(name, value);
} else {
node.properties[name] = value;
}
}
function setWidgetValue(node, name, value) {
const widget = getWidget(node, name);
if (!widget) return;
widget.value = value;
widget.callback?.(value);
}
function hideWidget(node, name) {
const widget = getWidget(node, name);
if (!widget) return;
if (!widget.options) widget.options = {};
widget.options.serialize = true;
widget.hidden = true;
widget.computeSize = () => [0, -4];
widget.serialize = true;
}
function removeWidgetByName(node, name) {
const widget = getWidget(node, name);
if (!widget) return;
widget.onRemove?.();
const index = node.widgets?.indexOf(widget) ?? -1;
if (index >= 0) node.widgets.splice(index, 1);
}
function buildManager(node) {
node.serialize_widgets = true;
removeWidgetByName(node, "upload");
hideWidget(node, "image");
hideWidget(node, "managed_images");
node.imgs = [];
const imageWidget = getWidget(node, "image");
const itemsWidget = getWidget(node, "managed_images");
if (!imageWidget || !itemsWidget) return;
const panel = makeEl("div", "rim-panel");
const fileInput = makeEl("input", "rim-hidden");
fileInput.type = "file";
fileInput.accept = "image/*";
fileInput.multiple = true;
const toolbar = makeEl("div", "rim-toolbar");
const title = makeEl("div", "rim-title", "参考图管理");
const addBtn = makeEl("button", "rim-btn rim-btn-primary", "添加图片");
const replaceBtn = makeEl("button", "rim-btn", "替换当前");
toolbar.append(title, addBtn, replaceBtn);
const preview = makeEl("div", "rim-preview");
const previewImg = document.createElement("img");
const emptyPreview = makeEl("div", "rim-empty", "先添加图片,然后点击缩略图切换输出。");
preview.append(emptyPreview);
const editor = makeEl("div", "rim-editor");
const nameInput = document.createElement("input");
nameInput.placeholder = "显示名称";
const pathInput = document.createElement("input");
pathInput.placeholder = "原始路径";
const folderInput = document.createElement("input");
folderInput.placeholder = "文件夹";
editor.append(nameInput, pathInput, folderInput);
const controls = makeEl("div", "rim-toolbar");
const search = document.createElement("input");
search.className = "rim-search";
search.placeholder = "搜索名称 / 路径 / 文件夹";
const showAllBtn = makeEl("button", "rim-tab rim-tab-active", "全部");
const showFolderBtn = makeEl("button", "rim-tab", "同文件夹");
const showStarBtn = makeEl("button", "rim-tab", "收藏");
controls.append(showAllBtn, showFolderBtn, showStarBtn);
const actions = makeEl("div", "rim-toolbar");
const saveMetaBtn = makeEl("button", "rim-btn", "保存信息");
const starBtn = makeEl("button", "rim-btn", "收藏");
const deleteBtn = makeEl("button", "rim-btn rim-btn-danger", "删除");
const clearBtn = makeEl("button", "rim-btn", "清空列表");
actions.append(saveMetaBtn, starBtn, deleteBtn, clearBtn);
const list = makeEl("div", "rim-list");
panel.append(toolbar, preview, editor, controls, search, actions, list, fileInput);
const configuredValues = node[CONFIG_VALUES] || node.widgets_values || [];
const configuredImage = configuredValues[0] || imageWidget.value || "";
const configuredItems = readConfiguredItems(node, configuredValues);
const storedItems = configuredItems || itemsWidget.value || node.properties?.rim_items || "[]";
let items = cleanItems(parseItems(storedItems));
let selectedId =
node.properties?.rim_selected_id ||
items.find((item) => item.image === configuredImage)?.id ||
items[0]?.id ||
"";
if (configuredImage) imageWidget.value = configuredImage;
itemsWidget.value = JSON.stringify(items);
node.__rim_state_json = itemsWidget.value;
imageWidget.serializeValue = () => imageWidget.value || "";
itemsWidget.serializeValue = () => node.__rim_state_json || itemsWidget.value || "[]";
let filterMode = "all";
let uploadMode = "add";
function selectedItem() {
return items.find((item) => item.id === selectedId) || null;
}
function persist() {
items = cleanItems(items);
const json = JSON.stringify(items);
node.__rim_state_json = json;
node[CONFIG_VALUES] = [imageWidget.value || "", json];
setWidgetValue(node, "managed_images", json);
setNodeProperty(node, "rim_items", json);
setNodeProperty(node, "rim_selected_id", selectedId || "");
}
function loadStateFromWidgets() {
const json = getWidgetValue(node, "managed_images") || node.__rim_state_json || node.properties?.rim_items || "[]";
items = cleanItems(parseItems(json));
node.__rim_state_json = JSON.stringify(items);
node[CONFIG_VALUES] = [imageWidget.value || "", node.__rim_state_json];
node.__rim_config_dirty = false;
selectedId =
node.properties?.rim_selected_id ||
items.find((item) => item.image === imageWidget.value)?.id ||
items[0]?.id ||
"";
if (selectedId) {
const item = items.find((entry) => entry.id === selectedId);
if (item) imageWidget.value = item.image;
}
}
function selectItem(item) {
if (!item) return;
selectedId = item.id;
setWidgetValue(node, "image", item.image);
node.imgs = [];
render();
}
function updateButtons() {
showAllBtn.classList.toggle("rim-tab-active", filterMode === "all");
showFolderBtn.classList.toggle("rim-tab-active", filterMode === "folder");
showStarBtn.classList.toggle("rim-tab-active", filterMode === "star");
}
function renderEditor(item) {
nameInput.value = item?.label || "";
pathInput.value = item?.original_path || "";
folderInput.value = item?.folder || "";
title.textContent = item ? basename(item.label || item.original_path || item.image) : "参考图管理";
}
function renderPreview(item) {
preview.replaceChildren();
if (!item) {
preview.append(emptyPreview);
return;
}
previewImg.src = viewUrl(item);
preview.append(previewImg);
}
function filteredItems() {
const q = search.value.trim().toLowerCase();
const currentFolder = selectedItem()?.folder || "";
return items.filter((item) => {
if (filterMode === "folder" && currentFolder && item.folder !== currentFolder) return false;
if (filterMode === "star" && !item.starred) return false;
if (!q) return true;
return `${item.label} ${item.name} ${item.original_path} ${item.folder}`.toLowerCase().includes(q);
});
}
function renderList() {
const active = selectedItem();
list.replaceChildren();
const visibleItems = filteredItems();
for (const item of visibleItems) {
const card = makeEl("div", `rim-card${item.id === selectedId ? " rim-card-active" : ""}`);
const thumb = makeEl("div", "rim-thumb");
const img = document.createElement("img");
img.loading = "lazy";
img.src = viewUrl(item);
thumb.append(img);
const name = makeEl("div", "rim-name", item.label || basename(item.original_path || item.name || item.image));
const meta = makeEl("div", "rim-meta", item.folder || item.type || "input");
const badge = makeEl("div", "rim-meta", item.starred ? "已收藏" : "点击选择");
card.append(thumb, name, meta, badge);
card.onclick = () => selectItem(item);
list.append(card);
}
if (!visibleItems.length) {
list.append(makeEl("div", "rim-empty", items.length ? "当前筛选没有图片。" : "列表为空。点击“添加图片”创建你的参考图库。"));
}
renderPreview(active);
renderEditor(active);
starBtn.textContent = active?.starred ? "取消收藏" : "收藏";
updateButtons();
}
function render() {
persist();
renderList();
requestAnimationFrame(() => {
node.setSize([Math.max(node.size[0], 460), Math.max(node.size[1], 560)]);
app.graph.setDirtyCanvas(true, true);
});
}
async function uploadFiles(files) {
const selectedBefore = selectedItem();
const uploads = [];
for (const file of files) {
const body = new FormData();
body.append("image", file);
body.append("type", "input");
const response = await api.fetchApi("/upload/image", { method: "POST", body });
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
const upload = await response.json();
const originalPath = file.path || file.webkitRelativePath || file.name;
uploads.push({
id: `${Date.now()}-${Math.random().toString(36).slice(2)}`,
image: annotatedImageName(upload),
name: upload.name,
label: basename(originalPath || upload.name),
subfolder: upload.subfolder || "",
type: upload.type || "input",
original_path: originalPath,
folder: dirname(originalPath),
starred: false,
added_at: Date.now(),
});
}
if (!uploads.length) return;
if (uploadMode === "replace" && selectedBefore) {
const index = items.findIndex((item) => item.id === selectedBefore.id);
items.splice(index, 1, uploads[0]);
selectedId = uploads[0].id;
if (uploads.length > 1) items.splice(index + 1, 0, ...uploads.slice(1));
} else {
items.push(...uploads);
selectedId = uploads[0].id;
}
selectItem(items.find((item) => item.id === selectedId));
}
addBtn.onclick = () => {
uploadMode = "add";
fileInput.multiple = true;
fileInput.click();
};
replaceBtn.onclick = () => {
uploadMode = "replace";
fileInput.multiple = false;
fileInput.click();
};
fileInput.onchange = async () => {
try {
await uploadFiles([...fileInput.files]);
} finally {
fileInput.value = "";
}
};
showAllBtn.onclick = () => {
filterMode = "all";
renderList();
};
showFolderBtn.onclick = () => {
filterMode = "folder";
renderList();
};
showStarBtn.onclick = () => {
filterMode = "star";
renderList();
};
search.oninput = renderList;
saveMetaBtn.onclick = () => {
const item = selectedItem();
if (!item) return;
item.label = nameInput.value.trim();
item.original_path = pathInput.value.trim();
item.folder = folderInput.value.trim() || dirname(item.original_path);
render();
};
starBtn.onclick = () => {
const item = selectedItem();
if (!item) return;
item.starred = !item.starred;
render();
};
deleteBtn.onclick = () => {
const item = selectedItem();
if (!item) return;
items = items.filter((entry) => entry.id !== item.id);
selectedId = items[0]?.id || "";
if (selectedId) selectItem(items[0]);
else {
setWidgetValue(node, "image", "");
node.imgs = [];
render();
}
};
clearBtn.onclick = () => {
items = [];
selectedId = "";
setWidgetValue(node, "image", "");
node.imgs = [];
render();
};
const imageCallback = imageWidget.callback;
imageWidget.callback = function () {
imageCallback?.apply(this, arguments);
node.imgs = [];
};
node.__rim_persist = persist;
const widget = node.addDOMWidget("manager", "reference-image-manager", panel, {
getValue() {
return itemsWidget.value;
},
setValue(value) {
const stored = node.properties?.rim_items || value;
items = cleanItems(parseItems(stored));
selectedId =
node.properties?.rim_selected_id ||
items.find((item) => item.image === imageWidget.value)?.id ||
items[0]?.id ||
"";
renderList();
},
serialize: false,
getMinHeight() {
return 470;
},
getMaxHeight() {
return 900;
},
});
widget.serialize = false;
const serialize = node.onSerialize;
node.onSerialize = function (workflowNode) {
if (node.__rim_config_dirty) {
loadStateFromWidgets();
} else {
persist();
}
serialize?.apply(this, arguments);
writeSerializableState(node, workflowNode);
};
node.__rim_reload = () => {
loadStateFromWidgets();
render();
};
loadStateFromWidgets();
render();
}
app.registerExtension({
name: "Comfy.ReferenceImageManager",
init() {
ensureStyles();
},
async beforeRegisterNodeDef(nodeType, nodeData) {
if (nodeData.name !== NODE_NAME) return;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
onNodeCreated?.apply(this, arguments);
buildManager(this);
};
const configure = nodeType.prototype.configure;
nodeType.prototype.configure = function (info) {
this[CONFIG_VALUES] = info?.widgets_values ? [...info.widgets_values] : [];
this.__rim_config_dirty = !!this[CONFIG_VALUES].length;
return configure?.apply(this, arguments);
};
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function () {
onConfigure?.apply(this, arguments);
requestAnimationFrame(() => {
const itemsWidget = getWidget(this, "managed_images");
if (itemsWidget && this[CONFIG_VALUES]?.length) {
const configuredItems = readConfiguredItems(this);
if (configuredItems) {
itemsWidget.value = configuredItems;
this.__rim_state_json = configuredItems;
}
}
this.__rim_reload?.();
});
};
const clone = nodeType.prototype.clone;
nodeType.prototype.clone = function () {
const cloned = clone?.apply(this, arguments);
if (cloned) {
cloned[CONFIG_VALUES] = [
getWidgetValue(this, "image"),
readManagedJson(this),
];
cloned.__rim_state_json = cloned[CONFIG_VALUES][1];
const imageWidget = getWidget(cloned, "image");
const itemsWidget = getWidget(cloned, "managed_images");
if (imageWidget) imageWidget.value = cloned[CONFIG_VALUES][0];
if (itemsWidget) itemsWidget.value = cloned[CONFIG_VALUES][1];
if (!cloned.properties) cloned.properties = {};
cloned.properties.rim_items = cloned[CONFIG_VALUES][1];
cloned.properties.rim_selected_id = this.properties?.rim_selected_id || "";
}
return cloned;
};
const onSerialize = nodeType.prototype.onSerialize;
nodeType.prototype.onSerialize = function (workflowNode) {
onSerialize?.apply(this, arguments);
writeSerializableState(this, workflowNode);
};
const onDrawBackground = nodeType.prototype.onDrawBackground;
nodeType.prototype.onDrawBackground = function () {
const oldImgs = this.imgs;
this.imgs = [];
const result = onDrawBackground?.apply(this, arguments);
this.imgs = oldImgs?.length ? [] : oldImgs;
return result;
};
},
});