mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-09 21:12:36 +08:00
init i18n extension
This commit is contained in:
parent
0ce8a540ce
commit
2542a6bf93
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ venv/
|
||||
web/extensions/*
|
||||
!web/extensions/logging.js.example
|
||||
!web/extensions/core/
|
||||
!web/extensions/i18n/
|
||||
|
||||
@ -435,7 +435,7 @@ app.registerExtension({
|
||||
$el("td", [
|
||||
$el("label", {
|
||||
for: id.replaceAll(".", "-"),
|
||||
textContent: "Color palette",
|
||||
textContent: i18next.t("settings.Comfy.ColorPalette"),
|
||||
}),
|
||||
]),
|
||||
$el("td", [
|
||||
@ -449,7 +449,7 @@ app.registerExtension({
|
||||
}, [
|
||||
$el("input", {
|
||||
type: "button",
|
||||
value: "Export",
|
||||
value: i18next.t("settings.Comfy.ColorPalette.export"),
|
||||
onclick: async () => {
|
||||
const colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId);
|
||||
const colorPalette = await completeColorPalette(getColorPalette(colorPaletteId));
|
||||
@ -471,14 +471,14 @@ app.registerExtension({
|
||||
}),
|
||||
$el("input", {
|
||||
type: "button",
|
||||
value: "Import",
|
||||
value: i18next.t("settings.Comfy.ColorPalette.import"),
|
||||
onclick: () => {
|
||||
fileInput.click();
|
||||
}
|
||||
}),
|
||||
$el("input", {
|
||||
type: "button",
|
||||
value: "Template",
|
||||
value: i18next.t("settings.Comfy.ColorPalette.template"),
|
||||
onclick: async () => {
|
||||
const colorPalette = await getColorPaletteTemplate();
|
||||
const json = JSON.stringify(colorPalette, null, 2); // convert the data to a JSON string
|
||||
@ -499,7 +499,7 @@ app.registerExtension({
|
||||
}),
|
||||
$el("input", {
|
||||
type: "button",
|
||||
value: "Delete",
|
||||
value: i18next.t("settings.Comfy.ColorPalette.delete"),
|
||||
onclick: async () => {
|
||||
let colorPaletteId = app.ui.settings.getSettingValue(id, defaultColorPaletteId);
|
||||
|
||||
|
||||
46
web/extensions/core/i18n.js
Normal file
46
web/extensions/core/i18n.js
Normal file
@ -0,0 +1,46 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "i18next",
|
||||
addCustomNodeDefs(defs) {
|
||||
for (const k in defs) {
|
||||
defs[k].display_name = i18next.t(`node.title.${k}`)
|
||||
|
||||
if ("input" in defs[k] && defs[k].input.required) {
|
||||
for (const i in defs[k].input.required) {
|
||||
if (defs[k].input.required[i].length > 1) {
|
||||
defs[k].input.required[i][1].label = i18next.t(`node.input.${k}.${i}`)
|
||||
} else {
|
||||
defs[k].input.required[i].push({ label: i18next.t(`node.input.${k}.${i}`) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
nodeCreated(node) {
|
||||
if ("inputs" in node) {
|
||||
for (const item of node.inputs) {
|
||||
item.label = i18next.t(`node.input.${node.comfyClass}.${item.name}`)
|
||||
}
|
||||
}
|
||||
|
||||
if ("widgets" in node) {
|
||||
for (const item of node.widgets) {
|
||||
item.label = i18next.t(`node.input.${node.comfyClass}.${item.name}`)
|
||||
}
|
||||
}
|
||||
|
||||
if ("outputs" in node) {
|
||||
for (const item of node.outputs) {
|
||||
item.label = i18next.t(`node.output.${node.comfyClass}.${item.name}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
afterNodesRegistrations() {
|
||||
const defs = LiteGraph.registered_node_types
|
||||
|
||||
for (const k in defs) {
|
||||
defs[k].category = i18next.t(`category.${defs[k].category}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -57,6 +57,7 @@ function convertToInput(node, widget, config) {
|
||||
const sz = node.size;
|
||||
node.addInput(widget.name, linkType, {
|
||||
widget: { name: widget.name, config },
|
||||
label: config?.[1] ? i18next.t(config?.[1].label) : void 0,
|
||||
});
|
||||
|
||||
for (const widget of node.widgets) {
|
||||
|
||||
125
web/i18n/en_US.js
Normal file
125
web/i18n/en_US.js
Normal file
@ -0,0 +1,125 @@
|
||||
export default {
|
||||
translation: {
|
||||
"ui.queue_btn": "Queue Prompt",
|
||||
"ui.queue_front_btn": "Queue Front",
|
||||
"ui.view_queue_btn": "View Queue",
|
||||
"ui.view_history_btn": "View History",
|
||||
"ui.save_btn": "Save",
|
||||
"ui.load_btn": "Load",
|
||||
"ui.refresh_btn": "Refresh",
|
||||
"ui.clipspace_btn": "Clipspace",
|
||||
"ui.clear_btn": "Clear",
|
||||
"ui.load_default_btn": "Load Default",
|
||||
"ui.close_btn": "Close",
|
||||
"ui.queue_size": "Queue size: ",
|
||||
"ui.extra_options": "Extra options",
|
||||
|
||||
"ui.settings.title": "Settings",
|
||||
|
||||
"ui.canvas_menu_add_node": "Add Node",
|
||||
"ui.canvas_menu_add_group": "Add Group",
|
||||
|
||||
"ui.node_panel.header.properties": "Properties",
|
||||
"ui.node_panel.header.title": "Title",
|
||||
"ui.node_panel.header.mode": "Mode",
|
||||
"ui.node_panel.header.color": "Color",
|
||||
|
||||
"node.title.KSampler": "KSampler",
|
||||
"node.title.KSamplerAdvanced": "KSampler (Advanced)",
|
||||
// Loaders
|
||||
"node.title.CheckpointLoader": "Load Checkpoint (With Config)",
|
||||
"node.title.CheckpointLoaderSimple": "Load Checkpoint",
|
||||
"node.title.VAELoader": "Load VAE",
|
||||
"node.title.LoraLoader": "Load LoRA",
|
||||
"node.title.CLIPLoader": "Load CLIP",
|
||||
"node.title.ControlNetLoader": "Load ControlNet Model",
|
||||
"node.title.DiffControlNetLoader": "Load ControlNet Model (diff)",
|
||||
"node.title.StyleModelLoader": "Load Style Model",
|
||||
"node.title.CLIPVisionLoader": "Load CLIP Vision",
|
||||
"node.title.UpscaleModelLoader": "Load Upscale Model",
|
||||
// Conditioning
|
||||
"node.title.CLIPVisionEncode": "CLIP Vision Encode",
|
||||
"node.title.StyleModelApply": "Apply Style Model",
|
||||
"node.title.CLIPTextEncode": "CLIP Text Encode (Prompt)",
|
||||
"node.title.CLIPSetLastLayer": "CLIP Set Last Layer",
|
||||
"node.title.ConditioningCombine": "Conditioning (Combine)",
|
||||
"node.title.ConditioningAverage ": "Conditioning (Average)",
|
||||
"node.title.ConditioningConcat": "Conditioning (Concat)",
|
||||
"node.title.ConditioningSetArea": "Conditioning (Set Area)",
|
||||
"node.title.ConditioningSetMask": "Conditioning (Set Mask)",
|
||||
"node.title.ControlNetApply": "Apply ControlNet",
|
||||
"node.title.ControlNetApplyAdvanced": "Apply ControlNet (Advanced)",
|
||||
// Latent
|
||||
"node.title.VAEEncodeForInpaint": "VAE Encode (for Inpainting)",
|
||||
"node.title.SetLatentNoiseMask": "Set Latent Noise Mask",
|
||||
"node.title.VAEDecode": "VAE Decode",
|
||||
"node.title.VAEEncode": "VAE Encode",
|
||||
"node.title.LatentRotate": "Rotate Latent",
|
||||
"node.title.LatentFlip": "Flip Latent",
|
||||
"node.title.LatentCrop": "Crop Latent",
|
||||
"node.title.EmptyLatentImage": "Empty Latent Image",
|
||||
"node.title.LatentUpscale": "Upscale Latent",
|
||||
"node.title.LatentUpscaleBy": "Upscale Latent By",
|
||||
"node.title.LatentComposite": "Latent Composite",
|
||||
"node.title.LatentBlend": "Latent Blend",
|
||||
"LatentFromBatch": "Latent From Batch",
|
||||
"node.title.RepeatLatentBatch": "Repeat Latent Batch",
|
||||
// Image
|
||||
"node.title.SaveImage": "Save Image",
|
||||
"node.title.PreviewImage": "Preview Image",
|
||||
"node.title.LoadImage": "Load Image",
|
||||
"node.title.LoadImageMask": "Load Image (as Mask)",
|
||||
"node.title.ImageScale": "Upscale Image",
|
||||
"node.title.ImageScaleBy": "Upscale Image By",
|
||||
"node.title.ImageUpscaleWithModel": "Upscale Image (using Model)",
|
||||
"node.title.ImageInvert": "Invert Image",
|
||||
"node.title.ImagePadForOutpaint": "Pad Image for Outpainting",
|
||||
// _for_testing
|
||||
"node.title.VAEDecodeTiled": "VAE Decode (Tiled)",
|
||||
"node.title.VAEEncodeTiled": "VAE Encode (Tiled)",
|
||||
|
||||
"node.input.SaveImage.filename_prefix": "filename_prefix",
|
||||
"node.input.SaveImage.images": "images",
|
||||
|
||||
"node.output.CheckpointLoaderSimple.MODEL": "MODEL",
|
||||
|
||||
"category.conditioning": "conditioning",
|
||||
"category.loaders": "loaders",
|
||||
"category.latent": "latent",
|
||||
"category.latent/inpaint": "latent/inpaint",
|
||||
"category.latent/batch": "latent/batch",
|
||||
"category.image": "image",
|
||||
"category.mask": "mask",
|
||||
"category.image/upscaling": "image/upscaling",
|
||||
"category.sampling": "sampling",
|
||||
"category._for_testing": "_for_testing",
|
||||
"category.latent/transform": "latent/transform",
|
||||
"category.advanced/loaders": "advanced/loaders",
|
||||
"category.conditioning/style_model": "conditioning/style_model",
|
||||
"category.conditioning/gligen": "conditioning/gligen",
|
||||
"category.advanced/loaders/deprecated": "advanced/loaders/deprecated",
|
||||
"category.advanced/conditioning": "advanced/conditioning",
|
||||
"category.image/postprocessing": "image/postprocessing",
|
||||
"category.advanced/model_merging": "advanced/model_merging",
|
||||
"category.image/preprocessors": "image/preprocessors",
|
||||
"category.utils": "utils",
|
||||
|
||||
"settings.Comfy.ConfirmClear": "Require confirmation when clearing workflow",
|
||||
"settings.Comfy.PromptFilename": "Prompt for filename when saving workflow",
|
||||
"settings.Comfy.PreviewFormat": "When displaying a preview in the image widget, convert it to a lightweight image, e.g. webp, jpeg, webp;50, etc.",
|
||||
"settings.Comfy.DisableSliders": "Disable sliders.",
|
||||
"settings.Comfy.DevMode": "Enable Dev mode Options",
|
||||
"settings.Comfy.ColorPalette": "Color Palette",
|
||||
"settings.Comfy.EditAttention.Delta": "Ctrl+up/down precision",
|
||||
"settings.Comfy.InvertMenuScrolling": "Invert Menu Scrolling",
|
||||
"settings.Comfy.LinkRenderMode": "Link Render Mode",
|
||||
"settings.Comfy.NodeSuggestions.number": "Number of nodes suggestions",
|
||||
"settings.Comfy.SnapToGrid.GridSize": "Grid Size",
|
||||
"settings.Comfy.Logging.Enabled": "Comfy.Logging.Enabled",
|
||||
"settings.Comfy.MenuPosition": "Save menu position",
|
||||
"settings.Comfy.ColorPalette.export": "Export",
|
||||
"settings.Comfy.ColorPalette.import": "Import",
|
||||
"settings.Comfy.ColorPalette.template": "Template",
|
||||
"settings.Comfy.ColorPalette.delete": "Delete",
|
||||
}
|
||||
}
|
||||
125
web/i18n/zh_CN.js
Normal file
125
web/i18n/zh_CN.js
Normal file
@ -0,0 +1,125 @@
|
||||
export default {
|
||||
translation: {
|
||||
"ui.queue_btn": "冲冲冲",
|
||||
"ui.queue_front_btn": "插队冲冲冲",
|
||||
"ui.view_queue_btn": "查看队列",
|
||||
"ui.view_history_btn": "查看历史",
|
||||
"ui.save_btn": "保存",
|
||||
"ui.load_btn": "加载",
|
||||
"ui.refresh_btn": "刷新",
|
||||
"ui.clipspace_btn": "Clipspace",
|
||||
"ui.clear_btn": "清空",
|
||||
"ui.load_default_btn": "加载默认配置",
|
||||
"ui.close_btn": "关闭",
|
||||
"ui.queue_size": "队列数量: ",
|
||||
"ui.extra_options": "额外选项",
|
||||
|
||||
"ui.settings.title": "设置",
|
||||
|
||||
"ui.canvas_menu_add_node": "添加节点",
|
||||
"ui.canvas_menu_add_group": "添加组",
|
||||
|
||||
"ui.node_panel.header.properties": "属性",
|
||||
"ui.node_panel.header.title": "标题",
|
||||
"ui.node_panel.header.mode": "模式",
|
||||
"ui.node_panel.header.color": "颜色",
|
||||
|
||||
"node.title.KSampler": "采样器",
|
||||
"node.title.KSamplerAdvanced": "采样器 (高级)",
|
||||
// Loaders
|
||||
"node.title.CheckpointLoader": "Load Checkpoint (With Config)",
|
||||
"node.title.CheckpointLoaderSimple": "加载模型",
|
||||
"node.title.VAELoader": "Load VAE",
|
||||
"node.title.LoraLoader": "Load LoRA",
|
||||
"node.title.CLIPLoader": "Load CLIP",
|
||||
"node.title.ControlNetLoader": "Load ControlNet Model",
|
||||
"node.title.DiffControlNetLoader": "Load ControlNet Model (diff)",
|
||||
"node.title.StyleModelLoader": "Load Style Model",
|
||||
"node.title.CLIPVisionLoader": "Load CLIP Vision",
|
||||
"node.title.UpscaleModelLoader": "Load Upscale Model",
|
||||
// Conditioning
|
||||
"node.title.CLIPVisionEncode": "CLIP Vision Encode",
|
||||
"node.title.StyleModelApply": "Apply Style Model",
|
||||
"node.title.CLIPTextEncode": "CLIP Text Encode (Prompt)",
|
||||
"node.title.CLIPSetLastLayer": "CLIP Set Last Layer",
|
||||
"node.title.ConditioningCombine": "Conditioning (Combine)",
|
||||
"node.title.ConditioningAverage ": "Conditioning (Average)",
|
||||
"node.title.ConditioningConcat": "Conditioning (Concat)",
|
||||
"node.title.ConditioningSetArea": "Conditioning (Set Area)",
|
||||
"node.title.ConditioningSetMask": "Conditioning (Set Mask)",
|
||||
"node.title.ControlNetApply": "Apply ControlNet",
|
||||
"node.title.ControlNetApplyAdvanced": "Apply ControlNet (Advanced)",
|
||||
// Latent
|
||||
"node.title.VAEEncodeForInpaint": "VAE Encode (for Inpainting)",
|
||||
"node.title.SetLatentNoiseMask": "Set Latent Noise Mask",
|
||||
"node.title.VAEDecode": "VAE Decode",
|
||||
"node.title.VAEEncode": "VAE Encode",
|
||||
"node.title.LatentRotate": "Rotate Latent",
|
||||
"node.title.LatentFlip": "Flip Latent",
|
||||
"node.title.LatentCrop": "Crop Latent",
|
||||
"node.title.EmptyLatentImage": "Empty Latent Image",
|
||||
"node.title.LatentUpscale": "Upscale Latent",
|
||||
"node.title.LatentUpscaleBy": "Upscale Latent By",
|
||||
"node.title.LatentComposite": "Latent Composite",
|
||||
"node.title.LatentBlend": "Latent Blend",
|
||||
"LatentFromBatch": "Latent From Batch",
|
||||
"node.title.RepeatLatentBatch": "Repeat Latent Batch",
|
||||
// Image
|
||||
"node.title.SaveImage": "Save Image",
|
||||
"node.title.PreviewImage": "Preview Image",
|
||||
"node.title.LoadImage": "Load Image",
|
||||
"node.title.LoadImageMask": "Load Image (as Mask)",
|
||||
"node.title.ImageScale": "Upscale Image",
|
||||
"node.title.ImageScaleBy": "Upscale Image By",
|
||||
"node.title.ImageUpscaleWithModel": "Upscale Image (using Model)",
|
||||
"node.title.ImageInvert": "Invert Image",
|
||||
"node.title.ImagePadForOutpaint": "Pad Image for Outpainting",
|
||||
// _for_testing
|
||||
"node.title.VAEDecodeTiled": "VAE Decode (Tiled)",
|
||||
"node.title.VAEEncodeTiled": "VAE Encode (Tiled)",
|
||||
|
||||
"node.input.SaveImage.filename_prefix": "文件名前缀",
|
||||
"node.input.SaveImage.images": "图片",
|
||||
|
||||
"node.output.CheckpointLoaderSimple.MODEL": "模型",
|
||||
|
||||
"category.conditioning": "可调参数",
|
||||
"category.loaders": "加载器",
|
||||
"category.latent": "潜在",
|
||||
"category.latent/inpaint": "潜在/修复",
|
||||
"category.latent/batch": "潜在/批量",
|
||||
"category.image": "图像",
|
||||
"category.mask": "遮罩",
|
||||
"category.image/upscaling": "图像/外扩",
|
||||
"category.sampling": "采样",
|
||||
"category._for_testing": "测试",
|
||||
"category.latent/transform": "潜在/转换",
|
||||
"category.advanced/loaders": "高级/加载器",
|
||||
"category.conditioning/style_model": "可调参数/风格模型",
|
||||
"category.conditioning/gligen": "可调参数/gligen",
|
||||
"category.advanced/loaders/deprecated": "高级/加载器/已弃用",
|
||||
"category.advanced/conditioning": "高级/可调参数",
|
||||
"category.image/postprocessing": "图像/后期处理",
|
||||
"category.advanced/model_merging": "高级/模型合并",
|
||||
"category.image/preprocessors": "图像/前期处理",
|
||||
"category.utils": "工具",
|
||||
|
||||
"settings.Comfy.ConfirmClear": "清空工作流需要确认",
|
||||
"settings.Comfy.PromptFilename": "Prompt for filename when saving workflow",
|
||||
"settings.Comfy.PreviewFormat": "预览图格式和压缩尺寸, e.g. webp, jpeg, webp;50, etc.",
|
||||
"settings.Comfy.DisableSliders": "Disable sliders.",
|
||||
"settings.Comfy.DevMode": "启用开发模式",
|
||||
"settings.Comfy.ColorPalette": "主题",
|
||||
"settings.Comfy.EditAttention.Delta": "Ctrl+up/down precision",
|
||||
"settings.Comfy.InvertMenuScrolling": "反转滚动",
|
||||
"settings.Comfy.LinkRenderMode": "链接渲染模式",
|
||||
"settings.Comfy.NodeSuggestions.number": "Number of nodes suggestions",
|
||||
"settings.Comfy.SnapToGrid.GridSize": "单元格尺寸",
|
||||
"settings.Comfy.Logging.Enabled": "记录日志",
|
||||
"settings.Comfy.MenuPosition": "保存菜单位置",
|
||||
"settings.Comfy.ColorPalette.export": "导出",
|
||||
"settings.Comfy.ColorPalette.import": "导入",
|
||||
"settings.Comfy.ColorPalette.template": "模版",
|
||||
"settings.Comfy.ColorPalette.delete": "删除",
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<link rel="stylesheet" type="text/css" href="./lib/litegraph.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
<script type="text/javascript" src="./lib/i18next.js"></script>
|
||||
<script type="text/javascript" src="./lib/i18nextBrowserLanguageDetector.js"></script>
|
||||
<script type="text/javascript" src="./lib/litegraph.core.js"></script>
|
||||
<script type="text/javascript" src="./lib/litegraph.extensions.js" defer></script>
|
||||
<script type="module">
|
||||
|
||||
2265
web/lib/i18next.js
Normal file
2265
web/lib/i18next.js
Normal file
File diff suppressed because it is too large
Load Diff
422
web/lib/i18nextBrowserLanguageDetector.js
Normal file
422
web/lib/i18nextBrowserLanguageDetector.js
Normal file
@ -0,0 +1,422 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.i18nextBrowserLanguageDetector = factory());
|
||||
})(this, (function () { 'use strict';
|
||||
|
||||
function _classCallCheck(instance, Constructor) {
|
||||
if (!(instance instanceof Constructor)) {
|
||||
throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
}
|
||||
|
||||
function _typeof(obj) {
|
||||
"@babel/helpers - typeof";
|
||||
|
||||
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
||||
return typeof obj;
|
||||
} : function (obj) {
|
||||
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
||||
}, _typeof(obj);
|
||||
}
|
||||
|
||||
function _toPrimitive(input, hint) {
|
||||
if (_typeof(input) !== "object" || input === null) return input;
|
||||
var prim = input[Symbol.toPrimitive];
|
||||
if (prim !== undefined) {
|
||||
var res = prim.call(input, hint || "default");
|
||||
if (_typeof(res) !== "object") return res;
|
||||
throw new TypeError("@@toPrimitive must return a primitive value.");
|
||||
}
|
||||
return (hint === "string" ? String : Number)(input);
|
||||
}
|
||||
|
||||
function _toPropertyKey(arg) {
|
||||
var key = _toPrimitive(arg, "string");
|
||||
return _typeof(key) === "symbol" ? key : String(key);
|
||||
}
|
||||
|
||||
function _defineProperties(target, props) {
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var descriptor = props[i];
|
||||
descriptor.enumerable = descriptor.enumerable || false;
|
||||
descriptor.configurable = true;
|
||||
if ("value" in descriptor) descriptor.writable = true;
|
||||
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
|
||||
}
|
||||
}
|
||||
function _createClass(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||||
Object.defineProperty(Constructor, "prototype", {
|
||||
writable: false
|
||||
});
|
||||
return Constructor;
|
||||
}
|
||||
|
||||
var arr = [];
|
||||
var each = arr.forEach;
|
||||
var slice = arr.slice;
|
||||
function defaults(obj) {
|
||||
each.call(slice.call(arguments, 1), function (source) {
|
||||
if (source) {
|
||||
for (var prop in source) {
|
||||
if (obj[prop] === undefined) obj[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
|
||||
var serializeCookie = function serializeCookie(name, val, options) {
|
||||
var opt = options || {};
|
||||
opt.path = opt.path || '/';
|
||||
var value = encodeURIComponent(val);
|
||||
var str = "".concat(name, "=").concat(value);
|
||||
if (opt.maxAge > 0) {
|
||||
var maxAge = opt.maxAge - 0;
|
||||
if (Number.isNaN(maxAge)) throw new Error('maxAge should be a Number');
|
||||
str += "; Max-Age=".concat(Math.floor(maxAge));
|
||||
}
|
||||
if (opt.domain) {
|
||||
if (!fieldContentRegExp.test(opt.domain)) {
|
||||
throw new TypeError('option domain is invalid');
|
||||
}
|
||||
str += "; Domain=".concat(opt.domain);
|
||||
}
|
||||
if (opt.path) {
|
||||
if (!fieldContentRegExp.test(opt.path)) {
|
||||
throw new TypeError('option path is invalid');
|
||||
}
|
||||
str += "; Path=".concat(opt.path);
|
||||
}
|
||||
if (opt.expires) {
|
||||
if (typeof opt.expires.toUTCString !== 'function') {
|
||||
throw new TypeError('option expires is invalid');
|
||||
}
|
||||
str += "; Expires=".concat(opt.expires.toUTCString());
|
||||
}
|
||||
if (opt.httpOnly) str += '; HttpOnly';
|
||||
if (opt.secure) str += '; Secure';
|
||||
if (opt.sameSite) {
|
||||
var sameSite = typeof opt.sameSite === 'string' ? opt.sameSite.toLowerCase() : opt.sameSite;
|
||||
switch (sameSite) {
|
||||
case true:
|
||||
str += '; SameSite=Strict';
|
||||
break;
|
||||
case 'lax':
|
||||
str += '; SameSite=Lax';
|
||||
break;
|
||||
case 'strict':
|
||||
str += '; SameSite=Strict';
|
||||
break;
|
||||
case 'none':
|
||||
str += '; SameSite=None';
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('option sameSite is invalid');
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
var cookie = {
|
||||
create: function create(name, value, minutes, domain) {
|
||||
var cookieOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {
|
||||
path: '/',
|
||||
sameSite: 'strict'
|
||||
};
|
||||
if (minutes) {
|
||||
cookieOptions.expires = new Date();
|
||||
cookieOptions.expires.setTime(cookieOptions.expires.getTime() + minutes * 60 * 1000);
|
||||
}
|
||||
if (domain) cookieOptions.domain = domain;
|
||||
document.cookie = serializeCookie(name, encodeURIComponent(value), cookieOptions);
|
||||
},
|
||||
read: function read(name) {
|
||||
var nameEQ = "".concat(name, "=");
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1, c.length);
|
||||
}
|
||||
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
remove: function remove(name) {
|
||||
this.create(name, '', -1);
|
||||
}
|
||||
};
|
||||
var cookie$1 = {
|
||||
name: 'cookie',
|
||||
lookup: function lookup(options) {
|
||||
var found;
|
||||
if (options.lookupCookie && typeof document !== 'undefined') {
|
||||
var c = cookie.read(options.lookupCookie);
|
||||
if (c) found = c;
|
||||
}
|
||||
return found;
|
||||
},
|
||||
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
||||
if (options.lookupCookie && typeof document !== 'undefined') {
|
||||
cookie.create(options.lookupCookie, lng, options.cookieMinutes, options.cookieDomain, options.cookieOptions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var querystring = {
|
||||
name: 'querystring',
|
||||
lookup: function lookup(options) {
|
||||
var found;
|
||||
if (typeof window !== 'undefined') {
|
||||
var search = window.location.search;
|
||||
if (!window.location.search && window.location.hash && window.location.hash.indexOf('?') > -1) {
|
||||
search = window.location.hash.substring(window.location.hash.indexOf('?'));
|
||||
}
|
||||
var query = search.substring(1);
|
||||
var params = query.split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var pos = params[i].indexOf('=');
|
||||
if (pos > 0) {
|
||||
var key = params[i].substring(0, pos);
|
||||
if (key === options.lookupQuerystring) {
|
||||
found = params[i].substring(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
var hasLocalStorageSupport = null;
|
||||
var localStorageAvailable = function localStorageAvailable() {
|
||||
if (hasLocalStorageSupport !== null) return hasLocalStorageSupport;
|
||||
try {
|
||||
hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null;
|
||||
var testKey = 'i18next.translate.boo';
|
||||
window.localStorage.setItem(testKey, 'foo');
|
||||
window.localStorage.removeItem(testKey);
|
||||
} catch (e) {
|
||||
hasLocalStorageSupport = false;
|
||||
}
|
||||
return hasLocalStorageSupport;
|
||||
};
|
||||
var localStorage = {
|
||||
name: 'localStorage',
|
||||
lookup: function lookup(options) {
|
||||
var found;
|
||||
if (options.lookupLocalStorage && localStorageAvailable()) {
|
||||
var lng = window.localStorage.getItem(options.lookupLocalStorage);
|
||||
if (lng) found = lng;
|
||||
}
|
||||
return found;
|
||||
},
|
||||
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
||||
if (options.lookupLocalStorage && localStorageAvailable()) {
|
||||
window.localStorage.setItem(options.lookupLocalStorage, lng);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var hasSessionStorageSupport = null;
|
||||
var sessionStorageAvailable = function sessionStorageAvailable() {
|
||||
if (hasSessionStorageSupport !== null) return hasSessionStorageSupport;
|
||||
try {
|
||||
hasSessionStorageSupport = window !== 'undefined' && window.sessionStorage !== null;
|
||||
var testKey = 'i18next.translate.boo';
|
||||
window.sessionStorage.setItem(testKey, 'foo');
|
||||
window.sessionStorage.removeItem(testKey);
|
||||
} catch (e) {
|
||||
hasSessionStorageSupport = false;
|
||||
}
|
||||
return hasSessionStorageSupport;
|
||||
};
|
||||
var sessionStorage = {
|
||||
name: 'sessionStorage',
|
||||
lookup: function lookup(options) {
|
||||
var found;
|
||||
if (options.lookupSessionStorage && sessionStorageAvailable()) {
|
||||
var lng = window.sessionStorage.getItem(options.lookupSessionStorage);
|
||||
if (lng) found = lng;
|
||||
}
|
||||
return found;
|
||||
},
|
||||
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
||||
if (options.lookupSessionStorage && sessionStorageAvailable()) {
|
||||
window.sessionStorage.setItem(options.lookupSessionStorage, lng);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var navigator$1 = {
|
||||
name: 'navigator',
|
||||
lookup: function lookup(options) {
|
||||
var found = [];
|
||||
if (typeof navigator !== 'undefined') {
|
||||
if (navigator.languages) {
|
||||
// chrome only; not an array, so can't use .push.apply instead of iterating
|
||||
for (var i = 0; i < navigator.languages.length; i++) {
|
||||
found.push(navigator.languages[i]);
|
||||
}
|
||||
}
|
||||
if (navigator.userLanguage) {
|
||||
found.push(navigator.userLanguage);
|
||||
}
|
||||
if (navigator.language) {
|
||||
found.push(navigator.language);
|
||||
}
|
||||
}
|
||||
return found.length > 0 ? found : undefined;
|
||||
}
|
||||
};
|
||||
|
||||
var htmlTag = {
|
||||
name: 'htmlTag',
|
||||
lookup: function lookup(options) {
|
||||
var found;
|
||||
var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null);
|
||||
if (htmlTag && typeof htmlTag.getAttribute === 'function') {
|
||||
found = htmlTag.getAttribute('lang');
|
||||
}
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
var path = {
|
||||
name: 'path',
|
||||
lookup: function lookup(options) {
|
||||
var found;
|
||||
if (typeof window !== 'undefined') {
|
||||
var language = window.location.pathname.match(/\/([a-zA-Z-]*)/g);
|
||||
if (language instanceof Array) {
|
||||
if (typeof options.lookupFromPathIndex === 'number') {
|
||||
if (typeof language[options.lookupFromPathIndex] !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
found = language[options.lookupFromPathIndex].replace('/', '');
|
||||
} else {
|
||||
found = language[0].replace('/', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
var subdomain = {
|
||||
name: 'subdomain',
|
||||
lookup: function lookup(options) {
|
||||
// If given get the subdomain index else 1
|
||||
var lookupFromSubdomainIndex = typeof options.lookupFromSubdomainIndex === 'number' ? options.lookupFromSubdomainIndex + 1 : 1;
|
||||
// get all matches if window.location. is existing
|
||||
// first item of match is the match itself and the second is the first group macht which sould be the first subdomain match
|
||||
// is the hostname no public domain get the or option of localhost
|
||||
var language = typeof window !== 'undefined' && window.location && window.location.hostname && window.location.hostname.match(/^(\w{2,5})\.(([a-z0-9-]{1,63}\.[a-z]{2,6})|localhost)/i);
|
||||
|
||||
// if there is no match (null) return undefined
|
||||
if (!language) return undefined;
|
||||
// return the given group match
|
||||
return language[lookupFromSubdomainIndex];
|
||||
}
|
||||
};
|
||||
|
||||
function getDefaults() {
|
||||
return {
|
||||
order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'],
|
||||
lookupQuerystring: 'lng',
|
||||
lookupCookie: 'i18next',
|
||||
lookupLocalStorage: 'i18nextLng',
|
||||
lookupSessionStorage: 'i18nextLng',
|
||||
// cache user language
|
||||
caches: ['localStorage'],
|
||||
excludeCacheFor: ['cimode'],
|
||||
// cookieMinutes: 10,
|
||||
// cookieDomain: 'myDomain'
|
||||
|
||||
convertDetectedLanguage: function convertDetectedLanguage(l) {
|
||||
return l;
|
||||
}
|
||||
};
|
||||
}
|
||||
var Browser = /*#__PURE__*/function () {
|
||||
function Browser(services) {
|
||||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
_classCallCheck(this, Browser);
|
||||
this.type = 'languageDetector';
|
||||
this.detectors = {};
|
||||
this.init(services, options);
|
||||
}
|
||||
_createClass(Browser, [{
|
||||
key: "init",
|
||||
value: function init(services) {
|
||||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||||
this.services = services || {
|
||||
languageUtils: {}
|
||||
}; // this way the language detector can be used without i18next
|
||||
this.options = defaults(options, this.options || {}, getDefaults());
|
||||
if (typeof this.options.convertDetectedLanguage === 'string' && this.options.convertDetectedLanguage.indexOf('15897') > -1) {
|
||||
this.options.convertDetectedLanguage = function (l) {
|
||||
return l.replace('-', '_');
|
||||
};
|
||||
}
|
||||
|
||||
// backwards compatibility
|
||||
if (this.options.lookupFromUrlIndex) this.options.lookupFromPathIndex = this.options.lookupFromUrlIndex;
|
||||
this.i18nOptions = i18nOptions;
|
||||
this.addDetector(cookie$1);
|
||||
this.addDetector(querystring);
|
||||
this.addDetector(localStorage);
|
||||
this.addDetector(sessionStorage);
|
||||
this.addDetector(navigator$1);
|
||||
this.addDetector(htmlTag);
|
||||
this.addDetector(path);
|
||||
this.addDetector(subdomain);
|
||||
}
|
||||
}, {
|
||||
key: "addDetector",
|
||||
value: function addDetector(detector) {
|
||||
this.detectors[detector.name] = detector;
|
||||
}
|
||||
}, {
|
||||
key: "detect",
|
||||
value: function detect(detectionOrder) {
|
||||
var _this = this;
|
||||
if (!detectionOrder) detectionOrder = this.options.order;
|
||||
var detected = [];
|
||||
detectionOrder.forEach(function (detectorName) {
|
||||
if (_this.detectors[detectorName]) {
|
||||
var lookup = _this.detectors[detectorName].lookup(_this.options);
|
||||
if (lookup && typeof lookup === 'string') lookup = [lookup];
|
||||
if (lookup) detected = detected.concat(lookup);
|
||||
}
|
||||
});
|
||||
detected = detected.map(function (d) {
|
||||
return _this.options.convertDetectedLanguage(d);
|
||||
});
|
||||
if (this.services.languageUtils.getBestMatchFromCodes) return detected; // new i18next v19.5.0
|
||||
return detected.length > 0 ? detected[0] : null; // a little backward compatibility
|
||||
}
|
||||
}, {
|
||||
key: "cacheUserLanguage",
|
||||
value: function cacheUserLanguage(lng, caches) {
|
||||
var _this2 = this;
|
||||
if (!caches) caches = this.options.caches;
|
||||
if (!caches) return;
|
||||
if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return;
|
||||
caches.forEach(function (cacheName) {
|
||||
if (_this2.detectors[cacheName]) _this2.detectors[cacheName].cacheUserLanguage(lng, _this2.options);
|
||||
});
|
||||
}
|
||||
}]);
|
||||
return Browser;
|
||||
}();
|
||||
Browser.type = 'languageDetector';
|
||||
|
||||
return Browser;
|
||||
|
||||
}));
|
||||
@ -12522,7 +12522,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
panel.content.innerHTML = ""; //clear
|
||||
panel.addHTML("<span class='node_type'>"+node.type+"</span><span class='node_desc'>"+(node.constructor.desc || "")+"</span><span class='separator'></span>");
|
||||
|
||||
panel.addHTML("<h3>Properties</h3>");
|
||||
panel.addHTML(`<h3>${i18next.t("ui.node_panel.header.properties")}</h3>`);
|
||||
|
||||
var fUpdate = function(name,value){
|
||||
graphcanvas.graph.beforeChange(node);
|
||||
@ -12554,16 +12554,16 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
graphcanvas.dirty_canvas = true;
|
||||
};
|
||||
|
||||
panel.addWidget( "string", "Title", node.title, {}, fUpdate);
|
||||
panel.addWidget( "string", i18next.t("ui.node_panel.header.title"), node.title, {}, fUpdate);
|
||||
|
||||
panel.addWidget( "combo", "Mode", LiteGraph.NODE_MODES[node.mode], {values: LiteGraph.NODE_MODES}, fUpdate);
|
||||
panel.addWidget( "combo", i18next.t("ui.node_panel.header.mode"), LiteGraph.NODE_MODES[node.mode], {values: LiteGraph.NODE_MODES}, fUpdate);
|
||||
|
||||
var nodeCol = "";
|
||||
if (node.color !== undefined){
|
||||
nodeCol = Object.keys(LGraphCanvas.node_colors).filter(function(nK){ return LGraphCanvas.node_colors[nK].color == node.color; });
|
||||
}
|
||||
|
||||
panel.addWidget( "combo", "Color", nodeCol, {values: Object.keys(LGraphCanvas.node_colors)}, fUpdate);
|
||||
panel.addWidget( "combo", i18next.t("ui.node_panel.header.color"), nodeCol, {values: Object.keys(LGraphCanvas.node_colors)}, fUpdate);
|
||||
|
||||
for(var pName in node.properties)
|
||||
{
|
||||
|
||||
@ -5,6 +5,19 @@ import { api } from "./api.js";
|
||||
import { defaultGraph } from "./defaultGraph.js";
|
||||
import { getPngMetadata, importA1111, getLatentMetadata } from "./pnginfo.js";
|
||||
|
||||
import en from "../i18n/en_US.js"
|
||||
import cn from "../i18n/zh_CN.js"
|
||||
|
||||
i18next.use(i18nextBrowserLanguageDetector).init({
|
||||
fallbackLng: 'en',
|
||||
resources: {
|
||||
"en-US": en,
|
||||
"en": en,
|
||||
"zh_CN": cn,
|
||||
"cn": cn,
|
||||
},
|
||||
})
|
||||
|
||||
/**
|
||||
* @typedef {import("types/comfy").ComfyExtension} ComfyExtension
|
||||
*/
|
||||
@ -61,7 +74,7 @@ export class ComfyApp {
|
||||
|
||||
getPreviewFormatParam() {
|
||||
let preview_format = this.ui.settings.getSettingValue("Comfy.PreviewFormat");
|
||||
if(preview_format)
|
||||
if (preview_format)
|
||||
return `&preview=${preview_format}`;
|
||||
else
|
||||
return "";
|
||||
@ -72,7 +85,7 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
static onClipspaceEditorSave() {
|
||||
if(ComfyApp.clipspace_return_node) {
|
||||
if (ComfyApp.clipspace_return_node) {
|
||||
ComfyApp.pasteFromClipspace(ComfyApp.clipspace_return_node);
|
||||
}
|
||||
}
|
||||
@ -83,13 +96,13 @@ export class ComfyApp {
|
||||
|
||||
static copyToClipspace(node) {
|
||||
var widgets = null;
|
||||
if(node.widgets) {
|
||||
if (node.widgets) {
|
||||
widgets = node.widgets.map(({ type, name, value }) => ({ type, name, value }));
|
||||
}
|
||||
|
||||
var imgs = undefined;
|
||||
var orig_imgs = undefined;
|
||||
if(node.imgs != undefined) {
|
||||
if (node.imgs != undefined) {
|
||||
imgs = [];
|
||||
orig_imgs = [];
|
||||
|
||||
@ -101,7 +114,7 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
var selectedIndex = 0;
|
||||
if(node.imageIndex) {
|
||||
if (node.imageIndex) {
|
||||
selectedIndex = node.imageIndex;
|
||||
}
|
||||
|
||||
@ -116,30 +129,30 @@ export class ComfyApp {
|
||||
|
||||
ComfyApp.clipspace_return_node = null;
|
||||
|
||||
if(ComfyApp.clipspace_invalidate_handler) {
|
||||
if (ComfyApp.clipspace_invalidate_handler) {
|
||||
ComfyApp.clipspace_invalidate_handler();
|
||||
}
|
||||
}
|
||||
|
||||
static pasteFromClipspace(node) {
|
||||
if(ComfyApp.clipspace) {
|
||||
if (ComfyApp.clipspace) {
|
||||
// image paste
|
||||
if(ComfyApp.clipspace.imgs && node.imgs) {
|
||||
if(node.images && ComfyApp.clipspace.images) {
|
||||
if(ComfyApp.clipspace['img_paste_mode'] == 'selected') {
|
||||
if (ComfyApp.clipspace.imgs && node.imgs) {
|
||||
if (node.images && ComfyApp.clipspace.images) {
|
||||
if (ComfyApp.clipspace['img_paste_mode'] == 'selected') {
|
||||
node.images = [ComfyApp.clipspace.images[ComfyApp.clipspace['selectedIndex']]];
|
||||
}
|
||||
else {
|
||||
node.images = ComfyApp.clipspace.images;
|
||||
}
|
||||
|
||||
if(app.nodeOutputs[node.id + ""])
|
||||
if (app.nodeOutputs[node.id + ""])
|
||||
app.nodeOutputs[node.id + ""].images = node.images;
|
||||
}
|
||||
|
||||
if(ComfyApp.clipspace.imgs) {
|
||||
if (ComfyApp.clipspace.imgs) {
|
||||
// deep-copy to cut link with clipspace
|
||||
if(ComfyApp.clipspace['img_paste_mode'] == 'selected') {
|
||||
if (ComfyApp.clipspace['img_paste_mode'] == 'selected') {
|
||||
const img = new Image();
|
||||
img.src = ComfyApp.clipspace.imgs[ComfyApp.clipspace['selectedIndex']].src;
|
||||
node.imgs = [img];
|
||||
@ -147,7 +160,7 @@ export class ComfyApp {
|
||||
}
|
||||
else {
|
||||
const imgs = [];
|
||||
for(let i=0; i<ComfyApp.clipspace.imgs.length; i++) {
|
||||
for (let i = 0; i < ComfyApp.clipspace.imgs.length; i++) {
|
||||
imgs[i] = new Image();
|
||||
imgs[i].src = ComfyApp.clipspace.imgs[i].src;
|
||||
node.imgs = imgs;
|
||||
@ -156,25 +169,25 @@ export class ComfyApp {
|
||||
}
|
||||
}
|
||||
|
||||
if(node.widgets) {
|
||||
if(ComfyApp.clipspace.images) {
|
||||
if (node.widgets) {
|
||||
if (ComfyApp.clipspace.images) {
|
||||
const clip_image = ComfyApp.clipspace.images[ComfyApp.clipspace['selectedIndex']];
|
||||
const index = node.widgets.findIndex(obj => obj.name === 'image');
|
||||
if(index >= 0) {
|
||||
if(node.widgets[index].type != 'image' && typeof node.widgets[index].value == "string" && clip_image.filename) {
|
||||
node.widgets[index].value = (clip_image.subfolder?clip_image.subfolder+'/':'') + clip_image.filename + (clip_image.type?` [${clip_image.type}]`:'');
|
||||
if (index >= 0) {
|
||||
if (node.widgets[index].type != 'image' && typeof node.widgets[index].value == "string" && clip_image.filename) {
|
||||
node.widgets[index].value = (clip_image.subfolder ? clip_image.subfolder + '/' : '') + clip_image.filename + (clip_image.type ? ` [${clip_image.type}]` : '');
|
||||
}
|
||||
else {
|
||||
node.widgets[index].value = clip_image;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ComfyApp.clipspace.widgets) {
|
||||
if (ComfyApp.clipspace.widgets) {
|
||||
ComfyApp.clipspace.widgets.forEach(({ type, name, value }) => {
|
||||
const prop = Object.values(node.widgets).find(obj => obj.type === type && obj.name === name);
|
||||
if (prop && prop.type != 'button') {
|
||||
if(prop.type != 'image' && typeof prop.value == "string" && value.filename) {
|
||||
prop.value = (value.subfolder?value.subfolder+'/':'') + value.filename + (value.type?` [${value.type}]`:'');
|
||||
if (prop.type != 'image' && typeof prop.value == "string" && value.filename) {
|
||||
prop.value = (value.subfolder ? value.subfolder + '/' : '') + value.filename + (value.type ? ` [${value.type}]` : '');
|
||||
}
|
||||
else {
|
||||
prop.value = value;
|
||||
@ -285,28 +298,28 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
// prevent conflict of clipspace content
|
||||
if(!ComfyApp.clipspace_return_node) {
|
||||
if (!ComfyApp.clipspace_return_node) {
|
||||
options.push({
|
||||
content: "Copy (Clipspace)",
|
||||
callback: (obj) => { ComfyApp.copyToClipspace(this); }
|
||||
});
|
||||
content: "Copy (Clipspace)",
|
||||
callback: (obj) => { ComfyApp.copyToClipspace(this); }
|
||||
});
|
||||
|
||||
if(ComfyApp.clipspace != null) {
|
||||
if (ComfyApp.clipspace != null) {
|
||||
options.push({
|
||||
content: "Paste (Clipspace)",
|
||||
callback: () => { ComfyApp.pasteFromClipspace(this); }
|
||||
});
|
||||
content: "Paste (Clipspace)",
|
||||
callback: () => { ComfyApp.pasteFromClipspace(this); }
|
||||
});
|
||||
}
|
||||
|
||||
if(ComfyApp.isImageNode(this)) {
|
||||
if (ComfyApp.isImageNode(this)) {
|
||||
options.push({
|
||||
content: "Open in MaskEditor",
|
||||
callback: (obj) => {
|
||||
ComfyApp.copyToClipspace(this);
|
||||
ComfyApp.clipspace_return_node = this;
|
||||
ComfyApp.open_maskeditor();
|
||||
}
|
||||
});
|
||||
content: "Open in MaskEditor",
|
||||
callback: (obj) => {
|
||||
ComfyApp.copyToClipspace(this);
|
||||
ComfyApp.clipspace_return_node = this;
|
||||
ComfyApp.open_maskeditor();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -316,7 +329,7 @@ export class ComfyApp {
|
||||
const app = this;
|
||||
const origNodeOnKeyDown = node.prototype.onKeyDown;
|
||||
|
||||
node.prototype.onKeyDown = function(e) {
|
||||
node.prototype.onKeyDown = function (e) {
|
||||
if (origNodeOnKeyDown && origNodeOnKeyDown.apply(this, e) === false) {
|
||||
return false;
|
||||
}
|
||||
@ -371,7 +384,7 @@ export class ComfyApp {
|
||||
if (w.computeSize) {
|
||||
shiftY += w.computeSize()[1] + 4;
|
||||
}
|
||||
else if(w.computedHeight) {
|
||||
else if (w.computedHeight) {
|
||||
shiftY += w.computedHeight;
|
||||
}
|
||||
else {
|
||||
@ -616,7 +629,7 @@ export class ComfyApp {
|
||||
}
|
||||
// Dragging from Chrome->Firefox there is a file but its a bmp, so ignore that
|
||||
if (event.dataTransfer.files.length && event.dataTransfer.files[0].type !== "image/bmp") {
|
||||
await this.handleFile(event.dataTransfer.files[0]);
|
||||
await this.handleFile(event.dataTransfer.files[0]);
|
||||
} else {
|
||||
// Try loading the first URI in the transfer list
|
||||
const validTypes = ["text/uri-list", "text/x-moz-url"];
|
||||
@ -676,7 +689,7 @@ export class ComfyApp {
|
||||
data = data.slice(data.indexOf("workflow\n"));
|
||||
data = data.slice(data.indexOf("{"));
|
||||
workflow = JSON.parse(data);
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
if (workflow && workflow.version && workflow.nodes && workflow.extra) {
|
||||
@ -694,7 +707,7 @@ export class ComfyApp {
|
||||
const self = this;
|
||||
|
||||
const origProcessMouseDown = LGraphCanvas.prototype.processMouseDown;
|
||||
LGraphCanvas.prototype.processMouseDown = function(e) {
|
||||
LGraphCanvas.prototype.processMouseDown = function (e) {
|
||||
const res = origProcessMouseDown.apply(this, arguments);
|
||||
|
||||
this.selected_group_moving = false;
|
||||
@ -714,7 +727,7 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
const origProcessMouseMove = LGraphCanvas.prototype.processMouseMove;
|
||||
LGraphCanvas.prototype.processMouseMove = function(e) {
|
||||
LGraphCanvas.prototype.processMouseMove = function (e) {
|
||||
const orig_selected_group = this.selected_group;
|
||||
|
||||
if (this.selected_group && !this.selected_group_resizing && !this.selected_group_moving) {
|
||||
@ -739,7 +752,7 @@ export class ComfyApp {
|
||||
#addProcessKeyHandler() {
|
||||
const self = this;
|
||||
const origProcessKey = LGraphCanvas.prototype.processKey;
|
||||
LGraphCanvas.prototype.processKey = function(e) {
|
||||
LGraphCanvas.prototype.processKey = function (e) {
|
||||
const res = origProcessKey.apply(this, arguments);
|
||||
|
||||
if (res === false) {
|
||||
@ -804,7 +817,7 @@ export class ComfyApp {
|
||||
const self = this;
|
||||
|
||||
const origDrawGroups = LGraphCanvas.prototype.drawGroups;
|
||||
LGraphCanvas.prototype.drawGroups = function(canvas, ctx) {
|
||||
LGraphCanvas.prototype.drawGroups = function (canvas, ctx) {
|
||||
if (!this.graph) {
|
||||
return;
|
||||
}
|
||||
@ -891,7 +904,7 @@ export class ComfyApp {
|
||||
12 + size[0] + 1,
|
||||
12 + size[1] + LiteGraph.NODE_TITLE_HEIGHT,
|
||||
[this.round_radius * 2, this.round_radius * 2, 2, 2]
|
||||
);
|
||||
);
|
||||
else if (shape == LiteGraph.CIRCLE_SHAPE)
|
||||
ctx.arc(size[0] * 0.5, size[1] * 0.5, size[0] * 0.5 + 6, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = color;
|
||||
@ -1117,9 +1130,10 @@ export class ComfyApp {
|
||||
const defs = await api.getNodeDefs();
|
||||
await this.registerNodesFromDefs(defs);
|
||||
await this.#invokeExtensionsAsync("registerCustomNodes");
|
||||
await this.#invokeExtensionsAsync("afterNodesRegistrations")
|
||||
}
|
||||
|
||||
async registerNodesFromDefs(defs) {
|
||||
async registerNodesFromDefs(defs) {
|
||||
await this.#invokeExtensionsAsync("addCustomNodeDefs", defs);
|
||||
|
||||
// Generate list of known widgets
|
||||
@ -1135,15 +1149,15 @@ export class ComfyApp {
|
||||
const node = Object.assign(
|
||||
function ComfyNode() {
|
||||
var inputs = nodeData["input"]["required"];
|
||||
if (nodeData["input"]["optional"] != undefined){
|
||||
inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"])
|
||||
if (nodeData["input"]["optional"] != undefined) {
|
||||
inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"])
|
||||
}
|
||||
const config = { minWidth: 1, minHeight: 1 };
|
||||
for (const inputName in inputs) {
|
||||
const inputData = inputs[inputName];
|
||||
const type = inputData[0];
|
||||
|
||||
if(inputData[1]?.forceInput) {
|
||||
if (inputData[1]?.forceInput) {
|
||||
this.addInput(inputName, type);
|
||||
} else {
|
||||
if (Array.isArray(type)) {
|
||||
@ -1165,7 +1179,7 @@ export class ComfyApp {
|
||||
for (const o in nodeData["output"]) {
|
||||
const output = nodeData["output"][o];
|
||||
const outputName = nodeData["output_name"][o] || output;
|
||||
const outputShape = nodeData["output_is_list"][o] ? LiteGraph.GRID_SHAPE : LiteGraph.CIRCLE_SHAPE ;
|
||||
const outputShape = nodeData["output_is_list"][o] ? LiteGraph.GRID_SHAPE : LiteGraph.CIRCLE_SHAPE;
|
||||
this.addOutput(outputName, output, { shape: outputShape });
|
||||
}
|
||||
|
||||
@ -1430,9 +1444,9 @@ export class ComfyApp {
|
||||
else if (error.response) {
|
||||
let message = error.response.error.message;
|
||||
if (error.response.error.details)
|
||||
message += ": " + error.response.error.details;
|
||||
message += ": " + error.response.error.details;
|
||||
for (const [nodeID, nodeError] of Object.entries(error.response.node_errors)) {
|
||||
message += "\n" + nodeError.class_type + ":"
|
||||
message += "\n" + nodeError.class_type + ":"
|
||||
for (const errorReason of nodeError.errors) {
|
||||
message += "\n - " + errorReason.message + ": " + errorReason.details
|
||||
}
|
||||
@ -1558,22 +1572,22 @@ export class ComfyApp {
|
||||
async refreshComboInNodes() {
|
||||
const defs = await api.getNodeDefs();
|
||||
|
||||
for(let nodeNum in this.graph._nodes) {
|
||||
for (let nodeNum in this.graph._nodes) {
|
||||
const node = this.graph._nodes[nodeNum];
|
||||
|
||||
const def = defs[node.type];
|
||||
|
||||
// HOTFIX: The current patch is designed to prevent the rest of the code from breaking due to primitive nodes,
|
||||
// and additional work is needed to consider the primitive logic in the refresh logic.
|
||||
if(!def)
|
||||
if (!def)
|
||||
continue;
|
||||
|
||||
for(const widgetNum in node.widgets) {
|
||||
for (const widgetNum in node.widgets) {
|
||||
const widget = node.widgets[widgetNum]
|
||||
if(widget.type == "combo" && def["input"]["required"][widget.name] !== undefined) {
|
||||
if (widget.type == "combo" && def["input"]["required"][widget.name] !== undefined) {
|
||||
widget.options.values = def["input"]["required"][widget.name][0];
|
||||
|
||||
if(widget.name != 'image' && !widget.options.values.includes(widget.value)) {
|
||||
if (widget.name != 'image' && !widget.options.values.includes(widget.value)) {
|
||||
widget.value = widget.options.values[0];
|
||||
widget.callback(widget.value);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {api} from "./api.js";
|
||||
import { api } from "./api.js";
|
||||
|
||||
export function $el(tag, propsOrChildren, children) {
|
||||
const split = tag.split(".");
|
||||
@ -11,7 +11,7 @@ export function $el(tag, propsOrChildren, children) {
|
||||
if (Array.isArray(propsOrChildren)) {
|
||||
element.append(...propsOrChildren);
|
||||
} else {
|
||||
const {parent, $: cb, dataset, style} = propsOrChildren;
|
||||
const { parent, $: cb, dataset, style } = propsOrChildren;
|
||||
delete propsOrChildren.parent;
|
||||
delete propsOrChildren.$;
|
||||
delete propsOrChildren.dataset;
|
||||
@ -178,7 +178,7 @@ export class ComfyDialog {
|
||||
return [
|
||||
$el("button", {
|
||||
type: "button",
|
||||
textContent: "Close",
|
||||
textContent: i18next.t("ui.close_btn"),
|
||||
onclick: () => this.close(),
|
||||
}),
|
||||
];
|
||||
@ -206,11 +206,11 @@ class ComfySettingsDialog extends ComfyDialog {
|
||||
parent: document.body,
|
||||
}, [
|
||||
$el("table.comfy-modal-content.comfy-table", [
|
||||
$el("caption", {textContent: "Settings"}),
|
||||
$el("tbody", {$: (tbody) => (this.textElement = tbody)}),
|
||||
$el("caption", { textContent: i18next.t("ui.settings.title") }),
|
||||
$el("tbody", { $: (tbody) => (this.textElement = tbody) }),
|
||||
$el("button", {
|
||||
type: "button",
|
||||
textContent: "Close",
|
||||
textContent: i18next.t("ui.close_btn"),
|
||||
style: {
|
||||
cursor: "pointer",
|
||||
},
|
||||
@ -234,7 +234,7 @@ class ComfySettingsDialog extends ComfyDialog {
|
||||
localStorage[settingId] = JSON.stringify(value);
|
||||
}
|
||||
|
||||
addSetting({id, name, type, defaultValue, onChange, attrs = {}, tooltip = "", options = undefined}) {
|
||||
addSetting({ id, name, type, defaultValue, onChange, attrs = {}, tooltip = "", options = undefined }) {
|
||||
if (!id) {
|
||||
throw new Error("Settings must have an ID");
|
||||
}
|
||||
@ -270,7 +270,7 @@ class ComfySettingsDialog extends ComfyDialog {
|
||||
$el("label", {
|
||||
for: htmlID,
|
||||
classList: [tooltip !== "" ? "comfy-tooltip-indicator" : ""],
|
||||
textContent: name,
|
||||
textContent: i18next.t(`settings.${id}`),
|
||||
})
|
||||
]);
|
||||
|
||||
@ -337,7 +337,7 @@ class ComfySettingsDialog extends ComfyDialog {
|
||||
value,
|
||||
id: htmlID,
|
||||
type: "number",
|
||||
style: {maxWidth: "4rem"},
|
||||
style: { maxWidth: "4rem" },
|
||||
oninput: (e) => {
|
||||
setter(e.target.value);
|
||||
e.target.previousElementSibling.value = e.target.value;
|
||||
@ -417,10 +417,10 @@ class ComfySettingsDialog extends ComfyDialog {
|
||||
show() {
|
||||
this.textElement.replaceChildren(
|
||||
$el("tr", {
|
||||
style: {display: "none"},
|
||||
style: { display: "none" },
|
||||
}, [
|
||||
$el("th"),
|
||||
$el("th", {style: {width: "33%"}})
|
||||
$el("th", { style: { width: "33%" } })
|
||||
]),
|
||||
...this.settings.map((s) => s.render()),
|
||||
)
|
||||
@ -457,7 +457,7 @@ class ComfyList {
|
||||
name: "Delete",
|
||||
cb: () => api.deleteItem(this.#type, item.prompt[1]),
|
||||
};
|
||||
return $el("div", {textContent: item.prompt[0] + ": "}, [
|
||||
return $el("div", { textContent: item.prompt[0] + ": " }, [
|
||||
$el("button", {
|
||||
textContent: "Load",
|
||||
onclick: () => {
|
||||
@ -486,7 +486,7 @@ class ComfyList {
|
||||
await this.load();
|
||||
},
|
||||
}),
|
||||
$el("button", {textContent: "Refresh", onclick: () => this.load()}),
|
||||
$el("button", { textContent: "Refresh", onclick: () => this.load() }),
|
||||
])
|
||||
);
|
||||
}
|
||||
@ -579,14 +579,14 @@ export class ComfyUI {
|
||||
id: "comfy-file-input",
|
||||
type: "file",
|
||||
accept: ".json,image/png,.latent,.safetensors",
|
||||
style: {display: "none"},
|
||||
style: { display: "none" },
|
||||
parent: document.body,
|
||||
onchange: () => {
|
||||
app.handleFile(fileInput.files[0]);
|
||||
},
|
||||
});
|
||||
|
||||
this.menuContainer = $el("div.comfy-menu", {parent: document.body}, [
|
||||
this.menuContainer = $el("div.comfy-menu", { parent: document.body }, [
|
||||
$el("div.drag-handle", {
|
||||
style: {
|
||||
overflow: "hidden",
|
||||
@ -596,16 +596,16 @@ export class ComfyUI {
|
||||
}
|
||||
}, [
|
||||
$el("span.drag-handle"),
|
||||
$el("span", {$: (q) => (this.queueSize = q)}),
|
||||
$el("button.comfy-settings-btn", {textContent: "⚙️", onclick: () => this.settings.show()}),
|
||||
$el("span", { $: (q) => (this.queueSize = q) }),
|
||||
$el("button.comfy-settings-btn", { textContent: "⚙️", onclick: () => this.settings.show() }),
|
||||
]),
|
||||
$el("button.comfy-queue-btn", {
|
||||
id: "queue-button",
|
||||
textContent: "Queue Prompt",
|
||||
textContent: i18next.t("ui.queue_btn"),
|
||||
onclick: () => app.queuePrompt(0, this.batchCount),
|
||||
}),
|
||||
$el("div", {}, [
|
||||
$el("label", {innerHTML: "Extra options"}, [
|
||||
$el("label", { innerHTML: i18next.t("ui.extra_options") }, [
|
||||
$el("input", {
|
||||
type: "checkbox",
|
||||
onchange: (i) => {
|
||||
@ -616,14 +616,14 @@ export class ComfyUI {
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
$el("div", {id: "extraOptions", style: {width: "100%", display: "none"}}, [
|
||||
$el("label", {innerHTML: "Batch count"}, [
|
||||
$el("div", { id: "extraOptions", style: { width: "100%", display: "none" } }, [
|
||||
$el("label", { innerHTML: "Batch count" }, [
|
||||
$el("input", {
|
||||
id: "batchCountInputNumber",
|
||||
type: "number",
|
||||
value: this.batchCount,
|
||||
min: "1",
|
||||
style: {width: "35%", "margin-left": "0.4em"},
|
||||
style: { width: "35%", "margin-left": "0.4em" },
|
||||
oninput: (i) => {
|
||||
this.batchCount = i.target.value;
|
||||
document.getElementById("batchCountInputRange").value = this.batchCount;
|
||||
@ -651,13 +651,13 @@ export class ComfyUI {
|
||||
$el("div.comfy-menu-btns", [
|
||||
$el("button", {
|
||||
id: "queue-front-button",
|
||||
textContent: "Queue Front",
|
||||
textContent: i18next.t("ui.queue_front_btn"),
|
||||
onclick: () => app.queuePrompt(-1, this.batchCount)
|
||||
}),
|
||||
$el("button", {
|
||||
$: (b) => (this.queue.button = b),
|
||||
id: "comfy-view-queue-button",
|
||||
textContent: "View Queue",
|
||||
textContent: i18next.t("ui.view_queue_btn"),
|
||||
onclick: () => {
|
||||
this.history.hide();
|
||||
this.queue.toggle();
|
||||
@ -666,7 +666,7 @@ export class ComfyUI {
|
||||
$el("button", {
|
||||
$: (b) => (this.history.button = b),
|
||||
id: "comfy-view-history-button",
|
||||
textContent: "View History",
|
||||
textContent: i18next.t("ui.view_history_btn"),
|
||||
onclick: () => {
|
||||
this.queue.hide();
|
||||
this.history.toggle();
|
||||
@ -677,7 +677,7 @@ export class ComfyUI {
|
||||
this.history.element,
|
||||
$el("button", {
|
||||
id: "comfy-save-button",
|
||||
textContent: "Save",
|
||||
textContent: i18next.t("ui.save_btn"),
|
||||
onclick: () => {
|
||||
let filename = "workflow.json";
|
||||
if (promptFilename.value) {
|
||||
@ -688,12 +688,12 @@ export class ComfyUI {
|
||||
}
|
||||
}
|
||||
const json = JSON.stringify(app.graph.serialize(), null, 2); // convert the data to a JSON string
|
||||
const blob = new Blob([json], {type: "application/json"});
|
||||
const blob = new Blob([json], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = $el("a", {
|
||||
href: url,
|
||||
download: filename,
|
||||
style: {display: "none"},
|
||||
style: { display: "none" },
|
||||
parent: document.body,
|
||||
});
|
||||
a.click();
|
||||
@ -706,7 +706,7 @@ export class ComfyUI {
|
||||
$el("button", {
|
||||
id: "comfy-dev-save-api-button",
|
||||
textContent: "Save (API Format)",
|
||||
style: {width: "100%", display: "none"},
|
||||
style: { width: "100%", display: "none" },
|
||||
onclick: () => {
|
||||
let filename = "workflow_api.json";
|
||||
if (promptFilename.value) {
|
||||
@ -716,14 +716,14 @@ export class ComfyUI {
|
||||
filename += ".json";
|
||||
}
|
||||
}
|
||||
app.graphToPrompt().then(p=>{
|
||||
app.graphToPrompt().then(p => {
|
||||
const json = JSON.stringify(p.output, null, 2); // convert the data to a JSON string
|
||||
const blob = new Blob([json], {type: "application/json"});
|
||||
const blob = new Blob([json], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = $el("a", {
|
||||
href: url,
|
||||
download: filename,
|
||||
style: {display: "none"},
|
||||
style: { display: "none" },
|
||||
parent: document.body,
|
||||
});
|
||||
a.click();
|
||||
@ -734,15 +734,15 @@ export class ComfyUI {
|
||||
});
|
||||
},
|
||||
}),
|
||||
$el("button", {id: "comfy-load-button", textContent: "Load", onclick: () => fileInput.click()}),
|
||||
$el("button", { id: "comfy-load-button", textContent: i18next.t("ui.load_btn"), onclick: () => fileInput.click() }),
|
||||
$el("button", {
|
||||
id: "comfy-refresh-button",
|
||||
textContent: "Refresh",
|
||||
textContent: i18next.t("ui.refresh_btn"),
|
||||
onclick: () => app.refreshComboInNodes()
|
||||
}),
|
||||
$el("button", {id: "comfy-clipspace-button", textContent: "Clipspace", onclick: () => app.openClipspace()}),
|
||||
$el("button", { id: "comfy-clipspace-button", textContent: i18next.t("ui.clipspace_btn"), onclick: () => app.openClipspace() }),
|
||||
$el("button", {
|
||||
id: "comfy-clear-button", textContent: "Clear", onclick: () => {
|
||||
id: "comfy-clear-button", textContent: i18next.t("ui.clear_btn"), onclick: () => {
|
||||
if (!confirmClear.value || confirm("Clear workflow?")) {
|
||||
app.clean();
|
||||
app.graph.clear();
|
||||
@ -750,7 +750,7 @@ export class ComfyUI {
|
||||
}
|
||||
}),
|
||||
$el("button", {
|
||||
id: "comfy-load-default-button", textContent: "Load Default", onclick: () => {
|
||||
id: "comfy-load-default-button", textContent: i18next.t("ui.load_default_btn"), onclick: () => {
|
||||
if (!confirmClear.value || confirm("Load default workflow?")) {
|
||||
app.loadGraphData()
|
||||
}
|
||||
@ -763,16 +763,16 @@ export class ComfyUI {
|
||||
name: "Enable Dev mode Options",
|
||||
type: "boolean",
|
||||
defaultValue: false,
|
||||
onChange: function(value) { document.getElementById("comfy-dev-save-api-button").style.display = value ? "block" : "none"},
|
||||
onChange: function (value) { document.getElementById("comfy-dev-save-api-button").style.display = value ? "block" : "none" },
|
||||
});
|
||||
|
||||
dragElement(this.menuContainer, this.settings);
|
||||
|
||||
this.setStatus({exec_info: {queue_remaining: "X"}});
|
||||
this.setStatus({ exec_info: { queue_remaining: "X" } });
|
||||
}
|
||||
|
||||
setStatus(status) {
|
||||
this.queueSize.textContent = "Queue size: " + (status ? status.exec_info.queue_remaining : "ERR");
|
||||
this.queueSize.textContent = i18next.t("ui.queue_size") + (status ? status.exec_info.queue_remaining : "ERR");
|
||||
if (status) {
|
||||
if (
|
||||
this.lastQueueSize != 0 &&
|
||||
|
||||
Loading…
Reference in New Issue
Block a user