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:
Matteo Spinelli 2023-11-02 17:29:57 +01:00 committed by GitHub
parent dd116abfc4
commit 6e84a01ecc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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);
}, },
}), }),
] ]
), ),
]
)
]; ];
}) })
) )