Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
ComfyUI
Commits
e07f8eab
Commit
e07f8eab
authored
Apr 08, 2023
by
comfyanonymous
Browse files
Merge branch 'node-templates' of
https://github.com/pythongosssss/ComfyUI
parents
15da5404
fe932614
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
215 additions
and
19 deletions
+215
-19
web/extensions/core/nodeTemplates.js
web/extensions/core/nodeTemplates.js
+184
-0
web/scripts/ui.js
web/scripts/ui.js
+29
-18
web/style.css
web/style.css
+2
-1
No files found.
web/extensions/core/nodeTemplates.js
0 → 100644
View file @
e07f8eab
import
{
app
}
from
"
/scripts/app.js
"
;
import
{
ComfyDialog
,
$el
}
from
"
/scripts/ui.js
"
;
// Adds the ability to save and add multiple nodes as a template
// To save:
// Select multiple nodes (ctrl + drag to select a region or ctrl+click individual nodes)
// Right click the canvas
// Save Node Template -> give it a name
//
// To add:
// Right click the canvas
// Node templates -> click the one to add
//
// To delete/rename:
// Right click the canvas
// Node templates -> Manage
const
id
=
"
Comfy.NodeTemplates
"
;
class
ManageTemplates
extends
ComfyDialog
{
constructor
()
{
super
();
this
.
element
.
classList
.
add
(
"
comfy-manage-templates
"
);
this
.
templates
=
this
.
load
();
}
createButtons
()
{
const
btns
=
super
.
createButtons
();
btns
[
0
].
textContent
=
"
Cancel
"
;
btns
.
unshift
(
$el
(
"
button
"
,
{
type
:
"
button
"
,
textContent
:
"
Save
"
,
onclick
:
()
=>
this
.
save
(),
})
);
return
btns
;
}
load
()
{
const
templates
=
localStorage
.
getItem
(
id
);
if
(
templates
)
{
return
JSON
.
parse
(
templates
);
}
else
{
return
[];
}
}
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
()
{
localStorage
.
setItem
(
id
,
JSON
.
stringify
(
this
.
templates
));
}
show
()
{
// Show list of template names + delete button
super
.
show
(
$el
(
"
div
"
,
{
style
:
{
display
:
"
grid
"
,
gridTemplateColumns
:
"
1fr auto
"
,
gap
:
"
5px
"
,
},
},
this
.
templates
.
flatMap
((
t
)
=>
{
let
nameInput
;
return
[
$el
(
"
label
"
,
{
textContent
:
"
Name:
"
,
},
[
$el
(
"
input
"
,
{
value
:
t
.
name
,
dataset
:
{
name
:
t
.
name
},
$
:
(
el
)
=>
(
nameInput
=
el
),
}),
]
),
$el
(
"
button
"
,
{
textContent
:
"
Delete
"
,
style
:
{
fontSize
:
"
12px
"
,
color
:
"
red
"
,
fontWeight
:
"
normal
"
,
},
onclick
:
(
e
)
=>
{
nameInput
.
value
=
""
;
e
.
target
.
style
.
display
=
"
none
"
;
e
.
target
.
previousElementSibling
.
style
.
display
=
"
none
"
;
},
}),
];
})
)
);
}
}
app
.
registerExtension
({
name
:
id
,
setup
()
{
const
manage
=
new
ManageTemplates
();
const
clipboardAction
=
(
cb
)
=>
{
// We use the clipboard functions but dont want to overwrite the current user clipboard
// Restore it after we've run our callback
const
old
=
localStorage
.
getItem
(
"
litegrapheditor_clipboard
"
);
cb
();
localStorage
.
setItem
(
"
litegrapheditor_clipboard
"
,
old
);
};
const
orig
=
LGraphCanvas
.
prototype
.
getCanvasMenuOptions
;
LGraphCanvas
.
prototype
.
getCanvasMenuOptions
=
function
()
{
const
options
=
orig
.
apply
(
this
,
arguments
);
options
.
push
(
null
);
options
.
push
({
content
:
`Save Selected as Template`
,
disabled
:
!
Object
.
keys
(
app
.
canvas
.
selected_nodes
||
{}).
length
,
callback
:
()
=>
{
const
name
=
prompt
(
"
Enter name
"
);
if
(
!
name
||
!
name
.
trim
())
return
;
clipboardAction
(()
=>
{
app
.
canvas
.
copyToClipboard
();
manage
.
templates
.
push
({
name
,
data
:
localStorage
.
getItem
(
"
litegrapheditor_clipboard
"
),
});
manage
.
store
();
});
},
});
// Map each template to a menu item
const
subItems
=
manage
.
templates
.
map
((
t
)
=>
({
content
:
t
.
name
,
callback
:
()
=>
{
clipboardAction
(()
=>
{
localStorage
.
setItem
(
"
litegrapheditor_clipboard
"
,
t
.
data
);
app
.
canvas
.
pasteFromClipboard
();
});
},
}));
if
(
subItems
.
length
)
{
subItems
.
push
(
null
,
{
content
:
"
Manage
"
,
callback
:
()
=>
manage
.
show
(),
});
options
.
push
({
content
:
"
Node Templates
"
,
submenu
:
{
options
:
subItems
,
},
});
}
return
options
;
};
},
});
web/scripts/ui.js
View file @
e07f8eab
...
@@ -8,14 +8,18 @@ export function $el(tag, propsOrChildren, children) {
...
@@ -8,14 +8,18 @@ export function $el(tag, propsOrChildren, children) {
if
(
Array
.
isArray
(
propsOrChildren
))
{
if
(
Array
.
isArray
(
propsOrChildren
))
{
element
.
append
(...
propsOrChildren
);
element
.
append
(...
propsOrChildren
);
}
else
{
}
else
{
const
parent
=
propsOrChildren
.
parent
;
const
{
parent
,
$
:
cb
,
dataset
,
style
}
=
propsOrChildren
;
delete
propsOrChildren
.
parent
;
delete
propsOrChildren
.
parent
;
const
cb
=
propsOrChildren
.
$
;
delete
propsOrChildren
.
$
;
delete
propsOrChildren
.
$
;
delete
propsOrChildren
.
dataset
;
delete
propsOrChildren
.
style
;
if
(
propsOrChildren
.
style
)
{
if
(
style
)
{
Object
.
assign
(
element
.
style
,
propsOrChildren
.
style
);
Object
.
assign
(
element
.
style
,
style
);
delete
propsOrChildren
.
style
;
}
if
(
dataset
)
{
Object
.
assign
(
element
.
dataset
,
dataset
);
}
}
Object
.
assign
(
element
,
propsOrChildren
);
Object
.
assign
(
element
,
propsOrChildren
);
...
@@ -76,7 +80,7 @@ function dragElement(dragEl, settings) {
...
@@ -76,7 +80,7 @@ function dragElement(dragEl, settings) {
dragEl
.
style
.
left
=
newPosX
+
"
px
"
;
dragEl
.
style
.
left
=
newPosX
+
"
px
"
;
dragEl
.
style
.
right
=
"
unset
"
;
dragEl
.
style
.
right
=
"
unset
"
;
}
}
dragEl
.
style
.
top
=
newPosY
+
"
px
"
;
dragEl
.
style
.
top
=
newPosY
+
"
px
"
;
dragEl
.
style
.
bottom
=
"
unset
"
;
dragEl
.
style
.
bottom
=
"
unset
"
;
...
@@ -145,7 +149,7 @@ function dragElement(dragEl, settings) {
...
@@ -145,7 +149,7 @@ function dragElement(dragEl, settings) {
}
}
window
.
addEventListener
(
"
resize
"
,
()
=>
{
window
.
addEventListener
(
"
resize
"
,
()
=>
{
ensureInBounds
();
ensureInBounds
();
});
});
function
closeDragElement
()
{
function
closeDragElement
()
{
...
@@ -155,26 +159,33 @@ function dragElement(dragEl, settings) {
...
@@ -155,26 +159,33 @@ function dragElement(dragEl, settings) {
}
}
}
}
class
ComfyDialog
{
export
class
ComfyDialog
{
constructor
()
{
constructor
()
{
this
.
element
=
$el
(
"
div.comfy-modal
"
,
{
parent
:
document
.
body
},
[
this
.
element
=
$el
(
"
div.comfy-modal
"
,
{
parent
:
document
.
body
},
[
$el
(
"
div.comfy-modal-content
"
,
[
$el
(
"
div.comfy-modal-content
"
,
[
$el
(
"
p
"
,
{
$
:
(
p
)
=>
(
this
.
textElement
=
p
)
}),
...
this
.
createButtons
()]),
$el
(
"
p
"
,
{
$
:
(
p
)
=>
(
this
.
textElement
=
p
)
}),
$el
(
"
button
"
,
{
type
:
"
button
"
,
textContent
:
"
Close
"
,
onclick
:
()
=>
this
.
close
(),
}),
]),
]);
]);
}
}
createButtons
()
{
return
[
$el
(
"
button
"
,
{
type
:
"
button
"
,
textContent
:
"
Close
"
,
onclick
:
()
=>
this
.
close
(),
}),
];
}
close
()
{
close
()
{
this
.
element
.
style
.
display
=
"
none
"
;
this
.
element
.
style
.
display
=
"
none
"
;
}
}
show
(
html
)
{
show
(
html
)
{
this
.
textElement
.
innerHTML
=
html
;
if
(
typeof
html
===
"
string
"
)
{
this
.
textElement
.
innerHTML
=
html
;
}
else
{
this
.
textElement
.
replaceChildren
(
html
);
}
this
.
element
.
style
.
display
=
"
flex
"
;
this
.
element
.
style
.
display
=
"
flex
"
;
}
}
}
}
...
@@ -419,7 +430,7 @@ export class ComfyUI {
...
@@ -419,7 +430,7 @@ export class ComfyUI {
type
:
"
boolean
"
,
type
:
"
boolean
"
,
defaultValue
:
true
,
defaultValue
:
true
,
});
});
const
fileInput
=
$el
(
"
input
"
,
{
const
fileInput
=
$el
(
"
input
"
,
{
type
:
"
file
"
,
type
:
"
file
"
,
accept
:
"
.json,image/png
"
,
accept
:
"
.json,image/png
"
,
...
...
web/style.css
View file @
e07f8eab
...
@@ -202,7 +202,8 @@ button.comfy-queue-btn {
...
@@ -202,7 +202,8 @@ button.comfy-queue-btn {
margin
:
6px
0
!important
;
margin
:
6px
0
!important
;
}
}
.comfy-modal.comfy-settings
{
.comfy-modal.comfy-settings
,
.comfy-modal.comfy-manage-templates
{
text-align
:
center
;
text-align
:
center
;
font-family
:
sans-serif
;
font-family
:
sans-serif
;
color
:
#999
;
color
:
#999
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment