248 lines
11 KiB
JavaScript
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;
|