| import { app } from "../../../scripts/app.js"; |
|
|
| |
| |
|
|
| let replaceRegex; |
| const id = "pysssss.PresetText.Presets"; |
|
|
| const getPresets = () => { |
| let items; |
| try { |
| items = JSON.parse(localStorage.getItem(id)); |
| } catch (error) {} |
| if (!items || !items.length) { |
| items = [{ name: "default negative", value: "worst quality" }]; |
| } |
| return items; |
| }; |
|
|
| let presets = getPresets(); |
|
|
| app.registerExtension({ |
| name: "pysssss.PresetText", |
| setup() { |
| app.ui.settings.addSetting({ |
| id: "pysssss.PresetText.ReplacementRegex", |
| name: "🐍 Preset Text Replacement Regex", |
| type: "text", |
| defaultValue: "(?:^|[^\\w])(?<replace>@(?<id>[\\w-]+))", |
| tooltip: |
| "The regex should return two named capture groups: id (the name of the preset text to use), replace (the matched text to replace)", |
| attrs: { |
| style: { |
| fontFamily: "monospace", |
| }, |
| }, |
| onChange(value) { |
| if (!value) { |
| replaceRegex = null; |
| return; |
| } |
| try { |
| replaceRegex = new RegExp(value, "g"); |
| } catch (error) { |
| alert("Error creating regex for preset text replacement, no replacements will be performed."); |
| replaceRegex = null; |
| } |
| }, |
| }); |
| }, |
| registerCustomNodes() { |
| class PresetTextNode { |
| constructor() { |
| this.isVirtualNode = true; |
| this.serialize_widgets = true; |
| this.addOutput("text", "STRING"); |
|
|
| const widget = this.addWidget("combo", "value", presets[0].name, () => {}, { |
| values: presets.map((p) => p.name), |
| }); |
| this.addWidget("button", "Manage", "Manage", () => { |
| const container = document.createElement("div"); |
| Object.assign(container.style, { |
| display: "grid", |
| gridTemplateColumns: "1fr 1fr", |
| gap: "10px", |
| }); |
|
|
| const addNew = document.createElement("button"); |
| addNew.textContent = "Add New"; |
| addNew.classList.add("pysssss-presettext-addnew"); |
| Object.assign(addNew.style, { |
| fontSize: "13px", |
| gridColumn: "1 / 3", |
| color: "dodgerblue", |
| width: "auto", |
| textAlign: "center", |
| }); |
| addNew.onclick = () => { |
| addRow({ name: "", value: "" }); |
| }; |
| container.append(addNew); |
|
|
| function addRow(p) { |
| const name = document.createElement("input"); |
| const nameLbl = document.createElement("label"); |
| name.value = p.name; |
| nameLbl.textContent = "Name:"; |
| nameLbl.append(name); |
|
|
| const value = document.createElement("input"); |
| const valueLbl = document.createElement("label"); |
| value.value = p.value; |
| valueLbl.textContent = "Value:"; |
| valueLbl.append(value); |
|
|
| addNew.before(nameLbl, valueLbl); |
| } |
| for (const p of presets) { |
| addRow(p); |
| } |
|
|
| const help = document.createElement("span"); |
| help.textContent = "To remove a preset set the name or value to blank"; |
| help.style.gridColumn = "1 / 3"; |
| container.append(help); |
|
|
| dialog.show(""); |
| dialog.textElement.append(container); |
| }); |
|
|
| const dialog = new app.ui.dialog.constructor(); |
| dialog.element.classList.add("comfy-settings"); |
|
|
| const closeButton = dialog.element.querySelector("button"); |
| closeButton.textContent = "CANCEL"; |
| const saveButton = document.createElement("button"); |
| saveButton.textContent = "SAVE"; |
| saveButton.onclick = function () { |
| const inputs = dialog.element.querySelectorAll("input"); |
| const p = []; |
| for (let i = 0; i < inputs.length; i += 2) { |
| const n = inputs[i]; |
| const v = inputs[i + 1]; |
| if (!n.value.trim() || !v.value.trim()) { |
| continue; |
| } |
| p.push({ name: n.value, value: v.value }); |
| } |
|
|
| widget.options.values = p.map((p) => p.name); |
| if (!widget.options.values.includes(widget.value)) { |
| widget.value = widget.options.values[0]; |
| } |
|
|
| presets = p; |
| localStorage.setItem(id, JSON.stringify(presets)); |
|
|
| dialog.close(); |
| }; |
|
|
| closeButton.before(saveButton); |
|
|
| this.applyToGraph = function (workflow) { |
| |
| if (this.outputs[0].links && this.outputs[0].links.length) { |
| for (const l of this.outputs[0].links) { |
| const link_info = app.graph.links[l]; |
| const outNode = app.graph.getNodeById(link_info.target_id); |
| const outIn = outNode && outNode.inputs && outNode.inputs[link_info.target_slot]; |
| if (outIn.widget) { |
| const w = outNode.widgets.find((w) => w.name === outIn.widget.name); |
| if (!w) continue; |
| const preset = presets.find((p) => p.name === widget.value); |
| if (!preset) { |
| const msg = `Preset text '${widget.value}' not found. Please fix this and queue again.`; |
| alert(msg); |
| throw new Error(msg); |
| } |
| w.value = preset.value; |
| } |
| } |
| } |
| }; |
| } |
| } |
|
|
| LiteGraph.registerNodeType( |
| "PresetText|pysssss", |
| Object.assign(PresetTextNode, { |
| title: "Preset Text 🐍", |
| }) |
| ); |
|
|
| PresetTextNode.category = "utils"; |
| }, |
| nodeCreated(node) { |
| if (node.widgets) { |
| |
| const widgets = node.widgets.filter((n) => n.type === "customtext" || n.type === "text"); |
| for (const widget of widgets) { |
| const callbacks = [ |
| () => { |
| let prompt = widget.value; |
| if (replaceRegex && typeof prompt.replace !== 'undefined') { |
| prompt = prompt.replace(replaceRegex, (match, p1, p2, index, text, groups) => { |
| if (!groups.replace || !groups.id) return match; |
|
|
| const preset = presets.find((p) => p.name.replaceAll(/\s/g, "-") === groups.id); |
| if (!preset) return match; |
|
|
| const pos = match.indexOf(groups.replace); |
| return match.substring(0, pos) + preset.value; |
| }); |
| } |
| return prompt; |
| }, |
| ]; |
| if (widget.serializeValue) { |
| callbacks.push(widget.serializeValue); |
| } |
|
|
| let called = false; |
| const serializeValue = async (workflowNode, widgetIndex) => { |
| const widgetValue = widget.value; |
| if (called) return widgetValue; |
| called = true; |
|
|
| for (const cb of callbacks) { |
| widget.value = await cb(workflowNode, widgetIndex); |
| } |
|
|
| const prompt = widget.value; |
| widget.value = widgetValue; |
|
|
| called = false; |
|
|
| return prompt; |
| }; |
|
|
| Object.defineProperty(widget, "serializeValue", { |
| get() { |
| return serializeValue; |
| }, |
| set(cb) { |
| callbacks.push(cb); |
| }, |
| }); |
| } |
| } |
| }, |
| }); |
|
|