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; }