mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
refactor: Simplify TriggerWord Toggle node height handling
- Remove max height setting, let ComfyUI handle widget sizing - Widget now uses getMinHeight() to declare 150px minimum - Container fills available space with overflow: auto for scrollbars - Users can freely resize the node; content overflows show scrollbar - Simplified renderTags by removing height calculation logic Fixes #706
This commit is contained in:
@@ -7,9 +7,6 @@ import { app } from "../../scripts/app.js";
|
|||||||
const TRIGGER_WORD_WHEEL_SENSITIVITY_ID = "loramanager.trigger_word_wheel_sensitivity";
|
const TRIGGER_WORD_WHEEL_SENSITIVITY_ID = "loramanager.trigger_word_wheel_sensitivity";
|
||||||
const TRIGGER_WORD_WHEEL_SENSITIVITY_DEFAULT = 0.02;
|
const TRIGGER_WORD_WHEEL_SENSITIVITY_DEFAULT = 0.02;
|
||||||
|
|
||||||
const TRIGGER_WORD_MAX_HEIGHT_ID = "loramanager.trigger_word_max_height";
|
|
||||||
const TRIGGER_WORD_MAX_HEIGHT_DEFAULT = 300;
|
|
||||||
|
|
||||||
const AUTO_PATH_CORRECTION_SETTING_ID = "loramanager.auto_path_correction";
|
const AUTO_PATH_CORRECTION_SETTING_ID = "loramanager.auto_path_correction";
|
||||||
const AUTO_PATH_CORRECTION_DEFAULT = true;
|
const AUTO_PATH_CORRECTION_DEFAULT = true;
|
||||||
|
|
||||||
@@ -171,50 +168,11 @@ app.registerExtension({
|
|||||||
tooltip: "When enabled, tag names with underscores will have them replaced with spaces when inserted (e.g., 'blonde_hair' becomes 'blonde hair').",
|
tooltip: "When enabled, tag names with underscores will have them replaced with spaces when inserted (e.g., 'blonde_hair' becomes 'blonde hair').",
|
||||||
category: ["LoRA Manager", "Autocomplete", "Tag Formatting"],
|
category: ["LoRA Manager", "Autocomplete", "Tag Formatting"],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: TRIGGER_WORD_MAX_HEIGHT_ID,
|
|
||||||
name: "Trigger Word Toggle Max Height",
|
|
||||||
type: "slider",
|
|
||||||
attrs: {
|
|
||||||
min: 150,
|
|
||||||
max: 600,
|
|
||||||
step: 10,
|
|
||||||
},
|
|
||||||
defaultValue: TRIGGER_WORD_MAX_HEIGHT_DEFAULT,
|
|
||||||
tooltip: "Maximum height (in pixels) for the Trigger Word Toggle node. Content exceeding this height will be scrollable. Note: Requires page reload to take effect.",
|
|
||||||
category: ["LoRA Manager", "Trigger Word Toggle", "Max Height"],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const getTriggerWordMaxHeight = (() => {
|
|
||||||
let settingsUnavailableLogged = false;
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
const settingManager = app?.extensionManager?.setting;
|
|
||||||
if (!settingManager || typeof settingManager.get !== "function") {
|
|
||||||
if (!settingsUnavailableLogged) {
|
|
||||||
console.warn("LoRA Manager: settings API unavailable, using default max height.");
|
|
||||||
settingsUnavailableLogged = true;
|
|
||||||
}
|
|
||||||
return TRIGGER_WORD_MAX_HEIGHT_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const value = settingManager.get(TRIGGER_WORD_MAX_HEIGHT_ID);
|
|
||||||
return value ?? TRIGGER_WORD_MAX_HEIGHT_DEFAULT;
|
|
||||||
} catch (error) {
|
|
||||||
if (!settingsUnavailableLogged) {
|
|
||||||
console.warn("LoRA Manager: unable to read max height setting, using default.", error);
|
|
||||||
settingsUnavailableLogged = true;
|
|
||||||
}
|
|
||||||
return TRIGGER_WORD_MAX_HEIGHT_DEFAULT;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Exports
|
// Exports
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export { getWheelSensitivity, getAutoPathCorrectionPreference, getPromptTagAutocompletePreference, getTagSpaceReplacementPreference, getTriggerWordMaxHeight };
|
export { getWheelSensitivity, getAutoPathCorrectionPreference, getPromptTagAutocompletePreference, getTagSpaceReplacementPreference };
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { forwardMiddleMouseToCanvas } from "./utils.js";
|
import { forwardMiddleMouseToCanvas } from "./utils.js";
|
||||||
import { getTriggerWordMaxHeight } from "./settings.js";
|
|
||||||
|
const MIN_HEIGHT = 150;
|
||||||
|
|
||||||
export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.02, options = {}) {
|
export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.02, options = {}) {
|
||||||
// Create container for tags
|
// Create container for tags
|
||||||
@@ -9,12 +10,6 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
const { allowStrengthAdjustment = true } = options;
|
const { allowStrengthAdjustment = true } = options;
|
||||||
|
|
||||||
forwardMiddleMouseToCanvas(container);
|
forwardMiddleMouseToCanvas(container);
|
||||||
|
|
||||||
// Set initial height
|
|
||||||
const defaultHeight = 150;
|
|
||||||
|
|
||||||
// Get max height from settings
|
|
||||||
const maxHeight = getTriggerWordMaxHeight();
|
|
||||||
|
|
||||||
Object.assign(container.style, {
|
Object.assign(container.style, {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -24,22 +19,16 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
backgroundColor: "rgba(40, 44, 52, 0.6)",
|
backgroundColor: "rgba(40, 44, 52, 0.6)",
|
||||||
borderRadius: "6px",
|
borderRadius: "6px",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
alignItems: "flex-start", // Ensure tags align at the top of each row
|
alignItems: "flex-start",
|
||||||
maxHeight: `${maxHeight}px` // Set max height for scrollable container
|
alignContent: "flex-start"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize default value as array
|
// Initialize default value as array
|
||||||
const initialTagsData = opts?.defaultVal || [];
|
const initialTagsData = opts?.defaultVal || [];
|
||||||
|
|
||||||
// Fixed sizes for tag elements to avoid zoom-related calculation issues
|
|
||||||
const TAG_HEIGHT = 26; // Adjusted height of a single tag including margins
|
|
||||||
const TAGS_PER_ROW = 3; // Approximate number of tags per row
|
|
||||||
const ROW_GAP = 2; // Reduced gap between rows
|
|
||||||
const CONTAINER_PADDING = 12; // Top and bottom padding
|
|
||||||
const EMPTY_CONTAINER_HEIGHT = 60; // Height when no tags are present
|
|
||||||
|
|
||||||
// Function to render tags from array data
|
// Function to render tags from array data
|
||||||
const renderTags = (tagsData, widget) => {
|
const renderTags = (tagsData, widget) => {
|
||||||
// Clear existing tags
|
// Clear existing tags
|
||||||
@@ -66,25 +55,9 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
width: "100%"
|
width: "100%"
|
||||||
});
|
});
|
||||||
container.appendChild(emptyMessage);
|
container.appendChild(emptyMessage);
|
||||||
|
|
||||||
// Set fixed height for empty state
|
|
||||||
updateWidgetHeight(EMPTY_CONTAINER_HEIGHT);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a row container approach for better layout control
|
|
||||||
let rowContainer = document.createElement("div");
|
|
||||||
rowContainer.className = "comfy-tags-row";
|
|
||||||
Object.assign(rowContainer.style, {
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
gap: "4px",
|
|
||||||
width: "100%",
|
|
||||||
marginBottom: "2px" // Small gap between rows
|
|
||||||
});
|
|
||||||
container.appendChild(rowContainer);
|
|
||||||
|
|
||||||
let tagCount = 0;
|
|
||||||
normalizedTags.forEach((tagData, index) => {
|
normalizedTags.forEach((tagData, index) => {
|
||||||
const { text, active, highlighted, strength } = tagData;
|
const { text, active, highlighted, strength } = tagData;
|
||||||
const tagEl = document.createElement("div");
|
const tagEl = document.createElement("div");
|
||||||
@@ -134,7 +107,6 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
tagEl.addEventListener("click", (e) => {
|
tagEl.addEventListener("click", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
// Toggle active state for this specific tag using its index
|
|
||||||
const updatedTags = [...widget.value];
|
const updatedTags = [...widget.value];
|
||||||
updatedTags[index].active = !updatedTags[index].active;
|
updatedTags[index].active = !updatedTags[index].active;
|
||||||
textSpan.textContent = updatedTags[index].text;
|
textSpan.textContent = updatedTags[index].text;
|
||||||
@@ -158,29 +130,20 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
// Only adjust strength if the mouse is over the tag
|
|
||||||
const updatedTags = [...widget.value];
|
const updatedTags = [...widget.value];
|
||||||
let currentStrength = updatedTags[index].strength;
|
let currentStrength = updatedTags[index].strength;
|
||||||
|
|
||||||
// If no strength is set, default to 1.0
|
|
||||||
if (currentStrength === undefined || currentStrength === null) {
|
if (currentStrength === undefined || currentStrength === null) {
|
||||||
currentStrength = 1.0;
|
currentStrength = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust strength based on scroll direction
|
|
||||||
// DeltaY < 0 is scroll up, deltaY > 0 is scroll down
|
|
||||||
if (e.deltaY < 0) {
|
if (e.deltaY < 0) {
|
||||||
// Scroll up: increase strength by wheelSensitivity
|
|
||||||
currentStrength += wheelSensitivity;
|
currentStrength += wheelSensitivity;
|
||||||
} else {
|
} else {
|
||||||
// Scroll down: decrease strength by wheelSensitivity
|
|
||||||
currentStrength -= wheelSensitivity;
|
currentStrength -= wheelSensitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure strength doesn't go below 0
|
|
||||||
currentStrength = Math.max(0, currentStrength);
|
currentStrength = Math.max(0, currentStrength);
|
||||||
|
|
||||||
// Update the strength value
|
|
||||||
updatedTags[index].strength = currentStrength;
|
updatedTags[index].strength = currentStrength;
|
||||||
textSpan.textContent = updatedTags[index].text;
|
textSpan.textContent = updatedTags[index].text;
|
||||||
|
|
||||||
@@ -190,35 +153,8 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rowContainer.appendChild(tagEl);
|
container.appendChild(tagEl);
|
||||||
tagCount++;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Calculate height based on number of tags and fixed sizes
|
|
||||||
const tagsCount = normalizedTags.length;
|
|
||||||
const rows = Math.ceil(tagsCount / TAGS_PER_ROW);
|
|
||||||
const calculatedHeight = CONTAINER_PADDING + (rows * TAG_HEIGHT) + ((rows - 1) * ROW_GAP);
|
|
||||||
|
|
||||||
// Update widget height with calculated value
|
|
||||||
updateWidgetHeight(calculatedHeight);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to update widget height consistently
|
|
||||||
const updateWidgetHeight = (height) => {
|
|
||||||
const maxHeight = getTriggerWordMaxHeight();
|
|
||||||
// Ensure height is within bounds [defaultHeight, maxHeight]
|
|
||||||
const finalHeight = Math.min(Math.max(defaultHeight, height), maxHeight);
|
|
||||||
|
|
||||||
// Update CSS variables
|
|
||||||
container.style.setProperty('--comfy-widget-min-height', `${finalHeight}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-height', `${finalHeight}px`);
|
|
||||||
|
|
||||||
// Force node to update size after a short delay to ensure DOM is updated
|
|
||||||
if (node) {
|
|
||||||
setTimeout(() => {
|
|
||||||
node.setDirtyCanvas(true, true);
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to update tag style based on active state
|
// Helper function to update tag style based on active state
|
||||||
@@ -238,19 +174,19 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: "6px",
|
gap: "6px",
|
||||||
boxShadow: "0 1px 2px rgba(0,0,0,0.1)",
|
boxShadow: "0 1px 2px rgba(0,0,0,0.1)",
|
||||||
margin: "1px",
|
margin: "1px",
|
||||||
userSelect: "none",
|
userSelect: "none",
|
||||||
WebkitUserSelect: "none",
|
WebkitUserSelect: "none",
|
||||||
MozUserSelect: "none",
|
MozUserSelect: "none",
|
||||||
msUserSelect: "none",
|
msUserSelect: "none",
|
||||||
height: "22px", // Increased height to better fit text with descenders
|
height: "22px",
|
||||||
minHeight: "22px", // Matching minHeight
|
minHeight: "22px",
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
width: "fit-content",
|
width: "fit-content",
|
||||||
maxWidth: "200px",
|
maxWidth: "200px",
|
||||||
lineHeight: "16px", // Added explicit line-height
|
lineHeight: "16px",
|
||||||
verticalAlign: "middle", // Added vertical alignment
|
verticalAlign: "middle",
|
||||||
textAlign: "center", // Center text horizontally
|
textAlign: "center",
|
||||||
};
|
};
|
||||||
|
|
||||||
const highlightStyles = highlighted
|
const highlightStyles = highlighted
|
||||||
@@ -282,7 +218,6 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add hover effect
|
|
||||||
tagEl.onmouseenter = () => {
|
tagEl.onmouseenter = () => {
|
||||||
tagEl.style.transform = "translateY(-1px)";
|
tagEl.style.transform = "translateY(-1px)";
|
||||||
tagEl.dataset.prevBoxShadow = tagEl.style.boxShadow || "";
|
tagEl.dataset.prevBoxShadow = tagEl.style.boxShadow || "";
|
||||||
@@ -334,10 +269,8 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the value as array
|
|
||||||
let widgetValue = initialTagsData;
|
let widgetValue = initialTagsData;
|
||||||
|
|
||||||
// Create widget with new DOM Widget API
|
|
||||||
const widget = node.addDOMWidget(name, "custom", container, {
|
const widget = node.addDOMWidget(name, "custom", container, {
|
||||||
getValue: function() {
|
getValue: function() {
|
||||||
return widgetValue;
|
return widgetValue;
|
||||||
@@ -346,22 +279,17 @@ export function addTagsWidget(node, name, opts, callback, wheelSensitivity = 0.0
|
|||||||
widgetValue = v;
|
widgetValue = v;
|
||||||
renderTags(widgetValue, widget);
|
renderTags(widgetValue, widget);
|
||||||
},
|
},
|
||||||
getMaxHeight: function() {
|
getMinHeight: () => MIN_HEIGHT,
|
||||||
return getTriggerWordMaxHeight();
|
|
||||||
},
|
|
||||||
hideOnZoom: true,
|
hideOnZoom: true,
|
||||||
selectOn: ['click', 'focus']
|
selectOn: ['click', 'focus']
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set initial value
|
|
||||||
widget.value = initialTagsData;
|
widget.value = initialTagsData;
|
||||||
|
|
||||||
// Set callback
|
|
||||||
widget.callback = callback;
|
widget.callback = callback;
|
||||||
|
|
||||||
widget.serializeValue = () => {
|
widget.serializeValue = () => {
|
||||||
return widgetValue
|
return widgetValue
|
||||||
};
|
};
|
||||||
|
|
||||||
return { minWidth: 300, minHeight: defaultHeight, maxHeight: getTriggerWordMaxHeight(), widget };
|
return { minWidth: 300, minHeight: MIN_HEIGHT, widget };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user