Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
32
custom_nodes/rgthree-comfy/web/common/comfyui_shim.js
Normal file
32
custom_nodes/rgthree-comfy/web/common/comfyui_shim.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const shimCache = new Map();
|
||||
async function shimComfyUiModule(moduleName, prop) {
|
||||
var _a, _b;
|
||||
let module = shimCache.get(moduleName);
|
||||
if (!module) {
|
||||
if ((_a = window.comfyAPI) === null || _a === void 0 ? void 0 : _a[moduleName]) {
|
||||
module = (_b = window.comfyAPI) === null || _b === void 0 ? void 0 : _b[moduleName];
|
||||
}
|
||||
else {
|
||||
module = await import(`./comfyui_shim_${moduleName}.js`);
|
||||
}
|
||||
if (!module) {
|
||||
throw new Error(`Module ${moduleName} could not be loaded.`);
|
||||
}
|
||||
shimCache.set(moduleName, module);
|
||||
}
|
||||
if (prop) {
|
||||
if (!module[prop]) {
|
||||
throw new Error(`Property ${prop} on module ${moduleName} could not be loaded.`);
|
||||
}
|
||||
return module[prop];
|
||||
}
|
||||
return module;
|
||||
}
|
||||
export async function getPngMetadata(file) {
|
||||
const fn = (await shimComfyUiModule("pnginfo", "getPngMetadata"));
|
||||
return fn(file);
|
||||
}
|
||||
export async function getWebpMetadata(file) {
|
||||
const fn = (await shimComfyUiModule("pnginfo", "getWebpMetadata"));
|
||||
return fn(file);
|
||||
}
|
||||
392
custom_nodes/rgthree-comfy/web/common/comfyui_shim_pnginfo.js
Normal file
392
custom_nodes/rgthree-comfy/web/common/comfyui_shim_pnginfo.js
Normal file
@@ -0,0 +1,392 @@
|
||||
import { rgthreeApi } from "./rgthree_api.js";
|
||||
const api = {
|
||||
async getEmbeddings() {
|
||||
const resp = await rgthreeApi.fetchComfyApi('/embeddings', { cache: 'no-store' });
|
||||
return await resp.json();
|
||||
}
|
||||
};
|
||||
function getFromPngBuffer(buffer) {
|
||||
const pngData = new Uint8Array(buffer);
|
||||
const dataView = new DataView(pngData.buffer);
|
||||
if (dataView.getUint32(0) !== 0x89504e47) {
|
||||
console.error('Not a valid PNG file');
|
||||
return;
|
||||
}
|
||||
let offset = 8;
|
||||
let txt_chunks = {};
|
||||
while (offset < pngData.length) {
|
||||
const length = dataView.getUint32(offset);
|
||||
const type = String.fromCharCode(...pngData.slice(offset + 4, offset + 8));
|
||||
if (type === 'tEXt' || type == 'comf' || type === 'iTXt') {
|
||||
let keyword_end = offset + 8;
|
||||
while (pngData[keyword_end] !== 0) {
|
||||
keyword_end++;
|
||||
}
|
||||
const keyword = String.fromCharCode(...pngData.slice(offset + 8, keyword_end));
|
||||
const contentArraySegment = pngData.slice(keyword_end + 1, offset + 8 + length);
|
||||
const contentJson = new TextDecoder('utf-8').decode(contentArraySegment);
|
||||
txt_chunks[keyword] = contentJson;
|
||||
}
|
||||
offset += 12 + length;
|
||||
}
|
||||
return txt_chunks;
|
||||
}
|
||||
function getFromPngFile(file) {
|
||||
return new Promise((r) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
r(getFromPngBuffer(event.target.result));
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
function parseExifData(exifData) {
|
||||
const isLittleEndian = String.fromCharCode(...exifData.slice(0, 2)) === 'II';
|
||||
function readInt(offset, isLittleEndian, length) {
|
||||
let arr = exifData.slice(offset, offset + length);
|
||||
if (length === 2) {
|
||||
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength).getUint16(0, isLittleEndian);
|
||||
}
|
||||
else if (length === 4) {
|
||||
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength).getUint32(0, isLittleEndian);
|
||||
}
|
||||
throw new Error('Shouldn\'t get here.');
|
||||
}
|
||||
const ifdOffset = readInt(4, isLittleEndian, 4);
|
||||
function parseIFD(offset) {
|
||||
const numEntries = readInt(offset, isLittleEndian, 2);
|
||||
const result = {};
|
||||
for (let i = 0; i < numEntries; i++) {
|
||||
const entryOffset = offset + 2 + i * 12;
|
||||
const tag = readInt(entryOffset, isLittleEndian, 2);
|
||||
const type = readInt(entryOffset + 2, isLittleEndian, 2);
|
||||
const numValues = readInt(entryOffset + 4, isLittleEndian, 4);
|
||||
const valueOffset = readInt(entryOffset + 8, isLittleEndian, 4);
|
||||
let value;
|
||||
if (type === 2) {
|
||||
value = new TextDecoder('utf-8').decode(exifData.subarray(valueOffset, valueOffset + numValues - 1));
|
||||
}
|
||||
result[tag] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const ifdData = parseIFD(ifdOffset);
|
||||
return ifdData;
|
||||
}
|
||||
function splitValues(input) {
|
||||
var output = {};
|
||||
for (var key in input) {
|
||||
var value = input[key];
|
||||
var splitValues = value.split(':', 2);
|
||||
output[splitValues[0]] = splitValues[1];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
export function getPngMetadata(file) {
|
||||
return getFromPngFile(file);
|
||||
}
|
||||
export function getWebpMetadata(file) {
|
||||
return new Promise((r) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const webp = new Uint8Array(event.target.result);
|
||||
const dataView = new DataView(webp.buffer);
|
||||
if (dataView.getUint32(0) !== 0x52494646 ||
|
||||
dataView.getUint32(8) !== 0x57454250) {
|
||||
console.error('Not a valid WEBP file');
|
||||
r({});
|
||||
return;
|
||||
}
|
||||
let offset = 12;
|
||||
let txt_chunks = {};
|
||||
while (offset < webp.length) {
|
||||
const chunk_length = dataView.getUint32(offset + 4, true);
|
||||
const chunk_type = String.fromCharCode(...webp.slice(offset, offset + 4));
|
||||
if (chunk_type === 'EXIF') {
|
||||
if (String.fromCharCode(...webp.slice(offset + 8, offset + 8 + 6)) ==
|
||||
'Exif\0\0') {
|
||||
offset += 6;
|
||||
}
|
||||
let data = parseExifData(webp.slice(offset + 8, offset + 8 + chunk_length));
|
||||
for (var key in data) {
|
||||
const value = data[key];
|
||||
if (typeof value === 'string') {
|
||||
const index = value.indexOf(':');
|
||||
txt_chunks[value.slice(0, index)] = value.slice(index + 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
offset += 8 + chunk_length;
|
||||
}
|
||||
r(txt_chunks);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
export function getLatentMetadata(file) {
|
||||
return new Promise((r) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const safetensorsData = new Uint8Array(event.target.result);
|
||||
const dataView = new DataView(safetensorsData.buffer);
|
||||
let header_size = dataView.getUint32(0, true);
|
||||
let offset = 8;
|
||||
let header = JSON.parse(new TextDecoder().decode(safetensorsData.slice(offset, offset + header_size)));
|
||||
r(header.__metadata__);
|
||||
};
|
||||
var slice = file.slice(0, 1024 * 1024 * 4);
|
||||
reader.readAsArrayBuffer(slice);
|
||||
});
|
||||
}
|
||||
export async function importA1111(graph, parameters) {
|
||||
const p = parameters.lastIndexOf('\nSteps:');
|
||||
if (p > -1) {
|
||||
const embeddings = await api.getEmbeddings();
|
||||
const opts = parameters
|
||||
.substr(p)
|
||||
.split('\n')[1]
|
||||
.match(new RegExp('\\s*([^:]+:\\s*([^"\\{].*?|".*?"|\\{.*?\\}))\\s*(,|$)', 'g'))
|
||||
.reduce((p, n) => {
|
||||
const s = n.split(':');
|
||||
if (s[1].endsWith(',')) {
|
||||
s[1] = s[1].substr(0, s[1].length - 1);
|
||||
}
|
||||
p[s[0].trim().toLowerCase()] = s[1].trim();
|
||||
return p;
|
||||
}, {});
|
||||
const p2 = parameters.lastIndexOf('\nNegative prompt:', p);
|
||||
if (p2 > -1) {
|
||||
let positive = parameters.substr(0, p2).trim();
|
||||
let negative = parameters.substring(p2 + 18, p).trim();
|
||||
const ckptNode = LiteGraph.createNode('CheckpointLoaderSimple');
|
||||
const clipSkipNode = LiteGraph.createNode('CLIPSetLastLayer');
|
||||
const positiveNode = LiteGraph.createNode('CLIPTextEncode');
|
||||
const negativeNode = LiteGraph.createNode('CLIPTextEncode');
|
||||
const samplerNode = LiteGraph.createNode('KSampler');
|
||||
const imageNode = LiteGraph.createNode('EmptyLatentImage');
|
||||
const vaeNode = LiteGraph.createNode('VAEDecode');
|
||||
const vaeLoaderNode = LiteGraph.createNode('VAELoader');
|
||||
const saveNode = LiteGraph.createNode('SaveImage');
|
||||
let hrSamplerNode = null;
|
||||
let hrSteps = null;
|
||||
const ceil64 = (v) => Math.ceil(v / 64) * 64;
|
||||
const getWidget = (node, name) => {
|
||||
return node.widgets.find((w) => w.name === name);
|
||||
};
|
||||
const setWidgetValue = (node, name, value, isOptionPrefix) => {
|
||||
const w = getWidget(node, name);
|
||||
if (isOptionPrefix) {
|
||||
const o = w.options.values.find((w) => w.startsWith(value));
|
||||
if (o) {
|
||||
w.value = o;
|
||||
}
|
||||
else {
|
||||
console.warn(`Unknown value '${value}' for widget '${name}'`, node);
|
||||
w.value = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
w.value = value;
|
||||
}
|
||||
};
|
||||
const createLoraNodes = (clipNode, text, prevClip, prevModel) => {
|
||||
const loras = [];
|
||||
text = text.replace(/<lora:([^:]+:[^>]+)>/g, function (m, c) {
|
||||
const s = c.split(':');
|
||||
const weight = parseFloat(s[1]);
|
||||
if (isNaN(weight)) {
|
||||
console.warn('Invalid LORA', m);
|
||||
}
|
||||
else {
|
||||
loras.push({ name: s[0], weight });
|
||||
}
|
||||
return '';
|
||||
});
|
||||
for (const l of loras) {
|
||||
const loraNode = LiteGraph.createNode('LoraLoader');
|
||||
graph.add(loraNode);
|
||||
setWidgetValue(loraNode, 'lora_name', l.name, true);
|
||||
setWidgetValue(loraNode, 'strength_model', l.weight);
|
||||
setWidgetValue(loraNode, 'strength_clip', l.weight);
|
||||
prevModel.node.connect(prevModel.index, loraNode, 0);
|
||||
prevClip.node.connect(prevClip.index, loraNode, 1);
|
||||
prevModel = { node: loraNode, index: 0 };
|
||||
prevClip = { node: loraNode, index: 1 };
|
||||
}
|
||||
prevClip.node.connect(1, clipNode, 0);
|
||||
prevModel.node.connect(0, samplerNode, 0);
|
||||
if (hrSamplerNode) {
|
||||
prevModel.node.connect(0, hrSamplerNode, 0);
|
||||
}
|
||||
return { text, prevModel, prevClip };
|
||||
};
|
||||
const replaceEmbeddings = (text) => {
|
||||
if (!embeddings.length)
|
||||
return text;
|
||||
return text.replaceAll(new RegExp('\\b(' +
|
||||
embeddings
|
||||
.map((e) => e.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
||||
.join('\\b|\\b') +
|
||||
')\\b', 'ig'), 'embedding:$1');
|
||||
};
|
||||
const popOpt = (name) => {
|
||||
const v = opts[name];
|
||||
delete opts[name];
|
||||
return v;
|
||||
};
|
||||
graph.clear();
|
||||
graph.add(ckptNode);
|
||||
graph.add(clipSkipNode);
|
||||
graph.add(positiveNode);
|
||||
graph.add(negativeNode);
|
||||
graph.add(samplerNode);
|
||||
graph.add(imageNode);
|
||||
graph.add(vaeNode);
|
||||
graph.add(vaeLoaderNode);
|
||||
graph.add(saveNode);
|
||||
ckptNode.connect(1, clipSkipNode, 0);
|
||||
clipSkipNode.connect(0, positiveNode, 0);
|
||||
clipSkipNode.connect(0, negativeNode, 0);
|
||||
ckptNode.connect(0, samplerNode, 0);
|
||||
positiveNode.connect(0, samplerNode, 1);
|
||||
negativeNode.connect(0, samplerNode, 2);
|
||||
imageNode.connect(0, samplerNode, 3);
|
||||
vaeNode.connect(0, saveNode, 0);
|
||||
samplerNode.connect(0, vaeNode, 0);
|
||||
vaeLoaderNode.connect(0, vaeNode, 1);
|
||||
const handlers = {
|
||||
model(v) {
|
||||
setWidgetValue(ckptNode, 'ckpt_name', v, true);
|
||||
},
|
||||
vae(v) {
|
||||
setWidgetValue(vaeLoaderNode, 'vae_name', v, true);
|
||||
},
|
||||
'cfg scale'(v) {
|
||||
setWidgetValue(samplerNode, 'cfg', +v);
|
||||
},
|
||||
'clip skip'(v) {
|
||||
setWidgetValue(clipSkipNode, 'stop_at_clip_layer', -v);
|
||||
},
|
||||
sampler(v) {
|
||||
let name = v.toLowerCase().replace('++', 'pp').replaceAll(' ', '_');
|
||||
if (name.includes('karras')) {
|
||||
name = name.replace('karras', '').replace(/_+$/, '');
|
||||
setWidgetValue(samplerNode, 'scheduler', 'karras');
|
||||
}
|
||||
else {
|
||||
setWidgetValue(samplerNode, 'scheduler', 'normal');
|
||||
}
|
||||
const w = getWidget(samplerNode, 'sampler_name');
|
||||
const o = w.options.values.find((w) => w === name || w === 'sample_' + name);
|
||||
if (o) {
|
||||
setWidgetValue(samplerNode, 'sampler_name', o);
|
||||
}
|
||||
},
|
||||
size(v) {
|
||||
const wxh = v.split('x');
|
||||
const w = ceil64(+wxh[0]);
|
||||
const h = ceil64(+wxh[1]);
|
||||
const hrUp = popOpt('hires upscale');
|
||||
const hrSz = popOpt('hires resize');
|
||||
hrSteps = popOpt('hires steps');
|
||||
let hrMethod = popOpt('hires upscaler');
|
||||
setWidgetValue(imageNode, 'width', w);
|
||||
setWidgetValue(imageNode, 'height', h);
|
||||
if (hrUp || hrSz) {
|
||||
let uw, uh;
|
||||
if (hrUp) {
|
||||
uw = w * hrUp;
|
||||
uh = h * hrUp;
|
||||
}
|
||||
else {
|
||||
const s = hrSz.split('x');
|
||||
uw = +s[0];
|
||||
uh = +s[1];
|
||||
}
|
||||
let upscaleNode;
|
||||
let latentNode;
|
||||
if (hrMethod.startsWith('Latent')) {
|
||||
latentNode = upscaleNode = LiteGraph.createNode('LatentUpscale');
|
||||
graph.add(upscaleNode);
|
||||
samplerNode.connect(0, upscaleNode, 0);
|
||||
switch (hrMethod) {
|
||||
case 'Latent (nearest-exact)':
|
||||
hrMethod = 'nearest-exact';
|
||||
break;
|
||||
}
|
||||
setWidgetValue(upscaleNode, 'upscale_method', hrMethod, true);
|
||||
}
|
||||
else {
|
||||
const decode = LiteGraph.createNode('VAEDecodeTiled');
|
||||
graph.add(decode);
|
||||
samplerNode.connect(0, decode, 0);
|
||||
vaeLoaderNode.connect(0, decode, 1);
|
||||
const upscaleLoaderNode = LiteGraph.createNode('UpscaleModelLoader');
|
||||
graph.add(upscaleLoaderNode);
|
||||
setWidgetValue(upscaleLoaderNode, 'model_name', hrMethod, true);
|
||||
const modelUpscaleNode = LiteGraph.createNode('ImageUpscaleWithModel');
|
||||
graph.add(modelUpscaleNode);
|
||||
decode.connect(0, modelUpscaleNode, 1);
|
||||
upscaleLoaderNode.connect(0, modelUpscaleNode, 0);
|
||||
upscaleNode = LiteGraph.createNode('ImageScale');
|
||||
graph.add(upscaleNode);
|
||||
modelUpscaleNode.connect(0, upscaleNode, 0);
|
||||
const vaeEncodeNode = (latentNode =
|
||||
LiteGraph.createNode('VAEEncodeTiled'));
|
||||
graph.add(vaeEncodeNode);
|
||||
upscaleNode.connect(0, vaeEncodeNode, 0);
|
||||
vaeLoaderNode.connect(0, vaeEncodeNode, 1);
|
||||
}
|
||||
setWidgetValue(upscaleNode, 'width', ceil64(uw));
|
||||
setWidgetValue(upscaleNode, 'height', ceil64(uh));
|
||||
hrSamplerNode = LiteGraph.createNode('KSampler');
|
||||
graph.add(hrSamplerNode);
|
||||
ckptNode.connect(0, hrSamplerNode, 0);
|
||||
positiveNode.connect(0, hrSamplerNode, 1);
|
||||
negativeNode.connect(0, hrSamplerNode, 2);
|
||||
latentNode.connect(0, hrSamplerNode, 3);
|
||||
hrSamplerNode.connect(0, vaeNode, 0);
|
||||
}
|
||||
},
|
||||
steps(v) {
|
||||
setWidgetValue(samplerNode, 'steps', +v);
|
||||
},
|
||||
seed(v) {
|
||||
setWidgetValue(samplerNode, 'seed', +v);
|
||||
}
|
||||
};
|
||||
for (const opt in opts) {
|
||||
if (opt in handlers) {
|
||||
handlers[opt](popOpt(opt));
|
||||
}
|
||||
}
|
||||
if (hrSamplerNode) {
|
||||
setWidgetValue(hrSamplerNode, 'steps', hrSteps ? +hrSteps : getWidget(samplerNode, 'steps').value);
|
||||
setWidgetValue(hrSamplerNode, 'cfg', getWidget(samplerNode, 'cfg').value);
|
||||
setWidgetValue(hrSamplerNode, 'scheduler', getWidget(samplerNode, 'scheduler').value);
|
||||
setWidgetValue(hrSamplerNode, 'sampler_name', getWidget(samplerNode, 'sampler_name').value);
|
||||
setWidgetValue(hrSamplerNode, 'denoise', +(popOpt('denoising strength') || '1'));
|
||||
}
|
||||
let n = createLoraNodes(positiveNode, positive, { node: clipSkipNode, index: 0 }, { node: ckptNode, index: 0 });
|
||||
positive = n.text;
|
||||
n = createLoraNodes(negativeNode, negative, n.prevClip, n.prevModel);
|
||||
negative = n.text;
|
||||
setWidgetValue(positiveNode, 'text', replaceEmbeddings(positive));
|
||||
setWidgetValue(negativeNode, 'text', replaceEmbeddings(negative));
|
||||
graph.arrange();
|
||||
for (const opt of [
|
||||
'model hash',
|
||||
'ensd',
|
||||
'version',
|
||||
'vae hash',
|
||||
'ti hashes',
|
||||
'lora hashes',
|
||||
'hashes'
|
||||
]) {
|
||||
delete opts[opt];
|
||||
}
|
||||
console.warn('Unhandled parameters:', opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
import { $el, getActionEls } from "../../common/utils_dom.js";
|
||||
import { bind } from "../utils_templates.js";
|
||||
const CSS_STYLE_SHEETS = new Map();
|
||||
const CSS_STYLE_SHEETS_ADDED = new Map();
|
||||
const HTML_TEMPLATE_FILES = new Map();
|
||||
function getCommonPath(name, extension) {
|
||||
return `rgthree/common/components/${name.replace("rgthree-", "").replace(/\-/g, "_")}.${extension}`;
|
||||
}
|
||||
async function getStyleSheet(name, markupOrPath) {
|
||||
if (markupOrPath.includes("{")) {
|
||||
return markupOrPath;
|
||||
}
|
||||
if (!CSS_STYLE_SHEETS.has(name)) {
|
||||
try {
|
||||
const path = markupOrPath || getCommonPath(name, "css");
|
||||
const text = await (await fetch(path)).text();
|
||||
CSS_STYLE_SHEETS.set(name, text);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
return CSS_STYLE_SHEETS.get(name);
|
||||
}
|
||||
async function addStyleSheet(name, markupOrPath) {
|
||||
if (markupOrPath.includes("{")) {
|
||||
throw new Error("Page-level stylesheets should be passed a path.");
|
||||
}
|
||||
if (!CSS_STYLE_SHEETS_ADDED.has(name)) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = markupOrPath;
|
||||
document.head.appendChild(link);
|
||||
CSS_STYLE_SHEETS_ADDED.set(name, link);
|
||||
}
|
||||
return CSS_STYLE_SHEETS_ADDED.get(name);
|
||||
}
|
||||
async function getTemplateMarkup(name, markupOrPath) {
|
||||
if (markupOrPath.includes("<template")) {
|
||||
return markupOrPath;
|
||||
}
|
||||
if (!HTML_TEMPLATE_FILES.has(name)) {
|
||||
try {
|
||||
const path = markupOrPath || getCommonPath(name, "html");
|
||||
const text = await (await fetch(path)).text();
|
||||
HTML_TEMPLATE_FILES.set(name, text);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
return HTML_TEMPLATE_FILES.get(name);
|
||||
}
|
||||
export class RgthreeCustomElement extends HTMLElement {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.ctor = this.constructor;
|
||||
this.hasBeenConnected = false;
|
||||
this.connected = false;
|
||||
this.templates = new Map();
|
||||
this.firstConnectedPromise = new Promise((resolve) => (this.firstConnectedPromiseResolver = resolve));
|
||||
this.eventElements = new Map();
|
||||
}
|
||||
static create() {
|
||||
if (this.NAME === "rgthree-override") {
|
||||
throw new Error("Must override component NAME");
|
||||
}
|
||||
if (!window.customElements.get(this.NAME)) {
|
||||
window.customElements.define(this.NAME, this);
|
||||
}
|
||||
return document.createElement(this.NAME);
|
||||
}
|
||||
onFirstConnected() {
|
||||
}
|
||||
onReconnected() {
|
||||
}
|
||||
onConnected() {
|
||||
}
|
||||
onDisconnected() {
|
||||
}
|
||||
onAction(action, e) {
|
||||
console.log("onAction", action, e);
|
||||
}
|
||||
getElement(query) {
|
||||
const el = this.querySelector(query);
|
||||
if (!el) {
|
||||
throw new Error("No element found for query: " + query);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
onActionInternal(action, e) {
|
||||
if (typeof this[action] === "function") {
|
||||
this[action](e);
|
||||
}
|
||||
else {
|
||||
this.onAction(action, e);
|
||||
}
|
||||
}
|
||||
onConnectedInternal() {
|
||||
this.connectActionElements();
|
||||
this.onConnected();
|
||||
}
|
||||
onDisconnectedInternal() {
|
||||
this.disconnectActionElements();
|
||||
this.onDisconnected();
|
||||
}
|
||||
async connectedCallback() {
|
||||
const elementName = this.ctor.NAME;
|
||||
const wasConnected = this.connected;
|
||||
if (!wasConnected) {
|
||||
this.connected = true;
|
||||
}
|
||||
if (!this.hasBeenConnected) {
|
||||
const [stylesheet, markup] = await Promise.all([
|
||||
this.ctor.USE_SHADOW
|
||||
? getStyleSheet(elementName, this.ctor.CSS)
|
||||
: addStyleSheet(elementName, this.ctor.CSS),
|
||||
getTemplateMarkup(elementName, this.ctor.TEMPLATES),
|
||||
]);
|
||||
if (markup) {
|
||||
const temp = $el("div");
|
||||
const templatesMarkup = markup.match(/<template[^]*?<\/template>/gm) || [];
|
||||
for (const markup of templatesMarkup) {
|
||||
temp.innerHTML = markup;
|
||||
const template = temp.children[0];
|
||||
if (!(template instanceof HTMLTemplateElement)) {
|
||||
throw new Error("Not a template element.");
|
||||
}
|
||||
let id = template.getAttribute("id");
|
||||
if (!id) {
|
||||
id = this.ctor.NAME;
|
||||
}
|
||||
this.templates.set(id, template);
|
||||
}
|
||||
}
|
||||
if (this.ctor.USE_SHADOW) {
|
||||
this.root = this.attachShadow({ mode: "open" });
|
||||
if (typeof stylesheet === "string") {
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync(stylesheet);
|
||||
this.root.adoptedStyleSheets = [sheet];
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.root = this;
|
||||
}
|
||||
let template;
|
||||
if (this.templates.has(elementName)) {
|
||||
template = this.templates.get(elementName);
|
||||
}
|
||||
else if (this.templates.has(elementName.replace("rgthree-", ""))) {
|
||||
template = this.templates.get(elementName.replace("rgthree-", ""));
|
||||
}
|
||||
if (template) {
|
||||
this.root.appendChild(template.content.cloneNode(true));
|
||||
for (const name of template.getAttributeNames()) {
|
||||
if (name != "id" && template.getAttribute(name)) {
|
||||
this.setAttribute(name, template.getAttribute(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.onFirstConnected();
|
||||
this.hasBeenConnected = true;
|
||||
this.firstConnectedPromiseResolver();
|
||||
}
|
||||
else {
|
||||
this.onReconnected();
|
||||
}
|
||||
this.onConnectedInternal();
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.connected = false;
|
||||
this.onDisconnected();
|
||||
}
|
||||
connectActionElements() {
|
||||
const data = getActionEls(this);
|
||||
for (const dataItem of Object.values(data)) {
|
||||
const mapItem = this.eventElements.get(dataItem.el) || {};
|
||||
for (const [event, action] of Object.entries(dataItem.actions)) {
|
||||
if (mapItem[event]) {
|
||||
console.warn(`Element already has an event for ${event}`);
|
||||
continue;
|
||||
}
|
||||
mapItem[event] = (e) => {
|
||||
this.onActionInternal(action, e);
|
||||
};
|
||||
dataItem.el.addEventListener(event, mapItem[event]);
|
||||
}
|
||||
}
|
||||
}
|
||||
disconnectActionElements() {
|
||||
for (const [el, eventData] of this.eventElements.entries()) {
|
||||
for (const [event, fn] of Object.entries(eventData)) {
|
||||
el.removeEventListener(event, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
async bindWhenConnected(data, el) {
|
||||
await this.firstConnectedPromise;
|
||||
this.bind(data, el);
|
||||
}
|
||||
bind(data, el) {
|
||||
bind(el || this.root, data);
|
||||
}
|
||||
}
|
||||
RgthreeCustomElement.NAME = "rgthree-override";
|
||||
RgthreeCustomElement.USE_SHADOW = true;
|
||||
RgthreeCustomElement.TEMPLATES = "";
|
||||
RgthreeCustomElement.CSS = "";
|
||||
130
custom_nodes/rgthree-comfy/web/common/css/buttons.css
Normal file
130
custom_nodes/rgthree-comfy/web/common/css/buttons.css
Normal file
@@ -0,0 +1,130 @@
|
||||
:not(#fakeid) .rgthree-button-reset {
|
||||
position: relative;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:not(#fakeid) .rgthree-button {
|
||||
--padding-top: 7px;
|
||||
--padding-bottom: 9px;
|
||||
--padding-x: 16px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
border-radius: 0.33rem;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
font-family: system-ui, sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
margin: 0.25rem;
|
||||
box-shadow: 0px 0px 2px rgb(0, 0, 0);
|
||||
background: #212121;
|
||||
transition: all 0.1s ease-in-out;
|
||||
padding: var(--padding-top) var(--padding-x) var(--padding-bottom);
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button::before, :not(#fakeid) .rgthree-button::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
border-radius: 0.33rem;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 1px 1px 0px rgba(255, 255, 255, 0.12), inset -1px -1px 0px rgba(0, 0, 0, 0.75);
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.06), rgba(0, 0, 0, 0.15));
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button::after {
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button:hover {
|
||||
background: #303030;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button:active {
|
||||
box-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
|
||||
background: #121212;
|
||||
padding: calc(var(--padding-top) + 1px) calc(var(--padding-x) - 1px) calc(var(--padding-bottom) - 1px) calc(var(--padding-x) + 1px);
|
||||
}
|
||||
:not(#fakeid) .rgthree-button:active::before, :not(#fakeid) .rgthree-button:active::after {
|
||||
box-shadow: 1px 1px 0px rgba(255, 255, 255, 0.15), inset 1px 1px 0px rgba(0, 0, 0, 0.5), inset 1px 3px 5px rgba(0, 0, 0, 0.33);
|
||||
}
|
||||
:not(#fakeid) .rgthree-button.-blue {
|
||||
background: #346599 !important;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button.-blue:hover {
|
||||
background: #3b77b8 !important;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button.-blue:active {
|
||||
background: #1d5086 !important;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button.-green {
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.06), rgba(0, 0, 0, 0.15)), #14580b;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button.-green:hover {
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.06), rgba(0, 0, 0, 0.15)), #1a6d0f;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button.-green:active {
|
||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.06)), #0f3f09;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button[disabled] {
|
||||
box-shadow: none;
|
||||
background: #666 !important;
|
||||
color: #aaa;
|
||||
pointer-events: none;
|
||||
}
|
||||
:not(#fakeid) .rgthree-button[disabled]::before, :not(#fakeid) .rgthree-button[disabled]::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group {
|
||||
font-size: 0;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button {
|
||||
margin: 0;
|
||||
flex: 1 1;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
border-radius: 0;
|
||||
background: var(--p-button-secondary-background);
|
||||
color: var(--p-button-secondary-color);
|
||||
}
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button.-primary {
|
||||
background: var(--p-button-primary-background);
|
||||
color: var(--p-button-primary-color);
|
||||
}
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button::before, :not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button::after {
|
||||
border-radius: 0;
|
||||
}
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button svg {
|
||||
fill: currentColor;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button:first-of-type,
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button:first-of-type::before,
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button:first-of-type::after {
|
||||
border-top-left-radius: 0.33rem;
|
||||
border-bottom-left-radius: 0.33rem;
|
||||
}
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button:last-of-type,
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button:last-of-type::before,
|
||||
:not(#fakeid) .rgthree-comfybar-top-button-group .rgthree-comfybar-top-button:last-of-type::after {
|
||||
border-top-right-radius: 0.33rem;
|
||||
border-bottom-right-radius: 0.33rem;
|
||||
}
|
||||
124
custom_nodes/rgthree-comfy/web/common/css/dialog.css
Normal file
124
custom_nodes/rgthree-comfy/web/common/css/dialog.css
Normal file
@@ -0,0 +1,124 @@
|
||||
@charset "UTF-8";
|
||||
.rgthree-dialog {
|
||||
outline: 0;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
background: #414141;
|
||||
color: #fff;
|
||||
box-shadow: inset 1px 1px 0px rgba(255, 255, 255, 0.05), inset -1px -1px 0px rgba(0, 0, 0, 0.5), 2px 2px 20px rgb(0, 0, 0);
|
||||
max-width: 800px;
|
||||
box-sizing: border-box;
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
font-size: 1rem;
|
||||
padding: 0;
|
||||
max-height: calc(100% - 32px);
|
||||
}
|
||||
.rgthree-dialog *, .rgthree-dialog *::before, .rgthree-dialog *::after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container > * {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
.rgthree-dialog-container > *:first-child {
|
||||
padding-top: 16px;
|
||||
}
|
||||
.rgthree-dialog-container > *:last-child {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-iconed::after {
|
||||
content: "";
|
||||
font-size: 276px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
opacity: 0.15;
|
||||
display: block;
|
||||
width: 237px;
|
||||
overflow: hidden;
|
||||
height: 186px;
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-iconed.-help::after {
|
||||
content: "🛟";
|
||||
}
|
||||
|
||||
.rgthree-dialog.-iconed.-settings::after {
|
||||
content: "⚙️";
|
||||
}
|
||||
|
||||
@media (max-width: 832px) {
|
||||
.rgthree-dialog {
|
||||
max-width: calc(100% - 32px);
|
||||
}
|
||||
}
|
||||
.rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-title > svg:first-child {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-title h2 {
|
||||
font-size: 1.375rem;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-title h2 small {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: normal;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content {
|
||||
overflow: auto;
|
||||
max-height: calc(100vh - 200px); /* Arbitrary height to copensate for margin, title, and footer.*/
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content p {
|
||||
font-size: 0.8125rem;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content ul li p {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content ul li p + p {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content ul li ul {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-content p code {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
margin: 0px 2px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.rgthree-dialog-container-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-container) {
|
||||
filter: blur(5px);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
.rgthree-lora-chooser-dialog {
|
||||
max-width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-title h2 {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-search {
|
||||
margin-left: auto;
|
||||
border-radius: 50px;
|
||||
width: 50%;
|
||||
max-width: 170px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-chooser-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-lora-filters-container svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-dialog-container-content {
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog .rgthree-button-reset > svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
width: 170px;
|
||||
max-width: 100%;
|
||||
margin: 8px 8px 16px;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li label {
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox] {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: 0;
|
||||
z-index: 2;
|
||||
appearance: none;
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgb(120, 120, 120);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked {
|
||||
opacity: 1;
|
||||
background: #0060df;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li input[type=checkbox]:checked::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: inset 100px 100px #fff;
|
||||
clip-path: polygon(40.13% 68.39%, 23.05% 51.31%, 17.83% 48.26%, 12.61% 49.57%, 9.57% 53.04%, 8% 60%, 34.13% 85.87%, 39.82% 89.57%, 45.88% 86.73%, 90.66% 32.39%, 88.92% 26.1%, 83.03% 22.17%, 76.94% 22.62%);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(120, 120, 120, 0.8);
|
||||
background: rgba(120, 120, 120, 0.5);
|
||||
width: 100%;
|
||||
padding-top: 120%;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure:empty::before {
|
||||
content: "No image.";
|
||||
color: rgba(200, 200, 200, 0.8);
|
||||
position: absolute;
|
||||
display: block;
|
||||
inset: 0;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > img, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li figure > video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li div {
|
||||
word-wrap: break-word;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover figure::after {
|
||||
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ figure::after {
|
||||
box-shadow: 0 0 5px #fff, 0px 0px 15px rgba(49, 131, 255, 0.88), inset 0 0 3px #fff, inset 0px 0px 5px rgba(49, 131, 255, 0.88);
|
||||
}
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover *, .rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li:hover input[type=checkbox],
|
||||
.rgthree-lora-chooser-dialog ul.rgthree-lora-chooser-list > li :checked ~ * {
|
||||
opacity: 1;
|
||||
}
|
||||
336
custom_nodes/rgthree-comfy/web/common/css/dialog_model_info.css
Normal file
336
custom_nodes/rgthree-comfy/web/common/css/dialog_model_info.css
Normal file
@@ -0,0 +1,336 @@
|
||||
.rgthree-info-dialog {
|
||||
width: 90vw;
|
||||
max-width: 960px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li + li {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li:not(.-link) + li.-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > * {
|
||||
min-height: 24px;
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgb(69, 92, 85);
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.1em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > * > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > * > svg:last-child {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > *[href] {
|
||||
box-shadow: inset 0px 1px 0px rgba(255, 255, 255, 0.25), inset 0px -1px 0px rgba(0, 0, 0, 0.66);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-tag > *:empty {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.-type > * {
|
||||
background: rgb(73, 54, 94);
|
||||
color: rgb(228, 209, 248);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-menu {
|
||||
margin-left: auto;
|
||||
}
|
||||
:not(#fakeid) .rgthree-info-dialog .rgthree-info-area > li.rgthree-info-menu .rgthree-button {
|
||||
margin: 0;
|
||||
min-height: 24px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-area > li.rgthree-info-menu svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table {
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0px;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button {
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable button svg + svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.editable.-rgthree-editing button svg + svg {
|
||||
display: inline-block;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td {
|
||||
position: relative;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child {
|
||||
background: rgba(255, 255, 255, 0.075);
|
||||
width: 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child > *:first-child {
|
||||
white-space: nowrap;
|
||||
padding-right: 32px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child small {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child small > [data-action] {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td:first-child small > [data-action]:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td a, .rgthree-info-dialog .rgthree-info-table td a:hover, .rgthree-info-dialog .rgthree-info-table td a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg {
|
||||
width: 1.3333em;
|
||||
height: 1.3333em;
|
||||
vertical-align: -0.285em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td svg.logo-civitai {
|
||||
margin-right: 0.3333em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > *:first-child {
|
||||
display: block;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input, .rgthree-info-dialog .rgthree-info-table td > textarea {
|
||||
padding: 5px 10px;
|
||||
border: 0;
|
||||
box-shadow: inset 1px 1px 5px 0px rgba(0, 0, 0, 0.5);
|
||||
font: inherit;
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
color: #121212;
|
||||
resize: vertical;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > input:only-child, .rgthree-info-dialog .rgthree-info-table td > textarea:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
:not(#fakeid) .rgthree-info-dialog .rgthree-info-table td .rgthree-button[data-action=fetch-civitai] {
|
||||
font-size: inherit;
|
||||
padding: 6px 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr[data-field-name=userNote] td > span:first-child {
|
||||
white-space: pre;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 12px 4px 4px;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td > small {
|
||||
font-style: italic;
|
||||
opacity: 0.66;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td:empty {
|
||||
padding: 4px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help {
|
||||
border: 1px solid currentColor;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 6px;
|
||||
line-height: 1;
|
||||
font-size: 11px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
cursor: help;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td .-help::before {
|
||||
content: "?";
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list {
|
||||
list-style: none;
|
||||
padding: 2px 8px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
max-height: 15vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li {
|
||||
display: inline-flex;
|
||||
margin: 2px;
|
||||
vertical-align: top;
|
||||
border-radius: 4px;
|
||||
line-height: 1;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgb(73, 91, 106);
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
height: 1.6em;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: inset 0px 0px 0 1px rgba(0, 0, 0, 0.5);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
max-width: 183px;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li:hover {
|
||||
background: rgb(68, 109, 142);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li > svg {
|
||||
width: auto;
|
||||
height: 1.2em;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li > span {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
padding-bottom: 0.1em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li > small {
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.5em;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-table td > ul.rgthree-info-trained-words-list > li.-rgthree-is-selected {
|
||||
background: rgb(42, 126, 193);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
scroll-snap-type: x mandatory;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li {
|
||||
scroll-snap-align: start;
|
||||
max-width: 90%;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 6px;
|
||||
font-size: 0;
|
||||
position: relative;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure {
|
||||
margin: 0;
|
||||
position: static;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure video, .rgthree-info-dialog .rgthree-info-images > li figure img {
|
||||
max-height: 45vh;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
padding: 12px;
|
||||
font-size: 12px;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
opacity: 0;
|
||||
transform: translateY(50px);
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption > span {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
margin: 2px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
word-break: break-word;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption > span label {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption > span a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption > span a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption > span a svg {
|
||||
height: 10px;
|
||||
margin-left: 4px;
|
||||
fill: currentColor;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption:empty {
|
||||
text-align: center;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li figure figcaption:empty::before {
|
||||
content: "No data.";
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li:hover figure figcaption {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-images > li .rgthree-info-table {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link {
|
||||
margin: 8px;
|
||||
color: #eee;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link a, .rgthree-info-dialog .rgthree-info-civitai-link a:hover, .rgthree-info-dialog .rgthree-info-civitai-link a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.rgthree-info-dialog .rgthree-info-civitai-link > svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
103
custom_nodes/rgthree-comfy/web/common/css/menu.css
Normal file
103
custom_nodes/rgthree-comfy/web/common/css/menu.css
Normal file
@@ -0,0 +1,103 @@
|
||||
.rgthree-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.08s ease-in-out;
|
||||
color: #dde;
|
||||
background-color: #111;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 0 10px black !important;
|
||||
}
|
||||
.rgthree-menu > li {
|
||||
position: relative;
|
||||
padding: 4px 6px;
|
||||
z-index: 9999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rgthree-menu > li[role=button] {
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
color: var(--input-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
.rgthree-menu > li[role=button]:hover {
|
||||
filter: brightness(155%);
|
||||
}
|
||||
.rgthree-menu[state^=measuring] {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
.rgthree-menu[state=open] {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.rgthree-top-menu {
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
background: var(--content-bg);
|
||||
color: var(--content-fg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.rgthree-top-menu * {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid) {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid) > button {
|
||||
cursor: pointer;
|
||||
padding: 8px 12px 8px 8px;
|
||||
width: 100%;
|
||||
text-align: start;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid) > button:hover {
|
||||
background-color: var(--comfy-input-bg);
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid) > button svg {
|
||||
height: 16px;
|
||||
width: auto;
|
||||
margin-inline-end: 0.6em;
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid) > button svg.github-star {
|
||||
fill: rgb(227, 179, 65);
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid).rgthree-message {
|
||||
min-height: 32px;
|
||||
}
|
||||
.rgthree-top-menu > li:not(#fakeid).rgthree-message > span {
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rgthree-top-menu.-modal::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.0666666667);
|
||||
}
|
||||
|
||||
body.rgthree-modal-menu-open > *:not(.rgthree-menu):not(.rgthree-top-messages-container) {
|
||||
filter: blur(2px);
|
||||
}
|
||||
66
custom_nodes/rgthree-comfy/web/common/css/pages_base.css
Normal file
66
custom_nodes/rgthree-comfy/web/common/css/pages_base.css
Normal file
@@ -0,0 +1,66 @@
|
||||
html {
|
||||
font-size: 100%;
|
||||
overflow-y: scroll;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
:root {
|
||||
--header-height: 56px;
|
||||
--progress-height: 12px;
|
||||
}
|
||||
|
||||
button {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
.-bevel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.-bevel::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid red;
|
||||
border-color: rgba(255, 255, 255, 0.15) rgba(255, 255, 255, 0.15) rgba(0, 0, 0, 0.5) rgba(0, 0, 0, 0.5);
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #202020;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
padding-top: calc(var(--header-height) + var(--progress-height));
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
height: var(--header-height);
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #353535;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
109
custom_nodes/rgthree-comfy/web/common/dialog.js
Normal file
109
custom_nodes/rgthree-comfy/web/common/dialog.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import { createElement as $el, getClosestOrSelf, setAttributes } from "./utils_dom.js";
|
||||
export class RgthreeDialog extends EventTarget {
|
||||
constructor(options) {
|
||||
super();
|
||||
this.options = options;
|
||||
let container = $el("div.rgthree-dialog-container");
|
||||
this.element = $el("dialog", {
|
||||
classes: ["rgthree-dialog", options.class || ""],
|
||||
child: container,
|
||||
parent: document.body,
|
||||
events: {
|
||||
click: (event) => {
|
||||
if (!this.element.open ||
|
||||
event.target === container ||
|
||||
getClosestOrSelf(event.target, `.rgthree-dialog-container`) === container) {
|
||||
return;
|
||||
}
|
||||
return this.close();
|
||||
},
|
||||
},
|
||||
});
|
||||
this.element.addEventListener("close", (event) => {
|
||||
this.onDialogElementClose();
|
||||
});
|
||||
this.titleElement = $el("div.rgthree-dialog-container-title", {
|
||||
parent: container,
|
||||
children: !options.title
|
||||
? null
|
||||
: options.title instanceof Element || Array.isArray(options.title)
|
||||
? options.title
|
||||
: typeof options.title === "string"
|
||||
? !options.title.includes("<h2")
|
||||
? $el("h2", { html: options.title })
|
||||
: options.title
|
||||
: options.title,
|
||||
});
|
||||
this.contentElement = $el("div.rgthree-dialog-container-content", {
|
||||
parent: container,
|
||||
child: options.content,
|
||||
});
|
||||
const footerEl = $el("footer.rgthree-dialog-container-footer", { parent: container });
|
||||
for (const button of options.buttons || []) {
|
||||
$el("button", {
|
||||
text: button.label,
|
||||
className: button.className,
|
||||
disabled: !!button.disabled,
|
||||
parent: footerEl,
|
||||
events: {
|
||||
click: (e) => {
|
||||
var _a;
|
||||
(_a = button.callback) === null || _a === void 0 ? void 0 : _a.call(button, e);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
if (options.closeButtonLabel !== false) {
|
||||
$el("button", {
|
||||
text: options.closeButtonLabel || "Close",
|
||||
className: "rgthree-button",
|
||||
parent: footerEl,
|
||||
events: {
|
||||
click: (e) => {
|
||||
this.close(e);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
setTitle(content) {
|
||||
const title = typeof content !== "string" || content.includes("<h2")
|
||||
? content
|
||||
: $el("h2", { html: content });
|
||||
setAttributes(this.titleElement, { children: title });
|
||||
}
|
||||
setContent(content) {
|
||||
setAttributes(this.contentElement, { children: content });
|
||||
}
|
||||
show() {
|
||||
document.body.classList.add("rgthree-dialog-open");
|
||||
this.element.showModal();
|
||||
this.dispatchEvent(new CustomEvent("show"));
|
||||
return this;
|
||||
}
|
||||
async close(e) {
|
||||
if (this.options.onBeforeClose && !(await this.options.onBeforeClose())) {
|
||||
return;
|
||||
}
|
||||
this.element.close();
|
||||
}
|
||||
onDialogElementClose() {
|
||||
document.body.classList.remove("rgthree-dialog-open");
|
||||
this.element.remove();
|
||||
this.dispatchEvent(new CustomEvent("close", this.getCloseEventDetail()));
|
||||
}
|
||||
getCloseEventDetail() {
|
||||
return { detail: null };
|
||||
}
|
||||
}
|
||||
export class RgthreeHelpDialog extends RgthreeDialog {
|
||||
constructor(node, content, opts = {}) {
|
||||
const title = (node.type || node.title || "").replace(/\s*\(rgthree\).*/, " <small>by rgthree</small>");
|
||||
const options = Object.assign({}, opts, {
|
||||
class: "-iconed -help",
|
||||
title,
|
||||
content,
|
||||
});
|
||||
super(options);
|
||||
}
|
||||
}
|
||||
365
custom_nodes/rgthree-comfy/web/common/link_fixer.js
Normal file
365
custom_nodes/rgthree-comfy/web/common/link_fixer.js
Normal file
@@ -0,0 +1,365 @@
|
||||
var IoDirection;
|
||||
(function (IoDirection) {
|
||||
IoDirection[IoDirection["INPUT"] = 0] = "INPUT";
|
||||
IoDirection[IoDirection["OUTPUT"] = 1] = "OUTPUT";
|
||||
})(IoDirection || (IoDirection = {}));
|
||||
function getLinksData(links) {
|
||||
if (links instanceof Map) {
|
||||
const data = [];
|
||||
for (const [key, llink] of links.entries()) {
|
||||
if (!llink)
|
||||
continue;
|
||||
data.push(llink);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
if (!Array.isArray(links)) {
|
||||
const data = [];
|
||||
for (const key in links) {
|
||||
const llink = (links.hasOwnProperty(key) && links[key]) || null;
|
||||
if (!llink)
|
||||
continue;
|
||||
data.push(llink);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
return links.map((link) => ({
|
||||
id: link[0],
|
||||
origin_id: link[1],
|
||||
origin_slot: link[2],
|
||||
target_id: link[3],
|
||||
target_slot: link[4],
|
||||
type: link[5],
|
||||
}));
|
||||
}
|
||||
export class WorkflowLinkFixer {
|
||||
static create(graph) {
|
||||
if (typeof graph.getNodeById === "function") {
|
||||
return new WorkflowLinkFixerGraph(graph);
|
||||
}
|
||||
return new WorkflowLinkFixerSerialized(graph);
|
||||
}
|
||||
constructor(graph) {
|
||||
this.silent = false;
|
||||
this.checkedData = null;
|
||||
this.logger = console;
|
||||
this.patchedNodeSlots = {};
|
||||
this.instructions = [];
|
||||
this.graph = graph;
|
||||
}
|
||||
check(force = false) {
|
||||
var _a, _b;
|
||||
if (this.checkedData && !force) {
|
||||
return { ...this.checkedData };
|
||||
}
|
||||
this.instructions = [];
|
||||
this.patchedNodeSlots = {};
|
||||
const instructions = [];
|
||||
const links = getLinksData(this.graph.links);
|
||||
links.reverse();
|
||||
for (const link of links) {
|
||||
if (!link)
|
||||
continue;
|
||||
const originNode = this.getNodeById(link.origin_id);
|
||||
const originHasLink = () => this.nodeHasLinkId(originNode, IoDirection.OUTPUT, link.origin_slot, link.id);
|
||||
const patchOrigin = (op, id = link.id) => this.getNodePatchInstruction(originNode, IoDirection.OUTPUT, link.origin_slot, id, op);
|
||||
const targetNode = this.getNodeById(link.target_id);
|
||||
const targetHasLink = () => this.nodeHasLinkId(targetNode, IoDirection.INPUT, link.target_slot, link.id);
|
||||
const targetHasAnyLink = () => this.nodeHasAnyLink(targetNode, IoDirection.INPUT, link.target_slot);
|
||||
const patchTarget = (op, id = link.id) => this.getNodePatchInstruction(targetNode, IoDirection.INPUT, link.target_slot, id, op);
|
||||
const originLog = `origin(${link.origin_id}).outputs[${link.origin_slot}].links`;
|
||||
const targetLog = `target(${link.target_id}).inputs[${link.target_slot}].link`;
|
||||
if (!originNode || !targetNode) {
|
||||
if (!originNode && !targetNode) {
|
||||
}
|
||||
else if (!originNode && targetNode) {
|
||||
this.log(`Link ${link.id} is funky... ` +
|
||||
`origin ${link.origin_id} does not exist, but target ${link.target_id} does.`);
|
||||
if (targetHasLink()) {
|
||||
this.log(` > [PATCH] ${targetLog} does have link, will remove the inputs' link first.`);
|
||||
instructions.push(patchTarget("REMOVE", -1));
|
||||
}
|
||||
}
|
||||
else if (!targetNode && originNode) {
|
||||
this.log(`Link ${link.id} is funky... ` +
|
||||
`target ${link.target_id} does not exist, but origin ${link.origin_id} does.`);
|
||||
if (originHasLink()) {
|
||||
this.log(` > [PATCH] Origin's links' has ${link.id}; will remove the link first.`);
|
||||
instructions.push(patchOrigin("REMOVE"));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (targetHasLink() || originHasLink()) {
|
||||
if (!originHasLink()) {
|
||||
this.log(`${link.id} is funky... ${originLog} does NOT contain it, but ${targetLog} does.`);
|
||||
this.log(` > [PATCH] Attempt a fix by adding this ${link.id} to ${originLog}.`);
|
||||
instructions.push(patchOrigin("ADD"));
|
||||
}
|
||||
else if (!targetHasLink()) {
|
||||
this.log(`${link.id} is funky... ${targetLog} is NOT correct (is ${(_b = (_a = targetNode.inputs) === null || _a === void 0 ? void 0 : _a[link.target_slot]) === null || _b === void 0 ? void 0 : _b.link}), but ${originLog} contains it`);
|
||||
if (!targetHasAnyLink()) {
|
||||
this.log(` > [PATCH] ${targetLog} is not defined, will set to ${link.id}.`);
|
||||
let instruction = patchTarget("ADD");
|
||||
if (!instruction) {
|
||||
this.log(` > [PATCH] Nvm, ${targetLog} already patched. Removing ${link.id} from ${originLog}.`);
|
||||
instruction = patchOrigin("REMOVE");
|
||||
}
|
||||
instructions.push(instruction);
|
||||
}
|
||||
else {
|
||||
this.log(` > [PATCH] ${targetLog} is defined, removing ${link.id} from ${originLog}.`);
|
||||
instructions.push(patchOrigin("REMOVE"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let link of links) {
|
||||
if (!link)
|
||||
continue;
|
||||
const originNode = this.getNodeById(link.origin_id);
|
||||
const targetNode = this.getNodeById(link.target_id);
|
||||
if (!originNode && !targetNode) {
|
||||
instructions.push({
|
||||
op: "DELETE",
|
||||
linkId: link.id,
|
||||
reason: `Both nodes #${link.origin_id} & #${link.target_id} are removed`,
|
||||
});
|
||||
}
|
||||
if ((!originNode ||
|
||||
!this.nodeHasLinkId(originNode, IoDirection.OUTPUT, link.origin_slot, link.id)) &&
|
||||
(!targetNode ||
|
||||
!this.nodeHasLinkId(targetNode, IoDirection.INPUT, link.target_slot, link.id))) {
|
||||
instructions.push({
|
||||
op: "DELETE",
|
||||
linkId: link.id,
|
||||
reason: `both origin node #${link.origin_id} ` +
|
||||
`${!originNode ? "is removed" : `is missing link id output slot ${link.origin_slot}`}` +
|
||||
`and target node #${link.target_id} ` +
|
||||
`${!targetNode ? "is removed" : `is missing link id input slot ${link.target_slot}`}.`,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.instructions = instructions.filter((i) => !!i);
|
||||
this.checkedData = {
|
||||
hasBadLinks: !!this.instructions.length,
|
||||
graph: this.graph,
|
||||
patches: this.instructions.filter((i) => !!i.node)
|
||||
.length,
|
||||
deletes: this.instructions.filter((i) => i.op === "DELETE").length,
|
||||
};
|
||||
return { ...this.checkedData };
|
||||
}
|
||||
fix(force = false, times) {
|
||||
var _a, _b, _c, _d, _e, _f, _g;
|
||||
if (!this.checkedData || force) {
|
||||
this.check(force);
|
||||
}
|
||||
let patches = 0;
|
||||
let deletes = 0;
|
||||
for (const instruction of this.instructions) {
|
||||
if (instruction.node) {
|
||||
let { node, slot, linkIdToUse, dir, op } = instruction;
|
||||
if (dir == IoDirection.INPUT) {
|
||||
node.inputs = node.inputs || [];
|
||||
const old = (_a = node.inputs[slot]) === null || _a === void 0 ? void 0 : _a.link;
|
||||
node.inputs[slot] = node.inputs[slot] || {};
|
||||
node.inputs[slot].link = linkIdToUse;
|
||||
this.log(`Node #${node.id}: Set link ${linkIdToUse} to input slot ${slot} (was ${old})`);
|
||||
}
|
||||
else if (op === "ADD" && linkIdToUse != null) {
|
||||
node.outputs = node.outputs || [];
|
||||
node.outputs[slot] = node.outputs[slot] || {};
|
||||
node.outputs[slot].links = node.outputs[slot].links || [];
|
||||
node.outputs[slot].links.push(linkIdToUse);
|
||||
this.log(`Node #${node.id}: Add link ${linkIdToUse} to output slot #${slot}`);
|
||||
}
|
||||
else if (op === "REMOVE" && linkIdToUse != null) {
|
||||
if (((_d = (_c = (_b = node.outputs) === null || _b === void 0 ? void 0 : _b[slot]) === null || _c === void 0 ? void 0 : _c.links) === null || _d === void 0 ? void 0 : _d.length) === undefined) {
|
||||
this.log(`Node #${node.id}: Couldn't remove link ${linkIdToUse} from output slot #${slot}` +
|
||||
` because it didn't exist.`);
|
||||
}
|
||||
else {
|
||||
let linkIdIndex = node.outputs[slot].links.indexOf(linkIdToUse);
|
||||
node.outputs[slot].links.splice(linkIdIndex, 1);
|
||||
this.log(`Node #${node.id}: Remove link ${linkIdToUse} from output slot #${slot}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error("Unhandled Node Instruction");
|
||||
}
|
||||
patches++;
|
||||
}
|
||||
else if (instruction.op === "DELETE") {
|
||||
const wasDeleted = this.deleteGraphLink(instruction.linkId);
|
||||
if (wasDeleted === true) {
|
||||
this.log(`Link #${instruction.linkId}: Removed workflow link b/c ${instruction.reason}`);
|
||||
}
|
||||
else {
|
||||
this.log(`Error Link #${instruction.linkId} was not removed!`);
|
||||
}
|
||||
deletes += wasDeleted ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
throw new Error("Unhandled Instruction");
|
||||
}
|
||||
}
|
||||
const newCheck = this.check(force);
|
||||
times = times == null ? 5 : times;
|
||||
let newFix = null;
|
||||
if (newCheck.hasBadLinks && times > 0) {
|
||||
newFix = this.fix(true, times - 1);
|
||||
}
|
||||
return {
|
||||
hasBadLinks: (_e = newFix === null || newFix === void 0 ? void 0 : newFix.hasBadLinks) !== null && _e !== void 0 ? _e : newCheck.hasBadLinks,
|
||||
graph: this.graph,
|
||||
patches: patches + ((_f = newFix === null || newFix === void 0 ? void 0 : newFix.patches) !== null && _f !== void 0 ? _f : 0),
|
||||
deletes: deletes + ((_g = newFix === null || newFix === void 0 ? void 0 : newFix.deletes) !== null && _g !== void 0 ? _g : 0),
|
||||
};
|
||||
}
|
||||
log(...args) {
|
||||
if (this.silent)
|
||||
return;
|
||||
this.logger.log(...args);
|
||||
}
|
||||
getNodePatchInstruction(node, ioDir, slot, linkId, op) {
|
||||
var _a, _b;
|
||||
const nodeId = node.id;
|
||||
this.patchedNodeSlots[nodeId] = this.patchedNodeSlots[nodeId] || {};
|
||||
const patchedNode = this.patchedNodeSlots[nodeId];
|
||||
if (ioDir == IoDirection.INPUT) {
|
||||
patchedNode["inputs"] = patchedNode["inputs"] || {};
|
||||
if (patchedNode["inputs"][slot] !== undefined) {
|
||||
this.log(` > Already set ${nodeId}.inputs[${slot}] to ${patchedNode["inputs"][slot]} Skipping.`);
|
||||
return null;
|
||||
}
|
||||
let linkIdToUse = op === "REMOVE" ? null : linkId;
|
||||
patchedNode["inputs"][slot] = linkIdToUse;
|
||||
return { node, dir: ioDir, op, slot, linkId, linkIdToUse };
|
||||
}
|
||||
patchedNode["outputs"] = patchedNode["outputs"] || {};
|
||||
patchedNode["outputs"][slot] = patchedNode["outputs"][slot] || {
|
||||
links: [...(((_b = (_a = node.outputs) === null || _a === void 0 ? void 0 : _a[slot]) === null || _b === void 0 ? void 0 : _b.links) || [])],
|
||||
changes: {},
|
||||
};
|
||||
if (patchedNode["outputs"][slot]["changes"][linkId] !== undefined) {
|
||||
this.log(` > Already set ${nodeId}.outputs[${slot}] to ${patchedNode["outputs"][slot]}! Skipping.`);
|
||||
return null;
|
||||
}
|
||||
patchedNode["outputs"][slot]["changes"][linkId] = op;
|
||||
if (op === "ADD") {
|
||||
let linkIdIndex = patchedNode["outputs"][slot]["links"].indexOf(linkId);
|
||||
if (linkIdIndex !== -1) {
|
||||
this.log(` > Hmmm.. asked to add ${linkId} but it is already in list...`);
|
||||
return null;
|
||||
}
|
||||
patchedNode["outputs"][slot]["links"].push(linkId);
|
||||
return { node, dir: ioDir, op, slot, linkId, linkIdToUse: linkId };
|
||||
}
|
||||
let linkIdIndex = patchedNode["outputs"][slot]["links"].indexOf(linkId);
|
||||
if (linkIdIndex === -1) {
|
||||
this.log(` > Hmmm.. asked to remove ${linkId} but it doesn't exist...`);
|
||||
return null;
|
||||
}
|
||||
patchedNode["outputs"][slot]["links"].splice(linkIdIndex, 1);
|
||||
return { node, dir: ioDir, op, slot, linkId, linkIdToUse: linkId };
|
||||
}
|
||||
nodeHasLinkId(node, ioDir, slot, linkId) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
||||
const nodeId = node.id;
|
||||
let has = false;
|
||||
if (ioDir === IoDirection.INPUT) {
|
||||
let nodeHasIt = ((_b = (_a = node.inputs) === null || _a === void 0 ? void 0 : _a[slot]) === null || _b === void 0 ? void 0 : _b.link) === linkId;
|
||||
if ((_c = this.patchedNodeSlots[nodeId]) === null || _c === void 0 ? void 0 : _c["inputs"]) {
|
||||
let patchedHasIt = this.patchedNodeSlots[nodeId]["inputs"][slot] === linkId;
|
||||
has = patchedHasIt;
|
||||
}
|
||||
else {
|
||||
has = nodeHasIt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let nodeHasIt = (_f = (_e = (_d = node.outputs) === null || _d === void 0 ? void 0 : _d[slot]) === null || _e === void 0 ? void 0 : _e.links) === null || _f === void 0 ? void 0 : _f.includes(linkId);
|
||||
if ((_j = (_h = (_g = this.patchedNodeSlots[nodeId]) === null || _g === void 0 ? void 0 : _g["outputs"]) === null || _h === void 0 ? void 0 : _h[slot]) === null || _j === void 0 ? void 0 : _j["changes"][linkId]) {
|
||||
let patchedHasIt = this.patchedNodeSlots[nodeId]["outputs"][slot].links.includes(linkId);
|
||||
has = !!patchedHasIt;
|
||||
}
|
||||
else {
|
||||
has = !!nodeHasIt;
|
||||
}
|
||||
}
|
||||
return has;
|
||||
}
|
||||
nodeHasAnyLink(node, ioDir, slot) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
||||
const nodeId = node.id;
|
||||
let hasAny = false;
|
||||
if (ioDir === IoDirection.INPUT) {
|
||||
let nodeHasAny = ((_b = (_a = node.inputs) === null || _a === void 0 ? void 0 : _a[slot]) === null || _b === void 0 ? void 0 : _b.link) != null;
|
||||
if ((_c = this.patchedNodeSlots[nodeId]) === null || _c === void 0 ? void 0 : _c["inputs"]) {
|
||||
let patchedHasAny = this.patchedNodeSlots[nodeId]["inputs"][slot] != null;
|
||||
hasAny = patchedHasAny;
|
||||
}
|
||||
else {
|
||||
hasAny = !!nodeHasAny;
|
||||
}
|
||||
}
|
||||
else {
|
||||
let nodeHasAny = (_f = (_e = (_d = node.outputs) === null || _d === void 0 ? void 0 : _d[slot]) === null || _e === void 0 ? void 0 : _e.links) === null || _f === void 0 ? void 0 : _f.length;
|
||||
if ((_j = (_h = (_g = this.patchedNodeSlots[nodeId]) === null || _g === void 0 ? void 0 : _g["outputs"]) === null || _h === void 0 ? void 0 : _h[slot]) === null || _j === void 0 ? void 0 : _j["changes"]) {
|
||||
let patchedHasAny = (_k = this.patchedNodeSlots[nodeId]["outputs"][slot].links) === null || _k === void 0 ? void 0 : _k.length;
|
||||
hasAny = !!patchedHasAny;
|
||||
}
|
||||
else {
|
||||
hasAny = !!nodeHasAny;
|
||||
}
|
||||
}
|
||||
return hasAny;
|
||||
}
|
||||
}
|
||||
class WorkflowLinkFixerSerialized extends WorkflowLinkFixer {
|
||||
constructor(graph) {
|
||||
super(graph);
|
||||
}
|
||||
getNodeById(id) {
|
||||
var _a;
|
||||
return (_a = this.graph.nodes.find((node) => Number(node.id) === id)) !== null && _a !== void 0 ? _a : null;
|
||||
}
|
||||
fix(force = false, times) {
|
||||
const ret = super.fix(force, times);
|
||||
this.graph.links = this.graph.links.filter((l) => !!l);
|
||||
return ret;
|
||||
}
|
||||
deleteGraphLink(id) {
|
||||
const idx = this.graph.links.findIndex((l) => l && (l[0] === id || l.id === id));
|
||||
if (idx === -1) {
|
||||
return `Link #${id} not found in workflow links.`;
|
||||
}
|
||||
this.graph.links.splice(idx, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class WorkflowLinkFixerGraph extends WorkflowLinkFixer {
|
||||
constructor(graph) {
|
||||
super(graph);
|
||||
}
|
||||
getNodeById(id) {
|
||||
var _a;
|
||||
return (_a = this.graph.getNodeById(id)) !== null && _a !== void 0 ? _a : null;
|
||||
}
|
||||
deleteGraphLink(id) {
|
||||
if (this.graph.links instanceof Map) {
|
||||
if (!this.graph.links.has(id)) {
|
||||
return `Link #${id} not found in workflow links.`;
|
||||
}
|
||||
this.graph.links.delete(id);
|
||||
return true;
|
||||
}
|
||||
if (this.graph.links[id] == null) {
|
||||
return `Link #${id} not found in workflow links.`;
|
||||
}
|
||||
delete this.graph.links[id];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
7
custom_nodes/rgthree-comfy/web/common/media/rgthree.svg
Normal file
7
custom_nodes/rgthree-comfy/web/common/media/rgthree.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor">
|
||||
<path d="M88.503,158.997 L152.731,196.103 L152.738,196.092 L152.762,196.103 L152.769,196.106 L152.771,196.103 L183.922,142.084 L174.153,136.437 L148.611,180.676 L101.512,153.484 L132.193,30.415 L156.124,71.869 L165.896,66.225 L128.002,0.59 z"></path>
|
||||
<path d="M55.586,148.581l13.44,47.521l0.014,0.051l0.168-0.051l10.689-3.022l-6.589-23.313l45.609,26.335l0.087,0.051l0.027-0.051 l5.617-9.718l-42.648-24.622l35.771-143.45L33.232,164.729l9.77,5.645L55.586,148.581z M87.394,93.484l-16.708,67.018l-5.018-17.747 l-8.028,2.27L87.394,93.484z"></path>
|
||||
<path d="M189.85,107.717 L137.892,137.718 L143.532,147.49 L185.723,123.133 L231.109,201.746 L24.895,201.746 L37.363,180.146 L27.592,174.505 L5.347,213.03 L250.653,213.03 z"></path>
|
||||
<path d="M5.347,247.299v8.111h245.307v-8.111l-41.94-0.003c-1.336,0-2.404-1.065-2.441-2.396v-12.14 c0.037-1.315,1.089-2.368,2.41-2.385h41.972v-8.11H5.347v8.11h41.951c1.338,0.017,2.427,1.104,2.427,2.449v12.01 c0,1.365-1.105,2.462-2.457,2.462L5.347,247.299z M139.438,247.296c-1.334,0-2.406-1.065-2.439-2.396v-12.14 c0.033-1.315,1.085-2.368,2.41-2.385h46.415c1.335,0.017,2.425,1.104,2.425,2.449v12.01c0,1.365-1.103,2.462-2.459,2.462H139.438z M70.193,247.296c-1.339,0-2.408-1.065-2.441-2.396v-12.14c0.033-1.315,1.086-2.368,2.407-2.385h46.418 c1.336,0.017,2.425,1.104,2.425,2.449v12.01c0,1.365-1.103,2.462-2.458,2.462H70.193z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
183
custom_nodes/rgthree-comfy/web/common/media/svgs.js
Normal file
183
custom_nodes/rgthree-comfy/web/common/media/svgs.js
Normal file
@@ -0,0 +1,183 @@
|
||||
import { createElement as $el } from "../utils_dom.js";
|
||||
export let logoRgthree = "";
|
||||
export async function logoRgthreeAsync() {
|
||||
var _a;
|
||||
if (logoRgthree)
|
||||
return logoRgthree;
|
||||
let baseUrl = null;
|
||||
if (window.location.pathname.includes("/rgthree/")) {
|
||||
const parts = (_a = window.location.pathname.split("/rgthree/")[1]) === null || _a === void 0 ? void 0 : _a.split("/");
|
||||
if (parts && parts.length) {
|
||||
baseUrl = parts.map(() => "../").join("") + "rgthree";
|
||||
}
|
||||
}
|
||||
baseUrl = baseUrl || "./rgthree";
|
||||
return fetch(`${baseUrl}/logo_markup.svg?fg=currentColor&cssClass=rgthree-logo&w=auto&h=auto`)
|
||||
.then((r) => r.text())
|
||||
.then((t) => {
|
||||
if (t.length < 100) {
|
||||
t = `<svg viewBox="0 0 256 256" fill="currentColor" class="rgthree-logo">
|
||||
<path d="M88.503,158.997 L152.731,196.103 L152.738,196.092 L152.762,196.103 L152.769,196.106 L152.771,196.103 L183.922,142.084 L174.153,136.437 L148.611,180.676 L101.512,153.484 L132.193,30.415 L156.124,71.869 L165.896,66.225 L128.002,0.59 "></path>
|
||||
<path d="M55.586,148.581l13.44,47.521l0.014,0.051l0.168-0.051l10.689-3.022l-6.589-23.313l45.609,26.335l0.087,0.051l0.027-0.051 l5.617-9.718l-42.648-24.622l35.771-143.45L33.232,164.729l9.77,5.645L55.586,148.581z M87.394,93.484l-16.708,67.018l-5.018-17.747 l-8.028,2.27L87.394,93.484z"></path>
|
||||
<path d="M189.85,107.717 L137.892,137.718 L143.532,147.49 L185.723,123.133 L231.109,201.746 L24.895,201.746 L37.363,180.146 L27.592,174.505 L5.347,213.03 L250.653,213.03 "></path>
|
||||
<path d="M5.347,247.299v8.111h245.307v-8.111l-41.94-0.003c-1.336,0-2.404-1.065-2.441-2.396v-12.14 c0.037-1.315,1.089-2.368,2.41-2.385h41.972v-8.11H5.347v8.11h41.951c1.338,0.017,2.427,1.104,2.427,2.449v12.01 c0,1.365-1.105,2.462-2.457,2.462L5.347,247.299z M139.438,247.296c-1.334,0-2.406-1.065-2.439-2.396v-12.14 c0.033-1.315,1.085-2.368,2.41-2.385h46.415c1.335,0.017,2.425,1.104,2.425,2.449v12.01c0,1.365-1.103,2.462-2.459,2.462H139.438z M70.193,247.296c-1.339,0-2.408-1.065-2.441-2.396v-12.14c0.033-1.315,1.086-2.368,2.407-2.385h46.418 c1.336,0.017,2.425,1.104,2.425,2.449v12.01c0,1.365-1.103,2.462-2.458,2.462H70.193z"></path>
|
||||
</svg>`;
|
||||
}
|
||||
logoRgthree = t;
|
||||
return t;
|
||||
});
|
||||
}
|
||||
logoRgthreeAsync();
|
||||
export const github = `<svg viewBox="0 0 16 16" fill="currentColor" class="github-logo">
|
||||
<path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
|
||||
</svg>`;
|
||||
export const iconStarFilled = `<svg viewBox="0 0 16 16" fill="currentColor" class="github-star">
|
||||
<path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"></path>
|
||||
</svg>`;
|
||||
export const iconReplace = `<svg viewBox="0 0 52 52" fill="currentColor">
|
||||
<path d="M20,37.5c0-0.8-0.7-1.5-1.5-1.5h-15C2.7,36,2,36.7,2,37.5v11C2,49.3,2.7,50,3.5,50h15c0.8,0,1.5-0.7,1.5-1.5 V37.5z"/>
|
||||
<path d="M8.1,22H3.2c-1,0-1.5,0.9-0.9,1.4l8,8.3c0.4,0.3,1,0.3,1.4,0l8-8.3c0.6-0.6,0.1-1.4-0.9-1.4h-4.7 c0-5,4.9-10,9.9-10V6C15,6,8.1,13,8.1,22z"/>
|
||||
<path d="M41.8,20.3c-0.4-0.3-1-0.3-1.4,0l-8,8.3c-0.6,0.6-0.1,1.4,0.9,1.4h4.8c0,6-4.1,10-10.1,10v6 c9,0,16.1-7,16.1-16H49c1,0,1.5-0.9,0.9-1.4L41.8,20.3z"/>
|
||||
<path d="M50,3.5C50,2.7,49.3,2,48.5,2h-15C32.7,2,32,2.7,32,3.5v11c0,0.8,0.7,1.5,1.5,1.5h15c0.8,0,1.5-0.7,1.5-1.5 V3.5z"/>
|
||||
</svg>`;
|
||||
export const iconNode = `<svg viewBox="0 -0.5 25 25" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5 19H9.5C7.29086 19 5.5 17.2091 5.5 15V9C5.5 6.79086 7.29086 5 9.5 5H15.5C17.7091 5 19.5 6.79086 19.5 9V15C19.5 17.2091 17.7091 19 15.5 19Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M19.5 9.75C19.9142 9.75 20.25 9.41421 20.25 9C20.25 8.58579 19.9142 8.25 19.5 8.25V9.75ZM5.5 8.25C5.08579 8.25 4.75 8.58579 4.75 9C4.75 9.41421 5.08579 9.75 5.5 9.75V8.25ZM11.5 14.25C11.0858 14.25 10.75 14.5858 10.75 15C10.75 15.4142 11.0858 15.75 11.5 15.75V14.25ZM13.5 15.75C13.9142 15.75 14.25 15.4142 14.25 15C14.25 14.5858 13.9142 14.25 13.5 14.25V15.75ZM19.5 8.25H5.5V9.75H19.5V8.25ZM11.5 15.75H13.5V14.25H11.5V15.75Z" fill="currentColor" />
|
||||
</svg>`;
|
||||
export const iconGear = `<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7848 0.449982C13.8239 0.449982 14.7167 1.16546 14.9122 2.15495L14.9991 2.59495C15.3408 4.32442 17.1859 5.35722 18.9016 4.7794L19.3383 4.63233C20.3199 4.30175 21.4054 4.69358 21.9249 5.56605L22.7097 6.88386C23.2293 7.75636 23.0365 8.86366 22.2504 9.52253L21.9008 9.81555C20.5267 10.9672 20.5267 13.0328 21.9008 14.1844L22.2504 14.4774C23.0365 15.1363 23.2293 16.2436 22.7097 17.1161L21.925 18.4339C21.4054 19.3064 20.3199 19.6982 19.3382 19.3676L18.9017 19.2205C17.1859 18.6426 15.3408 19.6754 14.9991 21.405L14.9122 21.845C14.7167 22.8345 13.8239 23.55 12.7848 23.55H11.2152C10.1761 23.55 9.28331 22.8345 9.08781 21.8451L9.00082 21.4048C8.65909 19.6754 6.81395 18.6426 5.09822 19.2205L4.66179 19.3675C3.68016 19.6982 2.59465 19.3063 2.07505 18.4338L1.2903 17.1161C0.770719 16.2436 0.963446 15.1363 1.74956 14.4774L2.09922 14.1844C3.47324 13.0327 3.47324 10.9672 2.09922 9.8156L1.74956 9.52254C0.963446 8.86366 0.77072 7.75638 1.2903 6.8839L2.07508 5.56608C2.59466 4.69359 3.68014 4.30176 4.66176 4.63236L5.09831 4.77939C6.81401 5.35722 8.65909 4.32449 9.00082 2.59506L9.0878 2.15487C9.28331 1.16542 10.176 0.449982 11.2152 0.449982H12.7848ZM12 15.3C13.8225 15.3 15.3 13.8225 15.3 12C15.3 10.1774 13.8225 8.69998 12 8.69998C10.1774 8.69998 8.69997 10.1774 8.69997 12C8.69997 13.8225 10.1774 15.3 12 15.3Z" />
|
||||
</svg>`;
|
||||
export const checkmark = `<svg viewBox="0 0 32 32" fill="currentColor" class="icon-checkmark">
|
||||
<g transform="translate(-518.000000, -1039.000000)">
|
||||
<path d="M548.783,1040.2 C547.188,1038.57 544.603,1038.57 543.008,1040.2 L528.569,1054.92 L524.96,1051.24 C523.365,1049.62 520.779,1049.62 519.185,1051.24 C517.59,1052.87 517.59,1055.51 519.185,1057.13 L525.682,1063.76 C527.277,1065.39 529.862,1065.39 531.457,1063.76 L548.783,1046.09 C550.378,1044.46 550.378,1041.82 548.783,1040.2"></path>
|
||||
</g>
|
||||
</svg>`;
|
||||
export const logoCivitai = `<svg viewBox="0 0 178 178" class="logo-civitai">
|
||||
<defs>
|
||||
<linearGradient id="bgblue" gradientUnits="userSpaceOnUse" x1="89.3" y1="-665.5" x2="89.3" y2="-841.1" gradientTransform="matrix(1 0 0 -1 0 -664)">
|
||||
<stop offset="0" style="stop-color:#1284F7"/>
|
||||
<stop offset="1" style="stop-color:#0A20C9"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="#000" d="M13.3,45.4v87.7l76,43.9l76-43.9V45.4l-76-43.9L13.3,45.4z"/>
|
||||
<path style="fill:url(#bgblue);" d="M89.3,29.2l52,30v60l-52,30l-52-30v-60 L89.3,29.2 M89.3,1.5l-76,43.9v87.8l76,43.9l76-43.9V45.4L89.3,1.5z" />
|
||||
<path fill="#FFF" d="M104.1,97.2l-14.9,8.5l-14.9-8.5v-17l14.9-8.5l14.9,8.5h18.2V69.7l-33-19l-33,19v38.1l33,19l33-19V97.2H104.1z" />
|
||||
</svg>`;
|
||||
export const iconOutLink = `<svg viewBox="0 0 32 32">
|
||||
<path d="M 18 5 L 18 7 L 23.5625 7 L 11.28125 19.28125 L 12.71875 20.71875 L 25 8.4375 L 25 14 L 27 14 L 27 5 Z M 5 9 L 5 27 L 23 27 L 23 14 L 21 16 L 21 25 L 7 25 L 7 11 L 16 11 L 18 9 Z"></path>
|
||||
</svg>`;
|
||||
export const link = `<svg viewBox="0 0 640 512">
|
||||
<path d="M598.6 41.41C570.1 13.8 534.8 0 498.6 0s-72.36 13.8-99.96 41.41l-43.36 43.36c15.11 8.012 29.47 17.58 41.91 30.02c3.146 3.146 5.898 6.518 8.742 9.838l37.96-37.96C458.5 72.05 477.1 64 498.6 64c20.67 0 40.1 8.047 54.71 22.66c14.61 14.61 22.66 34.04 22.66 54.71s-8.049 40.1-22.66 54.71l-133.3 133.3C405.5 343.1 386 352 365.4 352s-40.1-8.048-54.71-22.66C296 314.7 287.1 295.3 287.1 274.6s8.047-40.1 22.66-54.71L314.2 216.4C312.1 212.5 309.9 208.5 306.7 205.3C298.1 196.7 286.8 192 274.6 192c-11.93 0-23.1 4.664-31.61 12.97c-30.71 53.96-23.63 123.6 22.39 169.6C293 402.2 329.2 416 365.4 416c36.18 0 72.36-13.8 99.96-41.41L598.6 241.3c28.45-28.45 42.24-66.01 41.37-103.3C639.1 102.1 625.4 68.16 598.6 41.41zM234 387.4L196.1 425.3C181.5 439.1 162 448 141.4 448c-20.67 0-40.1-8.047-54.71-22.66c-14.61-14.61-22.66-34.04-22.66-54.71s8.049-40.1 22.66-54.71l133.3-133.3C234.5 168 253.1 160 274.6 160s40.1 8.048 54.71 22.66c14.62 14.61 22.66 34.04 22.66 54.71s-8.047 40.1-22.66 54.71L325.8 295.6c2.094 3.939 4.219 7.895 7.465 11.15C341.9 315.3 353.3 320 365.4 320c11.93 0 23.1-4.664 31.61-12.97c30.71-53.96 23.63-123.6-22.39-169.6C346.1 109.8 310.8 96 274.6 96C238.4 96 202.3 109.8 174.7 137.4L41.41 270.7c-27.6 27.6-41.41 63.78-41.41 99.96c-.0001 36.18 13.8 72.36 41.41 99.97C69.01 498.2 105.2 512 141.4 512c36.18 0 72.36-13.8 99.96-41.41l43.36-43.36c-15.11-8.012-29.47-17.58-41.91-30.02C239.6 394.1 236.9 390.7 234 387.4z"/>
|
||||
</svg>`;
|
||||
export const pencil = `<svg viewBox="0 0 24 24">
|
||||
<path d="M 16.9375 1.0625 L 3.875 14.125 L 1.0742188 22.925781 L 9.875 20.125 L 22.9375 7.0625 C 22.9375 7.0625 22.8375 4.9615 20.9375 3.0625 C 19.0375 1.1625 16.9375 1.0625 16.9375 1.0625 z M 17.3125 2.6875 C 18.3845 2.8915 19.237984 3.3456094 19.896484 4.0214844 C 20.554984 4.6973594 21.0185 5.595 21.3125 6.6875 L 19.5 8.5 L 15.5 4.5 L 16.9375 3.0625 L 17.3125 2.6875 z M 4.9785156 15.126953 C 4.990338 15.129931 6.1809555 15.430955 7.375 16.625 C 8.675 17.825 8.875 18.925781 8.875 18.925781 L 8.9179688 18.976562 L 5.3691406 20.119141 L 3.8730469 18.623047 L 4.9785156 15.126953 z"/>
|
||||
</svg>`;
|
||||
export const dotdotdot = `<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<circle cy="12" r="3" cx="3"></circle>
|
||||
<circle cy="12" r="3" cx="12"></circle>
|
||||
<circle cx="21" cy="12" r="3"></circle>
|
||||
</svg>`;
|
||||
export const models = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 4h6v6h-6z"></path>
|
||||
<path d="M14 4h6v6h-6z"></path>
|
||||
<path d="M4 14h6v6h-6z"></path>
|
||||
<path d="M17 17m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0"></path>
|
||||
</svg>`;
|
||||
export const pencilColored = `<svg viewBox="0 0 64 64">
|
||||
<path fill="#ffce31" d="M7.934 41.132L39.828 9.246l14.918 14.922l-31.895 31.886z"></path>
|
||||
<path d="M61.3 4.6l-1.9-1.9C55.8-.9 50-.9 46.3 2.7l-6.5 6.5l15 15l6.5-6.5c3.6-3.6 3.6-9.5 0-13.1" fill="#ed4c5c"></path>
|
||||
<path fill="#93a2aa" d="M35.782 13.31l4.1-4.102l14.92 14.92l-4.1 4.101z"></path>
|
||||
<path fill="#c7d3d8" d="M37.338 14.865l4.1-4.101l11.739 11.738l-4.102 4.1z"></path>
|
||||
<path fill="#fed0ac" d="M7.9 41.1l-6.5 17l4.5 4.5l17-6.5z"/>
|
||||
<path d="M.3 61.1c-.9 2.4.3 3.5 2.7 2.6l8.2-3.1l-7.7-7.7l-3.2 8.2" fill="#333"></path>
|
||||
<path fill="#ffdf85" d="M7.89 41.175l27.86-27.86l4.95 4.95l-27.86 27.86z"/>
|
||||
<path fill="#ff8736" d="M17.904 51.142l27.86-27.86l4.95 4.95l-27.86 27.86z"></path>
|
||||
</svg>`;
|
||||
export const diskColored = `<svg viewBox="-0.01 -0.008 100.016 100.016">
|
||||
<path fill="#26f" fill_="#23475F" d="M88.555-.008H83v.016a2 2 0 0 1-2 2H19a2 2 0 0 1-2-2v-.016H4a4 4 0 0 0-4 4v92.016a4 4 0 0 0 4 4h92a4 4 0 0 0 4-4V11.517c.049-.089-11.436-11.454-11.445-11.525z"/>
|
||||
<path fill="#04d" fill_="#1C3C50" d="M81.04 53.008H18.96a2 2 0 0 0-2 2v45h66.08v-45c0-1.106-.895-2-2-2zm-61.957-10h61.834a2 2 0 0 0 2-2V.547A1.993 1.993 0 0 1 81 2.007H19c-.916 0-1.681-.62-1.917-1.46v40.46a2 2 0 0 0 2 2.001z"/>
|
||||
<path fill="#EBF0F1" d="M22 55.977h56a2 2 0 0 1 2 2v37.031a2 2 0 0 1-2 2H22c-1.104 0-2-.396-2-1.5V57.977a2 2 0 0 1 2-2z"/>
|
||||
<path fill="#BCC4C8" d="M25 77.008h50v1H25v-1zm0 10h50v1H25v-1z"/>
|
||||
<path fill="#1C3C50" d="M7 84.008h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2zm83 0h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2z"/>
|
||||
<path fill="#BCC4C8" d="M37 1.981v36.026a2 2 0 0 0 2 2h39a2 2 0 0 0 2-2V1.981c0 .007-42.982.007-43 0zm37 29.027a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2V10.981a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v20.027z"/>
|
||||
<path fill="#FF9D00" d="M78 55.977H22a2 2 0 0 0-2 2v10.031h60V57.977a2 2 0 0 0-2-2z"/>
|
||||
</svg>`;
|
||||
export const folderColored = `<svg viewBox="0 0 501.379 501.379">
|
||||
<path style="fill:#EF9F2C;" d="M406.423,93.889H205.889c-17.067,0-30.933-13.867-30.933-30.933s-13.867-30.933-30.933-30.933H30.956
|
||||
c-17.067,0-30.933,13.867-30.933,30.933v375.467c0,17.067,13.867,30.933,30.933,30.933h375.467
|
||||
c17.067,0,30.933-13.867,30.933-30.933v-313.6C436.289,107.756,422.423,93.889,406.423,93.889z"/>
|
||||
<path style="fill:#FEC656;" d="M470.423,157.889H97.089c-13.867,0-26.667,9.6-29.867,22.4l-66.133,249.6
|
||||
c-5.333,19.2,9.6,38.4,29.867,38.4h373.333c13.867,0,26.667-9.6,29.867-22.4l66.133-248.533
|
||||
C505.623,177.089,490.689,157.889,470.423,157.889z"/>
|
||||
</svg>`;
|
||||
export const modelsColored = `<svg viewBox="0 0 24 24">
|
||||
<path fill="#aa3366" d="M0 0h10v10h-10z"></path>
|
||||
<path d="M14 0h10v10h-10z" fill="#3366aa"></path>
|
||||
<path d="M0 14h10v10h-10z" fill="#66aa33"></path>
|
||||
<path fill="#dd9922" d="M19 19m-5 0 a5 5 0 1 0 10 0 a5 5 0 1 0 -10 0"></path>
|
||||
</svg>`;
|
||||
export const legoBlocksColored = `<svg viewBox="0 0 512 512">
|
||||
<g>
|
||||
<rect x="57.67" style="fill:#00BAB9;" width="101.275" height="78.769"/>
|
||||
<rect x="205.363" style="fill:#00BAB9;" width="101.275" height="78.769"/>
|
||||
<rect x="353.055" style="fill:#00BAB9;" width="101.275" height="78.769"/>
|
||||
</g>
|
||||
<polygon style="fill:#B8DE6F;" points="478.242,289.758 478.242,512 33.758,512 33.758,289.758 256,267.253 "/>
|
||||
<polygon style="fill:#41D4D3;" points="478.242,67.516 478.242,289.758 33.758,289.758 33.758,67.516 57.67,67.516 158.945,67.516
|
||||
205.363,67.516 306.637,67.516 353.055,67.516 454.33,67.516 "/>
|
||||
<g>
|
||||
<circle style="fill:#00BAB9;" cx="402.286" cy="143.473" r="8.44"/>
|
||||
<circle style="fill:#00BAB9;" cx="368.527" cy="177.231" r="8.44"/>
|
||||
</g>
|
||||
<circle style="fill:#7BD288;" cx="109.714" cy="436.044" r="8.44"/>
|
||||
</svg>`;
|
||||
export const legoBlockColored = `<svg viewBox="0 0 256 256">
|
||||
<style>
|
||||
.s0 { fill: #ff0000 }
|
||||
.s1 { fill: #c30000 }
|
||||
.s2 { fill: #800000 }
|
||||
.s3 { fill: #cc0000 }
|
||||
.s4 { fill: #e00000 }
|
||||
</style>
|
||||
<g id="Folder 2">
|
||||
<path id="Shape 1 copy 2" class="s0" d="m128 61l116 45-116 139-116-139z"/>
|
||||
<path id="Shape 1" class="s1" d="m12 106l116 45v95l-116-45z"/>
|
||||
<path id="Shape 1 copy" class="s2" d="m244 106l-116 45v95l116-45z"/>
|
||||
<g id="Folder 1">
|
||||
<path id="Shape 2" class="s3" d="m102 111.2c0-6.1 11.4-9.9 25.5-9.9 14.1 0 25.5 3.8 25.5 9.9 0 3.3 0 13.3 0 16.6 0 6.1-11.4 10.9-25.5 10.9-14.1 0-25.5-4.8-25.5-10.9 0-3.3 0-13.3 0-16.6z"/>
|
||||
<path id="Shape 2 copy 4" class="s1" d="m102 111.2c0-6.1 11.4-9.9 25.5-9.9 14.1 0 25.5 3.8 25.5 9.9 0 3.3 0 13.3 0 16.6 0 6.1-11.4 10.9-25.5 10.9-14.1 0-25.5-4.8-25.5-10.9 0-3.3 0-13.3 0-16.6z"/>
|
||||
<path id="Shape 2 copy 2" class="s2" d="m127.5 101.3c14.1 0 25.5 3.8 25.5 9.9 0 3.3 0 13.3 0 16.6 0 6.1-11.4 10.9-25.5 10.9 0-13.1 0-25.7 0-37.4z"/>
|
||||
<path id="Shape 2 copy" class="s0" d="m127.5 118.8c-12.2 0-22-3.4-22-7.6 0-4.2 9.8-7.7 22-7.7 12.2 0 22 3.5 22 7.7 0 4.2-9.8 7.6-22 7.6zm0 0c-12.2 0-22-3.4-22-7.6 0-4.2 9.8-7.7 22-7.7 12.2 0 22 3.5 22 7.7 0 4.2-9.8 7.6-22 7.6z"/>
|
||||
</g>
|
||||
<g id="Folder 1 copy">
|
||||
<path id="Shape 2" class="s4" d="m103 67.5c0-5.8 11-9.5 24.5-9.5 13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5-13.5 0-24.5-4.7-24.5-10.5 0-3.2 0-12.8 0-16z"/>
|
||||
<path id="Shape 2 copy 4" class="s1" d="m103 67.5c0-5.8 11-9.5 24.5-9.5 13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5-13.5 0-24.5-4.7-24.5-10.5 0-3.2 0-12.8 0-16z"/>
|
||||
<path id="Shape 2 copy 2" class="s2" d="m127.5 58c13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5 0-12.6 0-24.8 0-36z"/>
|
||||
<path id="Shape 2 copy" class="s0" d="m127.5 74.9c-11.7 0-21.2-3.3-21.2-7.4 0-4.1 9.5-7.4 21.2-7.4 11.7 0 21.2 3.3 21.2 7.4 0 4.1-9.5 7.4-21.2 7.4zm0 0c-11.7 0-21.2-3.3-21.2-7.4 0-4.1 9.5-7.4 21.2-7.4 11.7 0 21.2 3.3 21.2 7.4 0 4.1-9.5 7.4-21.2 7.4z"/>
|
||||
</g>
|
||||
<g id="Folder 1 copy 2">
|
||||
<path id="Shape 2" class="s4" d="m161 89.5c0-5.8 11-9.5 24.5-9.5 13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5-13.5 0-24.5-4.7-24.5-10.5 0-3.2 0-12.8 0-16z"/>
|
||||
<path id="Shape 2 copy 4" class="s1" d="m161 89.5c0-5.8 11-9.5 24.5-9.5 13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5-13.5 0-24.5-4.7-24.5-10.5 0-3.2 0-12.8 0-16z"/>
|
||||
<path id="Shape 2 copy 2" class="s2" d="m185.5 80c13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5 0-12.6 0-24.8 0-36z"/>
|
||||
<path id="Shape 2 copy" class="s0" d="m185.5 96.9c-11.7 0-21.2-3.3-21.2-7.4 0-4.1 9.5-7.4 21.2-7.4 11.7 0 21.2 3.3 21.2 7.4 0 4.1-9.5 7.4-21.2 7.4zm0 0c-11.7 0-21.2-3.3-21.2-7.4 0-4.1 9.5-7.4 21.2-7.4 11.7 0 21.2 3.3 21.2 7.4 0 4.1-9.5 7.4-21.2 7.4z"/>
|
||||
</g>
|
||||
<g id="Folder 1 copy 3">
|
||||
<path id="Shape 2" class="s4" d="m45 89.5c0-5.8 11-9.5 24.5-9.5 13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5-13.5 0-24.5-4.7-24.5-10.5 0-3.2 0-12.8 0-16z"/>
|
||||
<path id="Shape 2 copy 4" class="s1" d="m45 89.5c0-5.8 11-9.5 24.5-9.5 13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5-13.5 0-24.5-4.7-24.5-10.5 0-3.2 0-12.8 0-16z"/>
|
||||
<path id="Shape 2 copy 2" class="s2" d="m69.5 80c13.5 0 24.5 3.7 24.5 9.5 0 3.2 0 12.8 0 16 0 5.8-11 10.5-24.5 10.5 0-12.6 0-24.8 0-36z"/>
|
||||
<path id="Shape 2 copy" class="s0" d="m69.5 96.9c-11.7 0-21.2-3.3-21.2-7.4 0-4.1 9.5-7.4 21.2-7.4 11.7 0 21.2 3.3 21.2 7.4 0 4.1-9.5 7.4-21.2 7.4zm0 0c-11.7 0-21.2-3.3-21.2-7.4 0-4.1 9.5-7.4 21.2-7.4 11.7 0 21.2 3.3 21.2 7.4 0 4.1-9.5 7.4-21.2 7.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
export const gearColored = `<svg viewBox="0 0 128 128" preserveAspectRatio="xMidYMid meet">
|
||||
<path d="M124 71.85v-15.7c0-.59-.45-1.09-1.03-1.15l-17.83-1.89c-.47-.05-.85-.38-.98-.83c-.86-2.95-2.03-5.76-3.48-8.39c-.23-.41-.19-.92.11-1.28l11.28-13.94c.37-.46.34-1.13-.08-1.54l-11.1-11.1a1.15 1.15 0 0 0-1.54-.08L85.39 27.22c-.37.3-.87.33-1.28.11a41.796 41.796 0 0 0-8.39-3.48c-.45-.13-.78-.51-.83-.98L73 5.03C72.94 4.45 72.44 4 71.85 4h-15.7c-.59 0-1.09.45-1.15 1.03l-1.89 17.83c-.05.47-.38.85-.83.98c-2.95.86-5.76 2.03-8.39 3.48c-.41.23-.92.19-1.28-.11L28.67 15.94a1.15 1.15 0 0 0-1.54.08l-11.1 11.1a1.15 1.15 0 0 0-.08 1.54L27.23 42.6c.3.37.33.87.11 1.28a41.796 41.796 0 0 0-3.48 8.39c-.13.45-.51.78-.98.83L5.03 55c-.58.06-1.03.56-1.03 1.15v15.7c0 .59.45 1.09 1.03 1.15l17.83 1.89c.47.05.85.38.98.83c.86 2.95 2.03 5.76 3.48 8.39c.23.41.19.92-.11 1.28L15.94 99.33c-.37.46-.34 1.13.08 1.54l11.1 11.1c.42.42 1.08.45 1.54.08l13.94-11.28c.37-.3.87-.33 1.28-.11c2.64 1.45 5.45 2.62 8.39 3.48c.45.13.78.51.83.98l1.9 17.85c.06.59.56 1.03 1.15 1.03h15.7c.59 0 1.09-.45 1.15-1.03l1.89-17.83c.05-.47.38-.85.83-.98c2.95-.86 5.76-2.03 8.39-3.48c.41-.23.92-.19 1.28.11l13.94 11.28c.46.37 1.13.34 1.54-.08l11.1-11.1c.42-.42.45-1.08.08-1.54l-11.28-13.94c-.3-.37-.33-.87-.11-1.28c1.45-2.64 2.62-5.45 3.48-8.39c.13-.45.51-.78.98-.83L122.97 73c.58-.06 1.03-.56 1.03-1.15zm-60 3.43c-6.23 0-11.28-5.05-11.28-11.28S57.77 52.72 64 52.72S75.28 57.77 75.28 64S70.23 75.28 64 75.28z" fill="#82aec0"></path>
|
||||
<path d="M80.56 49.48c3.67 4.18 5.78 9.77 5.43 15.85c-.65 11.16-9.83 20.19-21 20.68c-4.75.21-9.18-1.09-12.86-3.45c-.28-.18-.58.2-.34.44a22.412 22.412 0 0 0 17.85 6.67c10.78-.85 19.56-9.5 20.55-20.27c.77-8.36-3.06-15.87-9.23-20.33c-.29-.2-.62.15-.4.41z" fill="#2f7889"></path>
|
||||
<path d="M43.87 65.32c-.67-13.15 7.83-22.79 20.01-22.79c.65 0 1.68 0 2.48.92c1.01 1.18 1.1 2.6 0 3.77c-.81.86-1.95.92-2.53 1c-12.3 1.59-15.18 9.35-15.83 16.77c-.03.33.06 2.35-1.71 2.56c-2.15.25-2.41-1.91-2.42-2.23z" fill="#b9e4ea"></path>
|
||||
<path d="M25.24 65.87c-.01-22.03 15.9-40.19 38.13-41.05c.68-.03 2.45 0 3.55.99c1.01.91 1.38 2.51.79 3.82c-.95 2.11-2.85 2.07-3.36 2.09c-18.51.66-34.18 15.73-34.19 33.95c0 .29-.05.58-.15.84l-.1.25c-.76 1.98-3.52 2.09-4.43.18c-.15-.34-.24-.7-.24-1.07z" fill="#94d1e0"></path>
|
||||
</svg>`;
|
||||
export function $svg(markup, attrs) {
|
||||
if (!markup.match(/^\s*<svg/)) {
|
||||
throw new Error("Cannot call $svg with non-svg markup.");
|
||||
}
|
||||
return $el(markup, attrs || {});
|
||||
}
|
||||
98
custom_nodes/rgthree-comfy/web/common/menu.js
Normal file
98
custom_nodes/rgthree-comfy/web/common/menu.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import { generateId, wait } from "./shared_utils.js";
|
||||
import { createElement as $el, getClosestOrSelf, setAttributes } from "./utils_dom.js";
|
||||
class Menu {
|
||||
constructor(options) {
|
||||
this.element = $el('menu.rgthree-menu');
|
||||
this.callbacks = new Map();
|
||||
this.handleWindowPointerDownBound = this.handleWindowPointerDown.bind(this);
|
||||
this.setOptions(options);
|
||||
this.element.addEventListener('pointerup', async (e) => {
|
||||
var _a, _b;
|
||||
const target = getClosestOrSelf(e.target, "[data-callback],menu");
|
||||
if (e.which !== 1) {
|
||||
return;
|
||||
}
|
||||
const callback = (_a = target === null || target === void 0 ? void 0 : target.dataset) === null || _a === void 0 ? void 0 : _a['callback'];
|
||||
if (callback) {
|
||||
const halt = await ((_b = this.callbacks.get(callback)) === null || _b === void 0 ? void 0 : _b(e));
|
||||
if (halt !== false) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
}
|
||||
setOptions(options) {
|
||||
for (const option of options) {
|
||||
if (option.type === 'title') {
|
||||
this.element.appendChild($el(`li`, {
|
||||
html: option.label
|
||||
}));
|
||||
}
|
||||
else {
|
||||
const id = generateId(8);
|
||||
this.callbacks.set(id, async (e) => { var _a; return (_a = option === null || option === void 0 ? void 0 : option.callback) === null || _a === void 0 ? void 0 : _a.call(option, e); });
|
||||
this.element.appendChild($el(`li[role="button"][data-callback="${id}"]`, {
|
||||
html: option.label
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
toElement() {
|
||||
return this.element;
|
||||
}
|
||||
async open(e) {
|
||||
const parent = e.target.closest('div,dialog,body');
|
||||
parent.appendChild(this.element);
|
||||
setAttributes(this.element, {
|
||||
style: {
|
||||
left: `${e.clientX + 16}px`,
|
||||
top: `${e.clientY - 16}px`,
|
||||
}
|
||||
});
|
||||
this.element.setAttribute('state', 'measuring-open');
|
||||
await wait(16);
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) {
|
||||
this.element.style.left = `${e.clientX - rect.width - 16}px`;
|
||||
await wait(16);
|
||||
}
|
||||
this.element.setAttribute('state', 'open');
|
||||
setTimeout(() => {
|
||||
window.addEventListener('pointerdown', this.handleWindowPointerDownBound);
|
||||
});
|
||||
}
|
||||
handleWindowPointerDown(e) {
|
||||
if (!this.element.contains(e.target)) {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
async close() {
|
||||
window.removeEventListener('pointerdown', this.handleWindowPointerDownBound);
|
||||
this.element.setAttribute('state', 'measuring-closed');
|
||||
await wait(16);
|
||||
this.element.setAttribute('state', 'closed');
|
||||
this.element.remove();
|
||||
}
|
||||
isOpen() {
|
||||
return (this.element.getAttribute('state') || '').includes('open');
|
||||
}
|
||||
}
|
||||
export class MenuButton {
|
||||
constructor(options) {
|
||||
this.element = $el('button.rgthree-button[data-action="open-menu"]');
|
||||
this.options = options;
|
||||
this.element.innerHTML = options.icon;
|
||||
this.menu = new Menu(options.options);
|
||||
this.element.addEventListener('pointerdown', (e) => {
|
||||
if (!this.menu.isOpen()) {
|
||||
this.menu.open(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
toElement() {
|
||||
return this.element;
|
||||
}
|
||||
}
|
||||
72
custom_nodes/rgthree-comfy/web/common/model_info_service.js
Normal file
72
custom_nodes/rgthree-comfy/web/common/model_info_service.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import { rgthreeApi } from "./rgthree_api.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
class BaseModelInfoService extends EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this.fileToInfo = new Map();
|
||||
this.init();
|
||||
}
|
||||
init() {
|
||||
api.addEventListener(this.apiRefreshEventString, this.handleAsyncUpdate.bind(this));
|
||||
}
|
||||
async getInfo(file, refresh, light) {
|
||||
if (this.fileToInfo.has(file) && !refresh) {
|
||||
return this.fileToInfo.get(file);
|
||||
}
|
||||
return this.fetchInfo(file, refresh, light);
|
||||
}
|
||||
async refreshInfo(file) {
|
||||
return this.fetchInfo(file, true);
|
||||
}
|
||||
async clearFetchedInfo(file) {
|
||||
await rgthreeApi.clearModelsInfo({ type: this.modelInfoType, files: [file] });
|
||||
this.fileToInfo.delete(file);
|
||||
return null;
|
||||
}
|
||||
async savePartialInfo(file, data) {
|
||||
let info = await rgthreeApi.saveModelInfo(this.modelInfoType, file, data);
|
||||
this.fileToInfo.set(file, info);
|
||||
return info;
|
||||
}
|
||||
handleAsyncUpdate(event) {
|
||||
var _a;
|
||||
const info = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.data;
|
||||
if (info === null || info === void 0 ? void 0 : info.file) {
|
||||
this.setFreshInfo(info.file, info);
|
||||
}
|
||||
}
|
||||
async fetchInfo(file, refresh = false, light = false) {
|
||||
var _a;
|
||||
let info = null;
|
||||
if (!refresh) {
|
||||
info = await rgthreeApi.getModelsInfo({ type: this.modelInfoType, files: [file], light });
|
||||
}
|
||||
else {
|
||||
info = await rgthreeApi.refreshModelsInfo({ type: this.modelInfoType, files: [file] });
|
||||
}
|
||||
info = (_a = info === null || info === void 0 ? void 0 : info[0]) !== null && _a !== void 0 ? _a : null;
|
||||
if (!light) {
|
||||
this.fileToInfo.set(file, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
setFreshInfo(file, info) {
|
||||
this.fileToInfo.set(file, info);
|
||||
}
|
||||
}
|
||||
class LoraInfoService extends BaseModelInfoService {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.apiRefreshEventString = "rgthree-refreshed-loras-info";
|
||||
this.modelInfoType = 'loras';
|
||||
}
|
||||
}
|
||||
class CheckpointInfoService extends BaseModelInfoService {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.apiRefreshEventString = "rgthree-refreshed-checkpoints-info";
|
||||
this.modelInfoType = 'checkpoints';
|
||||
}
|
||||
}
|
||||
export const LORA_INFO_SERVICE = new LoraInfoService();
|
||||
export const CHECKPOINT_INFO_SERVICE = new CheckpointInfoService();
|
||||
179
custom_nodes/rgthree-comfy/web/common/progress_bar.js
Normal file
179
custom_nodes/rgthree-comfy/web/common/progress_bar.js
Normal file
@@ -0,0 +1,179 @@
|
||||
import { SERVICE as PROMPT_SERVICE } from "../common/prompt_service.js";
|
||||
import { createElement } from "./utils_dom.js";
|
||||
export class RgthreeProgressBar extends HTMLElement {
|
||||
static create() {
|
||||
return document.createElement(RgthreeProgressBar.NAME);
|
||||
}
|
||||
get currentNodeId() {
|
||||
var _a, _b;
|
||||
const prompt = this.currentPromptExecution;
|
||||
const nodeId = ((_a = prompt === null || prompt === void 0 ? void 0 : prompt.errorDetails) === null || _a === void 0 ? void 0 : _a.node_id) || ((_b = prompt === null || prompt === void 0 ? void 0 : prompt.currentlyExecuting) === null || _b === void 0 ? void 0 : _b.nodeId);
|
||||
return nodeId || null;
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
this.shadow = null;
|
||||
this.currentPromptExecution = null;
|
||||
this.onProgressUpdateBound = this.onProgressUpdate.bind(this);
|
||||
this.connected = false;
|
||||
}
|
||||
onProgressUpdate(e) {
|
||||
var _a, _b, _c, _d;
|
||||
if (!this.connected)
|
||||
return;
|
||||
const prompt = e.detail.prompt;
|
||||
this.currentPromptExecution = prompt;
|
||||
if (prompt === null || prompt === void 0 ? void 0 : prompt.errorDetails) {
|
||||
let progressText = `${(_a = prompt.errorDetails) === null || _a === void 0 ? void 0 : _a.exception_type} ${((_b = prompt.errorDetails) === null || _b === void 0 ? void 0 : _b.node_id) || ""} ${((_c = prompt.errorDetails) === null || _c === void 0 ? void 0 : _c.node_type) || ""}`;
|
||||
this.progressTextEl.innerText = progressText;
|
||||
this.progressNodesEl.classList.add("-error");
|
||||
this.progressStepsEl.classList.add("-error");
|
||||
return;
|
||||
}
|
||||
if (prompt === null || prompt === void 0 ? void 0 : prompt.currentlyExecuting) {
|
||||
this.progressNodesEl.classList.remove("-error");
|
||||
this.progressStepsEl.classList.remove("-error");
|
||||
const current = prompt === null || prompt === void 0 ? void 0 : prompt.currentlyExecuting;
|
||||
let progressText = `(${e.detail.queue}) `;
|
||||
if (!prompt.totalNodes) {
|
||||
progressText += `??%`;
|
||||
this.progressNodesEl.style.width = `0%`;
|
||||
}
|
||||
else {
|
||||
const percent = (prompt.executedNodeIds.length / prompt.totalNodes) * 100;
|
||||
this.progressNodesEl.style.width = `${Math.max(2, percent)}%`;
|
||||
progressText += `${Math.round(percent)}%`;
|
||||
}
|
||||
let nodeLabel = (_d = current.nodeLabel) === null || _d === void 0 ? void 0 : _d.trim();
|
||||
let stepsLabel = "";
|
||||
if (current.step != null && current.maxSteps) {
|
||||
const percent = (current.step / current.maxSteps) * 100;
|
||||
this.progressStepsEl.style.width = `${percent}%`;
|
||||
if (current.pass > 1 || current.maxPasses != null) {
|
||||
stepsLabel += `#${current.pass}`;
|
||||
if (current.maxPasses && current.maxPasses > 0) {
|
||||
stepsLabel += `/${current.maxPasses}`;
|
||||
}
|
||||
stepsLabel += ` - `;
|
||||
}
|
||||
stepsLabel += `${Math.round(percent)}%`;
|
||||
}
|
||||
if (nodeLabel || stepsLabel) {
|
||||
progressText += ` - ${nodeLabel || "???"}${stepsLabel ? ` (${stepsLabel})` : ""}`;
|
||||
}
|
||||
if (!stepsLabel) {
|
||||
this.progressStepsEl.style.width = `0%`;
|
||||
}
|
||||
this.progressTextEl.innerText = progressText;
|
||||
}
|
||||
else {
|
||||
if (e === null || e === void 0 ? void 0 : e.detail.queue) {
|
||||
this.progressTextEl.innerText = `(${e.detail.queue}) Running... in another tab`;
|
||||
}
|
||||
else {
|
||||
this.progressTextEl.innerText = "Idle";
|
||||
}
|
||||
this.progressNodesEl.style.width = `0%`;
|
||||
this.progressStepsEl.style.width = `0%`;
|
||||
}
|
||||
}
|
||||
connectedCallback() {
|
||||
if (!this.connected) {
|
||||
PROMPT_SERVICE.addEventListener("progress-update", this.onProgressUpdateBound);
|
||||
this.connected = true;
|
||||
}
|
||||
if (this.shadow) {
|
||||
this.progressTextEl.innerText = "Idle";
|
||||
this.progressNodesEl.style.width = `0%`;
|
||||
this.progressStepsEl.style.width = `0%`;
|
||||
return;
|
||||
}
|
||||
this.shadow = this.attachShadow({ mode: "open" });
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync(`
|
||||
|
||||
:host {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: var(--rgthree-progress-bg-color);
|
||||
--rgthree-progress-bg-color: rgba(23, 23, 23, 0.9);
|
||||
--rgthree-progress-nodes-bg-color: rgb(0, 128, 0);
|
||||
--rgthree-progress-steps-bg-color: rgb(0, 128, 0);
|
||||
--rgthree-progress-error-bg-color: rgb(128, 0, 0);
|
||||
--rgthree-progress-text-color: #fff;
|
||||
}
|
||||
:host * {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
:host > div.bar {
|
||||
background: var(--rgthree-progress-nodes-bg-color);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 0%;
|
||||
height: 50%;
|
||||
z-index: 1;
|
||||
transition: width 50ms ease-in-out;
|
||||
}
|
||||
:host > div.bar + div.bar {
|
||||
background: var(--rgthree-progress-steps-bg-color);
|
||||
top: 50%;
|
||||
height: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
:host > div.bar.-error {
|
||||
background: var(--rgthree-progress-error-bg-color);
|
||||
}
|
||||
|
||||
:host > .overlay {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 5;
|
||||
background: linear-gradient(to bottom, rgba(255,255,255,0.25), rgba(0,0,0,0.25));
|
||||
mix-blend-mode: overlay;
|
||||
}
|
||||
|
||||
:host > span {
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
text-align: left;
|
||||
font-size: inherit;
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
text-shadow: 1px 1px 0px #000;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 0 6px;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
color: var(--rgthree-progress-text-color);
|
||||
text-shadow: black 0px 0px 2px;
|
||||
}
|
||||
|
||||
:host > div.bar[style*="width: 0%"]:first-child,
|
||||
:host > div.bar[style*="width:0%"]:first-child {
|
||||
height: 0%;
|
||||
}
|
||||
:host > div.bar[style*="width: 0%"]:first-child + div,
|
||||
:host > div.bar[style*="width:0%"]:first-child + div {
|
||||
bottom: 0%;
|
||||
}
|
||||
`);
|
||||
this.shadow.adoptedStyleSheets = [sheet];
|
||||
const overlayEl = createElement(`div.overlay[part="overlay"]`, { parent: this.shadow });
|
||||
this.progressNodesEl = createElement(`div.bar[part="progress-nodes"]`, { parent: this.shadow });
|
||||
this.progressStepsEl = createElement(`div.bar[part="progress-steps"]`, { parent: this.shadow });
|
||||
this.progressTextEl = createElement(`span[part="text"]`, { text: "Idle", parent: this.shadow });
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.connected = false;
|
||||
PROMPT_SERVICE.removeEventListener("progress-update", this.onProgressUpdateBound);
|
||||
}
|
||||
}
|
||||
RgthreeProgressBar.NAME = "rgthree-progress-bar";
|
||||
customElements.define(RgthreeProgressBar.NAME, RgthreeProgressBar);
|
||||
188
custom_nodes/rgthree-comfy/web/common/prompt_service.js
Normal file
188
custom_nodes/rgthree-comfy/web/common/prompt_service.js
Normal file
@@ -0,0 +1,188 @@
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { getResolver } from "./shared_utils.js";
|
||||
export class PromptExecution {
|
||||
constructor(id) {
|
||||
this.promptApi = null;
|
||||
this.executedNodeIds = [];
|
||||
this.totalNodes = 0;
|
||||
this.currentlyExecuting = null;
|
||||
this.errorDetails = null;
|
||||
this.apiPrompt = getResolver();
|
||||
this.id = id;
|
||||
}
|
||||
setPrompt(prompt) {
|
||||
this.promptApi = prompt.output;
|
||||
this.totalNodes = Object.keys(this.promptApi).length;
|
||||
this.apiPrompt.resolve(null);
|
||||
}
|
||||
getApiNode(nodeId) {
|
||||
var _a;
|
||||
return ((_a = this.promptApi) === null || _a === void 0 ? void 0 : _a[String(nodeId)]) || null;
|
||||
}
|
||||
getNodeLabel(nodeId) {
|
||||
var _a, _b;
|
||||
const apiNode = this.getApiNode(nodeId);
|
||||
let label = ((_a = apiNode === null || apiNode === void 0 ? void 0 : apiNode._meta) === null || _a === void 0 ? void 0 : _a.title) || (apiNode === null || apiNode === void 0 ? void 0 : apiNode.class_type) || undefined;
|
||||
if (!label) {
|
||||
const graphNode = (_b = this.maybeGetComfyGraph()) === null || _b === void 0 ? void 0 : _b.getNodeById(Number(nodeId));
|
||||
label = (graphNode === null || graphNode === void 0 ? void 0 : graphNode.title) || (graphNode === null || graphNode === void 0 ? void 0 : graphNode.type) || undefined;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
executing(nodeId, step, maxSteps) {
|
||||
var _a;
|
||||
if (nodeId == null) {
|
||||
this.currentlyExecuting = null;
|
||||
return;
|
||||
}
|
||||
if (((_a = this.currentlyExecuting) === null || _a === void 0 ? void 0 : _a.nodeId) !== nodeId) {
|
||||
if (this.currentlyExecuting != null) {
|
||||
this.executedNodeIds.push(nodeId);
|
||||
}
|
||||
this.currentlyExecuting = { nodeId, nodeLabel: this.getNodeLabel(nodeId), pass: 0 };
|
||||
this.apiPrompt.promise.then(() => {
|
||||
var _a;
|
||||
if (this.currentlyExecuting == null) {
|
||||
return;
|
||||
}
|
||||
const apiNode = this.getApiNode(nodeId);
|
||||
if (!this.currentlyExecuting.nodeLabel) {
|
||||
this.currentlyExecuting.nodeLabel = this.getNodeLabel(nodeId);
|
||||
}
|
||||
if ((apiNode === null || apiNode === void 0 ? void 0 : apiNode.class_type) === "UltimateSDUpscale") {
|
||||
this.currentlyExecuting.pass--;
|
||||
this.currentlyExecuting.maxPasses = -1;
|
||||
}
|
||||
else if ((apiNode === null || apiNode === void 0 ? void 0 : apiNode.class_type) === "IterativeImageUpscale") {
|
||||
this.currentlyExecuting.maxPasses = (_a = apiNode === null || apiNode === void 0 ? void 0 : apiNode.inputs["steps"]) !== null && _a !== void 0 ? _a : -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (step != null) {
|
||||
if (!this.currentlyExecuting.step || step < this.currentlyExecuting.step) {
|
||||
this.currentlyExecuting.pass++;
|
||||
}
|
||||
this.currentlyExecuting.step = step;
|
||||
this.currentlyExecuting.maxSteps = maxSteps;
|
||||
}
|
||||
}
|
||||
error(details) {
|
||||
this.errorDetails = details;
|
||||
}
|
||||
maybeGetComfyGraph() {
|
||||
var _a;
|
||||
return ((_a = window === null || window === void 0 ? void 0 : window.app) === null || _a === void 0 ? void 0 : _a.graph) || null;
|
||||
}
|
||||
}
|
||||
class PromptService extends EventTarget {
|
||||
constructor(api) {
|
||||
super();
|
||||
this.promptsMap = new Map();
|
||||
this.currentExecution = null;
|
||||
this.lastQueueRemaining = 0;
|
||||
const that = this;
|
||||
const queuePrompt = api.queuePrompt;
|
||||
api.queuePrompt = async function (num, prompt, ...args) {
|
||||
let response;
|
||||
try {
|
||||
response = await queuePrompt.apply(api, [...arguments]);
|
||||
}
|
||||
catch (e) {
|
||||
const promptExecution = that.getOrMakePrompt("error");
|
||||
promptExecution.error({ exception_type: "Unknown." });
|
||||
throw e;
|
||||
}
|
||||
const promptExecution = that.getOrMakePrompt(response.prompt_id);
|
||||
promptExecution.setPrompt(prompt);
|
||||
if (!that.currentExecution) {
|
||||
that.currentExecution = promptExecution;
|
||||
}
|
||||
that.promptsMap.set(response.prompt_id, promptExecution);
|
||||
that.dispatchEvent(new CustomEvent("queue-prompt", {
|
||||
detail: {
|
||||
prompt: promptExecution,
|
||||
},
|
||||
}));
|
||||
return response;
|
||||
};
|
||||
api.addEventListener("status", (e) => {
|
||||
var _a;
|
||||
if (!((_a = e.detail) === null || _a === void 0 ? void 0 : _a.exec_info))
|
||||
return;
|
||||
this.lastQueueRemaining = e.detail.exec_info.queue_remaining;
|
||||
this.dispatchProgressUpdate();
|
||||
});
|
||||
api.addEventListener("execution_start", (e) => {
|
||||
if (!this.promptsMap.has(e.detail.prompt_id)) {
|
||||
console.warn("'execution_start' fired before prompt was made.");
|
||||
}
|
||||
const prompt = this.getOrMakePrompt(e.detail.prompt_id);
|
||||
this.currentExecution = prompt;
|
||||
this.dispatchProgressUpdate();
|
||||
});
|
||||
api.addEventListener("executing", (e) => {
|
||||
if (!this.currentExecution) {
|
||||
this.currentExecution = this.getOrMakePrompt("unknown");
|
||||
console.warn("'executing' fired before prompt was made.");
|
||||
}
|
||||
this.currentExecution.executing(e.detail);
|
||||
this.dispatchProgressUpdate();
|
||||
if (e.detail == null) {
|
||||
this.currentExecution = null;
|
||||
}
|
||||
});
|
||||
api.addEventListener("progress", (e) => {
|
||||
if (!this.currentExecution) {
|
||||
this.currentExecution = this.getOrMakePrompt(e.detail.prompt_id);
|
||||
console.warn("'progress' fired before prompt was made.");
|
||||
}
|
||||
this.currentExecution.executing(e.detail.node, e.detail.value, e.detail.max);
|
||||
this.dispatchProgressUpdate();
|
||||
});
|
||||
api.addEventListener("execution_cached", (e) => {
|
||||
if (!this.currentExecution) {
|
||||
this.currentExecution = this.getOrMakePrompt(e.detail.prompt_id);
|
||||
console.warn("'execution_cached' fired before prompt was made.");
|
||||
}
|
||||
for (const cached of e.detail.nodes) {
|
||||
this.currentExecution.executing(cached);
|
||||
}
|
||||
this.dispatchProgressUpdate();
|
||||
});
|
||||
api.addEventListener("executed", (e) => {
|
||||
if (!this.currentExecution) {
|
||||
this.currentExecution = this.getOrMakePrompt(e.detail.prompt_id);
|
||||
console.warn("'executed' fired before prompt was made.");
|
||||
}
|
||||
});
|
||||
api.addEventListener("execution_error", (e) => {
|
||||
var _a;
|
||||
if (!this.currentExecution) {
|
||||
this.currentExecution = this.getOrMakePrompt(e.detail.prompt_id);
|
||||
console.warn("'execution_error' fired before prompt was made.");
|
||||
}
|
||||
(_a = this.currentExecution) === null || _a === void 0 ? void 0 : _a.error(e.detail);
|
||||
this.dispatchProgressUpdate();
|
||||
});
|
||||
}
|
||||
async queuePrompt(prompt) {
|
||||
return await api.queuePrompt(-1, prompt);
|
||||
}
|
||||
dispatchProgressUpdate() {
|
||||
this.dispatchEvent(new CustomEvent("progress-update", {
|
||||
detail: {
|
||||
queue: this.lastQueueRemaining,
|
||||
prompt: this.currentExecution,
|
||||
},
|
||||
}));
|
||||
}
|
||||
getOrMakePrompt(id) {
|
||||
let prompt = this.promptsMap.get(id);
|
||||
if (!prompt) {
|
||||
prompt = new PromptExecution(id);
|
||||
this.promptsMap.set(id, prompt);
|
||||
}
|
||||
return prompt;
|
||||
}
|
||||
}
|
||||
export const SERVICE = new PromptService(api);
|
||||
717
custom_nodes/rgthree-comfy/web/common/py_parser.js
Normal file
717
custom_nodes/rgthree-comfy/web/common/py_parser.js
Normal file
@@ -0,0 +1,717 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
||||
if (kind === "m") throw new TypeError("Private method is not writable");
|
||||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
||||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
||||
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
||||
};
|
||||
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
||||
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
||||
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
||||
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
||||
};
|
||||
var _PyDict_dict;
|
||||
import { check, deepFreeze } from "./shared_utils.js";
|
||||
const MEMOIZED = { parser: null };
|
||||
class ExecuteContext {
|
||||
constructor(existing = {}) {
|
||||
Object.assign(this, !!window.structuredClone ? structuredClone(existing) : { ...existing });
|
||||
}
|
||||
}
|
||||
class InitialExecuteContext extends ExecuteContext {
|
||||
}
|
||||
const TYPE_TO_HANDLER = new Map([
|
||||
["module", handleChildren],
|
||||
["expression_statement", handleChildren],
|
||||
["interpolation", handleInterpolation],
|
||||
["block", handleChildren],
|
||||
["comment", handleSwallow],
|
||||
["return_statement", handleReturn],
|
||||
["assignment", handleAssignment],
|
||||
["named_expression", handleNamedExpression],
|
||||
["identifier", handleIdentifier],
|
||||
["attribute", handleAttribute],
|
||||
["subscript", handleSubscript],
|
||||
["call", handleCall],
|
||||
["argument_list", handleArgumentsList],
|
||||
["for_statement", handleForStatement],
|
||||
["list_comprehension", handleListComprehension],
|
||||
["comparison_operator", handleComparisonOperator],
|
||||
["boolean_operator", handleBooleanOperator],
|
||||
["binary_operator", handleBinaryOperator],
|
||||
["not_operator", handleNotOperator],
|
||||
["unary_operator", handleUnaryOperator],
|
||||
["integer", handleNumber],
|
||||
["float", handleNumber],
|
||||
["string", handleString],
|
||||
["tuple", handleList],
|
||||
["list", handleList],
|
||||
["dictionary", handleDictionary],
|
||||
["pair", handleDictionaryPair],
|
||||
["true", async (...args) => true],
|
||||
["false", async (...args) => false],
|
||||
]);
|
||||
const DEFAULT_BUILT_INS = {
|
||||
round: { fn: (n) => Math.round(Number(n)) },
|
||||
ceil: { fn: (n) => Math.ceil(Number(n)) },
|
||||
floor: { fn: (n) => Math.floor(Number(n)) },
|
||||
len: { fn: (n) => { var _a, _b; return (_b = (_a = n === null || n === void 0 ? void 0 : n.__len__) === null || _a === void 0 ? void 0 : _a.call(n)) !== null && _b !== void 0 ? _b : n === null || n === void 0 ? void 0 : n.length; } },
|
||||
int: { fn: (n) => Math.floor(Number(n)) },
|
||||
float: { fn: (n) => Number(n) },
|
||||
str: { fn: (n) => String(n) },
|
||||
bool: { fn: (n) => !!n },
|
||||
list: { fn: (tupl = []) => new PyList(tupl) },
|
||||
tuple: { fn: (list = []) => new PyTuple(list) },
|
||||
dict: { fn: (dict = {}) => new PyDict(dict) },
|
||||
dir: { fn: (...args) => console.dir(...__unwrap__(...args)) },
|
||||
print: { fn: (...args) => console.log(...__unwrap__(...args)) },
|
||||
log: { fn: (...args) => console.log(...__unwrap__(...args)) },
|
||||
};
|
||||
export async function execute(code, ctx, additionalBuiltins) {
|
||||
var _a, _b;
|
||||
const builtIns = deepFreeze({ ...DEFAULT_BUILT_INS, ...(additionalBuiltins !== null && additionalBuiltins !== void 0 ? additionalBuiltins : {}) });
|
||||
ctx = new InitialExecuteContext(ctx);
|
||||
const root = (await parse(code)).rootNode;
|
||||
const value = await handleNode(new Node(root), ctx, builtIns);
|
||||
console.log("=====");
|
||||
console.log(`value`, (_b = (_a = value === null || value === void 0 ? void 0 : value.__unwrap__) === null || _a === void 0 ? void 0 : _a.call(value)) !== null && _b !== void 0 ? _b : value);
|
||||
console.log("context", ctx);
|
||||
return value;
|
||||
}
|
||||
async function parse(code) {
|
||||
if (!MEMOIZED.parser) {
|
||||
const TreeSitter = (await import("../lib/tree-sitter.js"));
|
||||
await TreeSitter.Parser.init();
|
||||
const lang = await TreeSitter.Language.load("rgthree/lib/tree-sitter-python.wasm");
|
||||
MEMOIZED.parser = new TreeSitter.Parser();
|
||||
MEMOIZED.parser.setLanguage(lang);
|
||||
}
|
||||
return MEMOIZED.parser.parse(code);
|
||||
}
|
||||
async function handleNode(node, ctx, builtIns) {
|
||||
const type = node.type;
|
||||
if (ctx.hasOwnProperty("__returned__"))
|
||||
return ctx["__returned__"];
|
||||
const handler = TYPE_TO_HANDLER.get(type);
|
||||
check(handler, "Unhandled type: " + type, node);
|
||||
return handler(node, ctx, builtIns);
|
||||
}
|
||||
async function handleChildren(node, ctx, builtIns) {
|
||||
let lastValue = null;
|
||||
for (const child of node.children) {
|
||||
if (!child)
|
||||
continue;
|
||||
lastValue = await handleNode(child, ctx, builtIns);
|
||||
}
|
||||
return lastValue;
|
||||
}
|
||||
async function handleSwallow(node, ctx, builtIns) {
|
||||
}
|
||||
async function handleReturn(node, ctx, builtIns) {
|
||||
const value = node.children.length > 1 ? handleNode(node.child(1), ctx, builtIns) : undefined;
|
||||
ctx["__returned__"] = value;
|
||||
return value;
|
||||
}
|
||||
async function handleIdentifier(node, ctx, builtIns) {
|
||||
var _a, _b;
|
||||
let value = ctx[node.text];
|
||||
if (value === undefined) {
|
||||
value = (_b = (_a = builtIns[node.text]) === null || _a === void 0 ? void 0 : _a.fn) !== null && _b !== void 0 ? _b : undefined;
|
||||
}
|
||||
return maybeWrapValue(value);
|
||||
}
|
||||
async function handleAttribute(node, ctx, builtIns) {
|
||||
const children = node.children;
|
||||
check(children.length === 3, "Expected 3 children for attribute.");
|
||||
check(children[1].type === ".", "Expected middle child to be '.' for attribute.");
|
||||
const inst = await handleNode(children[0], ctx, builtIns);
|
||||
const attr = children[2].text;
|
||||
checkAttributeAccessibility(inst, attr);
|
||||
let attribute = maybeWrapValue(inst[attr]);
|
||||
return typeof attribute === "function" ? attribute.bind(inst) : attribute;
|
||||
}
|
||||
async function handleSubscript(node, ctx, builtIns) {
|
||||
const children = node.children;
|
||||
check(children.length === 4, "Expected 4 children for subscript.");
|
||||
check(children[1].type === "[", "Expected 2nd child to be '[' for subscript.");
|
||||
check(children[3].type === "]", "Expected 4thd child to be ']' for subscript.");
|
||||
const inst = await handleNode(children[0], ctx, builtIns);
|
||||
const attr = await handleNode(children[2], ctx, builtIns);
|
||||
if (inst instanceof PyTuple && isInt(attr)) {
|
||||
return maybeWrapValue(inst.__at__(attr));
|
||||
}
|
||||
if (inst instanceof PyDict && typeof attr === "string") {
|
||||
return maybeWrapValue(inst.get(attr));
|
||||
}
|
||||
checkAttributeAccessibility(inst, attr);
|
||||
let attribute = maybeWrapValue(inst[attr]);
|
||||
return typeof attribute === "function" ? attribute.bind(inst) : attribute;
|
||||
}
|
||||
async function handleAssignment(node, ctx, builtIns) {
|
||||
check(node.children.length === 3, "Expected 3 children for assignment: identifier/attr, =, and value.");
|
||||
check(node.children[1].type === "=", "Expected middle child to be an '='.");
|
||||
let right = await handleNode(node.children[2], ctx, builtIns);
|
||||
const leftNode = node.children[0];
|
||||
let leftObj = ctx;
|
||||
let leftProp = "";
|
||||
if (leftNode.type === "identifier") {
|
||||
leftProp = leftNode.text;
|
||||
}
|
||||
else if (leftNode.type === "attribute") {
|
||||
leftObj = await handleNode(leftNode.children[0], ctx, builtIns);
|
||||
check(leftNode.children[2].type === "identifier", "Expected left hand assignment attribute to be an identifier.", leftNode);
|
||||
leftProp = leftNode.children[2].text;
|
||||
}
|
||||
else if (leftNode.type === "subscript") {
|
||||
leftObj = await handleNode(leftNode.children[0], ctx, builtIns);
|
||||
check(leftNode.children[1].type === "[");
|
||||
check(leftNode.children[3].type === "]");
|
||||
leftProp = await handleNode(leftNode.children[2], ctx, builtIns);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Unhandled left-hand assignement type: ${leftNode.type}`);
|
||||
}
|
||||
if (leftProp == null) {
|
||||
throw new Error(`No property to assign value`);
|
||||
}
|
||||
if (leftObj instanceof PyTuple) {
|
||||
check(isInt(leftProp), "Expected an int for list assignment");
|
||||
leftObj.__put__(leftProp, right);
|
||||
}
|
||||
else if (leftObj instanceof PyDict) {
|
||||
check(typeof leftProp === "string", "Expected a string for dict assignment");
|
||||
leftObj.__put__(leftProp, right);
|
||||
}
|
||||
else {
|
||||
check(typeof leftProp === "string", "Expected a string for object assignment");
|
||||
if (!(leftObj instanceof InitialExecuteContext)) {
|
||||
checkAttributeAccessibility(leftObj, leftProp);
|
||||
}
|
||||
leftObj[leftProp] = right;
|
||||
}
|
||||
return right;
|
||||
}
|
||||
async function handleNamedExpression(node, ctx, builtIns) {
|
||||
check(node.children.length === 3, "Expected three children for named expression.");
|
||||
check(node.child(0).type === "identifier", "Expected identifier first in named expression.");
|
||||
const varName = node.child(0).text;
|
||||
ctx[varName] = await handleNode(node.child(2), ctx, builtIns);
|
||||
return maybeWrapValue(ctx[varName]);
|
||||
}
|
||||
async function handleCall(node, ctx, builtIns) {
|
||||
check(node.children.length === 2, "Expected 2 children for call, identifier and arguments.");
|
||||
const fn = await handleNode(node.children[0], ctx, builtIns);
|
||||
const args = await handleNode(node.children[1], ctx, builtIns);
|
||||
console.log("handleCall", fn, args);
|
||||
return fn(...args);
|
||||
}
|
||||
async function handleArgumentsList(node, ctx, builtIns) {
|
||||
const args = (await handleList(node, ctx, builtIns)).__unwrap__(false);
|
||||
return [...args];
|
||||
}
|
||||
async function handleForStatement(node, ctx, builtIns) {
|
||||
const childs = node.children;
|
||||
check(childs.length === 6);
|
||||
check(childs[4].type === ":");
|
||||
check(childs[5].type === "block");
|
||||
await helperGetLoopForIn(node, ctx, builtIns, async (forCtx) => {
|
||||
await handleNode(childs[5], forCtx, builtIns);
|
||||
});
|
||||
}
|
||||
async function handleListComprehension(node, ctx, builtIns) {
|
||||
const finalList = new PyList();
|
||||
const newCtx = { ...ctx };
|
||||
let finalEntryNode;
|
||||
const loopNodes = [];
|
||||
for (const child of node.children) {
|
||||
if (!child || ["[", "]"].includes(child.type))
|
||||
continue;
|
||||
if (child.type === "identifier" || child.type === "attribute") {
|
||||
if (finalEntryNode) {
|
||||
throw Error("Already have a list comprehension finalEntryNode.");
|
||||
}
|
||||
finalEntryNode = child;
|
||||
}
|
||||
else if (child.type === "for_in_clause") {
|
||||
loopNodes.push({ forIn: child });
|
||||
}
|
||||
else if (child.type === "if_clause") {
|
||||
loopNodes[loopNodes.length - 1]["if"] = child;
|
||||
}
|
||||
}
|
||||
if (!finalEntryNode) {
|
||||
throw Error("No list comprehension finalEntryNode.");
|
||||
}
|
||||
console.log(`handleListComprehension.loopNodes`, loopNodes);
|
||||
const handleLoop = async (loopNodes) => {
|
||||
const loopNode = loopNodes.shift();
|
||||
await helperGetLoopForIn(loopNode.forIn, newCtx, builtIns, async (forCtx) => {
|
||||
if (loopNode.if) {
|
||||
const ifNode = loopNode.if;
|
||||
check(ifNode.children.length === 2, "Expected 2 children for if_clause.");
|
||||
check(ifNode.child(0).text === "if", "Expected first child to be 'if'.");
|
||||
const good = await handleNode(ifNode.child(1), forCtx, builtIns);
|
||||
if (!good)
|
||||
return;
|
||||
}
|
||||
Object.assign(newCtx, forCtx);
|
||||
if (loopNodes.length) {
|
||||
await handleLoop(loopNodes);
|
||||
}
|
||||
else {
|
||||
finalList.append(await handleNode(finalEntryNode, newCtx, builtIns));
|
||||
}
|
||||
}, () => ({ ...newCtx }));
|
||||
loopNodes.unshift(loopNode);
|
||||
};
|
||||
await handleLoop(loopNodes);
|
||||
return finalList;
|
||||
}
|
||||
async function helperGetLoopForIn(node, ctx, builtIns, eachFn, provideForCtx) {
|
||||
var _a;
|
||||
const childs = node.children;
|
||||
check(childs.length >= 3);
|
||||
check(childs[0].type === "for");
|
||||
check(["identifier", "pattern_list"].includes(childs[1].type), "Expected identifier for for loop.");
|
||||
check(childs[2].type === "in");
|
||||
let identifiers;
|
||||
if (childs[1].type === "identifier") {
|
||||
identifiers = [childs[1].text];
|
||||
}
|
||||
else {
|
||||
identifiers = childs[1].children
|
||||
.map((n) => {
|
||||
if (n.type === ",")
|
||||
return null;
|
||||
check(n.type === "identifier");
|
||||
return node.text;
|
||||
})
|
||||
.filter((n) => n != null);
|
||||
}
|
||||
const iterable = await handleNode(childs[3], ctx, builtIns);
|
||||
check(iterable instanceof PyTuple, "Expected for loop instance to be a list/tuple.");
|
||||
for (const item of iterable.__unwrap__(false)) {
|
||||
const forCtx = (_a = provideForCtx === null || provideForCtx === void 0 ? void 0 : provideForCtx()) !== null && _a !== void 0 ? _a : ctx;
|
||||
if (identifiers.length === 1) {
|
||||
forCtx[identifiers[0]] = item;
|
||||
}
|
||||
else {
|
||||
check(Array.isArray(item) && identifiers.length === item.length, "Expected iterable to be a list, like using dict.items()");
|
||||
for (let i = 0; i < identifiers.length; i++) {
|
||||
forCtx[identifiers[i]] = item[i];
|
||||
}
|
||||
}
|
||||
await eachFn(forCtx);
|
||||
}
|
||||
}
|
||||
async function handleNumber(node, ctx, builtIns) {
|
||||
return Number(node.text);
|
||||
}
|
||||
async function handleString(node, ctx, builtIns) {
|
||||
let str = "";
|
||||
for (const child of node.children) {
|
||||
if (!child || ["string_start", "string_end"].includes(child.type))
|
||||
continue;
|
||||
if (child.type === "string_content") {
|
||||
str += child.text;
|
||||
}
|
||||
else if (child.type === "interpolation") {
|
||||
check(child.children.length === 3, "Expected interpolation");
|
||||
str += await handleNode(child, ctx, builtIns);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
async function handleInterpolation(node, ...args) {
|
||||
check(node.children.length === 3, "Expected interpolation to be three nodes length.");
|
||||
check(node.children[0].type === "{" && node.children[2].type === "}", 'Expected interpolation to be wrapped in "{" and "}".');
|
||||
return await handleNode(node.children[1], ...args);
|
||||
}
|
||||
async function handleList(node, ctx, builtIns) {
|
||||
const list = [];
|
||||
for (const child of node.children) {
|
||||
if (!child || ["(", "[", ",", "]", ")"].includes(child.type))
|
||||
continue;
|
||||
list.push(await handleNode(child, ctx, builtIns));
|
||||
}
|
||||
if (node.type === "tuple") {
|
||||
return new PyTuple(list);
|
||||
}
|
||||
return new PyList(list);
|
||||
}
|
||||
async function handleComparisonOperator(node, ctx, builtIns) {
|
||||
const op = node.child(1).text;
|
||||
const left = await handleNode(node.child(0), ctx, builtIns);
|
||||
const right = await handleNode(node.child(2), ctx, builtIns);
|
||||
if (op === "==")
|
||||
return left === right;
|
||||
if (op === "!=")
|
||||
return left !== right;
|
||||
if (op === ">")
|
||||
return left > right;
|
||||
if (op === ">=")
|
||||
return left >= right;
|
||||
if (op === "<")
|
||||
return left < right;
|
||||
if (op === "<=")
|
||||
return left <= right;
|
||||
if (op === "in")
|
||||
return (right.__unwrap__ ? right.__unwrap__(false) : right).includes(left);
|
||||
throw new Error(`Comparison not handled: "${op}"`);
|
||||
}
|
||||
async function handleBooleanOperator(node, ctx, builtIns) {
|
||||
const op = node.child(1).text;
|
||||
const left = await handleNode(node.child(0), ctx, builtIns);
|
||||
if (!left && op === "and")
|
||||
return left;
|
||||
const right = await handleNode(node.child(2), ctx, builtIns);
|
||||
if (op === "and")
|
||||
return left && right;
|
||||
if (op === "or")
|
||||
return left || right;
|
||||
}
|
||||
async function handleBinaryOperator(node, ctx, builtIns) {
|
||||
const op = node.child(1).text;
|
||||
const left = await handleNode(node.child(0), ctx, builtIns);
|
||||
const right = await handleNode(node.child(2), ctx, builtIns);
|
||||
if (left.constructor !== right.constructor) {
|
||||
throw new Error(`Can only run ${op} operator on same type.`);
|
||||
}
|
||||
if (op === "+")
|
||||
return left.__add__ ? left.__add__(right) : left + right;
|
||||
if (op === "-")
|
||||
return left - right;
|
||||
if (op === "/")
|
||||
return left / right;
|
||||
if (op === "//")
|
||||
return Math.floor(left / right);
|
||||
if (op === "*")
|
||||
return left * right;
|
||||
if (op === "%")
|
||||
return left % right;
|
||||
if (op === "&")
|
||||
return left & right;
|
||||
if (op === "|")
|
||||
return left | right;
|
||||
if (op === "^")
|
||||
return left ^ right;
|
||||
if (op === "<<")
|
||||
return left << right;
|
||||
if (op === ">>")
|
||||
return left >> right;
|
||||
throw new Error(`Comparison not handled: "${op}"`);
|
||||
}
|
||||
async function handleNotOperator(node, ctx, builtIns) {
|
||||
check(node.children.length === 2, "Expected 2 children for not operator.");
|
||||
check(node.child(0).text === "not", "Expected first child to be 'not'.");
|
||||
const value = await handleNode(node.child(1), ctx, builtIns);
|
||||
return !value;
|
||||
}
|
||||
async function handleUnaryOperator(node, ctx, builtIns) {
|
||||
check(node.children.length === 2, "Expected 2 children for not operator.");
|
||||
const value = await handleNode(node.child(1), ctx, builtIns);
|
||||
const op = node.child(0).text;
|
||||
if (op === "-")
|
||||
return value * -1;
|
||||
console.warn(`Unhandled unary operator: ${op}`);
|
||||
return value;
|
||||
}
|
||||
async function handleDictionary(node, ctx, builtIns) {
|
||||
const dict = new PyDict();
|
||||
for (const child of node.children) {
|
||||
if (!child || ["{", ",", "}"].includes(child.type))
|
||||
continue;
|
||||
check(child.type === "pair", "Expected a pair type for dict.");
|
||||
const pair = await handleNode(child, ctx, builtIns);
|
||||
dict.__put__(pair[0], pair[1]);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
async function handleDictionaryPair(node, ctx, builtIns) {
|
||||
check(node.children.length === 3, "Expected 3 children for dict pair.");
|
||||
let varName = await handleNode(node.child(0), ctx, builtIns);
|
||||
let varValue = await handleNode(node.child(2), ctx, builtIns);
|
||||
check(typeof varName === "string", "Expected varname to be string.");
|
||||
return [varName, varValue];
|
||||
}
|
||||
class Node {
|
||||
constructor(node) {
|
||||
this.type = node.type;
|
||||
this.text = node.text;
|
||||
if (this.type === "ERROR") {
|
||||
throw new Error(`Error found in parsing near "${this.text}"`);
|
||||
}
|
||||
this.children = [];
|
||||
for (const child of node.children) {
|
||||
this.children.push(new Node(child));
|
||||
}
|
||||
this.node = node;
|
||||
}
|
||||
child(index) {
|
||||
const child = this.children[index];
|
||||
if (!child)
|
||||
throw Error(`No child at index ${index}.`);
|
||||
return child;
|
||||
}
|
||||
log(tab = "", showNode = false) {
|
||||
console.log(`${tab}--- Node`);
|
||||
console.log(`${tab} type: ${this.type}`);
|
||||
console.log(`${tab} text: ${this.text}`);
|
||||
console.log(`${tab} children:`, this.children);
|
||||
if (showNode) {
|
||||
console.log(`${tab} node:`, this.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class PyTuple {
|
||||
constructor(...args) {
|
||||
if (args.length === 1 && args[0] instanceof PyTuple) {
|
||||
args = args[0].__unwrap__(false);
|
||||
}
|
||||
if (args.length === 1 && Array.isArray(args[0])) {
|
||||
args = [...args[0]];
|
||||
}
|
||||
this.list = [...args];
|
||||
}
|
||||
count(v) {
|
||||
}
|
||||
index() {
|
||||
}
|
||||
__at__(index) {
|
||||
index = this.__get_relative_index__(index);
|
||||
return this.list[index];
|
||||
}
|
||||
__len__() {
|
||||
return this.list.length;
|
||||
}
|
||||
__add__(v) {
|
||||
if (!(v instanceof PyTuple)) {
|
||||
throw new Error("Can only concatenate tuple to tuple.");
|
||||
}
|
||||
return new PyTuple(this.__unwrap__(false).concat(v.__unwrap__(false)));
|
||||
}
|
||||
__put__(index, v) {
|
||||
throw new Error("Tuple does not support item assignment");
|
||||
}
|
||||
__get_relative_index__(index) {
|
||||
if (index >= 0) {
|
||||
check(this.list.length > index, `Index ${index} out of range.`);
|
||||
return index;
|
||||
}
|
||||
const relIndex = this.list.length + index;
|
||||
check(relIndex >= 0, `Index ${index} out of range.`);
|
||||
return relIndex;
|
||||
}
|
||||
__unwrap__(deep = true) {
|
||||
var _a;
|
||||
const l = [...this.list];
|
||||
if (deep) {
|
||||
for (let i = 0; i < l.length; i++) {
|
||||
l[i] = ((_a = l[i]) === null || _a === void 0 ? void 0 : _a.__unwrap__) ? l[i].__unwrap__(deep) : l[i];
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyTuple.prototype, "count", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyTuple.prototype, "index", null);
|
||||
export class PyList extends PyTuple {
|
||||
append(...args) {
|
||||
this.list.push(...args);
|
||||
}
|
||||
clear() {
|
||||
this.list.length = 0;
|
||||
}
|
||||
copy() {
|
||||
}
|
||||
count() {
|
||||
}
|
||||
extend() {
|
||||
}
|
||||
index() {
|
||||
}
|
||||
insert() {
|
||||
}
|
||||
pop() {
|
||||
}
|
||||
remove() {
|
||||
}
|
||||
reverse() {
|
||||
}
|
||||
sort() {
|
||||
}
|
||||
__add__(v) {
|
||||
if (!(v instanceof PyList)) {
|
||||
throw new Error("Can only concatenate list to list.");
|
||||
}
|
||||
return new PyList(this.__unwrap__(false).concat(v.__unwrap__(false)));
|
||||
}
|
||||
__put__(index, v) {
|
||||
index = this.__get_relative_index__(index);
|
||||
this.list[index] = v;
|
||||
}
|
||||
}
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "append", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "clear", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "copy", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "count", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "extend", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "index", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "insert", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "pop", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "remove", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "reverse", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyList.prototype, "sort", null);
|
||||
class PyInt {
|
||||
}
|
||||
class PyDict {
|
||||
constructor(dict) {
|
||||
_PyDict_dict.set(this, void 0);
|
||||
__classPrivateFieldSet(this, _PyDict_dict, { ...(dict !== null && dict !== void 0 ? dict : {}) }, "f");
|
||||
}
|
||||
clear() { }
|
||||
copy() { }
|
||||
fromkeys() { }
|
||||
get(key) {
|
||||
return __classPrivateFieldGet(this, _PyDict_dict, "f")[key];
|
||||
}
|
||||
items() {
|
||||
return new PyTuple(Object.entries(__classPrivateFieldGet(this, _PyDict_dict, "f")).map((e) => new PyTuple(e)));
|
||||
}
|
||||
keys() { }
|
||||
pop() { }
|
||||
popitem() { }
|
||||
setdefault() { }
|
||||
update() { }
|
||||
values() { }
|
||||
__put__(key, v) {
|
||||
__classPrivateFieldGet(this, _PyDict_dict, "f")[key] = v;
|
||||
}
|
||||
__len__() {
|
||||
return Object.keys(__classPrivateFieldGet(this, _PyDict_dict, "f")).length;
|
||||
}
|
||||
__unwrap__(deep = true) {
|
||||
var _a;
|
||||
const d = { ...__classPrivateFieldGet(this, _PyDict_dict, "f") };
|
||||
if (deep) {
|
||||
for (let k of Object.keys(d)) {
|
||||
d[k] = ((_a = d[k]) === null || _a === void 0 ? void 0 : _a.__unwrap__) ? d[k].__unwrap__(deep) : d[k];
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
_PyDict_dict = new WeakMap();
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "clear", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "copy", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "fromkeys", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "get", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "items", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "keys", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "pop", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "popitem", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "setdefault", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "update", null);
|
||||
__decorate([
|
||||
Exposed
|
||||
], PyDict.prototype, "values", null);
|
||||
function __unwrap__(...args) {
|
||||
var _a;
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = ((_a = args[i]) === null || _a === void 0 ? void 0 : _a.__unwrap__) ? args[i].__unwrap__(true) : args[i];
|
||||
}
|
||||
return args;
|
||||
}
|
||||
function checkAttributeAccessibility(inst, attr) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
const instType = typeof inst;
|
||||
check(instType === "object" || instType === "function", `Instance of type ${instType} does not have attributes.`);
|
||||
check(!attr.startsWith("__") && !attr.endsWith("__"), `"${attr}" is not accessible.`);
|
||||
const attrType = typeof inst[attr];
|
||||
if (attrType === "function") {
|
||||
const allowedMethods = (_c = (_b = (_a = inst.constructor) === null || _a === void 0 ? void 0 : _a.__ALLOWED_METHODS__) !== null && _b !== void 0 ? _b : inst.__ALLOWED_METHODS__) !== null && _c !== void 0 ? _c : [];
|
||||
check(allowedMethods.includes(attr), `Method ${attr} is not accessible.`);
|
||||
}
|
||||
else {
|
||||
const allowedProps = (_f = (_e = (_d = inst.constructor) === null || _d === void 0 ? void 0 : _d.__ALLOWED_PROPERTIES__) !== null && _e !== void 0 ? _e : inst.__ALLOWED_PROPERTIES__) !== null && _f !== void 0 ? _f : [];
|
||||
check(allowedProps.includes(attr), `Property ${attr} is not accessible.`);
|
||||
}
|
||||
}
|
||||
function maybeWrapValue(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return new PyList(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function isInt(value) {
|
||||
return typeof value === "number" && Math.round(value) === value;
|
||||
}
|
||||
function isIntLike(value) {
|
||||
let is = isInt(value);
|
||||
if (!is) {
|
||||
is = typeof value === "string" && !!/^\d+$/.exec(value);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
export function Exposed(target, key) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
||||
if (typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) === "function") {
|
||||
target.constructor.__ALLOWED_METHODS__ = target.constructor.__ALLOWED_METHODS__ || [];
|
||||
target.constructor.__ALLOWED_METHODS__.push(key);
|
||||
}
|
||||
else {
|
||||
target.constructor.__ALLOWED_PROPERTIES__ = target.constructor.__ALLOWED_PROPERTIES__ || [];
|
||||
target.constructor.__ALLOWED_PROPERTIES__.push(key);
|
||||
}
|
||||
}
|
||||
131
custom_nodes/rgthree-comfy/web/common/rgthree_api.js
Normal file
131
custom_nodes/rgthree-comfy/web/common/rgthree_api.js
Normal file
@@ -0,0 +1,131 @@
|
||||
class RgthreeApi {
|
||||
constructor(baseUrl) {
|
||||
this.getCheckpointsPromise = null;
|
||||
this.getSamplersPromise = null;
|
||||
this.getSchedulersPromise = null;
|
||||
this.getLorasPromise = null;
|
||||
this.getWorkflowsPromise = null;
|
||||
this.setBaseUrl(baseUrl);
|
||||
}
|
||||
setBaseUrl(baseUrlArg) {
|
||||
var _a;
|
||||
let baseUrl = null;
|
||||
if (baseUrlArg) {
|
||||
baseUrl = baseUrlArg;
|
||||
}
|
||||
else if (window.location.pathname.includes("/rgthree/")) {
|
||||
const parts = (_a = window.location.pathname.split("/rgthree/")[1]) === null || _a === void 0 ? void 0 : _a.split("/");
|
||||
if (parts && parts.length) {
|
||||
baseUrl = parts.map(() => "../").join("") + "rgthree/api";
|
||||
}
|
||||
}
|
||||
this.baseUrl = baseUrl || "./rgthree/api";
|
||||
const comfyBasePathname = location.pathname.includes("/rgthree/")
|
||||
? location.pathname.split("rgthree/")[0]
|
||||
: location.pathname;
|
||||
this.comfyBaseUrl = comfyBasePathname.split("/").slice(0, -1).join("/");
|
||||
}
|
||||
apiURL(route) {
|
||||
return `${this.baseUrl}${route}`;
|
||||
}
|
||||
fetchApi(route, options) {
|
||||
return fetch(this.apiURL(route), options);
|
||||
}
|
||||
async fetchJson(route, options) {
|
||||
const r = await this.fetchApi(route, options);
|
||||
return await r.json();
|
||||
}
|
||||
async postJson(route, json) {
|
||||
const body = new FormData();
|
||||
body.append("json", JSON.stringify(json));
|
||||
return await rgthreeApi.fetchJson(route, { method: "POST", body });
|
||||
}
|
||||
getLoras(force = false) {
|
||||
if (!this.getLorasPromise || force) {
|
||||
this.getLorasPromise = this.fetchJson("/loras?format=details", { cache: "no-store" });
|
||||
}
|
||||
return this.getLorasPromise;
|
||||
}
|
||||
async fetchApiJsonOrNull(route, options) {
|
||||
const response = await this.fetchJson(route, options);
|
||||
if (response.status === 200 && response.data) {
|
||||
return response.data || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async getModelsInfo(options) {
|
||||
var _a;
|
||||
const params = new URLSearchParams();
|
||||
if ((_a = options.files) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
params.set("files", options.files.join(","));
|
||||
}
|
||||
if (options.light) {
|
||||
params.set("light", "1");
|
||||
}
|
||||
if (options.format) {
|
||||
params.set("format", options.format);
|
||||
}
|
||||
const path = `/${options.type}/info?` + params.toString();
|
||||
return (await this.fetchApiJsonOrNull(path)) || [];
|
||||
}
|
||||
async getLorasInfo(options = {}) {
|
||||
return this.getModelsInfo({ type: "loras", ...options });
|
||||
}
|
||||
async getCheckpointsInfo(options = {}) {
|
||||
return this.getModelsInfo({ type: "checkpoints", ...options });
|
||||
}
|
||||
async refreshModelsInfo(options) {
|
||||
var _a;
|
||||
const params = new URLSearchParams();
|
||||
if ((_a = options.files) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
params.set("files", options.files.join(","));
|
||||
}
|
||||
const path = `/${options.type}/info/refresh?` + params.toString();
|
||||
const infos = await this.fetchApiJsonOrNull(path);
|
||||
return infos;
|
||||
}
|
||||
async refreshLorasInfo(options = {}) {
|
||||
return this.refreshModelsInfo({ type: "loras", ...options });
|
||||
}
|
||||
async refreshCheckpointsInfo(options = {}) {
|
||||
return this.refreshModelsInfo({ type: "checkpoints", ...options });
|
||||
}
|
||||
async clearModelsInfo(options) {
|
||||
var _a;
|
||||
const params = new URLSearchParams();
|
||||
if ((_a = options.files) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
params.set("files", options.files.join(","));
|
||||
}
|
||||
const path = `/${options.type}/info/clear?` + params.toString();
|
||||
await this.fetchApiJsonOrNull(path);
|
||||
return;
|
||||
}
|
||||
async clearLorasInfo(options = {}) {
|
||||
return this.clearModelsInfo({ type: "loras", ...options });
|
||||
}
|
||||
async clearCheckpointsInfo(options = {}) {
|
||||
return this.clearModelsInfo({ type: "checkpoints", ...options });
|
||||
}
|
||||
async saveModelInfo(type, file, data) {
|
||||
const body = new FormData();
|
||||
body.append("json", JSON.stringify(data));
|
||||
return await this.fetchApiJsonOrNull(`/${type}/info?file=${encodeURIComponent(file)}`, { cache: "no-store", method: "POST", body });
|
||||
}
|
||||
async saveLoraInfo(file, data) {
|
||||
return this.saveModelInfo("loras", file, data);
|
||||
}
|
||||
async saveCheckpointsInfo(file, data) {
|
||||
return this.saveModelInfo("checkpoints", file, data);
|
||||
}
|
||||
fetchComfyApi(route, options) {
|
||||
const url = this.comfyBaseUrl + "/api" + route;
|
||||
options = options || {};
|
||||
options.headers = options.headers || {};
|
||||
options.cache = options.cache || "no-cache";
|
||||
return fetch(url, options);
|
||||
}
|
||||
print(messageType) {
|
||||
this.fetchApi(`/print?type=${messageType}`, {});
|
||||
}
|
||||
}
|
||||
export const rgthreeApi = new RgthreeApi();
|
||||
416
custom_nodes/rgthree-comfy/web/common/shared_utils.js
Normal file
416
custom_nodes/rgthree-comfy/web/common/shared_utils.js
Normal file
@@ -0,0 +1,416 @@
|
||||
export function getResolver(timeout = 5000) {
|
||||
const resolver = {};
|
||||
resolver.id = generateId(8);
|
||||
resolver.completed = false;
|
||||
resolver.resolved = false;
|
||||
resolver.rejected = false;
|
||||
resolver.promise = new Promise((resolve, reject) => {
|
||||
resolver.reject = (e) => {
|
||||
resolver.completed = true;
|
||||
resolver.rejected = true;
|
||||
reject(e);
|
||||
};
|
||||
resolver.resolve = (data) => {
|
||||
resolver.completed = true;
|
||||
resolver.resolved = true;
|
||||
resolve(data);
|
||||
};
|
||||
});
|
||||
resolver.timeout = setTimeout(() => {
|
||||
if (!resolver.completed) {
|
||||
resolver.reject();
|
||||
}
|
||||
}, timeout);
|
||||
return resolver;
|
||||
}
|
||||
const DEBOUNCE_FN_TO_PROMISE = new WeakMap();
|
||||
export function debounce(fn, ms = 64) {
|
||||
if (!DEBOUNCE_FN_TO_PROMISE.get(fn)) {
|
||||
DEBOUNCE_FN_TO_PROMISE.set(fn, wait(ms).then(() => {
|
||||
DEBOUNCE_FN_TO_PROMISE.delete(fn);
|
||||
fn();
|
||||
}));
|
||||
}
|
||||
return DEBOUNCE_FN_TO_PROMISE.get(fn);
|
||||
}
|
||||
export function check(value, msg = "", ...args) {
|
||||
if (!value) {
|
||||
console.error(msg, ...(args || []));
|
||||
throw new Error(msg || "Error");
|
||||
}
|
||||
}
|
||||
export function wait(ms = 16) {
|
||||
if (ms === 16) {
|
||||
return new Promise((resolve) => {
|
||||
requestAnimationFrame(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
export function deepFreeze(obj) {
|
||||
const propNames = Reflect.ownKeys(obj);
|
||||
for (const name of propNames) {
|
||||
const value = obj[name];
|
||||
if ((value && typeof value === "object") || typeof value === "function") {
|
||||
deepFreeze(value);
|
||||
}
|
||||
}
|
||||
return Object.freeze(obj);
|
||||
}
|
||||
function dec2hex(dec) {
|
||||
return dec.toString(16).padStart(2, "0");
|
||||
}
|
||||
export function generateId(length) {
|
||||
const arr = new Uint8Array(length / 2);
|
||||
crypto.getRandomValues(arr);
|
||||
return Array.from(arr, dec2hex).join("");
|
||||
}
|
||||
export function getObjectValue(obj, objKey, def) {
|
||||
if (!obj || !objKey)
|
||||
return def;
|
||||
const keys = objKey.split(".");
|
||||
const key = keys.shift();
|
||||
const found = obj[key];
|
||||
if (keys.length) {
|
||||
return getObjectValue(found, keys.join("."), def);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
export function setObjectValue(obj, objKey, value, createMissingObjects = true) {
|
||||
if (!obj || !objKey)
|
||||
return obj;
|
||||
const keys = objKey.split(".");
|
||||
const key = keys.shift();
|
||||
if (obj[key] === undefined) {
|
||||
if (!createMissingObjects) {
|
||||
return;
|
||||
}
|
||||
obj[key] = {};
|
||||
}
|
||||
if (!keys.length) {
|
||||
obj[key] = value;
|
||||
}
|
||||
else {
|
||||
if (typeof obj[key] != "object") {
|
||||
obj[key] = {};
|
||||
}
|
||||
setObjectValue(obj[key], keys.join("."), value, createMissingObjects);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
export function moveArrayItem(arr, itemOrFrom, to) {
|
||||
const from = typeof itemOrFrom === "number" ? itemOrFrom : arr.indexOf(itemOrFrom);
|
||||
arr.splice(to, 0, arr.splice(from, 1)[0]);
|
||||
}
|
||||
export function removeArrayItem(arr, itemOrIndex) {
|
||||
const index = typeof itemOrIndex === "number" ? itemOrIndex : arr.indexOf(itemOrIndex);
|
||||
arr.splice(index, 1);
|
||||
}
|
||||
export function injectCss(href) {
|
||||
if (document.querySelector(`link[href^="${href}"]`)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const link = document.createElement("link");
|
||||
link.setAttribute("rel", "stylesheet");
|
||||
link.setAttribute("type", "text/css");
|
||||
const timeout = setTimeout(resolve, 1000);
|
||||
link.addEventListener("load", (e) => {
|
||||
clearInterval(timeout);
|
||||
resolve();
|
||||
});
|
||||
link.href = href;
|
||||
document.head.appendChild(link);
|
||||
});
|
||||
}
|
||||
export function defineProperty(instance, property, desc) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
const existingDesc = Object.getOwnPropertyDescriptor(instance, property);
|
||||
if ((existingDesc === null || existingDesc === void 0 ? void 0 : existingDesc.configurable) === false) {
|
||||
throw new Error(`Error: rgthree-comfy cannot define un-configurable property "${property}"`);
|
||||
}
|
||||
if ((existingDesc === null || existingDesc === void 0 ? void 0 : existingDesc.get) && desc.get) {
|
||||
const descGet = desc.get;
|
||||
desc.get = () => {
|
||||
existingDesc.get.apply(instance, []);
|
||||
return descGet.apply(instance, []);
|
||||
};
|
||||
}
|
||||
if ((existingDesc === null || existingDesc === void 0 ? void 0 : existingDesc.set) && desc.set) {
|
||||
const descSet = desc.set;
|
||||
desc.set = (v) => {
|
||||
existingDesc.set.apply(instance, [v]);
|
||||
return descSet.apply(instance, [v]);
|
||||
};
|
||||
}
|
||||
desc.enumerable = (_b = (_a = desc.enumerable) !== null && _a !== void 0 ? _a : existingDesc === null || existingDesc === void 0 ? void 0 : existingDesc.enumerable) !== null && _b !== void 0 ? _b : true;
|
||||
desc.configurable = (_d = (_c = desc.configurable) !== null && _c !== void 0 ? _c : existingDesc === null || existingDesc === void 0 ? void 0 : existingDesc.configurable) !== null && _d !== void 0 ? _d : true;
|
||||
if (!desc.get && !desc.set) {
|
||||
desc.writable = (_f = (_e = desc.writable) !== null && _e !== void 0 ? _e : existingDesc === null || existingDesc === void 0 ? void 0 : existingDesc.writable) !== null && _f !== void 0 ? _f : true;
|
||||
}
|
||||
return Object.defineProperty(instance, property, desc);
|
||||
}
|
||||
export function areDataViewsEqual(a, b) {
|
||||
if (a.byteLength !== b.byteLength) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < a.byteLength; i++) {
|
||||
if (a.getUint8(i) !== b.getUint8(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function looksLikeBase64(source) {
|
||||
return source.length > 500 || source.startsWith("data:") || source.includes(";base64,");
|
||||
}
|
||||
export function areArrayBuffersEqual(a, b) {
|
||||
if (a == b || !a || !b) {
|
||||
return a == b;
|
||||
}
|
||||
return areDataViewsEqual(new DataView(a), new DataView(b));
|
||||
}
|
||||
export function newCanvas(widthOrPtOrImage, height) {
|
||||
let width;
|
||||
if (typeof widthOrPtOrImage !== "number") {
|
||||
width = widthOrPtOrImage.width;
|
||||
height = widthOrPtOrImage.height;
|
||||
}
|
||||
else {
|
||||
width = widthOrPtOrImage;
|
||||
height = height;
|
||||
}
|
||||
if (height == null) {
|
||||
throw new Error("Invalid height supplied when creating new canvas object.");
|
||||
}
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
if (widthOrPtOrImage instanceof HTMLImageElement) {
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(widthOrPtOrImage, 0, 0, width, height);
|
||||
}
|
||||
return canvas;
|
||||
}
|
||||
export function getCanvasImageData(image) {
|
||||
const canvas = newCanvas(image);
|
||||
const ctx = canvas.getContext("2d");
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
return [canvas, ctx, imageData];
|
||||
}
|
||||
export async function convertToBase64(source) {
|
||||
if (source instanceof Promise) {
|
||||
source = await source;
|
||||
}
|
||||
if (typeof source === "string" && looksLikeBase64(source)) {
|
||||
return source;
|
||||
}
|
||||
if (typeof source === "string" || source instanceof Blob || source instanceof ArrayBuffer) {
|
||||
return convertToBase64(await loadImage(source));
|
||||
}
|
||||
if (source instanceof HTMLImageElement) {
|
||||
if (looksLikeBase64(source.src)) {
|
||||
return source.src;
|
||||
}
|
||||
const [canvas, ctx, imageData] = getCanvasImageData(source);
|
||||
return convertToBase64(canvas);
|
||||
}
|
||||
if (source instanceof HTMLCanvasElement) {
|
||||
return source.toDataURL("image/png");
|
||||
}
|
||||
throw Error("Unknown source to convert to base64.");
|
||||
}
|
||||
export async function convertToArrayBuffer(source) {
|
||||
if (source instanceof Promise) {
|
||||
source = await source;
|
||||
}
|
||||
if (source instanceof ArrayBuffer) {
|
||||
return source;
|
||||
}
|
||||
if (typeof source === "string") {
|
||||
if (looksLikeBase64(source)) {
|
||||
var binaryString = atob(source.replace(/^.*?;base64,/, ""));
|
||||
var bytes = new Uint8Array(binaryString.length);
|
||||
for (var i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
return convertToArrayBuffer(await loadImage(source));
|
||||
}
|
||||
if (source instanceof HTMLImageElement) {
|
||||
const [canvas, ctx, imageData] = getCanvasImageData(source);
|
||||
return convertToArrayBuffer(canvas);
|
||||
}
|
||||
if (source instanceof HTMLCanvasElement) {
|
||||
return convertToArrayBuffer(source.toDataURL());
|
||||
}
|
||||
if (source instanceof Blob) {
|
||||
return source.arrayBuffer();
|
||||
}
|
||||
throw Error("Unknown source to convert to arraybuffer.");
|
||||
}
|
||||
export async function loadImage(source) {
|
||||
if (source instanceof Promise) {
|
||||
source = await source;
|
||||
}
|
||||
if (source instanceof HTMLImageElement) {
|
||||
return loadImage(source.src);
|
||||
}
|
||||
if (source instanceof Blob) {
|
||||
return loadImage(source.arrayBuffer());
|
||||
}
|
||||
if (source instanceof HTMLCanvasElement) {
|
||||
return loadImage(source.toDataURL());
|
||||
}
|
||||
if (source instanceof ArrayBuffer) {
|
||||
var binary = "";
|
||||
var bytes = new Uint8Array(source);
|
||||
var len = bytes.byteLength;
|
||||
for (var i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return loadImage(`data:${getMimeTypeFromArrayBuffer(bytes)};base64,${btoa(binary)}`);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.addEventListener("load", () => {
|
||||
resolve(img);
|
||||
});
|
||||
img.addEventListener("error", () => {
|
||||
reject(img);
|
||||
});
|
||||
img.src = source;
|
||||
});
|
||||
}
|
||||
function getMimeTypeFromArrayBuffer(buffer) {
|
||||
const len = 4;
|
||||
if (buffer.length >= len) {
|
||||
let signatureArr = new Array(len);
|
||||
for (let i = 0; i < len; i++)
|
||||
signatureArr[i] = buffer[i].toString(16);
|
||||
const signature = signatureArr.join("").toUpperCase();
|
||||
switch (signature) {
|
||||
case "89504E47":
|
||||
return "image/png";
|
||||
case "47494638":
|
||||
return "image/gif";
|
||||
case "25504446":
|
||||
return "application/pdf";
|
||||
case "FFD8FFDB":
|
||||
case "FFD8FFE0":
|
||||
return "image/jpeg";
|
||||
case "504B0304":
|
||||
return "application/zip";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export class Broadcaster extends EventTarget {
|
||||
constructor(channelName) {
|
||||
super();
|
||||
this.queue = {};
|
||||
this.queue = {};
|
||||
this.channel = new BroadcastChannel(channelName);
|
||||
this.channel.addEventListener("message", (e) => {
|
||||
this.onMessage(e);
|
||||
});
|
||||
}
|
||||
getId() {
|
||||
let id;
|
||||
do {
|
||||
id = generateId(6);
|
||||
} while (this.queue[id]);
|
||||
return id;
|
||||
}
|
||||
async broadcastAndWait(action, payload, options) {
|
||||
const id = this.getId();
|
||||
this.queue[id] = getResolver(options === null || options === void 0 ? void 0 : options.timeout);
|
||||
this.channel.postMessage({
|
||||
id,
|
||||
action,
|
||||
payload,
|
||||
});
|
||||
let response;
|
||||
try {
|
||||
response = await this.queue[id].promise;
|
||||
}
|
||||
catch (e) {
|
||||
console.log("CAUGHT", e);
|
||||
response = [];
|
||||
}
|
||||
return response;
|
||||
}
|
||||
broadcast(action, payload) {
|
||||
this.channel.postMessage({
|
||||
id: this.getId(),
|
||||
action,
|
||||
payload,
|
||||
});
|
||||
}
|
||||
reply(replyId, action, payload) {
|
||||
this.channel.postMessage({
|
||||
id: this.getId(),
|
||||
replyId,
|
||||
action,
|
||||
payload,
|
||||
});
|
||||
}
|
||||
openWindowAndWaitForMessage(rgthreePath, windowName) {
|
||||
const id = this.getId();
|
||||
this.queue[id] = getResolver();
|
||||
const win = window.open(`/rgthree/${rgthreePath}#broadcastLoadMsgId=${id}`, windowName);
|
||||
return { window: win, promise: this.queue[id].promise };
|
||||
}
|
||||
onMessage(e) {
|
||||
var _a, _b;
|
||||
const msgId = ((_a = e.data) === null || _a === void 0 ? void 0 : _a.replyId) || "";
|
||||
const queueItem = this.queue[msgId];
|
||||
if (queueItem) {
|
||||
if (queueItem.completed) {
|
||||
console.error(`${msgId} already completed..`);
|
||||
}
|
||||
queueItem.deferment = queueItem.deferment || { data: [] };
|
||||
queueItem.deferment.data.push(e.data.payload);
|
||||
queueItem.deferment.timeout && clearTimeout(queueItem.deferment.timeout);
|
||||
queueItem.deferment.timeout = setTimeout(() => {
|
||||
queueItem.resolve(queueItem.deferment.data);
|
||||
}, 250);
|
||||
}
|
||||
else {
|
||||
this.dispatchEvent(new CustomEvent("rgthree-broadcast-message", {
|
||||
detail: Object.assign({ replyTo: (_b = e.data) === null || _b === void 0 ? void 0 : _b.id }, e.data),
|
||||
}));
|
||||
}
|
||||
}
|
||||
addMessageListener(callback, options) {
|
||||
return super.addEventListener("rgthree-broadcast-message", callback, options);
|
||||
}
|
||||
}
|
||||
const broadcastChannelMap = new Map();
|
||||
export function broadcastOnChannel(channel, action, payload) {
|
||||
let queue = broadcastChannelMap.get(channel);
|
||||
if (!queue) {
|
||||
broadcastChannelMap.set(channel, {});
|
||||
queue = broadcastChannelMap.get(channel);
|
||||
}
|
||||
let id;
|
||||
do {
|
||||
id = generateId(6);
|
||||
} while (queue[id]);
|
||||
queue[id] = getResolver();
|
||||
channel.postMessage({
|
||||
id,
|
||||
action,
|
||||
payload,
|
||||
});
|
||||
return queue[id].promise;
|
||||
}
|
||||
363
custom_nodes/rgthree-comfy/web/common/utils_dom.js
Normal file
363
custom_nodes/rgthree-comfy/web/common/utils_dom.js
Normal file
@@ -0,0 +1,363 @@
|
||||
const DIRECT_ATTRIBUTE_MAP = {
|
||||
cellpadding: "cellPadding",
|
||||
cellspacing: "cellSpacing",
|
||||
colspan: "colSpan",
|
||||
frameborder: "frameBorder",
|
||||
height: "height",
|
||||
maxlength: "maxLength",
|
||||
nonce: "nonce",
|
||||
role: "role",
|
||||
rowspan: "rowSpan",
|
||||
type: "type",
|
||||
usemap: "useMap",
|
||||
valign: "vAlign",
|
||||
width: "width",
|
||||
};
|
||||
const RGX_NUMERIC_STYLE_UNIT = "px";
|
||||
const RGX_NUMERIC_STYLE = /^((max|min)?(width|height)|margin|padding|(margin|padding)?(left|top|bottom|right)|fontsize|borderwidth)$/i;
|
||||
const RGX_DEFAULT_VALUE_PROP = /input|textarea|select/i;
|
||||
function localAssertNotFalsy(input, errorMsg = `Input is not of type.`) {
|
||||
if (input == null) {
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
const RGX_STRING_VALID = "[a-z0-9_-]";
|
||||
const RGX_TAG = new RegExp(`^([a-z]${RGX_STRING_VALID}*)(\\.|\\[|\\#|$)`, "i");
|
||||
const RGX_ATTR_ID = new RegExp(`#(${RGX_STRING_VALID}+)`, "gi");
|
||||
const RGX_ATTR_CLASS = new RegExp(`(^|\\S)\\.([a-z0-9_\\-\\.]+)`, "gi");
|
||||
const RGX_STRING_CONTENT_TO_SQUARES = "(.*?)(\\[|\\])";
|
||||
const RGX_ATTRS_MAYBE_OPEN = new RegExp(`\\[${RGX_STRING_CONTENT_TO_SQUARES}`, "gi");
|
||||
const RGX_ATTRS_FOLLOW_OPEN = new RegExp(`^${RGX_STRING_CONTENT_TO_SQUARES}`, "gi");
|
||||
export function queryAll(selectors, parent = document) {
|
||||
return Array.from(parent.querySelectorAll(selectors)).filter((n) => !!n);
|
||||
}
|
||||
export function query(selectors, parent = document) {
|
||||
var _a;
|
||||
return (_a = parent.querySelector(selectors)) !== null && _a !== void 0 ? _a : null;
|
||||
}
|
||||
export function createText(text) {
|
||||
return document.createTextNode(text);
|
||||
}
|
||||
export function getClosestOrSelf(element, query) {
|
||||
const el = element;
|
||||
return ((el === null || el === void 0 ? void 0 : el.closest) && ((el.matches(query) && el) || el.closest(query))) || null;
|
||||
}
|
||||
export function containsOrSelf(parent, contained) {
|
||||
var _a;
|
||||
return (parent === contained || ((_a = parent === null || parent === void 0 ? void 0 : parent.contains) === null || _a === void 0 ? void 0 : _a.call(parent, contained)) || false);
|
||||
}
|
||||
export function createElement(selectorOrMarkup, attrs) {
|
||||
const frag = getHtmlFragment(selectorOrMarkup);
|
||||
let element = frag === null || frag === void 0 ? void 0 : frag.firstElementChild;
|
||||
let selector = "";
|
||||
if (!element) {
|
||||
selector = selectorOrMarkup.replace(/[\r\n]\s*/g, "");
|
||||
const tag = getSelectorTag(selector) || "div";
|
||||
element = document.createElement(tag);
|
||||
selector = selector.replace(RGX_TAG, "$2");
|
||||
const brackets = selector.match(/(\[[^\]]+\])/g) || [];
|
||||
for (const bracket of brackets) {
|
||||
selector = selector.replace(bracket, "");
|
||||
}
|
||||
selector = selector.replace(RGX_ATTR_ID, '[id="$1"]');
|
||||
selector = selector.replace(RGX_ATTR_CLASS, (match, p1, p2) => `${p1}[class="${p2.replace(/\./g, " ")}"]`);
|
||||
selector += brackets.join("");
|
||||
}
|
||||
const selectorAttrs = getSelectorAttributes(selector);
|
||||
if (selectorAttrs) {
|
||||
for (const attr of selectorAttrs) {
|
||||
let matches = attr.substring(1, attr.length - 1).split("=");
|
||||
let key = localAssertNotFalsy(matches.shift());
|
||||
let value = matches.join("=");
|
||||
if (value === undefined) {
|
||||
setAttribute(element, key, true);
|
||||
}
|
||||
else {
|
||||
value = value.replace(/^['"](.*)['"]$/, "$1");
|
||||
setAttribute(element, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (attrs) {
|
||||
setAttributes(element, attrs);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
export const $el = createElement;
|
||||
function getSelectorTag(str) {
|
||||
return tryMatch(str, RGX_TAG);
|
||||
}
|
||||
function getSelectorAttributes(selector) {
|
||||
RGX_ATTRS_MAYBE_OPEN.lastIndex = 0;
|
||||
let attrs = [];
|
||||
let result;
|
||||
while ((result = RGX_ATTRS_MAYBE_OPEN.exec(selector))) {
|
||||
let attr = result[0];
|
||||
if (attr.endsWith("]")) {
|
||||
attrs.push(attr);
|
||||
}
|
||||
else {
|
||||
attr =
|
||||
result[0] + getOpenAttributesRecursive(selector.substr(RGX_ATTRS_MAYBE_OPEN.lastIndex), 2);
|
||||
RGX_ATTRS_MAYBE_OPEN.lastIndex += attr.length - result[0].length;
|
||||
attrs.push(attr);
|
||||
}
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
function getOpenAttributesRecursive(selectorSubstring, openCount) {
|
||||
let matches = selectorSubstring.match(RGX_ATTRS_FOLLOW_OPEN);
|
||||
let result = "";
|
||||
if (matches && matches.length) {
|
||||
result = matches[0];
|
||||
openCount += result.endsWith("]") ? -1 : 1;
|
||||
if (openCount > 0) {
|
||||
result += getOpenAttributesRecursive(selectorSubstring.substr(result.length), openCount);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function tryMatch(str, rgx, index = 1) {
|
||||
var _a;
|
||||
let found = "";
|
||||
try {
|
||||
found = ((_a = str.match(rgx)) === null || _a === void 0 ? void 0 : _a[index]) || "";
|
||||
}
|
||||
catch (e) {
|
||||
found = "";
|
||||
}
|
||||
return found;
|
||||
}
|
||||
export function setAttributes(element, data) {
|
||||
let attr;
|
||||
for (attr in data) {
|
||||
if (data.hasOwnProperty(attr)) {
|
||||
setAttribute(element, attr, data[attr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getHtmlFragment(value) {
|
||||
if (value.match(/^\s*<.*?>[\s\S]*<\/[a-z0-9]+>\s*$/)) {
|
||||
return document.createRange().createContextualFragment(value.trim());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getChild(value) {
|
||||
if (value instanceof Node) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
let child = getHtmlFragment(value);
|
||||
if (child) {
|
||||
return child;
|
||||
}
|
||||
if (getSelectorTag(value)) {
|
||||
return createElement(value);
|
||||
}
|
||||
return createText(value);
|
||||
}
|
||||
if (value && typeof value.toElement === "function") {
|
||||
return value.toElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export function setAttribute(element, attribute, value) {
|
||||
let isRemoving = value == null;
|
||||
if (attribute === "default") {
|
||||
attribute = RGX_DEFAULT_VALUE_PROP.test(element.nodeName) ? "value" : "text";
|
||||
}
|
||||
if (attribute === "text") {
|
||||
empty(element).appendChild(createText(value != null ? String(value) : ""));
|
||||
}
|
||||
else if (attribute === "html") {
|
||||
empty(element).innerHTML += value != null ? String(value) : "";
|
||||
}
|
||||
else if (attribute == "style") {
|
||||
if (typeof value === "string") {
|
||||
element.style.cssText = isRemoving ? "" : value != null ? String(value) : "";
|
||||
}
|
||||
else {
|
||||
for (const [styleKey, styleValue] of Object.entries(value)) {
|
||||
element.style[styleKey] = styleValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attribute == "events") {
|
||||
for (const [key, fn] of Object.entries(value)) {
|
||||
addEvent(element, key, fn);
|
||||
}
|
||||
}
|
||||
else if (attribute === "parent") {
|
||||
value.appendChild(element);
|
||||
}
|
||||
else if (attribute === "child" || attribute === "children") {
|
||||
if (typeof value === "string" && /^\[[^\[\]]+\]$/.test(value)) {
|
||||
const parseable = value.replace(/^\[([^\[\]]+)\]$/, '["$1"]').replace(/,/g, '","');
|
||||
try {
|
||||
const parsed = JSON.parse(parseable);
|
||||
value = parsed;
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
if (attribute === "children") {
|
||||
empty(element);
|
||||
}
|
||||
let children = value instanceof Array ? value : [value];
|
||||
for (let child of children) {
|
||||
child = getChild(child);
|
||||
if (child instanceof Node) {
|
||||
if (element instanceof HTMLTemplateElement) {
|
||||
element.content.appendChild(child);
|
||||
}
|
||||
else {
|
||||
element.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attribute == "for") {
|
||||
element.htmlFor = value != null ? String(value) : "";
|
||||
if (isRemoving) {
|
||||
element.removeAttribute("for");
|
||||
}
|
||||
}
|
||||
else if (attribute === "class" || attribute === "className" || attribute === "classes") {
|
||||
element.className = isRemoving ? "" : Array.isArray(value) ? value.join(" ") : String(value);
|
||||
}
|
||||
else if (attribute === "dataset") {
|
||||
if (typeof value !== "object") {
|
||||
console.error("Expecting an object for dataset");
|
||||
return;
|
||||
}
|
||||
for (const [key, val] of Object.entries(value)) {
|
||||
element.dataset[key] = String(val);
|
||||
}
|
||||
}
|
||||
else if (attribute.startsWith("on") && typeof value === "function") {
|
||||
element.addEventListener(attribute.substring(2), value);
|
||||
}
|
||||
else if (["checked", "disabled", "readonly", "required", "selected"].includes(attribute)) {
|
||||
element[attribute] = !!value;
|
||||
if (!value) {
|
||||
element.removeAttribute(attribute);
|
||||
}
|
||||
else {
|
||||
element.setAttribute(attribute, attribute);
|
||||
}
|
||||
}
|
||||
else if (DIRECT_ATTRIBUTE_MAP.hasOwnProperty(attribute)) {
|
||||
if (isRemoving) {
|
||||
element.removeAttribute(DIRECT_ATTRIBUTE_MAP[attribute]);
|
||||
}
|
||||
else {
|
||||
element.setAttribute(DIRECT_ATTRIBUTE_MAP[attribute], String(value));
|
||||
}
|
||||
}
|
||||
else if (isRemoving) {
|
||||
element.removeAttribute(attribute);
|
||||
}
|
||||
else {
|
||||
let oldVal = element.getAttribute(attribute);
|
||||
if (oldVal !== value) {
|
||||
element.setAttribute(attribute, String(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
function addEvent(element, key, fn) {
|
||||
element.addEventListener(key, fn);
|
||||
}
|
||||
function setStyles(element, styles = null) {
|
||||
if (styles) {
|
||||
for (let name in styles) {
|
||||
setStyle(element, name, styles[name]);
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
export function setStyle(element, name, value) {
|
||||
name = name.indexOf("float") > -1 ? "cssFloat" : name;
|
||||
if (name.indexOf("-") != -1) {
|
||||
name = name.replace(/-\D/g, (match) => {
|
||||
return match.charAt(1).toUpperCase();
|
||||
});
|
||||
}
|
||||
if (value == String(Number(value)) && RGX_NUMERIC_STYLE.test(name)) {
|
||||
value = value + RGX_NUMERIC_STYLE_UNIT;
|
||||
}
|
||||
if (name === "display" && typeof value !== "string") {
|
||||
value = !!value ? null : "none";
|
||||
}
|
||||
element.style[name] = value === null ? null : String(value);
|
||||
return element;
|
||||
}
|
||||
export function empty(element) {
|
||||
while (element.firstChild) {
|
||||
element.removeChild(element.firstChild);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
export function remove(element) {
|
||||
while (element.parentElement) {
|
||||
element.parentElement.removeChild(element);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
export function replaceChild(oldChildNode, newNode) {
|
||||
oldChildNode.parentNode.replaceChild(newNode, oldChildNode);
|
||||
return newNode;
|
||||
}
|
||||
export function appendChildren(el, children) {
|
||||
children = !Array.isArray(children) ? [children] : children;
|
||||
for (let child of children) {
|
||||
child = getChild(child);
|
||||
if (child instanceof Node) {
|
||||
if (el instanceof HTMLTemplateElement) {
|
||||
el.content.appendChild(child);
|
||||
}
|
||||
else {
|
||||
el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export function getActionEls(parent = document) {
|
||||
const els = Array.from(parent.querySelectorAll("[data-action],[on-action],[on]"));
|
||||
if (parent instanceof Element) {
|
||||
els.unshift(parent);
|
||||
}
|
||||
return els
|
||||
.map((actionEl) => {
|
||||
const actions = {};
|
||||
const actionSegments = (actionEl.getAttribute("data-action") ||
|
||||
actionEl.getAttribute("on-action") ||
|
||||
actionEl.getAttribute("on") ||
|
||||
"").split(";");
|
||||
for (let segment of actionSegments) {
|
||||
let actionsData = segment
|
||||
.trim()
|
||||
.split(/\s*:\s*/g)
|
||||
.filter((i) => !!i.trim());
|
||||
if (!actionsData.length)
|
||||
continue;
|
||||
if (actionsData.length === 1) {
|
||||
if (actionEl instanceof HTMLInputElement) {
|
||||
actionsData.unshift("input");
|
||||
}
|
||||
else {
|
||||
actionsData.unshift("click");
|
||||
}
|
||||
}
|
||||
if (actionsData[0] && actionsData[1]) {
|
||||
actions[actionsData[0]] = actionsData[1];
|
||||
}
|
||||
}
|
||||
return {
|
||||
el: actionEl,
|
||||
actions,
|
||||
};
|
||||
})
|
||||
.filter((el) => !!el);
|
||||
}
|
||||
592
custom_nodes/rgthree-comfy/web/common/utils_templates.js
Normal file
592
custom_nodes/rgthree-comfy/web/common/utils_templates.js
Normal file
@@ -0,0 +1,592 @@
|
||||
import * as dom from "./utils_dom.js";
|
||||
import { getObjectValue } from "./shared_utils.js";
|
||||
const CONFIG_DEFAULT = {
|
||||
attrBind: "data-bind",
|
||||
attrIf: "data-if",
|
||||
attrIfIs: "data-if-is",
|
||||
};
|
||||
const CONFIG = Object.assign({}, CONFIG_DEFAULT, {
|
||||
attrBind: "bind",
|
||||
attrIf: "if",
|
||||
attrIfIs: "if-is",
|
||||
});
|
||||
const RGX_COMPARISON = (() => {
|
||||
let value = "((?:\\!*)[_a-z0-9\\.\\-\\[\\]'\"]+)";
|
||||
let comparison = "((?:<|>|==|\\!=)=?)";
|
||||
return new RegExp(`^(?:\\!*)\\(?${value}\\s*${comparison}\\s*${value}\\)?$`, "i");
|
||||
})();
|
||||
const RGXPART_BIND_FN_TEMPLATE_STRING = "template|tpl";
|
||||
const RGXPART_BIND_FN_ELEMENT_STRING = "element|el";
|
||||
const RGX_BIND_FN_TEMPLATE = new RegExp(`^(?:${RGXPART_BIND_FN_TEMPLATE_STRING})\\(([^\\)]+)\\)`, "i");
|
||||
const RGX_BIND_FN_ELEMENT = new RegExp(`^(?:${RGXPART_BIND_FN_ELEMENT_STRING})\\(([^\\)]+)\\)`, "i");
|
||||
const RGX_BIND_FN_TEMPLATE_OR_ELEMENT = new RegExp(`^(?:${RGXPART_BIND_FN_TEMPLATE_STRING}|${RGXPART_BIND_FN_ELEMENT_STRING})\\(([^\\)]+)\\)`, "i");
|
||||
const RGX_BIND_FN_LENGTH = /^(?:length|len|size)\(([^\)]+)\)/i;
|
||||
const RGX_BIND_FN_FORMAT = /^(?:format|fmt)\(([^\,]+),([^\)]+)\)/i;
|
||||
const RGX_BIND_FN_CALL = /^([^\(]+)\(([^\)]*)\)/i;
|
||||
const EMPTY_PREPROCESS_FN = (data) => data;
|
||||
const RGX_BIND_DECLARATIONS = /\s*(\!*(?:[\$_a-z0-9-\.\'\"]|\?\?|\|\||\&\&|(?:(?:<|>|==|\!=)=?))+(?:\`[^\`]+\`)?(?:\([^\)]*\))?)(?::(.*?))?(\s|$)/gi;
|
||||
function localAssertNotFalsy(input, errorMsg = `Input is not of type.`) {
|
||||
if (input == null) {
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
function cleanKey(key) {
|
||||
return key.toLowerCase().trim().replace(/\s/g, "");
|
||||
}
|
||||
function toArray(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
if (value instanceof Set) {
|
||||
return Array.from(value);
|
||||
}
|
||||
if (typeof value === "object" && typeof value.length === "number") {
|
||||
return [].slice.call(value);
|
||||
}
|
||||
return [value];
|
||||
}
|
||||
function flattenArray(arr) {
|
||||
return toArray(arr).reduce((acc, val) => {
|
||||
return acc.concat(Array.isArray(val) ? flattenArray(val) : val);
|
||||
}, []);
|
||||
}
|
||||
function getObjValue(lookup, obj) {
|
||||
let booleanMatch = lookup.match(/^(\!+)(.+?)$/i) || [];
|
||||
let booleanNots = [];
|
||||
if (booleanMatch[1] && booleanMatch[2]) {
|
||||
booleanNots = booleanMatch[1].split("");
|
||||
lookup = booleanMatch[2];
|
||||
}
|
||||
let value = getObjectValue(obj, lookup);
|
||||
while (booleanNots.length) {
|
||||
value = !value;
|
||||
booleanNots.shift();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function getPrimitiveOrObjValue(stringValue, data) {
|
||||
let value;
|
||||
if (stringValue == null) {
|
||||
return stringValue;
|
||||
}
|
||||
let negate = getNegates(stringValue);
|
||||
if (negate != null) {
|
||||
stringValue = stringValue.replace(/^\!+/, "");
|
||||
}
|
||||
try {
|
||||
const cleanedStringValue = stringValue.replace(/^'(.*)'$/, '"$1"');
|
||||
value = JSON.parse(cleanedStringValue);
|
||||
}
|
||||
catch (e) {
|
||||
value = getObjValue(stringValue, data);
|
||||
}
|
||||
value = negate !== null ? (negate === 1 ? !value : !!value) : value;
|
||||
return value;
|
||||
}
|
||||
function getNegates(stringValue) {
|
||||
let negate = null;
|
||||
let negateMatches = stringValue.match(/^(\!+)(.*)/);
|
||||
if (negateMatches && negateMatches.length >= 3) {
|
||||
negate = negateMatches[1].length % 2;
|
||||
}
|
||||
return negate;
|
||||
}
|
||||
function getStringComparisonExpression(bindingPropName, data) {
|
||||
let comparisonMatches = bindingPropName.match(RGX_COMPARISON);
|
||||
if (!(comparisonMatches === null || comparisonMatches === void 0 ? void 0 : comparisonMatches.length)) {
|
||||
return null;
|
||||
}
|
||||
let a = getPrimitiveOrObjValue(comparisonMatches[1], data);
|
||||
let b = getPrimitiveOrObjValue(comparisonMatches[3], data);
|
||||
let c = comparisonMatches[2];
|
||||
let value = (() => {
|
||||
switch (c) {
|
||||
case "===":
|
||||
return a === b;
|
||||
case "==":
|
||||
return a == b;
|
||||
case "<=":
|
||||
return a <= b;
|
||||
case ">=":
|
||||
return a >= b;
|
||||
case "!==":
|
||||
return a !== b;
|
||||
case "!=":
|
||||
return a != b;
|
||||
case "<":
|
||||
return a < b;
|
||||
case ">":
|
||||
return a > b;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
return value;
|
||||
}
|
||||
function replaceTplElementWithChildren(tplEl, fragOrElOrEls) {
|
||||
const els = Array.isArray(fragOrElOrEls) ? fragOrElOrEls : [fragOrElOrEls];
|
||||
tplEl.replaceWith(...els);
|
||||
const numOfChildren = Array.isArray(fragOrElOrEls)
|
||||
? fragOrElOrEls.length
|
||||
: fragOrElOrEls.childElementCount;
|
||||
if (numOfChildren === 1) {
|
||||
const firstChild = Array.isArray(fragOrElOrEls)
|
||||
? fragOrElOrEls[0]
|
||||
: fragOrElOrEls.firstElementChild;
|
||||
if (firstChild instanceof Element) {
|
||||
if (tplEl.className.length) {
|
||||
firstChild.className += ` ${tplEl.className}`;
|
||||
}
|
||||
let attr = tplEl.getAttribute("data");
|
||||
if (attr) {
|
||||
firstChild.setAttribute("data", attr);
|
||||
}
|
||||
attr = tplEl.getAttribute(CONFIG.attrBind);
|
||||
if (attr) {
|
||||
firstChild.setAttribute(CONFIG.attrBind, attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function getValueForBinding(bindingPropName, context) {
|
||||
console.log("getValueForBinding", bindingPropName, context);
|
||||
const data = context.data;
|
||||
let stringTemplate = null;
|
||||
let stringTemplates = /^(.*?)\`([^\`]*)\`$/.exec(bindingPropName.trim());
|
||||
if ((stringTemplates === null || stringTemplates === void 0 ? void 0 : stringTemplates.length) === 3) {
|
||||
bindingPropName = stringTemplates[1];
|
||||
stringTemplate = stringTemplates[2];
|
||||
}
|
||||
let value = null;
|
||||
let hadALogicalOp = false;
|
||||
const opsToValidation = new Map([
|
||||
[/\s*\?\?\s*/, (v) => v != null],
|
||||
[/\s*\|\|\s*/, (v) => !!v],
|
||||
[/\s*\&\&\s*/, (v) => !v],
|
||||
]);
|
||||
for (const [op, fn] of opsToValidation.entries()) {
|
||||
if (bindingPropName.match(op)) {
|
||||
hadALogicalOp = true;
|
||||
const bindingPropNames = bindingPropName.split(op);
|
||||
for (const propName of bindingPropNames) {
|
||||
value = getValueForBindingPropName(propName, context);
|
||||
if (fn(value)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hadALogicalOp) {
|
||||
value = getValueForBindingPropName(bindingPropName, context);
|
||||
}
|
||||
return stringTemplate && value != null
|
||||
? stringTemplate.replace(/\$\{value\}/g, String(value))
|
||||
: value;
|
||||
}
|
||||
function getValueForBindingPropName(bindingPropName, context) {
|
||||
var _a, _b, _c;
|
||||
const data = context.data;
|
||||
let negate = getNegates(bindingPropName);
|
||||
if (negate != null) {
|
||||
bindingPropName = bindingPropName.replace(/^\!+/, "");
|
||||
}
|
||||
let value;
|
||||
RGX_COMPARISON.lastIndex = 0;
|
||||
if (RGX_COMPARISON.test(bindingPropName)) {
|
||||
value = getStringComparisonExpression(bindingPropName, data);
|
||||
}
|
||||
else if (RGX_BIND_FN_LENGTH.test(bindingPropName)) {
|
||||
bindingPropName = RGX_BIND_FN_LENGTH.exec(bindingPropName)[1];
|
||||
value = getPrimitiveOrObjValue(bindingPropName, data);
|
||||
value = (value && value.length) || 0;
|
||||
}
|
||||
else if (RGX_BIND_FN_FORMAT.test(bindingPropName)) {
|
||||
let matches = RGX_BIND_FN_FORMAT.exec(bindingPropName);
|
||||
bindingPropName = matches[1];
|
||||
value = getPrimitiveOrObjValue(bindingPropName, data);
|
||||
value = matches[2].replace(/^['"]/, "").replace(/['"]$/, "").replace(/\$1/g, value);
|
||||
}
|
||||
else if (RGX_BIND_FN_CALL.test(bindingPropName)) {
|
||||
console.log("-----");
|
||||
console.log(bindingPropName);
|
||||
let matches = RGX_BIND_FN_CALL.exec(bindingPropName);
|
||||
const functionName = matches[1];
|
||||
const maybeDataName = (_a = matches[2]) !== null && _a !== void 0 ? _a : null;
|
||||
value = getPrimitiveOrObjValue(maybeDataName, data);
|
||||
console.log(functionName, maybeDataName, value);
|
||||
if (typeof (value === null || value === void 0 ? void 0 : value[functionName]) === "function") {
|
||||
value = value[functionName](value, data, context.currentElement, context.contextElement);
|
||||
}
|
||||
else if (typeof (data === null || data === void 0 ? void 0 : data[functionName]) === "function") {
|
||||
value = data[functionName](value, data, context.currentElement, context.contextElement);
|
||||
}
|
||||
else if (typeof ((_b = context.currentElement) === null || _b === void 0 ? void 0 : _b[functionName]) === "function") {
|
||||
value = context.currentElement[functionName](value, data, context.currentElement, context.contextElement);
|
||||
}
|
||||
else if (typeof ((_c = context.contextElement) === null || _c === void 0 ? void 0 : _c[functionName]) === "function") {
|
||||
value = context.contextElement[functionName](value, data, context.currentElement, context.contextElement);
|
||||
}
|
||||
else {
|
||||
console.error(`No method named ${functionName} on data or element instance. Just calling regular value.`);
|
||||
value = getPrimitiveOrObjValue(bindingPropName, data);
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = getPrimitiveOrObjValue(bindingPropName, data);
|
||||
}
|
||||
if (value !== undefined) {
|
||||
value = negate !== null ? (negate === 1 ? !value : !!value) : value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function removeBindingAttributes(elOrEls, deep = false) {
|
||||
flattenArray(elOrEls || []).forEach((el) => {
|
||||
el.removeAttribute(CONFIG.attrBind);
|
||||
const innerBinds = dom.queryAll(`:scope [${CONFIG.attrBind}]`, el);
|
||||
const innerTplBinds = deep ? [] : dom.queryAll(`:scope [data-tpl] [${CONFIG.attrBind}]`);
|
||||
innerBinds.forEach((el) => {
|
||||
if (deep || !innerTplBinds.includes(el)) {
|
||||
el.removeAttribute(CONFIG.attrBind);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
const templateCache = {};
|
||||
export function checkKey(key) {
|
||||
return !!templateCache[cleanKey(key)];
|
||||
}
|
||||
export function register(key, htmlOrElement = null, preProcessScript) {
|
||||
key = cleanKey(key);
|
||||
if (templateCache[key]) {
|
||||
return templateCache[key];
|
||||
}
|
||||
let fragment = null;
|
||||
if (typeof htmlOrElement === "string") {
|
||||
const frag = document.createDocumentFragment();
|
||||
if (htmlOrElement.includes("<")) {
|
||||
const html = htmlOrElement.trim();
|
||||
const htmlParentTag = (html.startsWith("<tr") && "tbody") ||
|
||||
(/^<t(body|head|foot)/i.test(html) && "table") ||
|
||||
(/^<t(d|h)/i.test(html) && "tr") ||
|
||||
"div";
|
||||
const temp = document.createElement(htmlParentTag);
|
||||
temp.innerHTML = html;
|
||||
for (const child of temp.children) {
|
||||
frag.appendChild(child);
|
||||
}
|
||||
}
|
||||
else {
|
||||
frag.appendChild(dom.createElement(htmlOrElement));
|
||||
}
|
||||
fragment = frag;
|
||||
}
|
||||
else if (htmlOrElement instanceof Element) {
|
||||
const element = htmlOrElement;
|
||||
const tag = element.nodeName.toLowerCase();
|
||||
if (tag === "template" && element.content) {
|
||||
fragment = element.content;
|
||||
}
|
||||
else {
|
||||
throw Error("Non-template element not handled");
|
||||
}
|
||||
}
|
||||
else if (!htmlOrElement) {
|
||||
let element = dom.query(`template[id="${key}"],template[data-id="${key}"]`);
|
||||
if (element && element.content) {
|
||||
fragment = element.content;
|
||||
}
|
||||
else {
|
||||
throw Error("Non-template element not handled");
|
||||
}
|
||||
}
|
||||
if (fragment) {
|
||||
templateCache[key] = {
|
||||
fragment,
|
||||
preProcessScript: preProcessScript || EMPTY_PREPROCESS_FN,
|
||||
};
|
||||
}
|
||||
return templateCache[key] || null;
|
||||
}
|
||||
export function getPreProcessScript(keyOrEl) {
|
||||
var _a;
|
||||
if (typeof keyOrEl === "string") {
|
||||
if (!templateCache[keyOrEl]) {
|
||||
throw Error(`Template key does not exist ${keyOrEl}`);
|
||||
}
|
||||
return templateCache[keyOrEl].preProcessScript;
|
||||
}
|
||||
if (keyOrEl instanceof Element) {
|
||||
const tpl = keyOrEl.getAttribute("data-tpl") || "";
|
||||
return ((_a = templateCache[tpl]) === null || _a === void 0 ? void 0 : _a.preProcessScript) || EMPTY_PREPROCESS_FN;
|
||||
}
|
||||
return EMPTY_PREPROCESS_FN;
|
||||
}
|
||||
export function getTemplateFragment(key) {
|
||||
key = cleanKey(key);
|
||||
if (!checkKey(key)) {
|
||||
register(key);
|
||||
}
|
||||
let templateData = templateCache[key];
|
||||
if (templateData && templateData.fragment) {
|
||||
let imported;
|
||||
if (document.importNode) {
|
||||
imported = document.importNode(templateData.fragment, true);
|
||||
}
|
||||
else {
|
||||
imported = templateData.fragment.cloneNode(true);
|
||||
}
|
||||
imported.__templateid__ = key;
|
||||
return imported;
|
||||
}
|
||||
else {
|
||||
throw new Error("Ain't no template called " + key + " (" + typeof templateCache[key] + ")");
|
||||
}
|
||||
}
|
||||
export function inflate(nodeOrKey, templateData = null, inflateOptions = {}) {
|
||||
let node = nodeOrKey;
|
||||
if (typeof node === "string") {
|
||||
node = getTemplateFragment(node);
|
||||
}
|
||||
if (node) {
|
||||
const els = dom.queryAll("[data-template], [data-templateid], [template]", node);
|
||||
for (const child of els) {
|
||||
let className = child.className || null;
|
||||
let childTemplateId = localAssertNotFalsy(child.getAttribute("data-template") ||
|
||||
child.getAttribute("data-templateid") ||
|
||||
child.getAttribute("template"), "No child template id provided.");
|
||||
const dataAttribute = child.getAttribute("data") || "";
|
||||
const childData = (dataAttribute && getObjValue(dataAttribute, templateData)) || templateData;
|
||||
const tplsInflateOptions = Object.assign({}, inflateOptions);
|
||||
if (tplsInflateOptions.skipInit != null) {
|
||||
tplsInflateOptions.skipInit = true;
|
||||
}
|
||||
let tpls = localAssertNotFalsy(inflate(childTemplateId, childData, tplsInflateOptions), `No template inflated from ${childTemplateId}.`);
|
||||
tpls = !Array.isArray(tpls) ? [tpls] : tpls;
|
||||
if (className) {
|
||||
for (const tpl of tpls) {
|
||||
tpl.classList.add(className);
|
||||
}
|
||||
}
|
||||
if (child.nodeName.toUpperCase() === "TPL") {
|
||||
replaceTplElementWithChildren(child, tpls);
|
||||
}
|
||||
else {
|
||||
child.append(...tpls);
|
||||
}
|
||||
child.remove();
|
||||
}
|
||||
let children = [];
|
||||
for (const child of node.children) {
|
||||
let tplAttributes = (child.getAttribute("data-tpl") || "").split(" ");
|
||||
if (!tplAttributes.includes(node.__templateid__)) {
|
||||
tplAttributes.push(node.__templateid__);
|
||||
}
|
||||
child.setAttribute("data-tpl", tplAttributes.join(" ").trim());
|
||||
children.push(child);
|
||||
}
|
||||
let childOrChildren = children.length === 1 ? children[0] : children;
|
||||
if (!inflateOptions.skipInit) {
|
||||
init(childOrChildren, templateData, inflateOptions.bindOptions);
|
||||
}
|
||||
return childOrChildren;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
export function inflateSingle(nodeOrKey, scriptData = null, bindOptions = {}) {
|
||||
const inflated = localAssertNotFalsy(inflate(nodeOrKey, scriptData, bindOptions));
|
||||
return Array.isArray(inflated) ? inflated[0] : inflated;
|
||||
}
|
||||
export function inflateOnce(nodeOrKey, templateData = null, inflateOptions = {}) {
|
||||
let children = inflate(nodeOrKey, templateData, inflateOptions);
|
||||
children && removeBindingAttributes(children, false);
|
||||
return children;
|
||||
}
|
||||
export function inflateSingleOnce(nodeOrKey, scriptData = null, bindOptions = {}) {
|
||||
const inflated = inflate(nodeOrKey, scriptData, bindOptions) || [];
|
||||
removeBindingAttributes(inflated, false);
|
||||
return Array.isArray(inflated) ? inflated[0] : inflated;
|
||||
}
|
||||
export function init(els, data, bindOptions = {}) {
|
||||
(!els ? [] : els instanceof Element ? [els] : els).forEach((el) => {
|
||||
const dataTplAttr = el.getAttribute("data-tpl");
|
||||
if (dataTplAttr) {
|
||||
const tpls = dataTplAttr.split(" ");
|
||||
tpls.forEach((tpl) => {
|
||||
const dataAttribute = el.getAttribute("data") || "";
|
||||
const childData = (dataAttribute && getObjValue(dataAttribute, data)) || data;
|
||||
bind(el, childData, bindOptions);
|
||||
});
|
||||
}
|
||||
else {
|
||||
bind(el, data, bindOptions);
|
||||
}
|
||||
});
|
||||
}
|
||||
export function bind(elOrEls, data = {}, bindOptions = {}) {
|
||||
var _a;
|
||||
if (elOrEls instanceof HTMLElement) {
|
||||
data = getPreProcessScript(elOrEls)({ ...data });
|
||||
}
|
||||
if (typeof data !== "object") {
|
||||
data = { value: data };
|
||||
if (elOrEls instanceof HTMLElement &&
|
||||
elOrEls.children.length === 0 &&
|
||||
!elOrEls.getAttribute(CONFIG.attrBind)) {
|
||||
dom.setAttributes(elOrEls, { [CONFIG.attrBind]: "value" });
|
||||
}
|
||||
}
|
||||
let passedEls = !Array.isArray(elOrEls) ? [elOrEls] : elOrEls;
|
||||
for (const el of passedEls) {
|
||||
const conditionEls = toArray(dom.queryAll(`[${CONFIG.attrIf}]`, el));
|
||||
const contextElement = (_a = bindOptions.contextElement) !== null && _a !== void 0 ? _a : (el instanceof ShadowRoot ? el.host : el);
|
||||
for (const conditionEl of conditionEls) {
|
||||
getValueForBindingPropName;
|
||||
let isTrue = getValueForBinding(conditionEl.getAttribute(CONFIG.attrIf), {
|
||||
data,
|
||||
contextElement: contextElement,
|
||||
currentElement: conditionEl,
|
||||
});
|
||||
conditionEl.setAttribute(CONFIG.attrIfIs, String(!!isTrue));
|
||||
}
|
||||
let toBindEls = toArray(dom.queryAll(`:not([${CONFIG.attrIfIs}="false"]) [${CONFIG.attrBind}]:not([data-tpl]):not([${CONFIG.attrIfIs}="false"])`, el));
|
||||
if (el instanceof HTMLElement && el.getAttribute(CONFIG.attrBind)) {
|
||||
toBindEls.unshift(el);
|
||||
}
|
||||
if (toBindEls.length) {
|
||||
let innerBindsElements = dom.queryAll(`:scope [data-tpl] [${CONFIG.attrBind}], :scope [data-autobind="false"] [${CONFIG.attrBind}]`, el);
|
||||
toBindEls = toBindEls.filter((maybeBind) => !innerBindsElements.includes(maybeBind));
|
||||
toBindEls.forEach((child) => {
|
||||
RGX_BIND_DECLARATIONS.lastIndex = 0;
|
||||
let bindings = [];
|
||||
let bindingMatch;
|
||||
while ((bindingMatch = RGX_BIND_DECLARATIONS.exec(child.getAttribute(CONFIG.attrBind).replace(/\s+/, " ").trim())) !== null) {
|
||||
bindings.push([bindingMatch[1], bindingMatch[2]]);
|
||||
}
|
||||
bindings.forEach((bindings) => {
|
||||
let bindingDataProperty = localAssertNotFalsy(bindings.shift());
|
||||
let bindingFields = ((bindings.length && bindings[0]) || "default")
|
||||
.trim()
|
||||
.replace(/^\[(.*?)\]$/i, "$1")
|
||||
.split(",");
|
||||
let value = getValueForBinding(bindingDataProperty, {
|
||||
data,
|
||||
contextElement: contextElement,
|
||||
currentElement: child,
|
||||
});
|
||||
if (value === undefined) {
|
||||
if (bindOptions.onlyDefined === true) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
bindingFields.forEach((field) => {
|
||||
if (field.startsWith("style.")) {
|
||||
let stringVal = String(value);
|
||||
if (value &&
|
||||
!stringVal.includes("url(") &&
|
||||
stringVal !== "none" &&
|
||||
(field.includes("background-image") || stringVal.startsWith("http"))) {
|
||||
value = `url(${value})`;
|
||||
}
|
||||
dom.setStyle(child, field.replace("style.", ""), value);
|
||||
}
|
||||
else if (field.startsWith("el.")) {
|
||||
if (field === "el.remove") {
|
||||
if (value === true) {
|
||||
child.remove();
|
||||
}
|
||||
}
|
||||
else if (field === "el.toggle") {
|
||||
dom.setStyle(child, "display", value === true ? "" : "none");
|
||||
}
|
||||
else if (field.startsWith("el.classList.toggle")) {
|
||||
const cssClass = field.replace(/el.classList.toggle\(['"]?(.*?)['"]?\)/, "$1");
|
||||
child.classList.toggle(cssClass, !!value);
|
||||
}
|
||||
}
|
||||
else if (RGX_BIND_FN_TEMPLATE_OR_ELEMENT.test(field)) {
|
||||
dom.empty(child);
|
||||
let elementOrTemplateName = RGX_BIND_FN_TEMPLATE_OR_ELEMENT.exec(field)[1];
|
||||
if (Array.isArray(value) || value instanceof Set) {
|
||||
const arrayVals = toArray(value);
|
||||
let isElement = RGX_BIND_FN_ELEMENT.test(field);
|
||||
let frag = document.createDocumentFragment();
|
||||
arrayVals.forEach((item, index) => {
|
||||
let itemData;
|
||||
if (typeof item === "object") {
|
||||
itemData = Object.assign({ $index: index }, item);
|
||||
}
|
||||
else {
|
||||
itemData = { $index: index, value: item };
|
||||
}
|
||||
const els = bindToElOrTemplate(elementOrTemplateName, itemData);
|
||||
frag.append(...els);
|
||||
});
|
||||
if (child.nodeName.toUpperCase() === "TPL") {
|
||||
replaceTplElementWithChildren(child, frag);
|
||||
}
|
||||
else {
|
||||
dom.empty(child).appendChild(frag);
|
||||
}
|
||||
}
|
||||
else if (value) {
|
||||
const els = bindToElOrTemplate(elementOrTemplateName, value);
|
||||
if (child.nodeName.toUpperCase() === "TPL") {
|
||||
replaceTplElementWithChildren(child, els);
|
||||
}
|
||||
else {
|
||||
child.append(...els);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
dom.setAttributes(child, { [field]: value });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
if (bindOptions.singleScoped !== true) {
|
||||
let toInitEls = toArray(el.querySelectorAll(":scope *[data-tpl]"));
|
||||
if (toInitEls.length) {
|
||||
let innerInits = dom.queryAll(':scope *[data-tpl] *[data-tpl], :scope [data-autobind="false"] [data-tpl]', el);
|
||||
toInitEls = toInitEls.filter((maybeInitEl) => {
|
||||
if (innerInits.includes(maybeInitEl)) {
|
||||
return false;
|
||||
}
|
||||
let tplKey = maybeInitEl.getAttribute("data-tpl");
|
||||
if (data && (data[tplKey] || data[tplKey.replace("tpl:", "")])) {
|
||||
return true;
|
||||
}
|
||||
return maybeInitEl.getAttribute("data-autobind") !== "false";
|
||||
});
|
||||
toInitEls.forEach((toInitEl) => {
|
||||
var tplKey = toInitEl.getAttribute("data-tpl");
|
||||
init(toInitEl, (data && (data[tplKey] || data[tplKey.replace("tpl:", "")])) || data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function bindToElOrTemplate(elementOrTemplateName, data) {
|
||||
let el = getTemplateFragment(elementOrTemplateName);
|
||||
if (!el) {
|
||||
el = dom.createElement(elementOrTemplateName, data);
|
||||
}
|
||||
else {
|
||||
el = inflateOnce(el, data, { skipInit: false });
|
||||
}
|
||||
const els = (Array.isArray(el) ? el : [el]).filter((el) => !!el);
|
||||
els.forEach((el) => {
|
||||
el.removeAttribute("data-tpl");
|
||||
let toBindEls = dom.queryAll("[data-tpl]", el);
|
||||
let innerBindsElements = dom.queryAll(`:scope [data-tpl] [${CONFIG.attrBind}], :scope [data-autobind="false"] [${CONFIG.attrBind}]`, el);
|
||||
toBindEls = toBindEls.filter((maybeBind) => !innerBindsElements.includes(maybeBind));
|
||||
toBindEls.forEach((c) => c.removeAttribute("data-tpl"));
|
||||
});
|
||||
return els;
|
||||
}
|
||||
55
custom_nodes/rgthree-comfy/web/common/utils_workflow.js
Normal file
55
custom_nodes/rgthree-comfy/web/common/utils_workflow.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { getResolver } from "./shared_utils.js";
|
||||
import { getPngMetadata, getWebpMetadata } from "./comfyui_shim.js";
|
||||
function parseWorkflowJson(stringJson) {
|
||||
stringJson = stringJson || "null";
|
||||
stringJson = stringJson.replace(/:\s*NaN/g, ": null");
|
||||
return JSON.parse(stringJson);
|
||||
}
|
||||
export async function tryToGetWorkflowDataFromEvent(e) {
|
||||
var _a, _b, _c, _d;
|
||||
let work;
|
||||
for (const file of ((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) || []) {
|
||||
const data = await tryToGetWorkflowDataFromFile(file);
|
||||
if (data.workflow || data.prompt) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
const validTypes = ["text/uri-list", "text/x-moz-url"];
|
||||
const match = (((_b = e.dataTransfer) === null || _b === void 0 ? void 0 : _b.types) || []).find((t) => validTypes.find((v) => t === v));
|
||||
if (match) {
|
||||
const uri = (_d = (_c = e.dataTransfer.getData(match)) === null || _c === void 0 ? void 0 : _c.split("\n")) === null || _d === void 0 ? void 0 : _d[0];
|
||||
if (uri) {
|
||||
return tryToGetWorkflowDataFromFile(await (await fetch(uri)).blob());
|
||||
}
|
||||
}
|
||||
return { workflow: null, prompt: null };
|
||||
}
|
||||
export async function tryToGetWorkflowDataFromFile(file) {
|
||||
var _a;
|
||||
if (file.type === "image/png") {
|
||||
const pngInfo = await getPngMetadata(file);
|
||||
return {
|
||||
workflow: parseWorkflowJson(pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.workflow),
|
||||
prompt: parseWorkflowJson(pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.prompt),
|
||||
};
|
||||
}
|
||||
if (file.type === "image/webp") {
|
||||
const pngInfo = await getWebpMetadata(file);
|
||||
const workflow = parseWorkflowJson((pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.workflow) || (pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.Workflow) || "null");
|
||||
const prompt = parseWorkflowJson((pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.prompt) || (pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.Prompt) || "null");
|
||||
return { workflow, prompt };
|
||||
}
|
||||
if (file.type === "application/json" || ((_a = file.name) === null || _a === void 0 ? void 0 : _a.endsWith(".json"))) {
|
||||
const resolver = getResolver();
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
const json = parseWorkflowJson(reader.result);
|
||||
const isApiJson = Object.values(json).every((v) => v.class_type);
|
||||
const prompt = isApiJson ? json : null;
|
||||
const workflow = !isApiJson && !(json === null || json === void 0 ? void 0 : json.templates) ? json : null;
|
||||
return { workflow, prompt };
|
||||
};
|
||||
return resolver.promise;
|
||||
}
|
||||
return { workflow: null, prompt: null };
|
||||
}
|
||||
Reference in New Issue
Block a user