mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
feat: replace nodeCreated with loadedGraphNode for LoraManager nodes
- Change lifecycle hook from nodeCreated to loadedGraphNode in Lora Loader, Lora Stacker, and TriggerWord Toggle nodes - Remove requestAnimationFrame wrappers as loadedGraphNode ensures proper initialization timing - Maintain same functionality for restoring saved values and widget initialization - Improves reliability by using the appropriate node lifecycle event
This commit is contained in:
@@ -229,20 +229,18 @@ app.registerExtension({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async nodeCreated(node) {
|
async loadedGraphNode(node) {
|
||||||
if (node.comfyClass == "Lora Loader (LoraManager)") {
|
if (node.comfyClass == "Lora Loader (LoraManager)") {
|
||||||
requestAnimationFrame(async () => {
|
// Restore saved value if exists
|
||||||
// Restore saved value if exists
|
let existingLoras = [];
|
||||||
let existingLoras = [];
|
if (node.widgets_values && node.widgets_values.length > 0) {
|
||||||
if (node.widgets_values && node.widgets_values.length > 0) {
|
// 0 for input widget, 1 for loras widget
|
||||||
// 0 for input widget, 1 for loras widget
|
const savedValue = node.widgets_values[1];
|
||||||
const savedValue = node.widgets_values[1];
|
existingLoras = savedValue || [];
|
||||||
existingLoras = savedValue || [];
|
}
|
||||||
}
|
// Merge the loras data
|
||||||
// Merge the loras data
|
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
|
||||||
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
|
node.lorasWidget.value = mergedLoras;
|
||||||
node.lorasWidget.value = mergedLoras;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -154,20 +154,18 @@ app.registerExtension({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async nodeCreated(node) {
|
async loadedGraphNode(node) {
|
||||||
if (node.comfyClass == "Lora Stacker (LoraManager)") {
|
if (node.comfyClass == "Lora Stacker (LoraManager)") {
|
||||||
requestAnimationFrame(async () => {
|
// Restore saved value if exists
|
||||||
// Restore saved value if exists
|
let existingLoras = [];
|
||||||
let existingLoras = [];
|
if (node.widgets_values && node.widgets_values.length > 0) {
|
||||||
if (node.widgets_values && node.widgets_values.length > 0) {
|
// 0 for input widget, 1 for loras widget
|
||||||
// 0 for input widget, 1 for loras widget
|
const savedValue = node.widgets_values[1];
|
||||||
const savedValue = node.widgets_values[1];
|
existingLoras = savedValue || [];
|
||||||
existingLoras = savedValue || [];
|
}
|
||||||
}
|
// Merge the loras data
|
||||||
// Merge the loras data
|
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
|
||||||
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
|
node.lorasWidget.value = mergedLoras;
|
||||||
node.lorasWidget.value = mergedLoras;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ app.registerExtension({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async nodeCreated(node) {
|
async loadedGraphNode(node) {
|
||||||
if (node.comfyClass === "TriggerWord Toggle (LoraManager)") {
|
if (node.comfyClass === "TriggerWord Toggle (LoraManager)") {
|
||||||
// Enable widget serialization
|
// Enable widget serialization
|
||||||
node.serialize_widgets = true;
|
node.serialize_widgets = true;
|
||||||
@@ -71,138 +71,135 @@ app.registerExtension({
|
|||||||
"shape": 7 // 7 is the shape of the optional input
|
"shape": 7 // 7 is the shape of the optional input
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for node to be properly initialized
|
// Get the wheel sensitivity setting
|
||||||
requestAnimationFrame(async () => {
|
const wheelSensitivity = getWheelSensitivity();
|
||||||
// Get the wheel sensitivity setting
|
|
||||||
const wheelSensitivity = getWheelSensitivity();
|
|
||||||
|
|
||||||
// Get the widget object directly from the returned object
|
// Get the widget object directly from the returned object
|
||||||
const result = addTagsWidget(node, "toggle_trigger_words", {
|
const result = addTagsWidget(node, "toggle_trigger_words", {
|
||||||
defaultVal: []
|
defaultVal: []
|
||||||
}, null, wheelSensitivity);
|
}, null, wheelSensitivity);
|
||||||
|
|
||||||
node.tagWidget = result.widget;
|
node.tagWidget = result.widget;
|
||||||
|
|
||||||
const normalizeTagText = (text) =>
|
const normalizeTagText = (text) =>
|
||||||
(typeof text === 'string' ? text.trim().toLowerCase() : '');
|
(typeof text === 'string' ? text.trim().toLowerCase() : '');
|
||||||
|
|
||||||
const collectHighlightTokens = (wordsArray) => {
|
const collectHighlightTokens = (wordsArray) => {
|
||||||
const tokens = new Set();
|
const tokens = new Set();
|
||||||
|
|
||||||
const addToken = (text) => {
|
const addToken = (text) => {
|
||||||
const normalized = normalizeTagText(text);
|
const normalized = normalizeTagText(text);
|
||||||
if (normalized) {
|
if (normalized) {
|
||||||
tokens.add(normalized);
|
tokens.add(normalized);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
wordsArray.forEach((rawWord) => {
|
|
||||||
if (typeof rawWord !== 'string') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addToken(rawWord);
|
|
||||||
|
|
||||||
const groupParts = rawWord.split(/,{2,}/);
|
|
||||||
groupParts.forEach((groupPart) => {
|
|
||||||
addToken(groupPart);
|
|
||||||
groupPart.split(',').forEach(addToken);
|
|
||||||
});
|
|
||||||
|
|
||||||
rawWord.split(',').forEach(addToken);
|
|
||||||
});
|
|
||||||
|
|
||||||
return tokens;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyHighlightState = () => {
|
wordsArray.forEach((rawWord) => {
|
||||||
if (!node.tagWidget) return;
|
if (typeof rawWord !== 'string') {
|
||||||
const highlightSet = node._highlightedTriggerWords || new Set();
|
return;
|
||||||
const updatedTags = (node.tagWidget.value || []).map(tag => ({
|
}
|
||||||
|
|
||||||
|
addToken(rawWord);
|
||||||
|
|
||||||
|
const groupParts = rawWord.split(/,{2,}/);
|
||||||
|
groupParts.forEach((groupPart) => {
|
||||||
|
addToken(groupPart);
|
||||||
|
groupPart.split(',').forEach(addToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
rawWord.split(',').forEach(addToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyHighlightState = () => {
|
||||||
|
if (!node.tagWidget) return;
|
||||||
|
const highlightSet = node._highlightedTriggerWords || new Set();
|
||||||
|
const updatedTags = (node.tagWidget.value || []).map(tag => ({
|
||||||
|
...tag,
|
||||||
|
highlighted: highlightSet.size > 0 && highlightSet.has(normalizeTagText(tag.text))
|
||||||
|
}));
|
||||||
|
node.tagWidget.value = updatedTags;
|
||||||
|
};
|
||||||
|
|
||||||
|
node.highlightTriggerWords = (triggerWords) => {
|
||||||
|
const wordsArray = Array.isArray(triggerWords)
|
||||||
|
? triggerWords
|
||||||
|
: triggerWords
|
||||||
|
? [triggerWords]
|
||||||
|
: [];
|
||||||
|
node._highlightedTriggerWords = collectHighlightTokens(wordsArray);
|
||||||
|
applyHighlightState();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (node.__pendingHighlightWords !== undefined) {
|
||||||
|
const pending = node.__pendingHighlightWords;
|
||||||
|
delete node.__pendingHighlightWords;
|
||||||
|
node.highlightTriggerWords(pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.applyTriggerHighlightState = applyHighlightState;
|
||||||
|
|
||||||
|
// Add hidden widget to store original message
|
||||||
|
const hiddenWidget = node.addWidget('text', 'orinalMessage', '');
|
||||||
|
hiddenWidget.type = CONVERTED_TYPE;
|
||||||
|
hiddenWidget.hidden = true;
|
||||||
|
hiddenWidget.computeSize = () => [0, -4];
|
||||||
|
|
||||||
|
// Restore saved value if exists
|
||||||
|
if (node.widgets_values && node.widgets_values.length > 0) {
|
||||||
|
// 0 is group mode, 1 is default_active, 2 is tag widget, 3 is original message
|
||||||
|
const savedValue = node.widgets_values[2];
|
||||||
|
if (savedValue) {
|
||||||
|
result.widget.value = Array.isArray(savedValue) ? savedValue : [];
|
||||||
|
}
|
||||||
|
const originalMessage = node.widgets_values[3];
|
||||||
|
if (originalMessage) {
|
||||||
|
hiddenWidget.value = originalMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(() => node.applyTriggerHighlightState?.());
|
||||||
|
|
||||||
|
const groupModeWidget = node.widgets[0];
|
||||||
|
groupModeWidget.callback = (value) => {
|
||||||
|
if (node.widgets[3].value) {
|
||||||
|
this.updateTagsBasedOnMode(node, node.widgets[3].value, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add callback for default_active widget
|
||||||
|
const defaultActiveWidget = node.widgets[1];
|
||||||
|
defaultActiveWidget.callback = (value) => {
|
||||||
|
// Set all existing tags' active state to the new value
|
||||||
|
if (node.tagWidget && node.tagWidget.value) {
|
||||||
|
const updatedTags = node.tagWidget.value.map(tag => ({
|
||||||
...tag,
|
...tag,
|
||||||
highlighted: highlightSet.size > 0 && highlightSet.has(normalizeTagText(tag.text))
|
active: value
|
||||||
}));
|
}));
|
||||||
node.tagWidget.value = updatedTags;
|
node.tagWidget.value = updatedTags;
|
||||||
};
|
node.applyTriggerHighlightState?.();
|
||||||
|
|
||||||
node.highlightTriggerWords = (triggerWords) => {
|
|
||||||
const wordsArray = Array.isArray(triggerWords)
|
|
||||||
? triggerWords
|
|
||||||
: triggerWords
|
|
||||||
? [triggerWords]
|
|
||||||
: [];
|
|
||||||
node._highlightedTriggerWords = collectHighlightTokens(wordsArray);
|
|
||||||
applyHighlightState();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (node.__pendingHighlightWords !== undefined) {
|
|
||||||
const pending = node.__pendingHighlightWords;
|
|
||||||
delete node.__pendingHighlightWords;
|
|
||||||
node.highlightTriggerWords(pending);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node.applyTriggerHighlightState = applyHighlightState;
|
// Override the serializeValue method to properly format trigger words with strength
|
||||||
|
const originalSerializeValue = result.widget.serializeValue;
|
||||||
// Add hidden widget to store original message
|
result.widget.serializeValue = function() {
|
||||||
const hiddenWidget = node.addWidget('text', 'orinalMessage', '');
|
const value = this.value || [];
|
||||||
hiddenWidget.type = CONVERTED_TYPE;
|
// Transform the values to include strength in the proper format
|
||||||
hiddenWidget.hidden = true;
|
const transformedValue = value.map(tag => {
|
||||||
hiddenWidget.computeSize = () => [0, -4];
|
// If strength is defined (even if it's 1.0), format as {text: "(original_text:strength)", ...}
|
||||||
|
if (tag.strength !== undefined && tag.strength !== null) {
|
||||||
// Restore saved value if exists
|
return {
|
||||||
if (node.widgets_values && node.widgets_values.length > 0) {
|
|
||||||
// 0 is group mode, 1 is default_active, 2 is tag widget, 3 is original message
|
|
||||||
const savedValue = node.widgets_values[2];
|
|
||||||
if (savedValue) {
|
|
||||||
result.widget.value = Array.isArray(savedValue) ? savedValue : [];
|
|
||||||
}
|
|
||||||
const originalMessage = node.widgets_values[3];
|
|
||||||
if (originalMessage) {
|
|
||||||
hiddenWidget.value = originalMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requestAnimationFrame(() => node.applyTriggerHighlightState?.());
|
|
||||||
|
|
||||||
const groupModeWidget = node.widgets[0];
|
|
||||||
groupModeWidget.callback = (value) => {
|
|
||||||
if (node.widgets[3].value) {
|
|
||||||
this.updateTagsBasedOnMode(node, node.widgets[3].value, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add callback for default_active widget
|
|
||||||
const defaultActiveWidget = node.widgets[1];
|
|
||||||
defaultActiveWidget.callback = (value) => {
|
|
||||||
// Set all existing tags' active state to the new value
|
|
||||||
if (node.tagWidget && node.tagWidget.value) {
|
|
||||||
const updatedTags = node.tagWidget.value.map(tag => ({
|
|
||||||
...tag,
|
...tag,
|
||||||
active: value
|
text: `(${tag.text}:${tag.strength.toFixed(2)})`
|
||||||
}));
|
};
|
||||||
node.tagWidget.value = updatedTags;
|
|
||||||
node.applyTriggerHighlightState?.();
|
|
||||||
}
|
}
|
||||||
}
|
return tag;
|
||||||
|
});
|
||||||
// Override the serializeValue method to properly format trigger words with strength
|
return transformedValue;
|
||||||
const originalSerializeValue = result.widget.serializeValue;
|
};
|
||||||
result.widget.serializeValue = function() {
|
|
||||||
const value = this.value || [];
|
|
||||||
// Transform the values to include strength in the proper format
|
|
||||||
const transformedValue = value.map(tag => {
|
|
||||||
// If strength is defined (even if it's 1.0), format as {text: "(original_text:strength)", ...}
|
|
||||||
if (tag.strength !== undefined && tag.strength !== null) {
|
|
||||||
return {
|
|
||||||
...tag,
|
|
||||||
text: `(${tag.text}:${tag.strength.toFixed(2)})`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return tag;
|
|
||||||
});
|
|
||||||
return transformedValue;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -107,20 +107,18 @@ app.registerExtension({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async nodeCreated(node) {
|
async loadedGraphNode(node) {
|
||||||
if (node.comfyClass == "WanVideo Lora Select (LoraManager)") {
|
if (node.comfyClass == "WanVideo Lora Select (LoraManager)") {
|
||||||
requestAnimationFrame(async () => {
|
// Restore saved value if exists
|
||||||
// Restore saved value if exists
|
let existingLoras = [];
|
||||||
let existingLoras = [];
|
if (node.widgets_values && node.widgets_values.length > 0) {
|
||||||
if (node.widgets_values && node.widgets_values.length > 0) {
|
// 0 for low_mem_load, 1 for merge_loras, 2 for text widget, 3 for loras widget
|
||||||
// 0 for low_mem_load, 1 for merge_loras, 2 for text widget, 3 for loras widget
|
const savedValue = node.widgets_values[3];
|
||||||
const savedValue = node.widgets_values[3];
|
existingLoras = savedValue || [];
|
||||||
existingLoras = savedValue || [];
|
}
|
||||||
}
|
// Merge the loras data
|
||||||
// Merge the loras data
|
const mergedLoras = mergeLoras(node.widgets[2].value, existingLoras);
|
||||||
const mergedLoras = mergeLoras(node.widgets[2].value, existingLoras);
|
node.lorasWidget.value = mergedLoras;
|
||||||
node.lorasWidget.value = mergedLoras;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user