137 lines
7.5 KiB
JavaScript
137 lines
7.5 KiB
JavaScript
// filename: ComfyUI/web/extensions/string_editor_persistent_tempfile_node.js
|
|
import { app } from "../../scripts/app.js";
|
|
import { api } from "../../scripts/api.js";
|
|
|
|
app.registerExtension({
|
|
name: "Comfy.StringEditorPersistentTempFileNode",
|
|
|
|
async nodeCreated(node) {
|
|
if (node.constructor.comfyClass !== "StringEditorPersistentTempFileNode") {
|
|
return;
|
|
}
|
|
console.log("StringEditorPersistentTempFileNode: nodeCreated", node.id);
|
|
|
|
const container = document.createElement("div");
|
|
container.style.display = "flex";
|
|
container.style.flexDirection = "column";
|
|
// Removed justify-content, let natural flow happen
|
|
// Removed height: 100%
|
|
container.style.padding = "2px";
|
|
container.style.margin = "0";
|
|
container.style.gap = "2px"; // Smaller gap
|
|
// --- Control Overflow ---
|
|
container.style.overflow = "hidden"; // Prevent container itself from overflowing node bounds
|
|
// -----------------------
|
|
|
|
// const label = document.createElement("label");
|
|
// label.textContent = "Edit Text & Continue (Persistent):";
|
|
// label.style.fontSize = "0.8em";
|
|
// label.style.color = "var(--descrip-text)";
|
|
// label.style.marginBottom = "3px";
|
|
// label.style.flexShrink = "0";
|
|
// container.appendChild(label); // Label directly in container
|
|
|
|
const textarea = document.createElement("textarea");
|
|
textarea.rows = 50; // Keep large default rows
|
|
textarea.placeholder = "Workflow paused. Edit text and click Continue.";
|
|
// --- Control Textarea Size/Overflow ---
|
|
// Let textarea be naturally sized by rows initially, but limit max height
|
|
textarea.style.minHeight = "160px"; // Reasonable minimum
|
|
textarea.style.maxHeight = "600px"; // Set a sensible maximum height (adjust as needed)
|
|
textarea.style.overflowY = "auto"; // Add scrollbar if content exceeds max height
|
|
textarea.style.resize = "vertical";
|
|
textarea.style.padding = "1px";
|
|
textarea.style.border = "1px solid var(--border-color)";
|
|
textarea.style.backgroundColor = "var(--comfy-input-bg)";
|
|
textarea.style.color = "var(--input-text)";
|
|
textarea.style.width = "calc(100% - 1px)"; // Ensure it fits horizontally within padding
|
|
textarea.disabled = true;
|
|
node.stringEditorTextarea = textarea;
|
|
container.appendChild(textarea); // Textarea directly in container
|
|
|
|
const button = document.createElement("button");
|
|
button.textContent = "Continue Workflow";
|
|
button.style.padding = "3px 10px";
|
|
button.style.marginTop = "5px";
|
|
button.style.cursor = "pointer";
|
|
button.style.border = "1px solid var(--border-color)";
|
|
button.style.backgroundColor = "var(--comfy-input-bg)";
|
|
button.style.color = "var(--input-text)";
|
|
button.style.flexShrink = "0"; // Prevent shrinking
|
|
button.style.borderRadius = "15px";
|
|
button.disabled = true;
|
|
node.stringEditorButton = button;
|
|
container.appendChild(button); // Button directly in container
|
|
|
|
const widget = node.addDOMWidget(`string_editor_persistent_widget_${node.id}`, "dom", container, {});
|
|
|
|
// --- computeSize (Simpler - let content mostly decide) ---
|
|
widget.computeSize = function(width) {
|
|
// Estimate minimum based on non-textarea elements + small textarea amount
|
|
const minHeight = 250; // Minimum needed for label, button, small textarea
|
|
// Get the container's *current* scrollHeight as a proxy for desired height
|
|
let contentHeight = container.scrollHeight;
|
|
const maxHeight = 800; // Absolute max node height (adjust)
|
|
|
|
// Use scrollHeight, but cap it and ensure minimum
|
|
let targetHeight = Math.max(minHeight, contentHeight + 10); // Add padding
|
|
targetHeight = Math.min(maxHeight, targetHeight); // Apply max height
|
|
|
|
console.log(`[computeSize] Request W: ${width}, scrollH: ${container.scrollHeight}, Target H: ${targetHeight}`);
|
|
return [width, Math.ceil(targetHeight)];
|
|
}
|
|
|
|
// --- Resize Observer (Still useful for manual drag) ---
|
|
let resizeTimeout;
|
|
new ResizeObserver(() => {
|
|
clearTimeout(resizeTimeout);
|
|
resizeTimeout = setTimeout(() => {
|
|
try {
|
|
// When textarea manually resizes, tell the node its overall size might need recalculating
|
|
node.computeSize(); // Trigger node's own size update based on widget
|
|
node.setDirtyCanvas(true, true);
|
|
} catch(e) { console.error("ResizeObserver error:", e); }
|
|
}, 150);
|
|
}).observe(textarea);
|
|
|
|
|
|
// --- Button Click Handler (Keep TempFile logic) ---
|
|
button.addEventListener("click", async () => {
|
|
// ...(Same logic: call /signal_continue, then app.queuePrompt() on success)...
|
|
const editedString = textarea.value; const nodeId = node.id;
|
|
console.log(`StringEditorPersistent: 'Continue' clicked for node ${nodeId}.`);
|
|
button.disabled = true; textarea.disabled = true;
|
|
try {
|
|
const response = await api.fetchApi("/string_editor/signal_continue", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ node_id: nodeId, edited_string: editedString }), });
|
|
if (!response.ok) { const errorData = await response.json(); const errorMsg = `Error saving state: ${errorData.message || response.statusText} (Status: ${response.status})`; console.error(`StringEditorPersistent: ${errorMsg} for node ${nodeId}`); alert(errorMsg); button.textContent = "Continue Workflow"; button.disabled = false; textarea.disabled = false; }
|
|
else { console.log(`StringEditorPersistent: State saved. Re-queueing prompt.`); app.queuePrompt(); }
|
|
} catch (error) { console.error(`StringEditorPersistent: Network error during continue for node ${nodeId}:`, error); alert(`Network error: ${error.message}`); button.textContent = "Continue Workflow"; button.disabled = false; textarea.disabled = false; }
|
|
});
|
|
|
|
// Initial size calculation
|
|
node.computeSize();
|
|
node.setDirtyCanvas(true, true);
|
|
|
|
}, // end nodeCreated
|
|
|
|
async setup(app) {
|
|
// ...(setup listener remains the same - listens for string_editor_persistent_tempfile_display)...
|
|
console.log("StringEditorPersistentTempFileNode: Setup.");
|
|
api.addEventListener("string_editor_persistent_tempfile_display", (event) => { // Listen for NEW event name
|
|
const { node_id, string_to_edit } = event.detail;
|
|
console.log(`StringEditorPersistent: Received 'display' event for node ${node_id}`);
|
|
const node = app.graph.getNodeById(node_id);
|
|
if (node && node.stringEditorTextarea && node.stringEditorButton) {
|
|
console.log(`StringEditorPersistent: Updating UI for node ${node_id}`);
|
|
node.stringEditorTextarea.value = string_to_edit;
|
|
node.stringEditorTextarea.disabled = false;
|
|
node.stringEditorButton.textContent = "Continue Workflow";
|
|
node.stringEditorButton.disabled = false;
|
|
node.computeSize(); // Recalculate size after content update
|
|
node.setDirtyCanvas(true, true);
|
|
} else { console.warn(`StringEditorPersistent: Could not find node/widgets for ID ${node_id}`); }
|
|
});
|
|
} // end setup
|
|
});
|
|
|
|
console.log("StringEditorPersistentTempFileNode: Extension registered."); |