ComfyUI/web/extensions/core/imageFeed.js
Silversith 5cf4d65c53 Update imageFeed.js
Remove disable deleteAll button, remove debugger, add tooltips to buttons
2023-04-11 11:07:45 +02:00

253 lines
10 KiB
JavaScript

import { api } from "/scripts/api.js";
import { app } from "/scripts/app.js";
// Adds a list of images that are generated to the bottom of the page
// This script was created by pythongosssss
// https://github.com/pythongosssss/ComfyUI-Custom-Scripts
app.registerExtension({
name: "Comfy.ImageFeed",
setup() {
//CODE HERE
//create imageList element
const imageList = document.createElement("div");
Object.assign(imageList.style, {
minHeight: "30px",
maxHeight: "1000px",
width: "100vw",
position: "absolute",
bottom: 0,
background: "#333",
overflow: "auto",
border: "2px solid #333",
zIndex: "99",
display: "flex",
flexWrap: "wrap",
userSelect: "none",
alignContent: "baseline"
});
// add CSS rules for resize cursor
const resizeHandle = document.createElement("div");
Object.assign(resizeHandle.style, {
position: "absolute",
top: "-5px",
right: "0",
left: "0",
height: "10px",
cursor: "row-resize",
zIndex: "1"
});
imageList.appendChild(resizeHandle);
// add hover style to resize handle
const hoverStyle = document.createElement("style");
hoverStyle.innerHTML = `
.resize-handle:hover {
background-color: #666;
}
`;
document.head.appendChild(hoverStyle);
// set class for resize handle
resizeHandle.classList.add("resize-handle");
// add mousedown event listener to resize handle
let startY = 0;
let startHeight = 0;
resizeHandle.addEventListener("mousedown", (event) => {
startY = event.clientY;
startHeight = parseInt(getComputedStyle(imageList).height);
document.addEventListener("mousemove", resize);
document.addEventListener("mouseup", stopResize);
});
// resize function
function resize(event) {
const newHeight = startHeight + startY - event.clientY;
imageList.style.height = newHeight + "px";
}
var allImages = []
function loadImages(detail) {
const images = detail.output.images.filter(
(img) => img.type === "output" && img.filename !== "_output_images_will_be_put_here"
);
allImages.push(...images);
for (const src of images) {
const imgContainer = document.createElement("div");
imgContainer.style.cssText = "height: 120px; width: 120px; position: relative;";
const imgDelete = document.createElement("button");
imgDelete.innerHTML = "🗑️";
imgDelete.style.cssText =
"position: absolute; top: 0; right: 0; width: 20px; text-indent: -4px; right: 5px; height: 20px; cursor: pointer; position: absolute; top: 5px; font-size: 12px; line-height: 12px;";
imgDelete.addEventListener("click", async () => {
const confirmDelete = confirm("Are you sure you want to delete this image?");
if (confirmDelete) {
await api.deleteImage(src.filename);
let newAllImages = allImages.filter(image => image.filename !== src.filename);
allImages = newAllImages;
imgContainer.remove();
}
});
const img = document.createElement("img");
img.setAttribute("filename", src.filename);
img.style.cssText = "height: 120px; width: 120px; object-fit: cover;";
img.src = `/view?filename=${encodeURIComponent(src.filename)}&type=${src.type}&subfolder=${encodeURIComponent(src.subfolder)}`;
img.addEventListener("click", () => {
const popup = document.createElement("div");
popup.style.cssText = "position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 999;";
const popupImg = document.createElement("img");
popupImg.src = img.src;
popupImg.style.cssText = "max-height: 80vh; max-width: 80vw;";
let currentIndex = allImages.indexOf(src);
const closeButton = document.createElement("button");
closeButton.innerHTML = "❌";
closeButton.style.cssText = "position: absolute; top: 0; right: 0; padding: 5px; font-size: 20px; line-height: 20px; background-color: transparent; border: none; color: white; cursor: pointer;";
const nextButton = document.createElement("button");
nextButton.innerHTML = "▶";
nextButton.style.cssText = "position: absolute; top: 50%; right: 10px; padding: 5px; font-size: 20px; line-height: 20px; background-color: transparent; border: none; color: white; cursor: pointer; transform: translateY(-50%);";
const prevButton = document.createElement("button");
prevButton.innerHTML = "◀";
prevButton.style.cssText = "position: absolute; top: 50%; left: 10px; padding: 5px; font-size: 20px; line-height: 20px; background-color: transparent; border: none; color: white; cursor: pointer; transform: translateY(-50%);";
closeButton.addEventListener("click", () => {
popup.remove();
});
nextButton.addEventListener("click", () => {
currentIndex--;
if (currentIndex < 0) {
currentIndex = allImages.length - 1;
}
popupImg.src = `/view?filename=${encodeURIComponent(allImages[currentIndex].filename)}&type=${allImages[currentIndex].type}&subfolder=${encodeURIComponent(allImages[currentIndex].subfolder)}`;
});
prevButton.addEventListener("click", () => {
currentIndex++;
if (currentIndex >= allImages.length) {
currentIndex = 0;
}
popupImg.src = `/view?filename=${encodeURIComponent(allImages[currentIndex].filename)}&type=${allImages[currentIndex].type}&subfolder=${encodeURIComponent(allImages[currentIndex].subfolder)}`;
});
popup.addEventListener("click", (event) => {
if (event.target === popup) {
popup.remove();
}
});
popup.append(popupImg);
popup.append(closeButton);
popup.append(nextButton);
popup.append(prevButton);
document.body.append(popup);
});
imgContainer.append(imgDelete);
imgContainer.append(img);
imageList.prepend(imgContainer);
}
}
// stop resize function
function stopResize() {
document.removeEventListener("mousemove", resize);
document.removeEventListener("mouseup", stopResize);
}
// append imageList element to document
document.body.append(imageList);
const menu = document.createElement("div");
Object.assign(menu.style, {
height: "100%",
width: "90px",
right:"0px",
top:"0px"
});
imageList.append(menu);
function makeButton(text, style, title) {
const btn = document.createElement("button");
btn.type = "button";
btn.textContent = text;
btn.title = title;
Object.assign(btn.style, {
...style,
height: "20px",
width: "80px",
cursor: "pointer",
position: "absolute",
fontSize: "12px",
lineHeight: "12px",
});
menu.append(btn);
return btn;
}
const showButton = document.createElement("button");
const closeButton = makeButton("❌ Close", {
textIndent: "-4px",
top: "5px",
right: "5px",
}, "Hide the image drawer (Open Drawer button will be displayed on main floating menu)"
);
closeButton.onclick = () => {
imageList.style.display = "none";
showButton.style.display = "unset";
};
const clearButton = makeButton("✖ Clear", {
top: "30px",
right: "5px",
}, "Clears all items displayed in image drawer (This won't delete anything, refreshing the page will reload from Output)"
);
clearButton.onclick = () => {
allImages = []
imageList.replaceChildren(menu, resizeHandle);
};
const deleteAllButton = makeButton("🗑️ Delete", {
top: "55px",
right: "5px",
}, "Delete all items displayed in image drawer (This won't delete the entire output folder)"
);
deleteAllButton.onclick = () => {
const confirmDelete = confirm("Are you sure you want to delete all images in the drawer?");
if (confirmDelete) {
api.deleteAllImages(allImages.map(item => item.filename));
allImages = []
imageList.replaceChildren(menu, resizeHandle);
}
};
api.getOutput().then(data => {
try {
if (data.message == "Success"){
var images = data.filenames[0].map((filename) => {
return { filename: filename, type: 'output', subfolder: '' };
});
var output = {images: images}
var detail = {output: output}
loadImages(detail);
}
} catch(err){
console.error(err);
}
});
showButton.classList.add("comfy-settings-btn");
showButton.style.right = "16px";
showButton.style.cursor = "pointer";
showButton.style.display = "none";
showButton.textContent = "🖼️";
showButton.onclick = () => {
imageList.style.display = "flex";
showButton.style.display = "none";
};
document.querySelector(".comfy-settings-btn").after(showButton);
api.addEventListener("executed", ({ detail }) => {
loadImages(detail);
});
},
});