mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-04-20 03:13:30 +00:00
Refactor the template manager (#1878)
* add drag-drop to node template manager * better dnd, save field on change * actually save templates --------- Co-authored-by: matt3o <matt3o@gmail.com>
This commit is contained in:
parent
dd116abfc4
commit
6e84a01ecc
@ -14,6 +14,9 @@ import { ComfyDialog, $el } from "../../scripts/ui.js";
|
|||||||
// To delete/rename:
|
// To delete/rename:
|
||||||
// Right click the canvas
|
// Right click the canvas
|
||||||
// Node templates -> Manage
|
// Node templates -> Manage
|
||||||
|
//
|
||||||
|
// To rearrange:
|
||||||
|
// Open the manage dialog and Drag and drop elements using the "Name:" label as handle
|
||||||
|
|
||||||
const id = "Comfy.NodeTemplates";
|
const id = "Comfy.NodeTemplates";
|
||||||
|
|
||||||
@ -22,6 +25,10 @@ class ManageTemplates extends ComfyDialog {
|
|||||||
super();
|
super();
|
||||||
this.element.classList.add("comfy-manage-templates");
|
this.element.classList.add("comfy-manage-templates");
|
||||||
this.templates = this.load();
|
this.templates = this.load();
|
||||||
|
this.draggedEl = null;
|
||||||
|
this.saveVisualCue = null;
|
||||||
|
this.emptyImg = new Image();
|
||||||
|
this.emptyImg.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
|
||||||
|
|
||||||
this.importInput = $el("input", {
|
this.importInput = $el("input", {
|
||||||
type: "file",
|
type: "file",
|
||||||
@ -35,14 +42,11 @@ class ManageTemplates extends ComfyDialog {
|
|||||||
|
|
||||||
createButtons() {
|
createButtons() {
|
||||||
const btns = super.createButtons();
|
const btns = super.createButtons();
|
||||||
btns[0].textContent = "Cancel";
|
btns[0].textContent = "Close";
|
||||||
btns.unshift(
|
btns[0].onclick = (e) => {
|
||||||
$el("button", {
|
clearTimeout(this.saveVisualCue);
|
||||||
type: "button",
|
this.close();
|
||||||
textContent: "Save",
|
};
|
||||||
onclick: () => this.save(),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
btns.unshift(
|
btns.unshift(
|
||||||
$el("button", {
|
$el("button", {
|
||||||
type: "button",
|
type: "button",
|
||||||
@ -71,25 +75,6 @@ class ManageTemplates extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
|
||||||
// Find all visible inputs and save them as our new list
|
|
||||||
const inputs = this.element.querySelectorAll("input");
|
|
||||||
const updated = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < inputs.length; i++) {
|
|
||||||
const input = inputs[i];
|
|
||||||
if (input.parentElement.style.display !== "none") {
|
|
||||||
const t = this.templates[i];
|
|
||||||
t.name = input.value.trim() || input.getAttribute("data-name");
|
|
||||||
updated.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.templates = updated;
|
|
||||||
this.store();
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
store() {
|
store() {
|
||||||
localStorage.setItem(id, JSON.stringify(this.templates));
|
localStorage.setItem(id, JSON.stringify(this.templates));
|
||||||
}
|
}
|
||||||
@ -143,29 +128,103 @@ class ManageTemplates extends ComfyDialog {
|
|||||||
show() {
|
show() {
|
||||||
// Show list of template names + delete button
|
// Show list of template names + delete button
|
||||||
super.show(
|
super.show(
|
||||||
|
$el(
|
||||||
|
"div",
|
||||||
|
{},
|
||||||
|
this.templates.flatMap((t,i) => {
|
||||||
|
let nameInput;
|
||||||
|
return [
|
||||||
$el(
|
$el(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
|
dataset: { id: i },
|
||||||
|
className: "tempateManagerRow",
|
||||||
style: {
|
style: {
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "1fr auto",
|
gridTemplateColumns: "1fr auto",
|
||||||
|
border: "1px dashed transparent",
|
||||||
gap: "5px",
|
gap: "5px",
|
||||||
|
backgroundColor: "var(--comfy-menu-bg)"
|
||||||
},
|
},
|
||||||
|
ondragstart: (e) => {
|
||||||
|
this.draggedEl = e.currentTarget;
|
||||||
|
e.currentTarget.style.opacity = "0.6";
|
||||||
|
e.currentTarget.style.border = "1px dashed yellow";
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
e.dataTransfer.setDragImage(this.emptyImg, 0, 0);
|
||||||
},
|
},
|
||||||
this.templates.flatMap((t) => {
|
ondragend: (e) => {
|
||||||
let nameInput;
|
e.target.style.opacity = "1";
|
||||||
return [
|
e.currentTarget.style.border = "1px dashed transparent";
|
||||||
|
e.currentTarget.removeAttribute("draggable");
|
||||||
|
|
||||||
|
// rearrange the elements in the localStorage
|
||||||
|
this.element.querySelectorAll('.tempateManagerRow').forEach((el,i) => {
|
||||||
|
var prev_i = el.dataset.id;
|
||||||
|
|
||||||
|
if ( el == this.draggedEl && prev_i != i ) {
|
||||||
|
[this.templates[i], this.templates[prev_i]] = [this.templates[prev_i], this.templates[i]];
|
||||||
|
}
|
||||||
|
el.dataset.id = i;
|
||||||
|
});
|
||||||
|
this.store();
|
||||||
|
},
|
||||||
|
ondragover: (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if ( e.currentTarget == this.draggedEl )
|
||||||
|
return;
|
||||||
|
|
||||||
|
let rect = e.currentTarget.getBoundingClientRect();
|
||||||
|
if (e.clientY > rect.top + rect.height / 2) {
|
||||||
|
e.currentTarget.parentNode.insertBefore(this.draggedEl, e.currentTarget.nextSibling);
|
||||||
|
} else {
|
||||||
|
e.currentTarget.parentNode.insertBefore(this.draggedEl, e.currentTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
$el(
|
$el(
|
||||||
"label",
|
"label",
|
||||||
{
|
{
|
||||||
textContent: "Name: ",
|
textContent: "Name: ",
|
||||||
|
style: {
|
||||||
|
cursor: "grab",
|
||||||
|
},
|
||||||
|
onmousedown: (e) => {
|
||||||
|
// enable dragging only from the label
|
||||||
|
if (e.target.localName == 'label')
|
||||||
|
e.currentTarget.parentNode.draggable = 'true';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$el("input", {
|
$el("input", {
|
||||||
value: t.name,
|
value: t.name,
|
||||||
dataset: { name: t.name },
|
dataset: { name: t.name },
|
||||||
|
style: {
|
||||||
|
transitionProperty: 'background-color',
|
||||||
|
transitionDuration: '0s',
|
||||||
|
},
|
||||||
|
onchange: (e) => {
|
||||||
|
clearTimeout(this.saveVisualCue);
|
||||||
|
var el = e.target;
|
||||||
|
var row = el.parentNode.parentNode;
|
||||||
|
this.templates[row.dataset.id].name = el.value.trim() || 'untitled';
|
||||||
|
this.store();
|
||||||
|
el.style.backgroundColor = 'rgb(40, 95, 40)';
|
||||||
|
el.style.transitionDuration = '0s';
|
||||||
|
this.saveVisualCue = setTimeout(function () {
|
||||||
|
el.style.transitionDuration = '.7s';
|
||||||
|
el.style.backgroundColor = 'var(--comfy-input-bg)';
|
||||||
|
}, 15);
|
||||||
|
},
|
||||||
|
onkeypress: (e) => {
|
||||||
|
var el = e.target;
|
||||||
|
clearTimeout(this.saveVisualCue);
|
||||||
|
el.style.transitionDuration = '0s';
|
||||||
|
el.style.backgroundColor = 'var(--comfy-input-bg)';
|
||||||
|
},
|
||||||
$: (el) => (nameInput = el),
|
$: (el) => (nameInput = el),
|
||||||
}),
|
})
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
$el(
|
$el(
|
||||||
@ -203,13 +262,23 @@ class ManageTemplates extends ComfyDialog {
|
|||||||
fontWeight: "normal",
|
fontWeight: "normal",
|
||||||
},
|
},
|
||||||
onclick: (e) => {
|
onclick: (e) => {
|
||||||
nameInput.value = "";
|
const item = e.target.parentNode.parentNode;
|
||||||
e.target.parentElement.style.display = "none";
|
item.parentNode.removeChild(item);
|
||||||
e.target.parentElement.previousElementSibling.style.display = "none";
|
this.templates.splice(item.dataset.id*1, 1);
|
||||||
|
this.store();
|
||||||
|
// update the rows index, setTimeout ensures that the list is updated
|
||||||
|
var that = this;
|
||||||
|
setTimeout(function (){
|
||||||
|
that.element.querySelectorAll('.tempateManagerRow').forEach((el,i) => {
|
||||||
|
el.dataset.id = i;
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user