| |
| |
| |
| |
| |
| |
| |
|
|
| import { app } from "../../../scripts/app.js"; |
| import { ComfyWidgets } from "../../../scripts/widgets.js"; |
| import { $el } from "../../../scripts/ui.js"; |
|
|
| app.registerExtension({ |
| name: "fl.widget.combo+", |
| init() { |
| const splitBy = /\//; |
|
|
| $el("style", { |
| textContent: ` |
| .litemenu-entry:hover .pysssss-combo-image { |
| display: block; |
| } |
| .pysssss-combo-image { |
| display: none; |
| position: absolute; |
| left: 0; |
| top: 0; |
| transform: translate(-100%, 0); |
| width: 384px; |
| height: 384px; |
| background-size: contain; |
| background-position: top right; |
| background-repeat: no-repeat; |
| filter: brightness(65%); |
| } |
| `, |
| parent: document.body, |
| }); |
|
|
| function buildMenu(widget, values) { |
| const lookup = { |
| "": { options: [] }, |
| }; |
|
|
| |
| for (let value of values) { |
| value = String(value); |
| const split = value.split(splitBy); |
| let path = ""; |
| for (let i = 0; i < split.length; i++) { |
| const s = split[i]; |
| const last = i === split.length - 1; |
| if (last) { |
| |
| lookup[path].options.push({ |
| ...value, |
| title: s, |
| callback: () => { |
| widget.value = value; |
| widget.callback(value); |
| app.graph.setDirtyCanvas(true); |
| }, |
| }); |
| } else { |
| const prevPath = path; |
| path += s + splitBy; |
| if (!lookup[path]) { |
| const sub = { |
| title: s, |
| submenu: { |
| options: [], |
| title: s, |
| }, |
| }; |
|
|
| |
| lookup[path] = sub.submenu; |
| lookup[prevPath].options.push(sub); |
| } |
| } |
| } |
| } |
| return lookup[""].options; |
| } |
|
|
| |
| const combo = ComfyWidgets["COMBO"]; |
| ComfyWidgets["COMBO"] = function (node) { |
| const res = combo.apply(this, arguments); |
| let value = res.widget.value; |
| if (value !== 'combo+') { |
| return res; |
| } |
| let values = res.widget.options.values; |
|
|
|
|
| let menu = null; |
| |
| Object.defineProperty(res.widget.options, "values", { |
| get() { |
| let v = values; |
| if (!menu) { |
| |
| menu = buildMenu(res.widget, values); |
| } |
| v = menu; |
|
|
| const valuesIncludes = v.includes; |
| v.includes = function (searchElement) { |
| const includesFromMenuItem = function (item) { |
| return includesFromMenuItems(item.submenu.options) |
| } |
| const includesFromMenuItems = function (items) { |
| for (const item of items) { |
| if (includesFromMenuItem(item)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| const includes = valuesIncludes.apply(this, arguments) || includesFromMenuItems(this); |
| return includes; |
| } |
|
|
| return v; |
| }, |
| set(v) { |
| |
| values = v; |
| menu = null; |
| }, |
| }); |
|
|
| Object.defineProperty(res.widget, "value", { |
| get() { |
| return value; |
| }, |
| set(v) { |
| if (v?.submenu) { |
| |
| return; |
| } |
| value = v; |
| }, |
| }); |
| const first = res.widget.options.values[0]; |
| const val = first?.submenu?.options?.[0] ?? undefined; |
| if (val !== undefined) { |
| res.widget.options.value = val.title; |
| } |
| return res; |
| }; |
| }, |
| }); |
|
|