import { api } from "../../../scripts/api.js" import { app } from "../../../scripts/app.js"; import { $el } from "../../../scripts/ui.js"; import {fuzzyMatch} from "./fts_fuzzy_match.js"; console.time('execution time'); async function api_get(url) { var response = await api.fetchApi(url, { cache: "no-store" }) return await response.json() } let CUSTOM_COLORS; try { const CONFIG_CORE = await api_get("/jovimetrix/config") CUSTOM_COLORS = CONFIG_CORE?.user?.default?.color?.theme; } catch {} let categorySearchToggle = false; let defaultSearchToggle = false; const settingsStyle = ` #comfy-settings-dialog input{ background: var(--comfy-input-bg); color: var(--input-text); border: 1px solid var(--border-color); padding: 5px; } #comfy-settings-dialog tr > td:first-child { text-align: left; } #comfy-settings-dialog select{ background: var(--bg-color); color: var(--drag-text); padding: 5px; } #comfy-settings-dialog { background: var(--bg-color); } #comfy-settings-dialog::-webkit-scrollbar { margin-top: 0.5rem; height: 1rem; width: .6rem; top: 10px; background-color: transparent; } #comfy-settings-dialog::-webkit-scrollbar:horizontal { height: .5rem; width: 2.5rem } #comfy-settings-dialog::-webkit-scrollbar-track { background-color: var(--comfy-input-bg); border-radius: 9999px } #comfy-settings-dialog::-webkit-scrollbar-thumb { --tw-border-opacity: 1; background-color: var(--border-color); border: 0; border-radius: 9999px; } #comfy-settings-dialog::-webkit-scrollbar-thumb:hover { --tw-bg-opacity: 1; background-color: var(--border-color); } .comfy-table td, .comfy-table th { border: 0px solid var(--border-color); padding: 8px; } ` function addSidebarStyles() { const sidebarStyle = ` .litegraph .dialog { z-index: 100 !important; } .sidebar { position: absolute; top: 0; left: -250px; left: -250px; width: fit-content; height: calc(100% - 19px); color: var(--drag-text); transition: left 0.3s ease; z-index: 2; padding-top: 19px; left: 0; user-select: none; } .sidebar ul { list-style-type: none; /* border-bottom: 6px solid rgb(from var(--comfy-input-bg) r g b / 60%);*/ padding-left: 5px; padding-right: 5px; margin-bottom: 8px; padding-top: 10px; } .sidebar li { padding: 10px; cursor: pointer; user-select: none; color: var(--input-text); } .content_sidebar { background:rgb(from var(--comfy-menu-bg) r g b / 100%); overflow-y: scroll; overflow-x: hidden; height: 100%; float:left; backdrop-filter: blur(5px); } .dragHandle { position: relative; float: left; right: 0; top: 0; height: 100%; width: 10px; cursor: ew-resize; background: rgb(62,62,62); background: linear-gradient(90deg, rgb(62 62 62 / 46%) 0%, rgb(39 39 39 / 47%) 50%, rgb(28 28 28 / 31%) 100%); } #searchInput { box-sizing: border-box; width: 100%; border-radius: 5px; padding: 10px; border: none; user-select: none; background: var(--comfy-input-bg); color: var(--input-text); line-height: 1.4; border: 1px solid var(--border-color); } .sidebar-header { position: absolute; width: calc(100% - 49px); margin-top: 5px; margin-bottom: 10px; margin-left: 10px; z-index: 400; } .clearIcon,.searchCategoryIcon{ position: absolute; padding: 5px; right: 30px; color: var(--input-text); font-size: x-large; cursor: pointer; opacity: 0.5; user-select: none; line-height: 1.4; } .clearIcon:hover{ opacity: 1.0; } .searchCategoryIcon{ right: 0px; padding: 3px; font-size: larger; background: var(--border-color); color:var(--drag-text); margin: 4px; border-radius: 5px; width: 18px; text-align: center; top: 0; } .searchCategoryIcon:hover{ opacity: 0.5; } .sidebarCategory, #sidebarBookmarks{ list-style-type: none; font-family: 'Open Sans',sans-serif; text-transform: capitalize; margin: 2px; background-color:var(--comfy-input-bg); opacity:1; border-radius: 8px; padding-top: 11px; font-size: 15px; padding-bottom: 8px; } #sidebarCustomNodes{ list-style-type: none; font-family: 'Open Sans', sans-serif; text-transform: capitalize; margin: 0px; background-color: transparent; opacity: 1; border-radius: 8px; font-size: 15px; padding-left: 0; padding-right: 0px; padding-top: 0px; padding-bottom: 40px; } .sidebarItem:hover{ background:color-mix(in srgb, currentColor 15%, transparent); } .sidebarItem { list-style-type: none; font-family: 'Open Sans',sans-serif; text-transform: capitalize; margin: 2px; background: color-mix(in srgb, var(--border-color) 35%, transparent) ; opacity:1; border-radius: 8px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width: calc(100% - 39px); } .content_sidebar::-webkit-scrollbar { margin-top: 0.5rem; height: 1rem; width: .5rem; top: 10px; } .content_sidebar::-webkit-scrollbar:horizontal { height: .5rem; width: 1rem } .content_sidebar::-webkit-scrollbar-track { background-color: transparent; border-radius: 9999px } .content_sidebar::-webkit-scrollbar-thumb { --tw-border-opacity: 1; background-color: hsla(0,0%,50%,.8); border-color: rgba(255,255,255,0,0,0); border-radius: 9999px; border-width: 1px } .content_sidebar::-webkit-scrollbar-thumb:hover { --tw-bg-opacity: 1; background-color: rgba(150,150,150,var(--tw-bg-opacity)) } #spacer { height: 45px; } #switch_sidebar { position: relative; float: left; left: 0; margin-left: -0.6rem; cursor: pointer; user-select: none; padding: 2px; font-size: 20px; background-color: var(--comfy-menu-bg); border-bottom-right-radius: 5px; border-top-right-radius: 5px; } #searchInput.closed { display: none; } #content_sidebar.closed { width: 0 !important; } .searchCategoryIcon.closed { display: none; } .clearIcon.closed { display: none; } .sidebarCategory .pinButton { background-color: transparent; border: 0; position: absolute; right: 0; } #sidebarBookmarks .pinButton { background-color: transparent; border: 0; position: absolute; right: 0; } .previewButton{ background-color: transparent; border: 0; position: absolute; right: 35px; } .pinned{ fill: var(--descrip-text) !important; opacity: 1 !important; } .svg_class{ width: 24px; height: 24px; fill: var(--border-color); cursor: pointer; /* hacky fix */ margin-top: -5px; margin-left: -25px; } .pin_normal{ opacity: 0.5; } .pin_normal:hover{ opacity: 1; } .svg_class:hover{ fill: var(--border-color); } #sidebarBookmarks .sidebarItem { margin-left: 10px; margin-right: 29px; } .sb_label { font-family: 'Open Sans',sans-serif; position: relative; margin: 5px; font-weight: bold; background: var(--comfy-input-bg); border-radius: 3px; padding-left: 6px; padding-right: 6px; display: block; width: calc(100% - 20px); text-align: center; user-select: none; cursor: pointer; } .expand_node, .pin_node{ position: absolute; right: 5px; background: transparent; border: 0; } .expand_node svg , .pin_node svg { width: 20px; height: 20px; background: transparent; fill: var(--input-text); cursor: pointer; } .sb_dot { width: 8px; height: 8px; border-radius: 50%; background-color: grey; } .node_header { line-height: 1; padding: 8px 13px 7px; background: var(--comfy-input-bg); margin-bottom: 5px; font-size: 15px; text-wrap: nowrap; overflow: hidden; } .headdot { width: 10px; height: 10px; float: inline-start; margin-right: 8px; } .sb_hidden { display: none; } .IMAGE { background-color: #64b5f6; } .VAE { background-color: #ff6e6e; } .LATENT { background-color: #ff9cf9; } .MASK{ background-color: #81c784; } .CONDITIONING{ background-color: #ffa931; } .CLIP{ background-color: #ffd500; } .MODEL{ background-color: #b39ddb; } .CONTROL_NET{ background-color: #a5d6a7; } #previewDiv { position: absolute; background-color: var(--comfy-menu-bg); font-family: 'Open Sans', sans-serif; font-size: small; color: var(--descrip-text); border: 1px solid var(--descrip-text); display: none; min-width: 300px; width: min-content; height: fit-content; z-index: 9999; border-radius: 12px; overflow: hidden; font-size: 12px; padding-bottom: 10px; } #previewDiv .sb_description { margin: 10px; padding: 6px; background: var(--border-color); border-radius: 5px; font-style: italic; font-weight: 500; font-size: 0.9rem; } .sb_table { display: grid; grid-column-gap: 10px; /* Spazio tra le colonne */ width: 100%; /* Imposta la larghezza della tabella al 100% del contenitore */ } .sb_row { display: grid; grid-template-columns: 10px 1fr 1fr 1fr 10px; grid-column-gap: 10px; align-items: baseline; padding-left: 9px; padding-right: 9px; } .sb_row_string{ grid-template-columns: 10px 1fr 1fr 10fr 1fr; } .sb_col { border: 0px solid #000; display: flex; align-items: flex-end; flex-direction: row-reverse; flex-wrap: nowrap; align-content: flex-start; justify-content: flex-end; } .sb_inherit{ display: inherit; } .long_field{ background: var(--bg-color); border: 2px solid var(--border-color); margin: 5px 5px 0 5px; border-radius: 10px; line-height: 1.7; } .sb_arrow{ color: var(--fg-color); } .sb_preview_badge{ text-align: center; background:var(--comfy-input-bg); font-weight: bold; color: var(--error-text); } #sb_scrollToTopButton { position: absolute; bottom: 2px; right: 34px; cursor: pointer; display: none; border-radius: 20%; background: var(--comfy-menu-bg); padding: 4px; border: 1px solid #4c4c4c; } #sb_scrollToTopButton svg { width: 20px; height: 20px; fill: var(--descrip-text); } .custom-menu { display: none; position: absolute; background-color: #fff; border: 1px solid #ccc; padding: 5px 0; list-style: none; z-index: 1000; } .custom-menu ul { margin: 0; padding: 0; } .custom-menu li { display: block; } .custom-menu li a { display: block; padding: 8px 12px; text-decoration: none; color: #333; } .custom-menu li a:hover { background-color: #f0f0f0; } `; const styleElement = $el("style", { parent: document.head, textContent: sidebarStyle }); } /* Utils */ function addDynamicCSSRule(selector, property, value) { const styleId = 'dynamic-styles'; let customStyle = document.getElementById(styleId); if (!customStyle) { customStyle = document.createElement('style'); customStyle.type = 'text/css'; customStyle.id = styleId; document.head.appendChild(customStyle); } const existingRule = Array.from(customStyle.sheet.cssRules).find(rule => rule.selectorText === selector); if (existingRule) { existingRule.style[property] = value; } else { customStyle.sheet.insertRule(`${selector} { ${property}: ${value} !important; }`, customStyle.sheet.cssRules.length); } } function getVar(name) { var varValue = localStorage.getItem(name); if (varValue === null) { const cookies = document.cookie.split(';'); for (const cookie of cookies) { const [cookieName, cookieValue] = cookie.trim().split('='); if (cookieName === name) { /*migration to localstorage*/ localStorage.setItem(name, cookieValue); return cookieValue; } } }else { return varValue; } return null; } function setVar(name, value, days) { /*migration to localstorage*/ localStorage.setItem(name, value); let expires = ''; if (days) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); expires = '; expires=' + date.toUTCString(); } document.cookie = name + '=' + value + expires + '; path=/'; } function getElementPosition(element) { const rect = element.getBoundingClientRect(); return { top: rect.top, left: rect.left }; } function reverseAndAppend(originalName) { let words; let lastWord; let reversedWords; let reversedString; let finalName; if (originalName.includes(' ')) { const words = originalName.split(' '); lastWord = words.pop(); reversedWords = words.reverse(); reversedString = reversedWords.join(' '); finalName = originalName + ' ' + reversedString; return finalName; } else { words = originalName.split(/(?=[A-Z])/); lastWord = words.pop(); reversedWords = words.reverse(); reversedString = reversedWords.join(''); finalName = originalName + reversedString; return finalName; } } function cleanText(text) { let cleanedText = text.replace(/[^a-zA-Z0-9\s\n\-]/g, ''); cleanedText = cleanedText.replace(/\s+/g, ' '); cleanedText = cleanedText.replace(/\n/g, ''); return cleanedText; } /* End Utils */ function getSidebarItemIds() { const sidebarItems = document.querySelectorAll("#sidebarBookmarks .sidebarItem"); const itemIds = []; sidebarItems.forEach(function(item) { itemIds.push(item.id); }); return itemIds; } function postPinned() { var dragItem = null; const categoriesList = document.getElementById("content_sidebar"); const pinnedElement= document.getElementById("sidebarBookmarks"); pinnedElement.querySelectorAll(".sidebarItem").forEach(function(item) { item.addEventListener("dragstart", function(event) { dragItem = event.target; }); item.addEventListener('mouseover', function() { if (this.classList.contains('sidebarItem') && this.tagName === 'LI') { let descriptionDiv = ""; const itemPosition = getElementPosition(this); let previewDivTop = 0; const [previewContent,node_description] = createNodePreview(item.id); if (node_description) { descriptionDiv = "
" + node_description + "
"; } previewDiv.innerHTML = previewContent+descriptionDiv; previewDiv.style.display = 'block'; const correction_offset = 45; if (itemPosition.top - this.offsetHeight >=0 && itemPosition.top + previewDiv.offsetHeight < document.body.offsetHeight) { previewDivTop = itemPosition.top - this.offsetHeight }else if (itemPosition.top - this.offsetHeight -previewDiv.offsetHeight <=0){ previewDivTop = 0 +correction_offset; } else { previewDivTop = (itemPosition.top + this.offsetHeight) - previewDiv.offsetHeight; } const previewDivLeft = itemPosition.left + this.offsetWidth + correction_offset; previewDiv.style.top = `${previewDivTop}px`; previewDiv.style.left = `${previewDivLeft}px`; } }); item.addEventListener('mouseout', function() { previewDiv.style.display = 'none'; }) }); pinnedElement.addEventListener("dragover", function(event) { event.preventDefault(); }); pinnedElement.addEventListener("drop", function(event) { event.preventDefault(); if (dragItem) { var dropZone = event.target.closest("ul"); dropZone.insertBefore(dragItem, event.target); dragItem = null; //list element in sidebarBookmarks savePinnedItems(getSidebarItemIds()); } }); } function sidebarAddNode(name, text, x, y) { const node = LiteGraph.createNode(name, text) if (node) { const pos = [ x, y ] node.pos = pos; app.graph.add(node) } } function saveSidebarWidth(sideb) { const width = sideb.style.width; document.cookie = setVar("sidebarWidth", width, 3000); } function restoreSidebarWidth() { let width_sidebar = "auto"; let cookieValue = getVar("sidebarWidth"); if (cookieValue) { width_sidebar = cookieValue; } return width_sidebar; } function savePinnedItems(pinnedItems) { const pinnedItemsString = JSON.stringify(pinnedItems); setVar('pinnedItems', pinnedItemsString, 9999); } function loadPinnedItems() { const pinnedItemsString = getVar('pinnedItems'); if (pinnedItemsString) { return JSON.parse(pinnedItemsString); } return []; } function pinItem(itemId) { const item = document.getElementById(itemId); const sidebarBookmarks = document.getElementById("sidebarBookmarks"); const pinnedItems = loadPinnedItems(); if (!pinnedItems.includes(itemId)) { let addedItem = sidebarBookmarks.appendChild(item.cloneNode(true)); addedItem.lastChild.lastChild.childNodes[1].classList.add("pinned"); pinnedItems.push(itemId); savePinnedItems(pinnedItems); postPinned(); } } function unpinItem(itemId) { const item = document.getElementById(itemId); const sidebarBookmarks = document.getElementById("sidebarBookmarks"); const pinnedItems = loadPinnedItems(); if (pinnedItems.includes(itemId)) { sidebarBookmarks.removeChild(item); pinnedItems.splice(pinnedItems.indexOf(itemId), 1); savePinnedItems(pinnedItems); } } function removePinnedClass(itemId) { const sidebarItems = document.querySelectorAll(".sidebarItem"); sidebarItems.forEach(function (item) { if (item.id === itemId) { const path = item.querySelector("path"); if (path) { path.classList.remove("pinned"); } } }); } function loadPinnedItemsAndAddToBookmarks() { const pinnedItems = loadPinnedItems(); const sidebarBookmarks = document.getElementById("sidebarBookmarks"); // delete pinned const sidebarCategories = sidebarBookmarks.querySelectorAll(".sidebarItem"); sidebarCategories.forEach(category => { category.remove(); }); pinnedItems.forEach(itemId => { pinItem(itemId); const item = document.getElementById(itemId); if (item) { let addedItem = sidebarBookmarks.appendChild(item.cloneNode(true)); addedItem.lastChild.lastChild.classList.add("pinned"); } }); postPinned(); } function sdExpandAll(forceExpand=0) { const categoryItems = document.querySelectorAll(".content_sidebar .sidebarCategory"); const side_bar_status = document.querySelector(".content_sidebar").dataset.expanded; const expand_node = document.getElementsByClassName("expand_node")[0]; let display_value = "true"; if (side_bar_status === "true" && forceExpand === 0) { display_value = "none"; expand_node.innerHTML = ` `; document.querySelector(".content_sidebar").dataset.expanded = "false"; } else { display_value = "block"; expand_node.innerHTML = ` `; document.querySelector(".content_sidebar").dataset.expanded = "true"; } categoryItems.forEach(function (categoryItem) { const displayNamesList = categoryItem.querySelector("ul"); if (expand_node) { displayNamesList.style.display = display_value; } }); } function safeObjectKeys(obj) { try { return Object.keys(obj); } catch (error) { //console.error('Error while trying to get object keys:', error); return []; } } function createNodePreview(nodeID) { let description = ""; let rows = ""; let last_rows = ""; const data = LiteGraph.registered_node_types; const category = data[nodeID].category; try{ description = data[nodeID].nodeData.description; }catch(err){ description = ""; } try{ let inputs = data[nodeID].nodeData.input; //divided between optional and required let outputs_name = data[nodeID].nodeData.output_name; let outputs = data[nodeID].nodeData.output; //console.log(category, inputs, outputs); //create array with objectkeys from input and output const inputArray = []; const outputArray = []; const inputKeysRequired = safeObjectKeys(inputs.required) const inputKeysOptional = safeObjectKeys(inputs.optional) for (let i = 0; i < inputKeysRequired.length; i++) { try{ let thirdV = null; let secondV = inputs.required[inputKeysRequired[i]][0]; if (Array.isArray(secondV)){ //array secondV = inputs.required[inputKeysRequired[i]][0][0]; thirdV = inputs.required[inputKeysRequired[i]][0][0]; } if (inputs.required[inputKeysRequired[i]][1]!=undefined){ //object thirdV = inputs.required[inputKeysRequired[i]][1].default; } inputArray.push([inputKeysRequired[i],secondV,thirdV]); }catch(err){ console.log("error",err) } } try{ for (let i = 0; i < inputKeysOptional.length; i++) { let thirdV = null; let secondV = inputs.optional[inputKeysOptional[i]][0]; if (Array.isArray(secondV)){ //array secondV = inputs.optional[inputKeysOptional[i]][0][0]; thirdV = inputs.optional[inputKeysOptional[i]][0][0]; } if (inputs.optional[inputKeysOptional[i]][1]!=undefined){ //object thirdV = inputs.optional[inputKeysOptional[i]][1].default; } inputArray.push([inputKeysOptional[i],secondV,thirdV]); } }catch(err){ console.log(err) } for (let i = 0; i < outputs.length; i++) { if (outputs_name[i] != undefined) { outputArray.push([outputs[i],outputs_name[i]]); } else{ outputArray.push(outputs[i],outputs[i]); } } let length_loop = outputArray.length; if (inputArray.length> outputArray.length){ length_loop = inputArray.length; } for (let i = 0; i < length_loop; i++) { const inputList= inputArray[i] ? inputArray[i] : null; const outputList= outputArray[i] ? outputArray[i] : null; let inputName = ""; let inputType = ""; let inputValue = null; let outputType = ""; let outputName = ""; if (inputList != null){ inputName = inputList[0]; inputType = inputList[1]; inputValue = inputList[2]; }else { inputName = ""; inputType = "sb_hidden"; inputValue = null; } if (outputList != null){ outputType = outputList[0]; outputName = outputList[1]; }else { outputType = "sb_hidden"; outputName = ""; } if (inputValue != null){ if (inputType == "STRING"){ last_rows += `
${inputName}
${inputValue}
`; }else{ last_rows += `
◀
${inputName}
${inputValue}
▶
`; } inputType = "sb_hidden"; inputName = ""; } rows += `
${inputName}
${outputName}
`; } //console.log( inputArray,outputArray); ////create preview //const nodePreview = document.createElement("div"); //nodePreview.classList.add("node_preview"); //nodePreview.id = nodeID; }catch(err){ rows = `
NOT AVAILABLE
` last_rows = `` } return [`
${nodeID}
PREVIEW
${rows} ${last_rows}
`,description]; } function toggleCollapsePinned() { // expand/collapse pinned const sidebarBookmarks = document.getElementById('sidebarBookmarks'); if (sidebarBookmarks.style.display === 'none') { sidebarBookmarks.style.display = 'block'; setVar('sb_pinned_collapsed', 'block', 3000); } else { sidebarBookmarks.style.display = 'none'; setVar('sb_pinned_collapsed', 'none', 3000); } } function toggleCollapseCustom() { if (sidebarCustomNodes.style.display === 'none') { sidebarCustomNodes.style.display = 'block'; setVar('sb_custom_collapsed', 'block', 3000); } else { sidebarCustomNodes.style.display = 'none'; setVar('sb_custom_collapsed', 'none', 3000); } } async function createCategoryList() { const data = LiteGraph.registered_node_types; let categories = {}; const pinnedItems = loadPinnedItems(); const categoriesList = document.getElementById("content_sidebar"); const itemSearchInput = document.getElementById("searchInput"); itemSearchInput.addEventListener("input", updateList); const clearIcon = document.querySelector(".clearIcon"); const searchCategoryIcon = document.querySelector(".searchCategoryIcon"); clearIcon.addEventListener("click", async function () { try { itemSearchInput.value = ""; const searchTerm = updateList(); } catch (error) { console.error("Error occurred during search:", error); } }); searchCategoryIcon.addEventListener("click", async function () { try { categorySearchToggle = !categorySearchToggle; searchCategoryIcon.style.opacity = categorySearchToggle ? "1" : "0.5"; const searchTerm = updateList(); } catch (error) { console.error("Error occurred during search:", error); } }); async function updateList() { return new Promise((resolve, reject) => { categories = {}; const itemSearchString = itemSearchInput.value.toLowerCase(); // delete all element conaining sidebarCategory class const sidebarCategories = categoriesList.querySelectorAll(".sidebarCategory"); sidebarCategories.forEach(category => { category.remove(); }); let shortedArray = {}; for (const objKey in data) { try { let searchable; const category = data[objKey].category.toLowerCase(); if (!categorySearchToggle) { searchable = data[objKey].title.toLowerCase(); } else{ searchable = category; } if (defaultSearchToggle) { if (searchable.includes(itemSearchString) || itemSearchString === "") { if (!categories[category]) { categories[category] = []; } categories[category].push(data[objKey]); //remove category if empty // if (categories[category].length === 0) { // delete categories[category]; // } } } else { if (itemSearchString === "") { if (!categories[category]) { categories[category] = []; } categories[category].push(data[objKey]); } else { const [accepted,rank] = fuzzyMatch(itemSearchString, reverseAndAppend(cleanText(searchable))); if (accepted && rank >= 130) { if (!shortedArray[rank]) { shortedArray[rank] = []; } shortedArray[rank].push(data[objKey]); } } } } catch (err) { console.log(err); } } if(itemSearchString != ""){ if (!defaultSearchToggle) { const ranks = Object.keys(shortedArray); ranks.sort((a, b) => b - a); ranks.forEach(rank => { const dataArr = shortedArray[rank]; dataArr.forEach(item => { if (!categories[item.category]) { categories[item.category] = []; } categories[item.category].push(item); }); }); } } else { // order categories alphabetically const sortedCategoriesData = {}; const sortedCategories = Object.keys(categories).sort(); sortedCategories.forEach(category => { sortedCategoriesData[category] = categories[category]; }); categories = sortedCategoriesData; } renderList(); resolve(itemSearchString); }); } async function renderList() { return new Promise((resolve, reject) => { const pinnedItems = loadPinnedItems(); // const sidebarCustomNodes = document.getElementById("sidebarCustomNodes"); for (const category in categories) { const categoryItem = document.createElement("li"); categoryItem.classList.add("sidebarCategory"); categoryItem.textContent = category; const displayNamesList = document.createElement("ul"); displayNamesList.style.display = "none"; categoryItem.appendChild(displayNamesList); categories[category].forEach(displayName => { try { const displayNameItem = document.createElement("li"); displayNameItem.classList.add("sidebarItem"); displayNameItem.textContent = displayName.title; displayNameItem.title = displayName.title; displayNameItem.draggable = true; // JOVIMETRIX CUT-OUT FOR CUSTOM COLORED NODES // if (CUSTOM_COLORS) { let color = CUSTOM_COLORS[displayName.title]; if (color === undefined) { const segments = displayName.nodeData.category.split('/') let k = segments.join('/') while (k) { color = CUSTOM_COLORS[k] if (color) { color = color.title break } const last = k.lastIndexOf('/') k = last !== -1 ? k.substring(0, last) : '' } } else { color = color.title } if (color) { displayNameItem.style = `background: ${color}`; } } // displayNameItem.id = displayName.type; /* Create Pin Button */ const pinButton = document.createElement("button"); pinButton.classList.add("pinButton"); let add_class = ""; if (pinnedItems.includes(displayName.type)) { add_class = "pinned"; } pinButton.innerHTML = ` `; displayNameItem.appendChild(pinButton); /* End Pin Button */ displayNamesList.appendChild(displayNameItem); } catch (err) { console.log(err); } }); categoryItem.addEventListener("click", function (event) { if (event.target === event.currentTarget) { displayNamesList.style.display = displayNamesList.style.display === "none" ? "block" : "none"; } }); sidebarCustomNodes.appendChild(categoryItem); } if (!categorySearchToggle && itemSearchInput.value != "") { sdExpandAll(1); } loadPinnedItemsAndAddToBookmarks(); /* preview */ const sidebarItems_cat = document.querySelectorAll('.sidebarItem'); const previewDiv = document.getElementById('previewDiv'); sidebarItems_cat.forEach(item => { item.addEventListener('mouseover', function() { if (this.classList.contains('sidebarItem') && this.tagName === 'LI') { let descriptionDiv = ""; const itemPosition = getElementPosition(this); let previewDivTop = 0; const [previewContent,node_description] = createNodePreview(item.id); if (node_description) { descriptionDiv = "
" + node_description + "
"; } previewDiv.innerHTML = previewContent+descriptionDiv; previewDiv.style.display = 'block'; const correction_offset = 45; if (itemPosition.top - this.offsetHeight >=0 && itemPosition.top + previewDiv.offsetHeight < document.body.offsetHeight) { previewDivTop = itemPosition.top - this.offsetHeight }else if (itemPosition.top - this.offsetHeight -previewDiv.offsetHeight <=0){ previewDivTop = 0 +correction_offset; } else { previewDivTop = (itemPosition.top + this.offsetHeight) - previewDiv.offsetHeight; } const previewDivLeft = itemPosition.left + this.offsetWidth + correction_offset; previewDiv.style.top = `${previewDivTop}px`; previewDiv.style.left = `${previewDivLeft}px`; } }); item.addEventListener('mouseout', function() { previewDiv.style.display = 'none'; }) }); categoriesList.addEventListener('scroll', function() { previewDiv.style.display = 'none'; }); window.addEventListener('click', function(event) { if (!event.target.classList.contains('sidebarItem')) { previewDiv.style.display = 'none'; } }); resolve(); }); } let udata = await updateList(); const dragHandle = document.getElementById("dragHandle"); let isDragging = false; let startX; let startWidth; dragHandle.addEventListener("mousedown", function (event) { isDragging = true; startX = event.clientX; startWidth = parseInt(window.getComputedStyle(categoriesList).width); }); document.addEventListener("mouseup", function () { if (isDragging) { isDragging = false; saveSidebarWidth(categoriesList); } }); document.addEventListener("mousemove", function (event) { if (!isDragging) return; const delta = event.clientX - startX; categoriesList.style.width = (startWidth + delta) + "px"; }); } function addSidebar() { let draggedElementId; const sidebar_width = restoreSidebarWidth(); const sidebarHtml = ` `; const canvas = $el("sidebar", { parent: document.body, innerHTML: sidebarHtml }); document.getElementById("content_sidebar").addEventListener("click", function (event) { const clickedElement = event.target; const pinnedItems = loadPinnedItems(); const pinButton = clickedElement.tagName; if (pinButton == "rect" && clickedElement.classList.contains("pin_node")) { let itemId; try { itemId = clickedElement.parentElement.parentElement.parentElement.id; } catch (err) { console.log(err); } if (!pinnedItems.includes(itemId)) { const sidebarItemId = itemId; pinItem(sidebarItemId); clickedElement.parentElement.getElementsByClassName("pin_normal")[0].classList.add("pinned"); }//remove from sidebar else { if (clickedElement.parentElement.parentElement.parentElement.parentElement.id == "sidebarBookmarks") { clickedElement.parentElement.parentElement.parentElement.remove(); const itemIndex = pinnedItems.indexOf(itemId); removePinnedClass(itemId); if (itemIndex !== -1) { pinnedItems.splice(itemIndex, 1); savePinnedItems(pinnedItems); } } else { unpinItem(itemId); } clickedElement.parentElement.getElementsByClassName("pin_normal")[0].classList.remove("pinned"); } } else if ((pinButton == "rect") && clickedElement.classList.contains("expand_node")) { sdExpandAll(); } else if ((pinButton == "LABEL") && clickedElement.id === "sb_label_custom") { toggleCollapseCustom(); } }); const sidebarItems = document.querySelectorAll(".sidebar li ul li"); sidebarItems.forEach(item => { item.draggable = true; }); function convertCanvasToOffset(canvas, pos, out) { out = out || [0, 0]; out[0] = pos[0] / canvas.scale - canvas.offset[0]; out[1] = pos[1] / canvas.scale - canvas.offset[1]; return out; }; function handleDrop(event) { event.preventDefault(); if (event.srcElement.tagName.toLowerCase() != "canvas") { return; } const coord = convertCanvasToOffset(app.canvasEl.data.ds, [event.clientX, event.clientY]); const x = coord[0]; const y = coord[1]; sidebarAddNode(draggedElementId, draggedElementId, x, y); draggedElementId = null; } function allowDrop(event) { event.preventDefault(); } // const search_bar = document.getElementById('searchInput'); canvas.addEventListener("dragstart", function (event) { draggedElementId = event.target.id; previewDiv.style.display = 'none'; }); document.getElementById('switch_sidebar').addEventListener('click', function () { toggleSHSB(); }); document.addEventListener('drop', handleDrop); canvas.addEventListener('dragover', allowDrop); // expand/collapse pinned const pinnedLabel = document.getElementById("sb_label_pinned"); pinnedLabel.addEventListener('click', function() { toggleCollapsePinned(); }); } function toggleSHSB() { const side_bar = document.getElementById('content_sidebar'); const search_bar = document.getElementById('searchInput'); const clearIcon = document.querySelector(".clearIcon"); const searchCategoryIcon = document.querySelector(".searchCategoryIcon"); search_bar.classList.toggle('closed'); side_bar.classList.toggle('closed'); clearIcon.classList.toggle('closed'); searchCategoryIcon.classList.toggle('closed'); if (side_bar.classList.contains('closed')) { setVar("sb_minimized", true, 3000); }else { setVar("sb_minimized", false, 3000); } } //Shortcuts function handleKeyPress(event) { if (event.altKey && event.key.toLowerCase() === "x") { //toggle sidebar if it's closed const side_bar = document.getElementById('content_sidebar'); if (side_bar.classList.contains('closed')) { toggleSHSB(); } //focus on searchInput searchInput.focus(); } if (event.altKey && event.key.toLowerCase() === "z") { toggleSHSB() } } function setContextMenu() { const sb =document.getElementById('content_sidebar'); //ContextMenu sb.addEventListener("contextmenu", function(event) { event.preventDefault(); const customMenu = document.getElementById("customMenu"); customMenu.style.display = "block"; customMenu.style.left = event.pageX + "px"; customMenu.style.top = event.pageY + "px"; }); window.addEventListener("click", function(event) { const customMenu = document.getElementById("customMenu"); customMenu.style.display = "none"; }); } //Settings function settingsSetup() { app.ui.settings.addSetting({ id: "0_sidebar_settings", name: "[Sidebar] Better ComfyUI Settings Style", type: "boolean", defaultValue: false, onChange(value) { let styleElement; if (value) { styleElement = $el("style", { id: "sb-settings-style", parent: document.head, textContent: settingsStyle }); } else { try{ document.getElementById("sb-settings-style").remove(); } catch(e) { } } }, }); app.ui.settings.addSetting({ id: "0_sidebar_default_search", name: "[Sidebar] Use Default Search", type: "boolean", defaultValue: false, onChange(value) { defaultSearchToggle = value; }, }); app.ui.settings.addSetting({ id: "sidebar_font_settings", name: "[Sidebar] Font Size", defaultValue: "13", type: "slider", attrs: { min: 5, max: 30, step: 1, }, onChange(value) { addDynamicCSSRule('.sidebarCategory, #sidebarBookmarks', 'font-size', value+'px'); }, }); app.ui.settings.addSetting({ id: "sidebar_node_settings", name: "[Sidebar] Node Size", defaultValue: "10", type: "slider", attrs: { min: 2, max: 40, step: 1, }, onChange(value) { addDynamicCSSRule('.sidebar li', 'padding', value+'px'); }, }); app.ui.settings.addSetting({ id: "sidebar_bartop", name: "[Sidebar] Space Top", defaultValue: "19", type: "slider", attrs: { min: 0, max: 300, step: 1, }, onChange(value) { //addDynamicCSSRule('.sidebar', 'height', 'calc(100% - '+value+'px'); addDynamicCSSRule('.sidebar', 'padding-top', value+'px'); } }); app.ui.settings.addSetting({ id: "sidebar_barbottom", name: "[Sidebar] Space Bottom", defaultValue: "19", type: "slider", attrs: { min: 0, max: 300, step: 1, }, onChange(value) { addDynamicCSSRule('.sidebar', 'height', 'calc(100% - '+value+'px'); } }); app.ui.settings.addSetting({ id: "sidebar_noderadius_settings", name: "[Sidebar] Node Radius Border", defaultValue: "9", type: "slider", attrs: { min: 0, max: 20, step: 1, }, onChange(value) { addDynamicCSSRule('.sidebarCategory, #sidebarBookmarks', 'border-radius', value+'px'); addDynamicCSSRule('.sidebarItem', 'border-radius', value+'px'); }, }); app.ui.settings.addSetting({ id: "sidebar_blur_settings", name: "[Sidebar] Blur Intesity", defaultValue: "5", type: "slider", attrs: { min: 0, max: 30, step: 1, }, onChange(value) { addDynamicCSSRule('.content_sidebar', 'backdrop-filter', 'blur('+value+'px)'); }, }); app.ui.settings.addSetting({ id: "sidebar_opacity_settings", name: "[Sidebar] Opacity", defaultValue: "1.0", type: "slider", attrs: { min: 0.1, max: 1, step: 0.1, }, onChange(value) { let value_perc = (value * 100).toFixed(0); addDynamicCSSRule('.content_sidebar', 'background', 'rgb(from var(--comfy-menu-bg) r g b / '+value_perc+'%)'); addDynamicCSSRule('.sidebarCategory, #sidebarBookmarks', 'opacity', value); }, }); } function SidebarPostBoot() { addSidebarStyles(); addSidebar(); if (getVar("sb_minimized")=="true") { toggleSHSB(); } document.addEventListener("keydown", handleKeyPress); const sb =document.getElementById('content_sidebar'); const scrollToTopButton = document.getElementById("sb_scrollToTopButton"); scrollToTopButton.addEventListener("click", function() { sb.scrollTo({ top: 0, behavior: "smooth" }); }); sb.addEventListener("scroll", function() { if (sb.scrollTop > 0) { scrollToTopButton.style.display = "block"; } else { scrollToTopButton.style.display = "none"; } }); const sidebarBookmarks = document.getElementById("sidebarBookmarks"); if (getVar("sb_pinned_collapsed")) { sidebarBookmarks.style.display = getVar('sb_pinned_collapsed'); } if (getVar("sb_custom_collapsed")) { sidebarCustomNodes.style.display = getVar('sb_custom_collapsed'); } } // Function to check if the element is not an empty object function SidebarBoot() { if (Object.keys(LiteGraph.registered_node_types).length > 10) { // Execute the function when the element is not an empty object settingsSetup(); createCategoryList(); //setContextMenu(); console.timeEnd('execution time'); } else { // Retry after a period of time setTimeout(SidebarBoot, 500); // Check every 100 milliseconds } } // Start checking the element SidebarBoot(); SidebarPostBoot();