Spaces:
Configuration error
Configuration error
| import {app} from "../../../../scripts/app.js"; | |
| import {api} from "../../../../scripts/api.js"; | |
| import {$el} from "../../../../scripts/ui.js"; | |
| import {$t} from "../common/i18n.js"; | |
| import {getExtension, spliceExtension} from '../common/utils.js' | |
| import {toast} from "../common/toast.js"; | |
| const setting_id = "Comfy.EasyUse.MenuNestSub" | |
| let enableMenuNestSub = false | |
| let thumbnails = [] | |
| export function addMenuNestSubSetting(app) { | |
| app.ui.settings.addSetting({ | |
| id: setting_id, | |
| name: $t("Enable ContextMenu Auto Nest Subdirectories (ComfyUI-Easy-Use)"), | |
| type: "boolean", | |
| defaultValue: enableMenuNestSub, | |
| onChange(value) { | |
| enableMenuNestSub = !!value; | |
| }, | |
| }); | |
| } | |
| const getEnableMenuNestSub = _ => app.ui.settings.getSettingValue(setting_id, enableMenuNestSub) | |
| const Loaders = ['easy fullLoader','easy a1111Loader','easy comfyLoader'] | |
| app.registerExtension({ | |
| name:"comfy.easyUse.contextMenu", | |
| async setup(app){ | |
| addMenuNestSubSetting(app) | |
| // 获取所有模型图像 | |
| const imgRes = await api.fetchApi(`/easyuse/models/thumbnail`) | |
| if (imgRes.status === 200) { | |
| let data = await imgRes.json(); | |
| thumbnails = data | |
| } | |
| else if(getEnableMenuNestSub()){ | |
| toast.error($t("Too many thumbnails, have closed the display")) | |
| } | |
| const existingContextMenu = LiteGraph.ContextMenu; | |
| LiteGraph.ContextMenu = function(values,options){ | |
| const threshold = 10; | |
| const enabled = getEnableMenuNestSub(); | |
| if(!enabled || (values?.length || 0) <= threshold || !(options?.callback) || values.some(i => typeof i !== 'string')){ | |
| if(enabled){ | |
| // console.log('Skipping context menu auto nesting for incompatible menu.'); | |
| } | |
| return existingContextMenu.apply(this,[...arguments]); | |
| } | |
| const compatValues = values; | |
| const originalValues = [...compatValues]; | |
| const folders = {}; | |
| const specialOps = []; | |
| const folderless = []; | |
| for(const value of compatValues){ | |
| const splitBy = value.indexOf('/') > -1 ? '/' : '\\'; | |
| const valueSplit = value.split(splitBy); | |
| if(valueSplit.length > 1){ | |
| const key = valueSplit.shift(); | |
| folders[key] = folders[key] || []; | |
| folders[key].push(valueSplit.join(splitBy)); | |
| }else if(value === 'CHOOSE' || value.startsWith('DISABLE ')){ | |
| specialOps.push(value); | |
| }else{ | |
| folderless.push(value); | |
| } | |
| } | |
| const foldersCount = Object.values(folders).length; | |
| if(foldersCount > 0){ | |
| const oldcallback = options.callback; | |
| options.callback = null; | |
| const newCallback = (item,options) => { | |
| if(['None','无','無','なし'].includes(item.content)) oldcallback('None',options) | |
| else oldcallback(originalValues.find(i => i.endsWith(item.content),options)); | |
| }; | |
| const addContent = (content, folderName='') => { | |
| const name = folderName ? folderName + '\\' + spliceExtension(content) : spliceExtension(content); | |
| const ext = getExtension(content) | |
| const time = new Date().getTime() | |
| let thumbnail = '' | |
| if(['ckpt', 'pt', 'bin', 'pth', 'safetensors'].includes(ext)){ | |
| for(let i=0;i<thumbnails.length;i++){ | |
| let thumb = thumbnails[i] | |
| if(name && thumb && thumb.indexOf(name) != -1){ | |
| thumbnail = thumbnails[i] | |
| break | |
| } | |
| } | |
| } | |
| let newContent | |
| if(thumbnail){ | |
| const protocol = window.location.protocol | |
| const host = window.location.host | |
| const base_url = `${protocol}//${host}` | |
| const thumb_url = thumbnail.replace(':','%3A').replace(/\\/g,'/') | |
| newContent = $el("div.easyuse-model", {},[$el("span",{},content + ' *'),$el("img",{src:`${base_url}/${thumb_url}?t=${time}`})]) | |
| }else{ | |
| newContent = $el("div.easyuse-model", {},[ | |
| $el("span",{},content) | |
| ]) | |
| } | |
| return { | |
| content, | |
| title:newContent.outerHTML, | |
| callback: newCallback | |
| } | |
| } | |
| const newValues = []; | |
| const add_sub_folder = (folder, folderName) => { | |
| let subs = [] | |
| let less = [] | |
| const b = folder.map(name=> { | |
| const _folders = {}; | |
| const splitBy = name.indexOf('/') > -1 ? '/' : '\\'; | |
| const valueSplit = name.split(splitBy); | |
| if(valueSplit.length > 1){ | |
| const key = valueSplit.shift(); | |
| _folders[key] = _folders[key] || []; | |
| _folders[key].push(valueSplit.join(splitBy)); | |
| } | |
| const foldersCount = Object.values(folders).length; | |
| if(foldersCount > 0){ | |
| let key = Object.keys(_folders)[0] | |
| if(key && _folders[key]) subs.push({key, value:_folders[key][0]}) | |
| else{ | |
| less.push(addContent(name,key)) | |
| } | |
| } | |
| return addContent(name,folderName) | |
| }) | |
| if(subs.length>0){ | |
| let subs_obj = {} | |
| subs.forEach(item => { | |
| subs_obj[item.key] = subs_obj[item.key] || [] | |
| subs_obj[item.key].push(item.value) | |
| }) | |
| return [...Object.entries(subs_obj).map(f => { | |
| return { | |
| content: f[0], | |
| has_submenu: true, | |
| callback: () => {}, | |
| submenu: { | |
| options: add_sub_folder(f[1], f[0]), | |
| } | |
| } | |
| }),...less] | |
| } | |
| else return b | |
| } | |
| for(const [folderName,folder] of Object.entries(folders)){ | |
| newValues.push({ | |
| content:folderName, | |
| has_submenu:true, | |
| callback:() => {}, | |
| submenu:{ | |
| options:add_sub_folder(folder,folderName), | |
| } | |
| }); | |
| } | |
| newValues.push(...folderless.map(f => addContent(f, ''))); | |
| if(specialOps.length > 0) newValues.push(...specialOps.map(f => addContent(f, ''))); | |
| return existingContextMenu.call(this,newValues,options); | |
| } | |
| return existingContextMenu.apply(this,[...arguments]); | |
| } | |
| LiteGraph.ContextMenu.prototype = existingContextMenu.prototype; | |
| }, | |
| }) | |