From ec8678c45afc3b5d422cca54063d8618023ad171 Mon Sep 17 00:00:00 2001
From: space-nuko <24979496+space-nuko@users.noreply.github.com>
Date: Thu, 8 Jun 2023 20:27:08 -0500
Subject: [PATCH] Load image batch improvements
- Uses filter list behavior for LiteGraph context menu
- "Replace" button
- Can select from combo widget on node directly
---
web/scripts/widgets.js | 77 ++++++++++++++++++++++++++++--------------
web/style.css | 14 ++++++++
2 files changed, 65 insertions(+), 26 deletions(-)
diff --git a/web/scripts/widgets.js b/web/scripts/widgets.js
index 308e8ad61..53b3d5c9b 100644
--- a/web/scripts/widgets.js
+++ b/web/scripts/widgets.js
@@ -453,14 +453,20 @@ async function loadImageAsync(imageURL) {
}
const MULTIIMAGEUPLOAD = (node, inputName, inputData, app) => {
- const imagesWidget = node.addWidget("text", inputName, inputData, () => {})
- imagesWidget.disabled = true;
+ let filepaths = { input: [], output: [] }
- imagesWidget._filepaths = {}
if (inputData[1] && inputData[1].filepaths) {
- imagesWidget._filepaths = inputData[1].filepaths
+ filepaths = inputData[1].filepaths
}
+ const update = function(v) {
+ this.value = v
+ }
+
+ const imagesWidget = node.addWidget("combo", inputName, inputData, update, { values: filepaths["input"] })
+ imagesWidget._filepaths = filepaths
+ imagesWidget._entries = filepaths["input"]
+
async function showImages(names) {
node.imgs = []
@@ -616,10 +622,11 @@ const MULTIIMAGEUPLOAD = (node, inputName, inputData, app) => {
-
+
-
+
+
`;
const previewElem = document.createElement("div");
previewElem.innerHTML = previewHtml;
@@ -628,46 +635,64 @@ const MULTIIMAGEUPLOAD = (node, inputName, inputData, app) => {
const folderTypeSel = previewElem.querySelector('.folder-type');
const imagePathSel = previewElem.querySelector('.image-path');
+ const imagePathText = previewElem.querySelector('.image-path-text');
const imagePreview = previewElem.querySelector('.image-preview');
- imagePathSel.addEventListener("change", (event) => {
- const filename = event.target.value;
- const type = folderTypeSel.value;
- imagePreview.src = `/view?filename=${filename}&type=${type}`
+ folderTypeSel.addEventListener("change", (event) => {
+ const filepaths = imagesWidget._filepaths[event.target.value];
+ imagesWidget._entries = filepaths
+ imagePathText.innerHTML = filepaths[0];
+ imagePreview.src = `/view?filename=${filepaths[0]}&type=${event.target.value}`
});
- folderTypeSel.addEventListener("change", (event) => {
- imagePathSel.innerHTML = "";
- const filepaths = imagesWidget._filepaths[event.target.value];
- if (filepaths == null)
- return;
+ imagePathSel.addEventListener("click", (event) => {
+ const type = folderTypeSel.value;
+ const filepaths = imagesWidget._filepaths[folderTypeSel.value];
+ const entries = imagesWidget._entries
- for (const filepath of filepaths) {
- const filename = filepath.split('\\').pop().split('/').pop();
- const opt = document.createElement('option');
- opt.value = filepath
- opt.innerHTML = filename
- imagePathSel.appendChild(opt);
+ const innerClicked = (v, _options, e, prev) => {
+ const filename = v;
+ imagePathText.innerHTML = filename;
+ imagePreview.src = `/view?filename=${filename}&type=${type}`
}
- imagePathSel.value = filepaths[0]
- imagePathSel.dispatchEvent(new Event('change'));
+ new LiteGraph.ContextMenu(entries, {
+ event,
+ callback: innerClicked,
+ node,
+ className: "dark" // required for contextMenuFilter.js to kick in
+ });
});
- folderTypeSel.value = "output";
+ folderTypeSel.value = "input";
folderTypeSel.dispatchEvent(new Event('change'));
const addButton = previewElem.querySelector('.add-image');
addButton.addEventListener("click", async (event) => {
- const filename = imagePathSel.value;
+ const filename = imagePathText.innerHTML;
const type = folderTypeSel.value;
- const value = `${filename} [${type}]`;
+ let value = filename;
+ if (type !== "input")
+ value += ` [${type}]`
imagesWidget._real_value.push(value)
imagesWidget.value = imagesWidget._real_value
await showImages(imagesWidget.value);
inner_refresh();
})
+ const replaceButton = previewElem.querySelector('.replace-image');
+ replaceButton.addEventListener("click", async (event) => {
+ const filename = imagePathText.innerHTML;
+ const type = folderTypeSel.value;
+ let value = filename;
+ if (type !== "input")
+ value += ` [${type}]`
+ imagesWidget._real_value = [value]
+ imagesWidget.value = imagesWidget._real_value
+ await showImages(imagesWidget.value);
+ inner_refresh();
+ })
+
imagesWidget.panel.footer.style.display = "flex";
const clearButton = imagesWidget.panel.addButton("Clear", () => {
diff --git a/web/style.css b/web/style.css
index ccde802e1..fd44f25df 100644
--- a/web/style.css
+++ b/web/style.css
@@ -381,6 +381,15 @@ button.comfy-queue-btn {
border-radius: 3px;
}
+.litegraph .dialog.multiimageupload_dialog .image-path-text {
+ max-width: 250px;
+ overflow: hidden;
+ white-space: nowrap;
+ display: block;
+ text-overflow: ellipsis;
+ text-align: left;
+}
+
.litegraph .dialog select {
margin-right: 20px;
padding-left: 4px;
@@ -471,6 +480,7 @@ button.comfy-queue-btn {
}
.multiimageupload_dialog button {
+ height: 28px;
background-color: #1c1c1c;
color: #aaa;
border: 0;
@@ -479,6 +489,10 @@ button.comfy-queue-btn {
cursor: pointer;
}
+.multiimageupload_dialog .actions button {
+ margin-right: 10px;
+}
+
.multiimageupload_dialog.extra {
color: #ccc;
}