refactor: ✨ cleaned up frontend code a bit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
||||
+13
-4
@@ -1,3 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding:utf-8 -*-
|
||||
###
|
||||
# File: __init__.py
|
||||
# Project: comfy_mtb
|
||||
# Author: Mel Massadian
|
||||
# Copyright (c) 2023 Mel Massadian
|
||||
#
|
||||
###
|
||||
import os
|
||||
|
||||
os.environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true"
|
||||
@@ -5,6 +14,7 @@ os.environ["TF_FORCE_GPU_ALLOW_GROWTH"] = "true"
|
||||
import traceback
|
||||
from .log import log, blue_text, cyan_text, get_summary, get_label
|
||||
from .utils import here
|
||||
from .utils import comfy_dir
|
||||
import importlib
|
||||
import os
|
||||
import ast
|
||||
@@ -89,7 +99,7 @@ def load_nodes():
|
||||
|
||||
|
||||
# - REGISTER WEB EXTENSIONS
|
||||
web_extensions_root = utils.comfy_dir / "web" / "extensions"
|
||||
web_extensions_root = comfy_dir / "web" / "extensions"
|
||||
web_mtb = web_extensions_root / "mtb"
|
||||
|
||||
if web_mtb.exists():
|
||||
@@ -158,12 +168,11 @@ log.info(
|
||||
|
||||
# - ENDPOINT
|
||||
from server import PromptServer
|
||||
from .log import mklog, log
|
||||
from .log import log
|
||||
from aiohttp import web
|
||||
from importlib import reload
|
||||
import logging
|
||||
|
||||
endlog = mklog("mtb endpoint")
|
||||
from .endpoint import endlog
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/mtb/status")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
from .utils import here
|
||||
from aiohttp import web
|
||||
from .log import mklog
|
||||
import os
|
||||
|
||||
endlog = mklog("mtb endpoint")
|
||||
|
||||
def render_table(table_dict, sort=True, title=None):
|
||||
table_rows = ""
|
||||
|
||||
+232
-205
@@ -1,282 +1,309 @@
|
||||
import { app } from "/scripts/app.js";
|
||||
import { app } from '/scripts/app.js'
|
||||
|
||||
export const log = (...args) => {
|
||||
if (window.MTB_DEBUG) {
|
||||
console.debug(...args);
|
||||
}
|
||||
|
||||
if (window.MTB?.DEBUG) {
|
||||
console.debug(...args)
|
||||
}
|
||||
}
|
||||
|
||||
//- WIDGET UTILS
|
||||
export const CONVERTED_TYPE = "converted-widget";
|
||||
export const CONVERTED_TYPE = 'converted-widget'
|
||||
|
||||
export function offsetDOMWidget(widget, ctx, node, widgetWidth, widgetY, height) {
|
||||
const margin = 10;
|
||||
const elRect = ctx.canvas.getBoundingClientRect();
|
||||
const transform = new DOMMatrix()
|
||||
.scaleSelf(elRect.width / ctx.canvas.width, elRect.height / ctx.canvas.height)
|
||||
.multiplySelf(ctx.getTransform())
|
||||
.translateSelf(margin, margin + widgetY);
|
||||
export function offsetDOMWidget(
|
||||
widget,
|
||||
ctx,
|
||||
node,
|
||||
widgetWidth,
|
||||
widgetY,
|
||||
height
|
||||
) {
|
||||
const margin = 10
|
||||
const elRect = ctx.canvas.getBoundingClientRect()
|
||||
const transform = new DOMMatrix()
|
||||
.scaleSelf(
|
||||
elRect.width / ctx.canvas.width,
|
||||
elRect.height / ctx.canvas.height
|
||||
)
|
||||
.multiplySelf(ctx.getTransform())
|
||||
.translateSelf(margin, margin + widgetY)
|
||||
|
||||
const scale = new DOMMatrix().scaleSelf(transform.a, transform.d)
|
||||
Object.assign(widget.inputEl.style, {
|
||||
transformOrigin: "0 0",
|
||||
transform: scale,
|
||||
left: `${transform.a + transform.e}px`,
|
||||
top: `${transform.d + transform.f}px`,
|
||||
width: `${widgetWidth - (margin * 2)}px`,
|
||||
// height: `${(widget.parent?.inputHeight || 32) - (margin * 2)}px`,
|
||||
height: `${(height || widget.parent?.inputHeight || 32) - (margin * 2)}px`,
|
||||
const scale = new DOMMatrix().scaleSelf(transform.a, transform.d)
|
||||
Object.assign(widget.inputEl.style, {
|
||||
transformOrigin: '0 0',
|
||||
transform: scale,
|
||||
left: `${transform.a + transform.e}px`,
|
||||
top: `${transform.d + transform.f}px`,
|
||||
width: `${widgetWidth - margin * 2}px`,
|
||||
// height: `${(widget.parent?.inputHeight || 32) - (margin * 2)}px`,
|
||||
height: `${(height || widget.parent?.inputHeight || 32) - margin * 2}px`,
|
||||
|
||||
position: "absolute",
|
||||
background: (!node.color) ? '' : node.color,
|
||||
color: (!node.color) ? '' : 'white',
|
||||
zIndex: app.graph._nodes.indexOf(node),
|
||||
})
|
||||
position: 'absolute',
|
||||
background: !node.color ? '' : node.color,
|
||||
color: !node.color ? '' : 'white',
|
||||
zIndex: app.graph._nodes.indexOf(node),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the type and link type from a widget config object.
|
||||
* @param {*} config
|
||||
* @returns
|
||||
* @param {*} config
|
||||
* @returns
|
||||
*/
|
||||
export function getWidgetType(config) {
|
||||
// Special handling for COMBO so we restrict links based on the entries
|
||||
let type = config[0];
|
||||
let linkType = type;
|
||||
if (type instanceof Array) {
|
||||
type = "COMBO";
|
||||
linkType = linkType.join(",");
|
||||
}
|
||||
return { type, linkType };
|
||||
// Special handling for COMBO so we restrict links based on the entries
|
||||
let type = config[0]
|
||||
let linkType = type
|
||||
if (type instanceof Array) {
|
||||
type = 'COMBO'
|
||||
linkType = linkType.join(',')
|
||||
}
|
||||
return { type, linkType }
|
||||
}
|
||||
|
||||
export const dynamic_connection = (node, index, connected, connectionPrefix = "input_", connectionType = "PSDLAYER") => {
|
||||
|
||||
// remove all non connected inputs
|
||||
if (!connected && node.inputs.length > 1) {
|
||||
log(`Removing input ${index} (${node.inputs[index].name})`)
|
||||
if (node.widgets) {
|
||||
const w = node.widgets.find((w) => w.name === node.inputs[index].name);
|
||||
if (w) {
|
||||
w.onRemove?.();
|
||||
node.widgets.length = node.widgets.length - 1
|
||||
}
|
||||
}
|
||||
node.removeInput(index)
|
||||
|
||||
// make inputs sequential again
|
||||
for (let i = 0; i < node.inputs.length; i++) {
|
||||
node.inputs[i].label = `${connectionPrefix}${i + 1}`
|
||||
}
|
||||
export const dynamic_connection = (
|
||||
node,
|
||||
index,
|
||||
connected,
|
||||
connectionPrefix = 'input_',
|
||||
connectionType = 'PSDLAYER'
|
||||
) => {
|
||||
// remove all non connected inputs
|
||||
if (!connected && node.inputs.length > 1) {
|
||||
log(`Removing input ${index} (${node.inputs[index].name})`)
|
||||
if (node.widgets) {
|
||||
const w = node.widgets.find((w) => w.name === node.inputs[index].name)
|
||||
if (w) {
|
||||
w.onRemoved?.()
|
||||
node.widgets.length = node.widgets.length - 1
|
||||
}
|
||||
}
|
||||
node.removeInput(index)
|
||||
|
||||
// add an extra input
|
||||
if (node.inputs[node.inputs.length - 1].link != undefined) {
|
||||
log(`Adding input ${node.inputs.length + 1} (${connectionPrefix}${node.inputs.length + 1})`)
|
||||
|
||||
node.addInput(`${connectionPrefix}${node.inputs.length + 1}`, connectionType)
|
||||
// make inputs sequential again
|
||||
for (let i = 0; i < node.inputs.length; i++) {
|
||||
node.inputs[i].label = `${connectionPrefix}${i + 1}`
|
||||
}
|
||||
}
|
||||
|
||||
// add an extra input
|
||||
if (node.inputs[node.inputs.length - 1].link != undefined) {
|
||||
log(
|
||||
`Adding input ${node.inputs.length + 1} (${connectionPrefix}${
|
||||
node.inputs.length + 1
|
||||
})`
|
||||
)
|
||||
|
||||
node.addInput(
|
||||
`${connectionPrefix}${node.inputs.length + 1}`,
|
||||
connectionType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends a callback to the extra menu options of a given node type.
|
||||
* @param {*} nodeType
|
||||
* @param {*} cb
|
||||
* @param {*} nodeType
|
||||
* @param {*} cb
|
||||
*/
|
||||
export function addMenuHandler(nodeType, cb) {
|
||||
const getOpts = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function () {
|
||||
const r = getOpts.apply(this, arguments);
|
||||
cb.apply(this, arguments);
|
||||
return r;
|
||||
};
|
||||
const getOpts = nodeType.prototype.getExtraMenuOptions
|
||||
nodeType.prototype.getExtraMenuOptions = function () {
|
||||
const r = getOpts.apply(this, arguments)
|
||||
cb.apply(this, arguments)
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
export function hideWidget(node, widget, suffix = "") {
|
||||
widget.origType = widget.type;
|
||||
widget.hidden = true
|
||||
widget.origComputeSize = widget.computeSize;
|
||||
widget.origSerializeValue = widget.serializeValue;
|
||||
widget.computeSize = () => [0, -4]; // -4 is due to the gap litegraph adds between widgets automatically
|
||||
widget.type = CONVERTED_TYPE + suffix;
|
||||
widget.serializeValue = () => {
|
||||
// Prevent serializing the widget if we have no input linked
|
||||
const { link } = node.inputs.find((i) => i.widget?.name === widget.name);
|
||||
if (link == null) {
|
||||
return undefined;
|
||||
}
|
||||
return widget.origSerializeValue ? widget.origSerializeValue() : widget.value;
|
||||
};
|
||||
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
hideWidget(node, w, ":" + widget.name);
|
||||
}
|
||||
export function hideWidget(node, widget, suffix = '') {
|
||||
widget.origType = widget.type
|
||||
widget.hidden = true
|
||||
widget.origComputeSize = widget.computeSize
|
||||
widget.origSerializeValue = widget.serializeValue
|
||||
widget.computeSize = () => [0, -4] // -4 is due to the gap litegraph adds between widgets automatically
|
||||
widget.type = CONVERTED_TYPE + suffix
|
||||
widget.serializeValue = () => {
|
||||
// Prevent serializing the widget if we have no input linked
|
||||
const { link } = node.inputs.find((i) => i.widget?.name === widget.name)
|
||||
if (link == null) {
|
||||
return undefined
|
||||
}
|
||||
return widget.origSerializeValue
|
||||
? widget.origSerializeValue()
|
||||
: widget.value
|
||||
}
|
||||
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
hideWidget(node, w, ':' + widget.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function showWidget(widget) {
|
||||
widget.type = widget.origType;
|
||||
widget.computeSize = widget.origComputeSize;
|
||||
widget.serializeValue = widget.origSerializeValue;
|
||||
widget.type = widget.origType
|
||||
widget.computeSize = widget.origComputeSize
|
||||
widget.serializeValue = widget.origSerializeValue
|
||||
|
||||
delete widget.origType;
|
||||
delete widget.origComputeSize;
|
||||
delete widget.origSerializeValue;
|
||||
delete widget.origType
|
||||
delete widget.origComputeSize
|
||||
delete widget.origSerializeValue
|
||||
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
showWidget(w);
|
||||
}
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
showWidget(w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function convertToWidget(node, widget) {
|
||||
showWidget(widget);
|
||||
const sz = node.size;
|
||||
node.removeInput(node.inputs.findIndex((i) => i.widget?.name === widget.name));
|
||||
showWidget(widget)
|
||||
const sz = node.size
|
||||
node.removeInput(node.inputs.findIndex((i) => i.widget?.name === widget.name))
|
||||
|
||||
for (const widget of node.widgets) {
|
||||
widget.last_y -= LiteGraph.NODE_SLOT_HEIGHT;
|
||||
}
|
||||
for (const widget of node.widgets) {
|
||||
widget.last_y -= LiteGraph.NODE_SLOT_HEIGHT
|
||||
}
|
||||
|
||||
// Restore original size but grow if needed
|
||||
node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])]);
|
||||
// Restore original size but grow if needed
|
||||
node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])])
|
||||
}
|
||||
|
||||
|
||||
export function convertToInput(node, widget, config) {
|
||||
hideWidget(node, widget);
|
||||
hideWidget(node, widget)
|
||||
|
||||
const { linkType } = getWidgetType(config);
|
||||
const { linkType } = getWidgetType(config)
|
||||
|
||||
// Add input and store widget config for creating on primitive node
|
||||
const sz = node.size;
|
||||
node.addInput(widget.name, linkType, {
|
||||
widget: { name: widget.name, config },
|
||||
});
|
||||
// Add input and store widget config for creating on primitive node
|
||||
const sz = node.size
|
||||
node.addInput(widget.name, linkType, {
|
||||
widget: { name: widget.name, config },
|
||||
})
|
||||
|
||||
for (const widget of node.widgets) {
|
||||
widget.last_y += LiteGraph.NODE_SLOT_HEIGHT;
|
||||
}
|
||||
for (const widget of node.widgets) {
|
||||
widget.last_y += LiteGraph.NODE_SLOT_HEIGHT
|
||||
}
|
||||
|
||||
// Restore original size but grow if needed
|
||||
node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])]);
|
||||
// Restore original size but grow if needed
|
||||
node.setSize([Math.max(sz[0], node.size[0]), Math.max(sz[1], node.size[1])])
|
||||
}
|
||||
|
||||
export function hideWidgetForGood(node, widget, suffix = "") {
|
||||
widget.origType = widget.type;
|
||||
widget.origComputeSize = widget.computeSize;
|
||||
widget.origSerializeValue = widget.serializeValue;
|
||||
widget.computeSize = () => [0, -4]; // -4 is due to the gap litegraph adds between widgets automatically
|
||||
widget.type = CONVERTED_TYPE + suffix;
|
||||
// widget.serializeValue = () => {
|
||||
// // Prevent serializing the widget if we have no input linked
|
||||
// const w = node.inputs?.find((i) => i.widget?.name === widget.name);
|
||||
// if (w?.link == null) {
|
||||
// return undefined;
|
||||
// }
|
||||
// return widget.origSerializeValue ? widget.origSerializeValue() : widget.value;
|
||||
// };
|
||||
export function hideWidgetForGood(node, widget, suffix = '') {
|
||||
widget.origType = widget.type
|
||||
widget.origComputeSize = widget.computeSize
|
||||
widget.origSerializeValue = widget.serializeValue
|
||||
widget.computeSize = () => [0, -4] // -4 is due to the gap litegraph adds between widgets automatically
|
||||
widget.type = CONVERTED_TYPE + suffix
|
||||
// widget.serializeValue = () => {
|
||||
// // Prevent serializing the widget if we have no input linked
|
||||
// const w = node.inputs?.find((i) => i.widget?.name === widget.name);
|
||||
// if (w?.link == null) {
|
||||
// return undefined;
|
||||
// }
|
||||
// return widget.origSerializeValue ? widget.origSerializeValue() : widget.value;
|
||||
// };
|
||||
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
hideWidgetForGood(node, w, ":" + widget.name);
|
||||
}
|
||||
// Hide any linked widgets, e.g. seed+seedControl
|
||||
if (widget.linkedWidgets) {
|
||||
for (const w of widget.linkedWidgets) {
|
||||
hideWidgetForGood(node, w, ':' + widget.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function fixWidgets(node) {
|
||||
if (node.inputs) {
|
||||
for (const input of node.inputs) {
|
||||
log(input)
|
||||
if (input.widget || node.widgets) {
|
||||
// if (newTypes.includes(input.type)) {
|
||||
const matching_widget = node.widgets.find((w) => w.name === input.name);
|
||||
if (matching_widget) {
|
||||
if (node.inputs) {
|
||||
for (const input of node.inputs) {
|
||||
log(input)
|
||||
if (input.widget || node.widgets) {
|
||||
// if (newTypes.includes(input.type)) {
|
||||
const matching_widget = node.widgets.find((w) => w.name === input.name)
|
||||
if (matching_widget) {
|
||||
// if (matching_widget.hidden) {
|
||||
// log(`Already hidden skipping ${matching_widget.name}`)
|
||||
// continue
|
||||
// }
|
||||
const w = node.widgets.find((w) => w.name === matching_widget.name)
|
||||
if (w && w.type != CONVERTED_TYPE) {
|
||||
log(w)
|
||||
log(`hidding ${w.name}(${w.type}) from ${node.type}`)
|
||||
log(node)
|
||||
hideWidget(node, w)
|
||||
} else {
|
||||
log(`converting to widget ${w}`)
|
||||
|
||||
|
||||
// if (matching_widget.hidden) {
|
||||
// log(`Already hidden skipping ${matching_widget.name}`)
|
||||
// continue
|
||||
// }
|
||||
const w = node.widgets.find((w) => w.name === matching_widget.name);
|
||||
if (w && w.type != CONVERTED_TYPE) {
|
||||
log(w)
|
||||
log(`hidding ${w.name}(${w.type}) from ${node.type}`)
|
||||
log(node)
|
||||
hideWidget(node, w);
|
||||
} else {
|
||||
log(`converting to widget ${w}`)
|
||||
|
||||
convertToWidget(node, input)
|
||||
}
|
||||
}
|
||||
}
|
||||
convertToWidget(node, input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export function inner_value_change(widget, value, event = undefined) {
|
||||
if (widget.type == "number" || widget.type == "BBOX") {
|
||||
value = Number(value);
|
||||
} else if (widget.type == "BOOL") {
|
||||
value = Boolean(value)
|
||||
}
|
||||
widget.value = value;
|
||||
if (widget.options && widget.options.property && node.properties[widget.options.property] !== undefined) {
|
||||
node.setProperty(widget.options.property, value);
|
||||
}
|
||||
if (widget.callback) {
|
||||
widget.callback(widget.value, app.canvas, node, pos, event);
|
||||
}
|
||||
if (widget.type == 'number' || widget.type == 'BBOX') {
|
||||
value = Number(value)
|
||||
} else if (widget.type == 'BOOL') {
|
||||
value = Boolean(value)
|
||||
}
|
||||
widget.value = value
|
||||
if (
|
||||
widget.options &&
|
||||
widget.options.property &&
|
||||
node.properties[widget.options.property] !== undefined
|
||||
) {
|
||||
node.setProperty(widget.options.property, value)
|
||||
}
|
||||
if (widget.callback) {
|
||||
widget.callback(widget.value, app.canvas, node, pos, event)
|
||||
}
|
||||
}
|
||||
|
||||
//- COLOR UTILS
|
||||
export function isColorBright(rgb, threshold = 240) {
|
||||
const brightess = getBrightness(rgb)
|
||||
return brightess > threshold
|
||||
const brightess = getBrightness(rgb)
|
||||
return brightess > threshold
|
||||
}
|
||||
|
||||
function getBrightness(rgbObj) {
|
||||
return Math.round(((parseInt(rgbObj[0]) * 299) + (parseInt(rgbObj[1]) * 587) + (parseInt(rgbObj[2]) * 114)) / 1000)
|
||||
return Math.round(
|
||||
(parseInt(rgbObj[0]) * 299 +
|
||||
parseInt(rgbObj[1]) * 587 +
|
||||
parseInt(rgbObj[2]) * 114) /
|
||||
1000
|
||||
)
|
||||
}
|
||||
|
||||
//- HTML / CSS UTILS
|
||||
export function defineClass(className, classStyles) {
|
||||
const styleSheets = document.styleSheets;
|
||||
const styleSheets = document.styleSheets
|
||||
|
||||
// Helper function to check if the class exists in a style sheet
|
||||
function classExistsInStyleSheet(styleSheet) {
|
||||
const rules = styleSheet.rules || styleSheet.cssRules;
|
||||
for (const rule of rules) {
|
||||
if (rule.selectorText === `.${className}`) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
// Helper function to check if the class exists in a style sheet
|
||||
function classExistsInStyleSheet(styleSheet) {
|
||||
const rules = styleSheet.rules || styleSheet.cssRules
|
||||
for (const rule of rules) {
|
||||
if (rule.selectorText === `.${className}`) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the class is already defined in any of the style sheets
|
||||
let classExists = false;
|
||||
for (const styleSheet of styleSheets) {
|
||||
if (classExistsInStyleSheet(styleSheet)) {
|
||||
classExists = true;
|
||||
break;
|
||||
}
|
||||
// Check if the class is already defined in any of the style sheets
|
||||
let classExists = false
|
||||
for (const styleSheet of styleSheets) {
|
||||
if (classExistsInStyleSheet(styleSheet)) {
|
||||
classExists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the class doesn't exist, add the new class definition to the first style sheet
|
||||
if (!classExists) {
|
||||
if (styleSheets[0].insertRule) {
|
||||
styleSheets[0].insertRule(`.${className} { ${classStyles} }`, 0);
|
||||
} else if (styleSheets[0].addRule) {
|
||||
styleSheets[0].addRule(`.${className}`, classStyles, 0);
|
||||
}
|
||||
// If the class doesn't exist, add the new class definition to the first style sheet
|
||||
if (!classExists) {
|
||||
if (styleSheets[0].insertRule) {
|
||||
styleSheets[0].insertRule(`.${className} { ${classStyles} }`, 0)
|
||||
} else if (styleSheets[0].addRule) {
|
||||
styleSheets[0].addRule(`.${className}`, classStyles, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+89
-70
@@ -1,80 +1,99 @@
|
||||
import { app } from "/scripts/app.js";
|
||||
/**
|
||||
* File: debug.js
|
||||
* Project: comfy_mtb
|
||||
* Author: Mel Massadian
|
||||
*
|
||||
* Copyright (c) 2023 Mel Massadian
|
||||
*
|
||||
*/
|
||||
|
||||
import { app } from '/scripts/app.js'
|
||||
import * as shared from '/extensions/mtb/comfy_shared.js'
|
||||
import { log } from '/extensions/mtb/comfy_shared.js'
|
||||
import { MtbWidgets } from '/extensions/mtb/mtb_widgets.js'
|
||||
|
||||
// TODO: respect inputs order...
|
||||
|
||||
|
||||
|
||||
app.registerExtension({
|
||||
name: "mtb.Debug",
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (nodeData.name === "Debug (mtb)") {
|
||||
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
|
||||
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
|
||||
const r = onConnectionsChange ? onConnectionsChange.apply(this, arguments) : undefined;
|
||||
// TODO: remove all widgets on disconnect once computed
|
||||
shared.dynamic_connection(this, index, connected, "anything_", "*")
|
||||
name: 'mtb.Debug',
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (nodeData.name === 'Debug (mtb)') {
|
||||
const onConnectionsChange = nodeType.prototype.onConnectionsChange
|
||||
nodeType.prototype.onConnectionsChange = function (
|
||||
type,
|
||||
index,
|
||||
connected,
|
||||
link_info
|
||||
) {
|
||||
const r = onConnectionsChange
|
||||
? onConnectionsChange.apply(this, arguments)
|
||||
: undefined
|
||||
// TODO: remove all widgets on disconnect once computed
|
||||
shared.dynamic_connection(this, index, connected, 'anything_', '*')
|
||||
|
||||
//- infer type
|
||||
if (link_info) {
|
||||
const fromNode = this.graph._nodes.find((otherNode) => otherNode.id == link_info.origin_id);
|
||||
const type = fromNode.outputs[link_info.origin_slot].type;
|
||||
this.inputs[index].type = type;
|
||||
// this.inputs[index].label = type.toLowerCase()
|
||||
}
|
||||
//- restore dynamic input
|
||||
if (!connected) {
|
||||
this.inputs[index].type = "*";
|
||||
this.inputs[index].label = `anything_${index + 1}`
|
||||
}
|
||||
}
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted;
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
log(message)
|
||||
onExecuted?.apply(this, arguments);
|
||||
log(message)
|
||||
if (this.widgets) {
|
||||
// const pos = this.widgets.findIndex((w) => w.name === "anything_1");
|
||||
// if (pos !== -1) {
|
||||
for (let i = 0; i < this.widgets.length; i++) {
|
||||
this.widgets[i].onRemove?.();
|
||||
}
|
||||
this.widgets.length = 0;
|
||||
|
||||
}
|
||||
let widgetI = 1
|
||||
if (message.text) {
|
||||
for (const txt of message.text) {
|
||||
const w = this.addCustomWidget(MtbWidgets.DEBUG_STRING(txt, widgetI))
|
||||
w.parent = this;
|
||||
widgetI++;
|
||||
}
|
||||
}
|
||||
if (message.b64_images) {
|
||||
for (const img of message.b64_images) {
|
||||
const w = this.addCustomWidget(MtbWidgets.DEBUG_IMG(img, widgetI))
|
||||
w.parent = this;
|
||||
widgetI++;
|
||||
}
|
||||
// this.onResize?.(this.size);
|
||||
// this.resize?.(this.size)
|
||||
this.setSize(this.computeSize())
|
||||
};
|
||||
|
||||
this.onRemoved = function () {
|
||||
// When removing this node we need to remove the input from the DOM
|
||||
for (let y in this.widgets) {
|
||||
if (this.widgets[y].canvas) {
|
||||
this.widgets[y].canvas.remove();
|
||||
}
|
||||
this.widgets[y].onRemove?.();
|
||||
}
|
||||
}
|
||||
}
|
||||
//- infer type
|
||||
if (link_info) {
|
||||
const fromNode = this.graph._nodes.find(
|
||||
(otherNode) => otherNode.id == link_info.origin_id
|
||||
)
|
||||
const type = fromNode.outputs[link_info.origin_slot].type
|
||||
this.inputs[index].type = type
|
||||
// this.inputs[index].label = type.toLowerCase()
|
||||
}
|
||||
//- restore dynamic input
|
||||
if (!connected) {
|
||||
this.inputs[index].type = '*'
|
||||
this.inputs[index].label = `anything_${index + 1}`
|
||||
}
|
||||
}
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments)
|
||||
|
||||
const prefix = 'anything_'
|
||||
|
||||
if (this.widgets) {
|
||||
// const pos = this.widgets.findIndex((w) => w.name === "anything_1");
|
||||
// if (pos !== -1) {
|
||||
for (let i = 0; i < this.widgets.length; i++) {
|
||||
this.widgets[i].onRemoved?.()
|
||||
}
|
||||
this.widgets.length = 0
|
||||
}
|
||||
let widgetI = 1
|
||||
if (message.text) {
|
||||
for (const txt of message.text) {
|
||||
const w = this.addCustomWidget(
|
||||
MtbWidgets.DEBUG_STRING(`${prefix}_${widgetI}`, txt)
|
||||
)
|
||||
w.parent = this
|
||||
widgetI++
|
||||
}
|
||||
}
|
||||
if (message.b64_images) {
|
||||
for (const img of message.b64_images) {
|
||||
const w = this.addCustomWidget(
|
||||
MtbWidgets.DEBUG_IMG(`${prefix}_${widgetI}`, img)
|
||||
)
|
||||
w.parent = this
|
||||
widgetI++
|
||||
}
|
||||
// this.onResize?.(this.size);
|
||||
// this.resize?.(this.size)
|
||||
this.setSize(this.computeSize())
|
||||
}
|
||||
|
||||
this.onRemoved = function () {
|
||||
// When removing this node we need to remove the input from the DOM
|
||||
for (let y in this.widgets) {
|
||||
if (this.widgets[y].canvas) {
|
||||
this.widgets[y].canvas.remove()
|
||||
}
|
||||
this.widgets[y].onRemoved?.()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
})
|
||||
|
||||
+270
-268
@@ -1,311 +1,313 @@
|
||||
import { api } from "/scripts/api.js";
|
||||
import { app } from "/scripts/app.js";
|
||||
/**
|
||||
* File: imageFeed.js
|
||||
* Project: comfy_mtb
|
||||
* Author: Mel Massadian
|
||||
*
|
||||
* Copyright (c) 2023 Mel Massadian
|
||||
*
|
||||
*/
|
||||
|
||||
// forked from pysssss's imageFeed.js
|
||||
|
||||
const styles = {
|
||||
lighbox: {
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
background: "rgba(0,0,0,0.5)",
|
||||
display: "none",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 999,
|
||||
},
|
||||
lightboxBtn: (extra) => ({
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
background: "none",
|
||||
border: "none",
|
||||
color: "#fff",
|
||||
zIndex: 9999999,
|
||||
fontSize: "30px",
|
||||
cursor: "pointer",
|
||||
pointerEvents: "bounding-box",
|
||||
...extra,
|
||||
})
|
||||
,
|
||||
img_list: {
|
||||
import { api } from '/scripts/api.js'
|
||||
import { app } from '/scripts/app.js'
|
||||
|
||||
minHeight: "30px",
|
||||
maxHeight: "300px",
|
||||
width: "100vw",
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
zIndex: 9999999,
|
||||
background: "#333",
|
||||
overflow: "auto",
|
||||
}
|
||||
const styles = {
|
||||
lighbox: {
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
background: 'rgba(0,0,0,0.5)',
|
||||
display: 'none',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 999,
|
||||
},
|
||||
lightboxBtn: (extra) => ({
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: '#fff',
|
||||
zIndex: 9999999,
|
||||
fontSize: '30px',
|
||||
cursor: 'pointer',
|
||||
pointerEvents: 'bounding-box',
|
||||
...extra,
|
||||
}),
|
||||
img_list: {
|
||||
minHeight: '30px',
|
||||
maxHeight: '300px',
|
||||
width: '100vw',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
zIndex: 9999999,
|
||||
background: '#333',
|
||||
overflow: 'auto',
|
||||
},
|
||||
}
|
||||
|
||||
let currentImageIndex = 0;
|
||||
const imageUrls = [];
|
||||
let currentImageIndex = 0
|
||||
const imageUrls = []
|
||||
|
||||
let image_menu = null
|
||||
|
||||
app.registerExtension({
|
||||
name: "mtb.ImageFeed",
|
||||
setup: async () => {
|
||||
// - HTML & CSS
|
||||
//- lightbox
|
||||
const lightboxContainer = document.createElement("div");
|
||||
Object.assign(lightboxContainer.style, styles.lighbox);
|
||||
name: 'mtb.ImageFeed',
|
||||
setup: async () => {
|
||||
// - HTML & CSS
|
||||
//- lightbox
|
||||
const lightboxContainer = document.createElement('div')
|
||||
Object.assign(lightboxContainer.style, styles.lighbox)
|
||||
|
||||
const lightboxImage = document.createElement("img");
|
||||
Object.assign(lightboxImage.style, {
|
||||
maxHeight: "100%",
|
||||
maxWidth: "100%",
|
||||
borderRadius: "5px",
|
||||
});
|
||||
const lightboxImage = document.createElement('img')
|
||||
Object.assign(lightboxImage.style, {
|
||||
maxHeight: '100%',
|
||||
maxWidth: '100%',
|
||||
borderRadius: '5px',
|
||||
})
|
||||
|
||||
// previous and next buttons
|
||||
const lightboxPrevBtn = document.createElement("button");
|
||||
const lightboxNextBtn = document.createElement("button");
|
||||
// previous and next buttons
|
||||
const lightboxPrevBtn = document.createElement('button')
|
||||
const lightboxNextBtn = document.createElement('button')
|
||||
|
||||
lightboxPrevBtn.textContent = "❮";
|
||||
lightboxNextBtn.textContent = "❯";
|
||||
lightboxPrevBtn.textContent = '❮'
|
||||
lightboxNextBtn.textContent = '❯'
|
||||
|
||||
Object.assign(lightboxPrevBtn.style, styles.lightboxBtn({ left: "0%" }));
|
||||
Object.assign(lightboxNextBtn.style, styles.lightboxBtn({ right: "0%" }));
|
||||
Object.assign(lightboxPrevBtn.style, styles.lightboxBtn({ left: '0%' }))
|
||||
Object.assign(lightboxNextBtn.style, styles.lightboxBtn({ right: '0%' }))
|
||||
|
||||
// close button
|
||||
const lightboxCloseBtn = document.createElement("button");
|
||||
Object.assign(lightboxCloseBtn.style, styles.lightboxBtn({ right: "0", top: "0" }));
|
||||
lightboxCloseBtn.textContent = "❌";
|
||||
// close button
|
||||
const lightboxCloseBtn = document.createElement('button')
|
||||
Object.assign(
|
||||
lightboxCloseBtn.style,
|
||||
styles.lightboxBtn({ right: '0', top: '0' })
|
||||
)
|
||||
lightboxCloseBtn.textContent = '❌'
|
||||
|
||||
const lightboxButtons = document.createElement("div");
|
||||
Object.assign(lightboxButtons.style, {
|
||||
position: "absolute",
|
||||
top: "0%",
|
||||
right: "0%",
|
||||
// transform: "translate(50%, -50%)",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
background: "none",
|
||||
border: "none",
|
||||
color: "#fff",
|
||||
fontSize: "30px",
|
||||
cursor: "pointer",
|
||||
pointerEvents: "none",
|
||||
});
|
||||
const lightboxButtons = document.createElement('div')
|
||||
Object.assign(lightboxButtons.style, {
|
||||
position: 'absolute',
|
||||
top: '0%',
|
||||
right: '0%',
|
||||
// transform: "translate(50%, -50%)",
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: '#fff',
|
||||
fontSize: '30px',
|
||||
cursor: 'pointer',
|
||||
pointerEvents: 'none',
|
||||
})
|
||||
|
||||
lightboxButtons.append(lightboxPrevBtn, lightboxNextBtn, lightboxCloseBtn);
|
||||
lightboxContainer.append(lightboxButtons, lightboxImage);
|
||||
lightboxButtons.append(lightboxPrevBtn, lightboxNextBtn, lightboxCloseBtn)
|
||||
lightboxContainer.append(lightboxButtons, lightboxImage)
|
||||
|
||||
//- image list
|
||||
const imageListContainer = document.createElement("div");
|
||||
Object.assign(imageListContainer.style, styles.img_list);
|
||||
//- image list
|
||||
const imageListContainer = document.createElement('div')
|
||||
Object.assign(imageListContainer.style, styles.img_list)
|
||||
|
||||
const createImgListBtn = (text, style) => {
|
||||
const btn = document.createElement('button')
|
||||
btn.type = 'button'
|
||||
btn.textContent = text
|
||||
Object.assign(btn.style, {
|
||||
...style,
|
||||
border: 'none',
|
||||
color: '#fff',
|
||||
background: 'none',
|
||||
height: '20px',
|
||||
cursor: 'pointer',
|
||||
position: 'absolute',
|
||||
top: '5px',
|
||||
fontSize: '12px',
|
||||
lineHeight: '12px',
|
||||
})
|
||||
imageListContainer.append(btn)
|
||||
return btn
|
||||
}
|
||||
const showBtn = document.createElement('button')
|
||||
const closeBtn = createImgListBtn('❌', {
|
||||
width: '20px',
|
||||
textIndent: '-4px',
|
||||
right: '5px',
|
||||
})
|
||||
const loadButton = createImgListBtn('Load Session History', {
|
||||
right: '90px',
|
||||
})
|
||||
const clearButton = createImgListBtn('Clear', {
|
||||
right: '30px',
|
||||
})
|
||||
|
||||
const createImgListBtn = (text, style) => {
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.textContent = text;
|
||||
Object.assign(btn.style, {
|
||||
...style,
|
||||
border: "none",
|
||||
color: "#fff",
|
||||
background: "none",
|
||||
height: "20px",
|
||||
cursor: "pointer",
|
||||
position: "absolute",
|
||||
top: "5px",
|
||||
fontSize: "12px",
|
||||
lineHeight: "12px",
|
||||
});
|
||||
imageListContainer.append(btn);
|
||||
return btn;
|
||||
}
|
||||
const showBtn = document.createElement("button");
|
||||
const closeBtn = createImgListBtn("❌", {
|
||||
width: "20px",
|
||||
textIndent: "-4px",
|
||||
right: "5px",
|
||||
});
|
||||
const loadButton = createImgListBtn("Load Session History", {
|
||||
right: "90px",
|
||||
});
|
||||
const clearButton = createImgListBtn("Clear", {
|
||||
right: "30px",
|
||||
});
|
||||
//- tools popup button
|
||||
showBtn.classList.add('comfy-settings-btn')
|
||||
Object.assign(showBtn.style, {
|
||||
right: '16px',
|
||||
cursor: 'pointer',
|
||||
display: 'none',
|
||||
})
|
||||
|
||||
//- append to DOM
|
||||
document.body.append(imageListContainer)
|
||||
|
||||
//- tools popup button
|
||||
showBtn.classList.add("comfy-settings-btn");
|
||||
Object.assign(showBtn.style, {
|
||||
right: "16px",
|
||||
cursor: "pointer",
|
||||
display: "none",
|
||||
});
|
||||
showBtn.textContent = '🖼️'
|
||||
showBtn.onclick = () => {
|
||||
imageListContainer.style.display = 'block'
|
||||
showBtn.style.display = 'none'
|
||||
}
|
||||
document.querySelector('.comfy-settings-btn').after(showBtn)
|
||||
document.querySelector('.comfy-settings-btn').after(lightboxContainer)
|
||||
|
||||
//- append to DOM
|
||||
document.body.append(imageListContainer);
|
||||
// for (const { output } of history) {
|
||||
// if (output?.images) {
|
||||
// for (const src of output.images) {
|
||||
// const img = document.createElement("img");
|
||||
// const but = document.createElement("button");
|
||||
|
||||
//- callbacks
|
||||
closeBtn.onclick = () => {
|
||||
imageListContainer.style.display = 'none'
|
||||
showBtn.style.display = 'unset'
|
||||
}
|
||||
|
||||
showBtn.textContent = "🖼️";
|
||||
showBtn.onclick = () => {
|
||||
imageListContainer.style.display = "block";
|
||||
showBtn.style.display = "none";
|
||||
};
|
||||
document.querySelector(".comfy-settings-btn").after(showBtn);
|
||||
document.querySelector(".comfy-settings-btn").after(lightboxContainer);
|
||||
clearButton.onclick = () => {
|
||||
imageListContainer.replaceChildren(closeBtn, clearButton, loadButton)
|
||||
}
|
||||
|
||||
lightboxNextBtn.onclick = () => {
|
||||
currentImageIndex = (currentImageIndex + 1) % imageUrls.length
|
||||
const imageUrl = imageUrls[currentImageIndex]
|
||||
lightboxImage.src = imageUrl
|
||||
}
|
||||
|
||||
// Modify the lightboxPrevBtn onclick callback
|
||||
lightboxPrevBtn.onclick = () => {
|
||||
currentImageIndex =
|
||||
(currentImageIndex - 1 + imageUrls.length) % imageUrls.length
|
||||
const imageUrl = imageUrls[currentImageIndex]
|
||||
lightboxImage.src = imageUrl
|
||||
}
|
||||
|
||||
// for (const { output } of history) {
|
||||
// if (output?.images) {
|
||||
// for (const src of output.images) {
|
||||
// const img = document.createElement("img");
|
||||
// const but = document.createElement("button");
|
||||
lightboxCloseBtn.onclick = () => {
|
||||
lightboxContainer.style.display = 'none'
|
||||
}
|
||||
lightboxImage.onclick = lightboxNextBtn.onclick
|
||||
/**
|
||||
* This is the function that creates the image buttons for the image list
|
||||
* They are wrapped in a button so that they can be clicked and open
|
||||
* the image in the lightbox.
|
||||
* @param {*} src
|
||||
*/
|
||||
const createImageBtn = (src) => {
|
||||
console.debug(`making image ${src.filename}`)
|
||||
const img = document.createElement('img')
|
||||
const but = document.createElement('button')
|
||||
|
||||
//- callbacks
|
||||
closeBtn.onclick = () => {
|
||||
imageListContainer.style.display = "none";
|
||||
showBtn.style.display = "unset";
|
||||
};
|
||||
Object.assign(but.style, {
|
||||
height: '120px',
|
||||
width: '120px',
|
||||
})
|
||||
Object.assign(img.style, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'scale-down',
|
||||
})
|
||||
|
||||
clearButton.onclick = () => {
|
||||
imageListContainer.replaceChildren(closeBtn, clearButton, loadButton);
|
||||
}
|
||||
img.src = `/view?filename=${encodeURIComponent(src.filename)}&type=${
|
||||
src.type
|
||||
}&subfolder=${encodeURIComponent(src.subfolder)}`
|
||||
|
||||
lightboxNextBtn.onclick = () => {
|
||||
currentImageIndex = (currentImageIndex + 1) % imageUrls.length;
|
||||
const imageUrl = imageUrls[currentImageIndex];
|
||||
lightboxImage.src = imageUrl;
|
||||
};
|
||||
imageUrls.push(img.src)
|
||||
|
||||
// Modify the lightboxPrevBtn onclick callback
|
||||
lightboxPrevBtn.onclick = () => {
|
||||
currentImageIndex = (currentImageIndex - 1 + imageUrls.length) % imageUrls.length;
|
||||
const imageUrl = imageUrls[currentImageIndex];
|
||||
lightboxImage.src = imageUrl;
|
||||
};
|
||||
console.debug(img.src)
|
||||
|
||||
but.onclick = () => {
|
||||
lightboxContainer.style.display = 'flex'
|
||||
// add the same image to the lightbox
|
||||
lightboxImage.src = img.src
|
||||
// lighboxContainer.replaceChildren(lightboxButtons, img);
|
||||
}
|
||||
|
||||
lightboxCloseBtn.onclick = () => {
|
||||
lightboxContainer.style.display = "none";
|
||||
};
|
||||
lightboxImage.onclick = lightboxNextBtn.onclick;
|
||||
/**
|
||||
* This is the function that creates the image buttons for the image list
|
||||
* They are wrapped in a button so that they can be clicked and open
|
||||
* the image in the lightbox.
|
||||
* @param {*} src
|
||||
*/
|
||||
const createImageBtn = (src) => {
|
||||
console.debug(`making image ${src.filename}`);
|
||||
const img = document.createElement("img");
|
||||
const but = document.createElement("button");
|
||||
// add right click menu
|
||||
but.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
Object.assign(but.style, {
|
||||
height: "120px",
|
||||
width: "120px",
|
||||
});
|
||||
Object.assign(img.style, {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "scale-down",
|
||||
});
|
||||
if (image_menu) {
|
||||
image_menu.remove()
|
||||
}
|
||||
|
||||
img.src = `/view?filename=${encodeURIComponent(src.filename)}&type=${src.type}&subfolder=${encodeURIComponent(
|
||||
src.subfolder
|
||||
)}`;
|
||||
image_menu = document.createElement('div')
|
||||
Object.assign(image_menu.style, {
|
||||
position: 'absolute',
|
||||
top: `${e.clientY}px`,
|
||||
left: `${e.clientX}px`,
|
||||
background: '#333',
|
||||
color: '#fff',
|
||||
padding: '5px',
|
||||
borderRadius: '5px',
|
||||
zIndex: 999,
|
||||
})
|
||||
const load_img = document.createElement('button')
|
||||
load_img.textContent = 'Load'
|
||||
load_img.onclick = () => {
|
||||
app.handleFile(img.src)
|
||||
}
|
||||
|
||||
imageUrls.push(img.src);
|
||||
image_menu.appendChild(load_img)
|
||||
document.body.appendChild(image_menu)
|
||||
})
|
||||
|
||||
console.debug(img.src)
|
||||
but.append(img)
|
||||
imageListContainer.prepend(but)
|
||||
}
|
||||
|
||||
but.onclick = () => {
|
||||
lightboxContainer.style.display = "flex";
|
||||
// add the same image to the lightbox
|
||||
lightboxImage.src = img.src;
|
||||
// lighboxContainer.replaceChildren(lightboxButtons, img);
|
||||
loadButton.onclick = async () => {
|
||||
const all_history = await api.getHistory()
|
||||
for (const history of all_history.History) {
|
||||
if (history.outputs) {
|
||||
for (const key of Object.keys(history.outputs)) {
|
||||
console.debug(key)
|
||||
for (const im of history.outputs[key].images) {
|
||||
console.debug(im)
|
||||
createImageBtn(im)
|
||||
}
|
||||
}
|
||||
// for (const src of outputs.outputs.images) {
|
||||
// console.debug(src)
|
||||
// makeImage(`${src.subfolder}/${src.filename}`)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
///////-------
|
||||
|
||||
// add right click menu
|
||||
but.addEventListener("contextmenu", (e) => {
|
||||
e.preventDefault();
|
||||
// const all_history = await api.getHistory()
|
||||
// for (const history of all_history.History) {
|
||||
// if (history.outputs) {
|
||||
// for (const key of Object.keys(history.outputs)) {
|
||||
// for (const im of history.outputs[key].images) {
|
||||
// makeImage(im)
|
||||
// }
|
||||
// }
|
||||
// // for (const src of outputs.outputs.images) {
|
||||
// // console.debug(src)
|
||||
// // makeImage(`${src.subfolder}/${src.filename}`)
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (image_menu) {
|
||||
image_menu.remove();
|
||||
}
|
||||
|
||||
image_menu = document.createElement("div");
|
||||
Object.assign(image_menu.style, {
|
||||
position: "absolute",
|
||||
top: `${e.clientY}px`,
|
||||
left: `${e.clientX}px`,
|
||||
background: "#333",
|
||||
color: "#fff",
|
||||
padding: "5px",
|
||||
borderRadius: "5px",
|
||||
zIndex: 999,
|
||||
});
|
||||
const load_img = document.createElement("button");
|
||||
load_img.textContent = "Load";
|
||||
load_img.onclick = () => {
|
||||
app.handleFile(img.src)
|
||||
|
||||
}
|
||||
|
||||
image_menu.appendChild(load_img)
|
||||
document.body.appendChild(image_menu)
|
||||
})
|
||||
|
||||
but.append(img)
|
||||
imageListContainer.prepend(but)
|
||||
};
|
||||
|
||||
|
||||
loadButton.onclick = async () => {
|
||||
const all_history = await api.getHistory();
|
||||
for (const history of all_history.History) {
|
||||
if (history.outputs) {
|
||||
for (const key of Object.keys(history.outputs)) {
|
||||
console.debug(key)
|
||||
for (const im of history.outputs[key].images) {
|
||||
console.debug(im)
|
||||
createImageBtn(im)
|
||||
}
|
||||
}
|
||||
// for (const src of outputs.outputs.images) {
|
||||
// console.debug(src)
|
||||
// makeImage(`${src.subfolder}/${src.filename}`)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////-------
|
||||
|
||||
// const all_history = await api.getHistory()
|
||||
// for (const history of all_history.History) {
|
||||
// if (history.outputs) {
|
||||
// for (const key of Object.keys(history.outputs)) {
|
||||
// for (const im of history.outputs[key].images) {
|
||||
// makeImage(im)
|
||||
// }
|
||||
// }
|
||||
// // for (const src of outputs.outputs.images) {
|
||||
// // console.debug(src)
|
||||
// // makeImage(`${src.subfolder}/${src.filename}`)
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
//- Hook into the API
|
||||
api.addEventListener("executed", ({ detail }) => {
|
||||
if (detail?.output?.images) {
|
||||
for (const src of detail.output.images) {
|
||||
console.debug(`Adding ${src} to image feed`)
|
||||
createImageBtn(src)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
//- Hook into the API
|
||||
api.addEventListener('executed', ({ detail }) => {
|
||||
if (detail?.output?.images) {
|
||||
for (const src of detail.output.images) {
|
||||
console.debug(`Adding ${src} to image feed`)
|
||||
createImageBtn(src)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
+855
-1058
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* File: notify.js
|
||||
* Project: comfy_mtb
|
||||
* Author: Mel Massadian
|
||||
*
|
||||
* Copyright (c) 2023 Mel Massadian
|
||||
*
|
||||
*/
|
||||
|
||||
import { app } from '/scripts/app.js'
|
||||
Reference in New Issue
Block a user