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:
Will Miao
2025-11-08 14:08:43 +08:00
parent c14e066f8f
commit 2e6aa5fe9f
4 changed files with 152 additions and 161 deletions

View File

@@ -229,20 +229,18 @@ app.registerExtension({
}
},
async nodeCreated(node) {
async loadedGraphNode(node) {
if (node.comfyClass == "Lora Loader (LoraManager)") {
requestAnimationFrame(async () => {
// Restore saved value if exists
let existingLoras = [];
if (node.widgets_values && node.widgets_values.length > 0) {
// 0 for input widget, 1 for loras widget
const savedValue = node.widgets_values[1];
existingLoras = savedValue || [];
}
// Merge the loras data
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
node.lorasWidget.value = mergedLoras;
});
// Restore saved value if exists
let existingLoras = [];
if (node.widgets_values && node.widgets_values.length > 0) {
// 0 for input widget, 1 for loras widget
const savedValue = node.widgets_values[1];
existingLoras = savedValue || [];
}
// Merge the loras data
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
node.lorasWidget.value = mergedLoras;
}
},
});

View File

@@ -154,20 +154,18 @@ app.registerExtension({
});
}
},
async nodeCreated(node) {
async loadedGraphNode(node) {
if (node.comfyClass == "Lora Stacker (LoraManager)") {
requestAnimationFrame(async () => {
// Restore saved value if exists
let existingLoras = [];
if (node.widgets_values && node.widgets_values.length > 0) {
// 0 for input widget, 1 for loras widget
const savedValue = node.widgets_values[1];
existingLoras = savedValue || [];
}
// Merge the loras data
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
node.lorasWidget.value = mergedLoras;
});
// Restore saved value if exists
let existingLoras = [];
if (node.widgets_values && node.widgets_values.length > 0) {
// 0 for input widget, 1 for loras widget
const savedValue = node.widgets_values[1];
existingLoras = savedValue || [];
}
// Merge the loras data
const mergedLoras = mergeLoras(node.widgets[0].value, existingLoras);
node.lorasWidget.value = mergedLoras;
}
},
});

View File

@@ -62,7 +62,7 @@ app.registerExtension({
});
},
async nodeCreated(node) {
async loadedGraphNode(node) {
if (node.comfyClass === "TriggerWord Toggle (LoraManager)") {
// Enable widget serialization
node.serialize_widgets = true;
@@ -71,138 +71,135 @@ app.registerExtension({
"shape": 7 // 7 is the shape of the optional input
});
// Wait for node to be properly initialized
requestAnimationFrame(async () => {
// Get the wheel sensitivity setting
const wheelSensitivity = getWheelSensitivity();
// Get the widget object directly from the returned object
const result = addTagsWidget(node, "toggle_trigger_words", {
defaultVal: []
}, null, wheelSensitivity);
node.tagWidget = result.widget;
// Get the wheel sensitivity setting
const wheelSensitivity = getWheelSensitivity();
// Get the widget object directly from the returned object
const result = addTagsWidget(node, "toggle_trigger_words", {
defaultVal: []
}, null, wheelSensitivity);
node.tagWidget = result.widget;
const normalizeTagText = (text) =>
(typeof text === 'string' ? text.trim().toLowerCase() : '');
const normalizeTagText = (text) =>
(typeof text === 'string' ? text.trim().toLowerCase() : '');
const collectHighlightTokens = (wordsArray) => {
const tokens = new Set();
const collectHighlightTokens = (wordsArray) => {
const tokens = new Set();
const addToken = (text) => {
const normalized = normalizeTagText(text);
if (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 addToken = (text) => {
const normalized = normalizeTagText(text);
if (normalized) {
tokens.add(normalized);
}
};
const applyHighlightState = () => {
if (!node.tagWidget) return;
const highlightSet = node._highlightedTriggerWords || new Set();
const updatedTags = (node.tagWidget.value || []).map(tag => ({
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 = () => {
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,
highlighted: highlightSet.size > 0 && highlightSet.has(normalizeTagText(tag.text))
active: value
}));
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?.();
}
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 => ({
}
// Override the serializeValue method to properly format trigger words with strength
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,
active: value
}));
node.tagWidget.value = updatedTags;
node.applyTriggerHighlightState?.();
text: `(${tag.text}:${tag.strength.toFixed(2)})`
};
}
}
// Override the serializeValue method to properly format trigger words with strength
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;
};
});
return tag;
});
return transformedValue;
};
}
},

View File

@@ -107,20 +107,18 @@ app.registerExtension({
});
}
},
async nodeCreated(node) {
async loadedGraphNode(node) {
if (node.comfyClass == "WanVideo Lora Select (LoraManager)") {
requestAnimationFrame(async () => {
// Restore saved value if exists
let existingLoras = [];
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
const savedValue = node.widgets_values[3];
existingLoras = savedValue || [];
}
// Merge the loras data
const mergedLoras = mergeLoras(node.widgets[2].value, existingLoras);
node.lorasWidget.value = mergedLoras;
});
// Restore saved value if exists
let existingLoras = [];
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
const savedValue = node.widgets_values[3];
existingLoras = savedValue || [];
}
// Merge the loras data
const mergedLoras = mergeLoras(node.widgets[2].value, existingLoras);
node.lorasWidget.value = mergedLoras;
}
},
});