// Global variables window.weilinGlobalSelectedLoras = []; // 添加标志避免循环更新 let isUpdatingFromVue = false; // Handle window messages - 用于同步Vue窗口的数据 function handleWindowMessage(event) { // 监听来自Vue窗口的更新消息 if (event.data.type && event.data.type.startsWith('weilin_prompt_ui_prompt_node_finish_lora_stack_')) { const seed = event.data.type.replace('weilin_prompt_ui_prompt_node_finish_lora_stack_', ''); if (event.data.data) { try { const jsonStr = JSON.parse(event.data.data); // 设置标志,避免循环更新 isUpdatingFromVue = true; // 更新全局数据 if (jsonStr.temp_lora && jsonStr.temp_lora.length > 0) { window.weilinGlobalSelectedLoras[seed] = jsonStr.temp_lora; } else if (jsonStr.lora && jsonStr.lora.length > 0) { window.weilinGlobalSelectedLoras[seed] = jsonStr.lora; } else { window.weilinGlobalSelectedLoras[seed] = []; } // 重新渲染 renderAllLoras(seed); // 重置标志 setTimeout(() => { isUpdatingFromVue = false; }, 100); } catch (e) { console.error('[weilin-comfyui] 解析Vue窗口lora数据失败:', e); isUpdatingFromVue = false; } } } // 兼容旧的消息类型 if (event.data.type === 'weilin_prompt_ui_node_lora_stack_update_lora_stack') { const seed = event.data.seed; renderAllLoras(seed); } } // 注册消息监听器 window.addEventListener('message', handleWindowMessage); // Open Lora Manager function openLoraManager(buttonElement) { // 确保参数是DOM元素而不是事件对象 const element = buttonElement && buttonElement.target ? buttonElement.currentTarget : buttonElement; if (!element) { console.warn('[weilin-comfyui] openLoraManager: Invalid button element'); return; } const seed = element.getAttribute("data-seed"); if (!seed) { console.warn('[weilin-comfyui] openLoraManager: No seed found on button'); return; } // console.log(seed) window.postMessage({ type: 'weilin_prompt_ui_openLoraManager_addLora_stack_node', seed: seed }, '*'); } // Add a new Lora function addLora(seed, lora) { // Initialize array if not exists if (!window.weilinGlobalSelectedLoras[seed]) { window.weilinGlobalSelectedLoras[seed] = []; } // Check if already exists if (!window.weilinGlobalSelectedLoras[seed].some(item => item.name === lora.name)) { // Ensure defaults are 1 and override any incoming 0.5 const newLora = { name: lora.name, weight: 1, text_encoder_weight: 1, hidden: false, ...lora, }; window.weilinGlobalSelectedLoras[seed].push(newLora); renderAllLoras(seed); updateLoraStackInfoToWindows(seed); } } // Remove a Lora function removeLora(seed, index) { if (index > -1 && window.weilinGlobalSelectedLoras[seed]) { // console.log(index) window.weilinGlobalSelectedLoras[seed].splice(index, 1); renderAllLoras(seed); updateLoraStackInfoToWindows(seed); } } // Toggle Lora visibility function toggleHideLora(seed, index) { if (index > -1 && window.weilinGlobalSelectedLoras[seed] && window.weilinGlobalSelectedLoras[seed][index]) { const lora = window.weilinGlobalSelectedLoras[seed][index]; lora.hidden = !lora.hidden; updateLoraStackInfoToWindows(seed); } } // 语言检测函数 function getSystemLanguage() { const lang = navigator.language || navigator.userLanguage; return lang.startsWith('zh') ? 'zh' : 'en'; } // 修改renderLoraItem函数中的HTML结构 // 修改renderLoraItem函数中的HTML结构 function renderLoraItem(seed, index, lora) { const loraListContainer = document.getElementById('loraListContainer_' + seed); const loraItem = document.createElement('div'); loraItem.className = `weilin-comfyui-lora-item ${lora.hidden ? 'weilin-comfyui-hidden-lora' : ''}`; loraItem.id = `weilin-comfyui-lora-item-${seed}-${index}`; loraItem.setAttribute('data-index', index.toString()); const displayName = lora.display_name || lora.name || lora.lora; loraItem.innerHTML = `
${displayName}
`; // 只在拖拽把手上添加拖拽事件 const dragHandle = loraItem.querySelector('.weilin-comfyui-drag-handle'); dragHandle.addEventListener('dragstart', (e) => handleDragStart(e, seed, index)); dragHandle.addEventListener('dragend', handleDragEnd); dragHandle.addEventListener('mousedown', (e) => { e.stopPropagation(); }); loraItem.querySelector('.weilin-comfyui-look-on-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); lookOnLora(lora.lora); }); loraItem.querySelector('.weilin-comfyui-look-on-btn').addEventListener('mousedown', (e) => { e.stopPropagation(); }); loraItem.querySelector('.weilin-comfyui-look-on-btn').addEventListener('mouseup', (e) => { e.stopPropagation(); }); loraItem.querySelector('.weilin-comfyui-remove-btn').addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); removeLora(seed, index); }); loraItem.querySelector('.weilin-comfyui-remove-btn').addEventListener('mousedown', (e) => { e.stopPropagation(); }); loraItem.querySelector('.weilin-comfyui-remove-btn').addEventListener('mouseup', (e) => { e.stopPropagation(); }); const weightInputs = loraItem.querySelectorAll('.weilin-comfyui-lora-weight'); weightInputs.forEach(input => { input.addEventListener('mousedown', (e) => { e.stopPropagation(); }); input.addEventListener('dragstart', (e) => { e.preventDefault(); e.stopPropagation(); }); input.addEventListener('change', (e) => { const lora = window.weilinGlobalSelectedLoras[seed][index]; if (lora) { if (input.id.startsWith('model-weight')) { lora.weight = parseFloat(e.target.value); } else if (input.id.startsWith('text-encoder-weight')) { lora.text_encoder_weight = parseFloat(e.target.value); } updateLoraStackInfoToWindows(seed); } }); }); // 防止点击 LoRA 项时触发其他事件(如 LiteGraph 的节点选择) loraItem.addEventListener('mousedown', (e) => { e.stopPropagation(); }); loraItem.addEventListener('mouseup', (e) => { e.stopPropagation(); }); loraItem.addEventListener('click', (e) => { e.stopPropagation(); }); loraListContainer.appendChild(loraItem); // 其余代码保持不变... if (!lora.display_name && lora.lora) { try { fetch(`/weilin/prompt_ui/api/lorainfo/api/loras/info?file=${encodeURIComponent(lora.lora)}`) .then(r => r.json()) .then(data => { const info = data && (data.data || data); if (info && info.name) { lora.display_name = info.name; const nameEl = loraItem.querySelector('.weilin-comfyui-lora-name'); if (nameEl) { nameEl.textContent = info.name; nameEl.setAttribute('title', info.name); } updateLoraStackInfoToWindows(seed); } }) .catch(() => { /* ignore network errors */ }); } catch (e) { /* ignore */ } } const visToggle = loraItem.querySelector(`#visible-toggle-${seed}-${index}`); if (visToggle) { visToggle.addEventListener('change', (e) => { const loraRef = window.weilinGlobalSelectedLoras[seed][index]; if (loraRef) { loraRef.hidden = !e.target.checked; renderAllLoras(seed); updateLoraStackInfoToWindows(seed); } }); } loraItem.querySelector('.weilin-comfyui-look-on-btn').addEventListener('mousedown', (e) => { e.stopPropagation(); }); loraItem.querySelector('.weilin-comfyui-remove-btn').addEventListener('mousedown', (e) => { e.stopPropagation(); }); } // 修改handleDragStart函数,从把手获取父元素信息 function handleDragStart(e, seed, index) { draggedIndex = index; const loraItem = e.target.closest('.weilin-comfyui-lora-item'); loraItem.classList.add('weilin-comfyui-dragging'); e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', loraItem.outerHTML); } // Get hide button content function getHideButtonContent(hidden) { return hidden ? ` ` : ` `; } // Look on Lora function lookOnLora(lora) { window.postMessage({ type: 'weilin_prompt_ui_openLoraDetail', lora: lora }, '*'); } // Initialize Lora Stack function initLoraStack() { window.postMessage({ type: 'weilin_prompt_ui_node_lora_stack_get_lora_info', seed: seed }, '*'); } // Render all Lora items function renderAllLoras(seed) { const loraListContainer = document.getElementById('loraListContainer_' + seed); if (!loraListContainer) { return; } loraListContainer.innerHTML = ''; // 移除旧的容器事件监听器(避免重复绑定) loraListContainer.removeEventListener('dragover', handleContainerDragOver); loraListContainer.removeEventListener('drop', handleContainerDrop); // 在容器上绑定拖放事件 loraListContainer.addEventListener('dragover', (e) => handleContainerDragOver(e, seed)); loraListContainer.addEventListener('drop', (e) => handleContainerDrop(e, seed)); const list = window.weilinGlobalSelectedLoras[seed] || []; list.forEach((lora, index) => { renderLoraItem(seed, index, lora); }); } // Update Lora stack info to windows function updateLoraStackInfoToWindows(seed) { // 如果是从Vue窗口更新触发的,不发送消息,避免循环 if (isUpdatingFromVue) { return; } // Ensure array exists if (!window.weilinGlobalSelectedLoras[seed]) { window.weilinGlobalSelectedLoras[seed] = []; } let putJson = { lora: "", temp_lora: window.weilinGlobalSelectedLoras[seed] }; const tempLora = window.weilinGlobalSelectedLoras[seed].filter(lora => !lora.hidden); if (tempLora.length > 0) { putJson.lora = tempLora; } const jsonStr = JSON.stringify(putJson); window.postMessage({ type: 'weilin_prompt_ui_prompt_node_finish_lora_stack_' + seed, data: jsonStr }, '*'); } let draggedIndex = null; let placeholder = null; let insertIndex = null; function handleDragStart(e, seed, index) { draggedIndex = index; e.target.classList.add('dragging'); e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', e.target.outerHTML); } function handleDragOver(e) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; let target = e.target; while (target && !target.classList.contains('weilin-comfyui-lora-item')) { target = target.parentElement; } if (!target || target.classList.contains('dragging')) return; const container = target.parentElement; const rect = target.getBoundingClientRect(); const mouseY = e.clientY; const elementMiddle = rect.top + rect.height / 2; // 简化索引计算:直接基于DOM顺序 const allItems = Array.from(container.querySelectorAll('.weilin-comfyui-lora-item:not(.weilin-comfyui-dragging)')); const targetIndex = allItems.indexOf(target); let newInsertIndex; if (mouseY < elementMiddle) { newInsertIndex = targetIndex; } else { newInsertIndex = targetIndex + 1; } if (newInsertIndex === insertIndex) return; insertIndex = newInsertIndex; removePlaceholderAndShifts(); createPlaceholder(); // 在DOM中插入占位框 if (insertIndex >= allItems.length) { container.appendChild(placeholder); } else { container.insertBefore(placeholder, allItems[insertIndex]); } } function createPlaceholder() { placeholder = document.createElement('div'); placeholder.className = 'weilin-comfyui-lora-placeholder'; placeholder.innerHTML = '放置位置'; } function removePlaceholderAndShifts() { if (placeholder && placeholder.parentElement) { placeholder.parentElement.removeChild(placeholder); } document.querySelectorAll('.weilin-comfyui-lora-item').forEach(item => { item.classList.remove('weilin-comfyui-shift-down'); }); } function addShiftEffects(container, insertPos) { // 这个函数可以添加让开位置的动画效果 // 暂时简化处理,主要依靠占位框显示插入位置 } function handleDrop(e, seed) { e.preventDefault(); if (draggedIndex !== null && insertIndex !== null) { const list = window.weilinGlobalSelectedLoras[seed]; if (draggedIndex >= 0 && draggedIndex < list.length) { const draggedItem = list[draggedIndex]; // 先移除被拖动的元素 list.splice(draggedIndex, 1); // 计算实际插入位置 let finalIndex = insertIndex; if (insertIndex > draggedIndex) { finalIndex--; } // 插入到新位置 list.splice(finalIndex, 0, draggedItem); renderAllLoras(seed); updateLoraStackInfoToWindows(seed); } } // 清理 removePlaceholderAndShifts(); draggedIndex = null; insertIndex = null; placeholder = null; } function handleDragEnd(e) { e.target.classList.remove('dragging'); removePlaceholderAndShifts(); draggedIndex = null; insertIndex = null; } function handleContainerDragOver(e, seed) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; const container = e.currentTarget; const mouseY = e.clientY; // 找到最近的 lora-item const allItems = Array.from(container.querySelectorAll('.weilin-comfyui-lora-item:not(.weilin-comfyui-dragging)')); let targetItem = null; let insertPosition = allItems.length; // 默认插入到最后 for (let i = 0; i < allItems.length; i++) { const item = allItems[i]; const rect = item.getBoundingClientRect(); const itemMiddle = rect.top + rect.height / 2; if (mouseY < itemMiddle) { targetItem = item; insertPosition = i; break; } } if (insertPosition === insertIndex) return; insertIndex = insertPosition; removePlaceholderAndShifts(); createPlaceholder(); // 插入占位框 if (insertIndex >= allItems.length) { container.appendChild(placeholder); } else { container.insertBefore(placeholder, allItems[insertIndex]); } } function handleContainerDrop(e, seed) { e.preventDefault(); if (draggedIndex !== null && placeholder && placeholder.parentElement) { const container = placeholder.parentElement; // 计算占位框前面有多少个非拖动的lora-item let actualInsertIndex = 0; let currentNode = placeholder.previousElementSibling; while (currentNode) { if (currentNode.classList.contains('weilin-comfyui-lora-item') && !currentNode.classList.contains('weilin-comfyui-dragging')) { actualInsertIndex++; } currentNode = currentNode.previousElementSibling; } const list = window.weilinGlobalSelectedLoras[seed]; if (draggedIndex >= 0 && draggedIndex < list.length) { const draggedItem = list[draggedIndex]; list.splice(draggedIndex, 1); list.splice(actualInsertIndex, 0, draggedItem); renderAllLoras(seed); updateLoraStackInfoToWindows(seed); } } removePlaceholderAndShifts(); insertIndex = null; }