mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 23:25:43 -03:00
fix: enable autocomplete in Vue DOM render mode
In Vue DOM render mode, widget.inputEl is not in the DOM, causing autocomplete to fail. This commit: - Adds findWidgetInputElement() helper to search DOM for actual input elements - Checks if widget.inputEl is in document before using it - Falls back to DOM search for Vue-rendered widgets using .lg-node-widget containers - Implements async initialization with retry logic (20 attempts, 50ms interval) - Adds debug logging for troubleshooting - Prevents duplicate initialization with isInitializing flag Fixes autocomplete functionality for Lora Loader nodes when ComfyUI uses Vue DOM rendering instead of canvas rendering.
This commit is contained in:
@@ -387,6 +387,58 @@ export function mergeLoras(lorasText, lorasArr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the actual input element for a widget
|
||||||
|
* @param {Object} node - The node instance
|
||||||
|
* @param {Object} widget - The widget to find input element for
|
||||||
|
* @returns {Promise<HTMLElement|null>} The input element or null
|
||||||
|
*/
|
||||||
|
async function findWidgetInputElement(node, widget) {
|
||||||
|
if (widget.inputEl && document.body.contains(widget.inputEl)) {
|
||||||
|
return widget.inputEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeId = node.id;
|
||||||
|
const widgetName = widget.name;
|
||||||
|
const maxAttempts = 20;
|
||||||
|
const searchInterval = 50;
|
||||||
|
|
||||||
|
const searchForInput = (attempt = 0) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const doSearch = () => {
|
||||||
|
let inputElement = null;
|
||||||
|
|
||||||
|
const allWidgetContainers = document.querySelectorAll('.lg-node-widget');
|
||||||
|
|
||||||
|
for (const container of allWidgetContainers) {
|
||||||
|
const hasInput = !!container.querySelector('input, textarea');
|
||||||
|
const textContent = container.textContent.toLowerCase();
|
||||||
|
const containsWidgetName = textContent.includes(widgetName.toLowerCase());
|
||||||
|
const containsNodeTitle = textContent.includes(node.title?.toLowerCase() || '');
|
||||||
|
|
||||||
|
if (hasInput && (containsWidgetName || (widgetName === 'text' && container.querySelector('textarea')))) {
|
||||||
|
inputElement = container.querySelector('input, textarea');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputElement) {
|
||||||
|
console.log(`[Lora Manager] Found input element for widget "${widgetName}" on node ${nodeId}`);
|
||||||
|
resolve(inputElement);
|
||||||
|
} else if (attempt < maxAttempts) {
|
||||||
|
setTimeout(() => searchForInput(attempt + 1).then(resolve), searchInterval);
|
||||||
|
} else {
|
||||||
|
console.warn(`[Lora Manager] Could not find input element for widget "${widgetName}" on node ${nodeId} after ${maxAttempts} attempts`);
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
doSearch();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return searchForInput();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize autocomplete for an input widget and setup cleanup
|
* Initialize autocomplete for an input widget and setup cleanup
|
||||||
* @param {Object} node - The node instance
|
* @param {Object} node - The node instance
|
||||||
@@ -398,6 +450,7 @@ export function mergeLoras(lorasText, lorasArr) {
|
|||||||
*/
|
*/
|
||||||
export function setupInputWidgetWithAutocomplete(node, inputWidget, originalCallback, modelType = 'loras', autocompleteOptions = {}) {
|
export function setupInputWidgetWithAutocomplete(node, inputWidget, originalCallback, modelType = 'loras', autocompleteOptions = {}) {
|
||||||
let autocomplete = null;
|
let autocomplete = null;
|
||||||
|
let isInitializing = false;
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
maxItems: 20,
|
maxItems: 20,
|
||||||
minChars: 1,
|
minChars: 1,
|
||||||
@@ -405,22 +458,45 @@ export function setupInputWidgetWithAutocomplete(node, inputWidget, originalCall
|
|||||||
};
|
};
|
||||||
const mergedOptions = { ...defaultOptions, ...autocompleteOptions };
|
const mergedOptions = { ...defaultOptions, ...autocompleteOptions };
|
||||||
|
|
||||||
// Enhanced callback that initializes autocomplete and calls original callback
|
const initializeAutocomplete = async () => {
|
||||||
const enhancedCallback = (value) => {
|
if (autocomplete || isInitializing) return;
|
||||||
// Initialize autocomplete on first callback if not already done
|
isInitializing = true;
|
||||||
if (!autocomplete && inputWidget.inputEl) {
|
|
||||||
autocomplete = new AutoComplete(inputWidget.inputEl, modelType, mergedOptions);
|
try {
|
||||||
// Store reference for cleanup
|
let inputElement = null;
|
||||||
node.autocomplete = autocomplete;
|
|
||||||
|
if (inputWidget.inputEl && document.body.contains(inputWidget.inputEl)) {
|
||||||
|
inputElement = inputWidget.inputEl;
|
||||||
|
console.log(`[Lora Manager] Using widget.inputEl for widget "${inputWidget.name}"`);
|
||||||
|
} else {
|
||||||
|
console.log(`[Lora Manager] Searching DOM for input element for widget "${inputWidget.name}"`);
|
||||||
|
inputElement = await findWidgetInputElement(node, inputWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputElement) {
|
||||||
|
autocomplete = new AutoComplete(inputElement, modelType, mergedOptions);
|
||||||
|
node.autocomplete = autocomplete;
|
||||||
|
console.log(`[Lora Manager] Autocomplete initialized for widget "${inputWidget.name}" on node ${node.id}`);
|
||||||
|
} else {
|
||||||
|
console.warn(`[Lora Manager] Could not find input element for widget "${inputWidget.name}" on node ${node.id}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Lora Manager] Error initializing autocomplete:', error);
|
||||||
|
} finally {
|
||||||
|
isInitializing = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const enhancedCallback = (value) => {
|
||||||
|
if (!autocomplete && !isInitializing) {
|
||||||
|
initializeAutocomplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the original callback
|
|
||||||
if (typeof originalCallback === "function") {
|
if (typeof originalCallback === "function") {
|
||||||
originalCallback.call(node, value);
|
originalCallback.call(node, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup cleanup on node removal
|
|
||||||
setupAutocompleteCleanup(node);
|
setupAutocompleteCleanup(node);
|
||||||
|
|
||||||
return enhancedCallback;
|
return enhancedCallback;
|
||||||
|
|||||||
Reference in New Issue
Block a user