Files
FunnyFinger-Dynamic_Sliders…/js/modern_slider_hider.js
FunnyFinger a92aaa7159 updated to v2.0.0
added new features such as dynamic sum adjustment and sum-lock dynamics
2025-04-19 20:22:11 +03:00

248 lines
11 KiB
JavaScript

/**
* Dynamic Sliders Stack - Modern Widget Hider
* Manages widget visibility based on slider count
*/
// REMOVE top-level import attempts for app
/*
// Import app with fallbacks
let app;
try { app = await import('/scripts/app.js'); } catch (e) {
try { app = await import('../../../scripts/app.js'); } catch (e) {
app = window.app;
}
}
*/
// REMOVE top-level check
// const isModernFrontend = app && app.extensionManager;
// Config
const NODE_CONFIG = {
controlWidgets: 3, // Number of control widgets
maxSliders: 50, // Maximum number of sliders
// nodeRadius removed as ComfyUI default is round
};
let domObserver = null; // DOM Mutation observer
// Helper to find node element
const findNodeElement = (nodeId) => document?.getElementById(nodeId) ||
document?.querySelector(`.litegraph-node[data-node-id="${nodeId}"]`) ||
document?.querySelector(`.comfy-node[data-node-id="${nodeId}"]`) ||
document?.querySelector(`.node_box[data-litegraph-id="${nodeId}"]`) ||
document?.querySelector(`.litegraph.litecontextualmenu .node_box[data-litegraph-id='${nodeId}']`);
// Extension definition
const extension = {
app: null, // Add property to store app instance
/** Set up the extension */
setup(app) { // Receive app as argument
// console.log("[DSS Modern Hider] setup() called.");
this.app = app; // Store app instance
// No need to check isModernFrontend here, this script should only load in modern
this.createGlobalStyles();
this.setupNodeTracking();
// console.log("[DSS Modern Hider] setup() completed.");
return true; // Indicate setup was successful (or based on actual success)
},
/** Update widget visibility (internal & DOM) */
updateWidgetVisibility(node, sliderCount) {
// console.log(`[DSS Modern Hider] updateWidgetVisibility called for node ${node.id}, sliderCount: ${sliderCount}`); // Log entry
if (!node?.widgets) {
// console.warn(`[DSS Modern Hider] No widgets found for node ${node.id}`);
return;
}
// Sanitize slider count
const originalSliderCount = sliderCount;
sliderCount = Math.max(1, Math.min(Math.floor(sliderCount), NODE_CONFIG.maxSliders));
if (originalSliderCount !== sliderCount) {
// console.log(`[DSS Modern Hider] Sanitized sliderCount from ${originalSliderCount} to ${sliderCount}`);
}
// Update internal widget visibility
let hiddenChangedCount = 0;
node.widgets.slice(NODE_CONFIG.controlWidgets).forEach((widget, i) => {
const shouldBeHidden = Math.floor(i / 2) + 1 > sliderCount;
if (widget.hidden !== shouldBeHidden) {
widget.hidden = shouldBeHidden;
hiddenChangedCount++;
// console.log(`[DSS Modern Hider] Set widget ${widget.name} (index ${i}) hidden: ${shouldBeHidden}`); // Optional detailed log
}
});
// console.log(`[DSS Modern Hider] Updated 'hidden' property for ${hiddenChangedCount} widgets.`);
// Remove the DOM manipulation block entirely
/*
// Update DOM widget visibility <-- REMOVED
const nodeElement = findNodeElement(node.id);
if (nodeElement) {
const widgetContainers = nodeElement.querySelectorAll('.slotcontainer .for_widget');
if (widgetContainers?.length > NODE_CONFIG.controlWidgets) {
widgetContainers.forEach((container, i) => {
if (i >= NODE_CONFIG.controlWidgets) {
container.style.display = Math.floor((i - NODE_CONFIG.controlWidgets) / 2) + 1 > sliderCount ? 'none' : '';
}
});
}
}
*/
},
/** Create global CSS */
createGlobalStyles() {
if (document.getElementById('dynamic-slider-stack-styles')) return;
const style = document.createElement('style');
style.id = 'dynamic-slider-stack-styles';
style.textContent = `
/* Hide disabled widgets */
.widget.disabled { display: none !important; }
`;
document.head.appendChild(style);
},
/** Setup node tracking */
setupNodeTracking() {
// console.log("[DSS Modern Hider] setupNodeTracking() called.");
// Use this.app instead of global app
if (!this.app?.graph) {
// console.warn("[DSS Modern Hider] this.app.graph not available during setupNodeTracking.");
return;
}
// Process existing nodes
// console.log(`[DSS Modern Hider] Processing ${this.app.graph.nodes?.length || 0} existing nodes.`);
this.app.graph.nodes?.forEach(node => {
// Add more comprehensive check including the suffixed name
if (node.type === "Slider Stacker (DSS)" || node.type === "SliderStacker" || node.title === "Slider Stacker") {
// console.log(`[DSS Modern Hider] Found existing Slider Stacker node (ID: ${node.id}, Type: ${node.type}, Title: ${node.title}). Processing...`);
this.processNewNode(node);
}
});
// Listen for new nodes
// console.log("[DSS Modern Hider] Adding nodeCreated listener.");
// Use this.app instead of global app
this.app.graph.addEventListener("nodeCreated", (node) => {
// console.log(`[DSS Modern Hider] nodeCreated event fired for node (ID: ${node.id}, Type: ${node.type}, Title: ${node.title})`);
// Add more comprehensive check including the suffixed name
if (node.type === "Slider Stacker (DSS)" || node.type === "SliderStacker" || node.title === "Slider Stacker") {
// console.log(`[DSS Modern Hider] nodeCreated is a Slider Stacker. Scheduling processNewNode...`);
// Pass 'this' context if processNewNode uses it, although it doesn't currently
setTimeout(() => this.processNewNode(node), 0);
} else if (node.title === "Slider Receiver") { // Also log receiver for context
// console.log(`[DSS Modern Hider] nodeCreated is a Slider Receiver.`);
// Potentially call processNewNode if receiver needs processing later
}
});
// Setup DOM observer
// Pass 'this' context if setupDOMObserver uses it (it doesn't currently)
this.setupDOMObserver();
// console.log("[DSS Modern Hider] setupNodeTracking() completed.");
},
/** Setup DOM observer */
setupDOMObserver() {
if (domObserver) domObserver.disconnect();
domObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes?.forEach(domNode => { // Rename to domNode to avoid confusion with LiteGraph node
if (domNode.classList?.contains('comfy-node') && // Check for modern class name
domNode.dataset?.nodeType?.includes('Slider Stacker')) { // Check data attribute if available
// console.log(`[DSS Modern Hider] DOM Observer detected node addition (ID: ${domNode.dataset?.nodeId}, Type: ${domNode.dataset?.nodeType})`);
// Attempt to find the LiteGraph node and re-process it
// Use this.app
const lgNode = this.app?.graph?.getNodeById(parseInt(domNode.dataset?.nodeId));
if (lgNode) {
// console.log(`[DSS Modern Hider] Found corresponding LiteGraph node ${lgNode.id}. Processing...`);
this.processNewNode(lgNode);
} else {
// console.warn(`[DSS Modern Hider] Could not find LiteGraph node for DOM node ID ${domNode.dataset?.nodeId}`);
}
}
});
});
});
// Assuming the main graph container might have a different ID or structure in modern
// Let's try a more generic approach or rely on setupNodeTracking initially
// const graphCanvas = document.getElementById('graph-canvas'); // This might be legacy
// For now, let's observe the body, which is less efficient but might catch additions
// Consider refining this later if needed
// console.log("[DSS Modern Hider] Setting up DOM Observer on document.body.");
domObserver.observe(document.body, { childList: true, subtree: true });
},
/** Process a new node */
processNewNode(node) {
// console.log(`[DSS Modern Hider] processNewNode called for node (ID: ${node.id}, Type: ${node.type}, Title: ${node.title})`); // Log process entry
if (!node) {
// console.warn("[DSS Modern Hider] processNewNode called with null node.");
return;
}
// Intercept widget and update visibility (only for Stacker)
// Use more robust check
if (node.type === "Slider Stacker (DSS)" || node.type === "SliderStacker" || node.title === "Slider Stacker") {
// console.log(`[DSS Modern Hider] Node ${node.id} confirmed as Slider Stacker, calling interceptAndUpdate.`);
this.interceptAndUpdate(node);
}
// No styling needed here, assuming ComfyUI default round shape
},
/** Intercept sliders_count widget setter and update visibility */
interceptAndUpdate(node) {
const widget = node.widgets?.find(w => w.name === "sliders_count");
if (!widget) {
// console.warn(`[DSS Modern Hider] 'sliders_count' widget not found for node ${node.id}`);
return;
}
if (widget._valueSetterOverridden) {
// console.log(`[DSS Modern Hider] Setter already overridden for node ${node.id}. Triggering initial update.`);
this.updateWidgetVisibility(node, widget.value);
return;
}
// console.log(`[DSS Modern Hider] Intercepting 'sliders_count' setter for node ${node.id}`);
const originalSetter = Object.getOwnPropertyDescriptor(widget, "value")?.set;
widget._valueSetterOverridden = true;
Object.defineProperty(widget, "value", {
get: function() { return this._value; },
set: function(v) {
// console.log(`[DSS Modern Hider] 'sliders_count' setter triggered for node ${node.id}. New value: ${v}, Old value: ${this._value}`);
const oldValue = this._value;
this._value = v;
if (originalSetter) originalSetter.call(this, v);
if (oldValue !== v) {
// console.log(`[DSS Modern Hider] Value changed, calling updateWidgetVisibility.`);
extension.updateWidgetVisibility(node, v);
} else {
// console.log(`[DSS Modern Hider] Value did not change, skipping update.`);
}
},
enumerable: true, configurable: true
});
// console.log(`[DSS Modern Hider] Triggering initial update for node ${node.id} with value ${widget.value}`);
this.updateWidgetVisibility(node, widget.value); // Initial update
},
/** Clean up resources */
cleanup() {
if (domObserver) { domObserver.disconnect(); domObserver = null; }
const style = document.getElementById('dynamic-slider-stack-styles');
if (style) style.remove();
}
};
export default extension;