|
import {app} from "../../scripts/app.js"; |
|
|
|
|
|
|
|
const ext = { |
|
name: "Comfy.ContextMenuFilter", |
|
init() { |
|
const ctxMenu = LiteGraph.ContextMenu; |
|
|
|
LiteGraph.ContextMenu = function (values, options) { |
|
const ctx = ctxMenu.call(this, values, options); |
|
|
|
|
|
if (options?.className === "dark" && values?.length > 10) { |
|
const filter = document.createElement("input"); |
|
filter.classList.add("comfy-context-menu-filter"); |
|
filter.placeholder = "Filter list"; |
|
this.root.prepend(filter); |
|
|
|
const items = Array.from(this.root.querySelectorAll(".litemenu-entry")); |
|
let displayedItems = [...items]; |
|
let itemCount = displayedItems.length; |
|
|
|
|
|
requestAnimationFrame(() => { |
|
const currentNode = LGraphCanvas.active_canvas.current_node; |
|
const clickedComboValue = currentNode.widgets |
|
.filter(w => w.type === "combo" && w.options.values.length === values.length) |
|
.find(w => w.options.values.every((v, i) => v === values[i])) |
|
?.value; |
|
|
|
let selectedIndex = clickedComboValue ? values.findIndex(v => v === clickedComboValue) : 0; |
|
if (selectedIndex < 0) { |
|
selectedIndex = 0; |
|
} |
|
let selectedItem = displayedItems[selectedIndex]; |
|
updateSelected(); |
|
|
|
|
|
function updateSelected() { |
|
selectedItem?.style.setProperty("background-color", ""); |
|
selectedItem?.style.setProperty("color", ""); |
|
selectedItem = displayedItems[selectedIndex]; |
|
selectedItem?.style.setProperty("background-color", "#ccc", "important"); |
|
selectedItem?.style.setProperty("color", "#000", "important"); |
|
} |
|
|
|
const positionList = () => { |
|
const rect = this.root.getBoundingClientRect(); |
|
|
|
|
|
if (rect.top < 0) { |
|
const scale = 1 - this.root.getBoundingClientRect().height / this.root.clientHeight; |
|
const shift = (this.root.clientHeight * scale) / 2; |
|
this.root.style.top = -shift + "px"; |
|
} |
|
} |
|
|
|
|
|
filter.addEventListener("keydown", (event) => { |
|
switch (event.key) { |
|
case "ArrowUp": |
|
event.preventDefault(); |
|
if (selectedIndex === 0) { |
|
selectedIndex = itemCount - 1; |
|
} else { |
|
selectedIndex--; |
|
} |
|
updateSelected(); |
|
break; |
|
case "ArrowRight": |
|
event.preventDefault(); |
|
selectedIndex = itemCount - 1; |
|
updateSelected(); |
|
break; |
|
case "ArrowDown": |
|
event.preventDefault(); |
|
if (selectedIndex === itemCount - 1) { |
|
selectedIndex = 0; |
|
} else { |
|
selectedIndex++; |
|
} |
|
updateSelected(); |
|
break; |
|
case "ArrowLeft": |
|
event.preventDefault(); |
|
selectedIndex = 0; |
|
updateSelected(); |
|
break; |
|
case "Enter": |
|
selectedItem?.click(); |
|
break; |
|
case "Escape": |
|
this.close(); |
|
break; |
|
} |
|
}); |
|
|
|
filter.addEventListener("input", () => { |
|
|
|
const term = filter.value.toLocaleLowerCase(); |
|
|
|
displayedItems = items.filter(item => { |
|
const isVisible = !term || item.textContent.toLocaleLowerCase().includes(term); |
|
item.style.display = isVisible ? "block" : "none"; |
|
return isVisible; |
|
}); |
|
|
|
selectedIndex = 0; |
|
if (displayedItems.includes(selectedItem)) { |
|
selectedIndex = displayedItems.findIndex(d => d === selectedItem); |
|
} |
|
itemCount = displayedItems.length; |
|
|
|
updateSelected(); |
|
|
|
|
|
if (options.event) { |
|
let top = options.event.clientY - 10; |
|
|
|
const bodyRect = document.body.getBoundingClientRect(); |
|
const rootRect = this.root.getBoundingClientRect(); |
|
if (bodyRect.height && top > bodyRect.height - rootRect.height - 10) { |
|
top = Math.max(0, bodyRect.height - rootRect.height - 10); |
|
} |
|
|
|
this.root.style.top = top + "px"; |
|
positionList(); |
|
} |
|
}); |
|
|
|
requestAnimationFrame(() => { |
|
|
|
filter.focus(); |
|
|
|
positionList(); |
|
}); |
|
}) |
|
} |
|
|
|
return ctx; |
|
}; |
|
|
|
LiteGraph.ContextMenu.prototype = ctxMenu.prototype; |
|
}, |
|
} |
|
|
|
app.registerExtension(ext); |
|
|