Update rs_bypass.js
This commit is contained in:
+394
-89
@@ -27,18 +27,21 @@ app.registerExtension({
|
||||
const result = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
|
||||
const self = this;
|
||||
|
||||
// Новая структура данных: храним объекты { id, enabled }
|
||||
self.data = {
|
||||
bypassedNodes: [],
|
||||
bypassedGroups: [],
|
||||
bypassedNodes: [], // массив { id, enabled }
|
||||
bypassedGroups: [], // массив { id, enabled }
|
||||
menuSearch: "",
|
||||
expandedGroups: {},
|
||||
menuOpen: false
|
||||
menuOpen: false,
|
||||
toggleAllOn: true
|
||||
};
|
||||
|
||||
self.rowHeight = 28;
|
||||
self.padding = 10;
|
||||
self.clickZones = [];
|
||||
self._lastBypassedCount = -1;
|
||||
self._lastSyncTimestamp = 0; // для ограничения частоты синхронизации
|
||||
|
||||
const stateWidget = self.widgets.find(w => w.name === "bypass_state");
|
||||
const isNewNode = !stateWidget.value || stateWidget.value === "{}";
|
||||
@@ -59,8 +62,22 @@ app.registerExtension({
|
||||
try {
|
||||
const savedData = JSON.parse(stateWidget.value || "{}");
|
||||
if (savedData && typeof savedData === 'object') {
|
||||
if (savedData.nodes) self.data.bypassedNodes = savedData.nodes;
|
||||
if (savedData.groups) self.data.bypassedGroups = savedData.groups;
|
||||
// Преобразуем старые форматы (массивы id) в новый формат
|
||||
if (Array.isArray(savedData.nodes)) {
|
||||
if (savedData.nodes.length && typeof savedData.nodes[0] === 'number') {
|
||||
self.data.bypassedNodes = savedData.nodes.map(id => ({ id, enabled: true }));
|
||||
} else {
|
||||
self.data.bypassedNodes = savedData.nodes;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(savedData.groups)) {
|
||||
if (savedData.groups.length && typeof savedData.groups[0] === 'number') {
|
||||
self.data.bypassedGroups = savedData.groups.map(id => ({ id, enabled: true }));
|
||||
} else {
|
||||
self.data.bypassedGroups = savedData.groups;
|
||||
}
|
||||
}
|
||||
if (savedData.toggleAllOn !== undefined) self.data.toggleAllOn = savedData.toggleAllOn;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Rayko] Error loading saved data", e);
|
||||
@@ -71,7 +88,8 @@ app.registerExtension({
|
||||
self._rs_syncData();
|
||||
return JSON.stringify({
|
||||
nodes: self.data.bypassedNodes,
|
||||
groups: self.data.bypassedGroups
|
||||
groups: self.data.bypassedGroups,
|
||||
toggleAllOn: self.data.toggleAllOn
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -80,7 +98,8 @@ app.registerExtension({
|
||||
|
||||
self.computeSize = function() {
|
||||
const count = self.data.bypassedNodes.length + self.data.bypassedGroups.length;
|
||||
const calculatedHeight = 63 + (count * 28);
|
||||
const hasItems = count > 0;
|
||||
const calculatedHeight = 43 + (hasItems ? 38 : 0) + (count * 28) + 8;
|
||||
return [240, Math.max(80, calculatedHeight)];
|
||||
};
|
||||
|
||||
@@ -110,18 +129,157 @@ app.registerExtension({
|
||||
ctx.lineWidth = 1;
|
||||
};
|
||||
|
||||
self.drawBypassedItem = function(ctx, title, x, y, w, h, index) {
|
||||
self.drawToggle = function(ctx, isOn, x, y, w, h) {
|
||||
const toggleW = 36;
|
||||
const toggleH = 18;
|
||||
const toggleX = x;
|
||||
const toggleY = y + (h - toggleH) / 2;
|
||||
const radius = toggleH / 2;
|
||||
const knobRadius = radius - 2;
|
||||
const knobOffset = isOn ? toggleW - radius - 2 : 2;
|
||||
|
||||
ctx.fillStyle = isOn ? "#4CAF50" : "#555";
|
||||
ctx.beginPath();
|
||||
ctx.roundRect(toggleX, toggleY, toggleW, toggleH, radius);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.beginPath();
|
||||
ctx.arc(toggleX + knobOffset, toggleY + radius, knobRadius, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
return { x: toggleX, y: toggleY, w: toggleW, h: toggleH };
|
||||
};
|
||||
|
||||
self.drawBypassedItem = function(ctx, title, x, y, w, h, index, isBypassed) {
|
||||
const toggleZone = self.drawToggle(ctx, isBypassed, x, y, 36, h);
|
||||
|
||||
const textX = x + 44;
|
||||
const textW = w - 64;
|
||||
|
||||
ctx.fillStyle = index % 2 === 0 ? "rgba(255,68,68,0.1)" : "rgba(255,68,68,0.05)";
|
||||
ctx.fillRect(x, y, w, h);
|
||||
ctx.fillRect(textX, y, textW, h);
|
||||
|
||||
ctx.fillStyle = "#ff4444";
|
||||
ctx.font = "11px sans-serif";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(title, x + 8, y + h/2 + 4);
|
||||
ctx.fillText(title, textX + 8, y + h/2 + 4);
|
||||
|
||||
ctx.fillStyle = "#ff6666";
|
||||
ctx.fillText("✕", x + w - 20, y + h/2 + 4);
|
||||
ctx.fillText("✕", textX + textW - 12, y + h/2 + 4);
|
||||
|
||||
return { toggle: toggleZone, remove: { x: textX + textW - 20, y: y, w: 20, h: h } };
|
||||
};
|
||||
|
||||
// Синхронизация с внешними изменениями (через интерфейс ComfyUI)
|
||||
self._rs_syncFromExternal = function() {
|
||||
const now = Date.now();
|
||||
// Ограничиваем частоту синхронизации (не чаще 1 раза в 300 мс)
|
||||
if (now - self._lastSyncTimestamp < 300) return;
|
||||
self._lastSyncTimestamp = now;
|
||||
|
||||
const nodes = app.graph._nodes || [];
|
||||
const groups = app.graph._groups || [];
|
||||
let changed = false;
|
||||
|
||||
// Синхронизация групп
|
||||
self.data.bypassedGroups.forEach(item => {
|
||||
const group = groups.find(g => g.id === item.id);
|
||||
if (!group) return;
|
||||
const groupNodes = nodes.filter(n => isNodeInGroup(n, group));
|
||||
if (groupNodes.length === 0) return;
|
||||
const allBypassed = groupNodes.every(n => n.mode === 4);
|
||||
const anyBypassed = groupNodes.some(n => n.mode === 4);
|
||||
// Если все забайпашены -> enabled = true; если ни одна -> false; иначе оставляем как есть (частичный байпас)
|
||||
if (allBypassed && !item.enabled) {
|
||||
item.enabled = true;
|
||||
changed = true;
|
||||
} else if (!anyBypassed && item.enabled) {
|
||||
item.enabled = false;
|
||||
changed = true;
|
||||
}
|
||||
// Частичный случай: оставляем текущее enabled (может быть true или false)
|
||||
// Но если включен частичный, мы не можем точно определить, поэтому лучше не трогать.
|
||||
// Можно также установить enabled = anyBypassed, но тогда при частичном байпасе тоггл будет включён.
|
||||
// Реализуем как anyBypassed для согласованности:
|
||||
if (anyBypassed && !allBypassed) {
|
||||
// Частичный байпас: если ранее было false, то меняем на true, чтобы отображать активность
|
||||
if (!item.enabled) {
|
||||
item.enabled = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Синхронизация отдельных нод
|
||||
self.data.bypassedNodes.forEach(item => {
|
||||
const node = nodes.find(n => n.id === item.id);
|
||||
if (!node) return;
|
||||
// Проверяем, не входит ли нода в группу из кэша
|
||||
const inCachedGroup = self.data.bypassedGroups.some(gItem => {
|
||||
const group = groups.find(g => g.id === gItem.id);
|
||||
return group && isNodeInGroup(node, group);
|
||||
});
|
||||
if (inCachedGroup) {
|
||||
// Если нода в группе, то она управляется группой, поэтому синхронизируем её enabled с группой
|
||||
const groupEntry = self.data.bypassedGroups.find(gItem => {
|
||||
const group = groups.find(g => g.id === gItem.id);
|
||||
return group && isNodeInGroup(node, group);
|
||||
});
|
||||
if (groupEntry && groupEntry.enabled !== item.enabled) {
|
||||
item.enabled = groupEntry.enabled;
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
// Отдельная нода
|
||||
const isBypassed = node.mode === 4;
|
||||
if (isBypassed !== item.enabled) {
|
||||
item.enabled = isBypassed;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Также проверяем, есть ли новые забайпашенные ноды/группы, которых нет в кэше
|
||||
// (это может быть, если пользователь забайпасил что-то вручную)
|
||||
groups.forEach(group => {
|
||||
if (!group || !group.bounding && !group._bounding) return;
|
||||
const groupNodes = nodes.filter(n => n.comfyClass !== "RS_Bypass" && isNodeInGroup(n, group));
|
||||
if (groupNodes.length === 0) return;
|
||||
const allBypassed = groupNodes.every(n => n.mode === 4);
|
||||
if (allBypassed) {
|
||||
if (!self.data.bypassedGroups.some(item => item.id === group.id)) {
|
||||
self.data.bypassedGroups.push({ id: group.id, enabled: true });
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
nodes.forEach(n => {
|
||||
if (n.comfyClass === "RS_Bypass") return;
|
||||
if (n.mode === 4) {
|
||||
const inGroup = groups.some(g => g && (g.bounding || g._bounding) && isNodeInGroup(n, g));
|
||||
if (!inGroup) {
|
||||
if (!self.data.bypassedNodes.some(item => item.id === n.id)) {
|
||||
self.data.bypassedNodes.push({ id: n.id, enabled: true });
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Если были изменения, обновляем UI и сохраняем
|
||||
if (changed) {
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
self.graph?.setDirtyCanvas(true, true);
|
||||
}
|
||||
};
|
||||
|
||||
self.onDrawForeground = function(ctx, visibleRect) {
|
||||
// Синхронизация с внешними изменениями перед отрисовкой
|
||||
self._rs_syncFromExternal();
|
||||
|
||||
self.clickZones = [];
|
||||
const pad = self.padding;
|
||||
const rowH = self.rowHeight;
|
||||
@@ -129,47 +287,92 @@ app.registerExtension({
|
||||
let y = 5;
|
||||
|
||||
self.drawLabel(ctx, "BYPASS", pad, y, 50, rowH);
|
||||
self.drawField(ctx, "SELECT...", pad + 50, y, self.size[0] - pad*2 - 50, rowH, self.data.menuOpen);
|
||||
self.drawField(ctx, "SELECT ITEM", pad + 50, y, self.size[0] - pad*2 - 50, rowH, self.data.menuOpen);
|
||||
self.clickZones.push({ type: "select", x: pad + 50, y: y, w: self.size[0] - pad*2 - 50, h: rowH });
|
||||
y += rowH + 10;
|
||||
|
||||
const bypassedItems = [];
|
||||
// Строим список из кэша, используя сохранённое состояние enabled
|
||||
const nodes = app.graph._nodes || [];
|
||||
const groups = app.graph._groups || [];
|
||||
|
||||
const fullyBypassedGroupIds = [];
|
||||
groups.forEach(group => {
|
||||
if (!group || !group.bounding && !group._bounding) return;
|
||||
const groupNodes = nodes.filter(n => n.comfyClass !== "RS_Bypass" && isNodeInGroup(n, group));
|
||||
if (groupNodes.length > 0 && groupNodes.every(n => n.mode === 4)) {
|
||||
fullyBypassedGroupIds.push(group.id);
|
||||
bypassedItems.push({ type: "group", id: group.id, title: "📁 " + (group.title || "Group") });
|
||||
const displayItems = [];
|
||||
|
||||
// Группы из кэша
|
||||
self.data.bypassedGroups.forEach(item => {
|
||||
const group = groups.find(g => g.id === item.id);
|
||||
if (group) {
|
||||
displayItems.push({
|
||||
type: "group",
|
||||
id: group.id,
|
||||
title: "📁 " + (group.title || "Group"),
|
||||
isBypassed: item.enabled
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
nodes.forEach(n => {
|
||||
if (n.comfyClass === "RS_Bypass") return;
|
||||
if (n.mode === 4) {
|
||||
const inBypassedGroup = fullyBypassedGroupIds.some(groupId => {
|
||||
const group = groups.find(g => g.id === groupId);
|
||||
return group && isNodeInGroup(n, group);
|
||||
// Отдельные ноды из кэша, исключая те, что входят в группы из кэша (чтобы не дублировать)
|
||||
self.data.bypassedNodes.forEach(item => {
|
||||
const targetNode = nodes.find(n => n.id === item.id);
|
||||
if (targetNode) {
|
||||
// Проверяем, не входит ли нода в какую-либо группу из кэша
|
||||
const inCachedGroup = self.data.bypassedGroups.some(gItem => {
|
||||
const group = groups.find(g => g.id === gItem.id);
|
||||
return group && isNodeInGroup(targetNode, group);
|
||||
});
|
||||
|
||||
if (!inBypassedGroup) {
|
||||
bypassedItems.push({ type: "node", id: n.id, title: "⚙️ " + (n.title || n.type) });
|
||||
if (!inCachedGroup) {
|
||||
displayItems.push({
|
||||
type: "node",
|
||||
id: targetNode.id,
|
||||
title: "️ " + (targetNode.title || targetNode.type),
|
||||
isBypassed: item.enabled
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
bypassedItems.forEach((item, index) => {
|
||||
// TOGGLE ALL строка
|
||||
if (displayItems.length > 0) {
|
||||
self.drawLabel(ctx, "TOGGLE ALL", pad, y, 100, rowH);
|
||||
const toggleZone = self.drawToggle(ctx, self.data.toggleAllOn, pad + 100, y, self.size[0] - pad*2 - 100, rowH);
|
||||
self.clickZones.push({
|
||||
type: "toggleAll",
|
||||
x: toggleZone.x,
|
||||
y: toggleZone.y,
|
||||
w: toggleZone.w,
|
||||
h: toggleZone.h
|
||||
});
|
||||
y += rowH + 10;
|
||||
}
|
||||
|
||||
// Рисуем элементы списка
|
||||
displayItems.forEach((item, index) => {
|
||||
const itemY = y + (index * rowH);
|
||||
self.drawBypassedItem(ctx, item.title, pad, itemY, self.size[0] - pad*2, rowH, index);
|
||||
self.clickZones.push({ type: "remove", itemType: item.type, id: item.id, x: pad, y: itemY, w: self.size[0] - pad*2, h: rowH });
|
||||
const zones = self.drawBypassedItem(ctx, item.title, pad, itemY, self.size[0] - pad*2, rowH, index, item.isBypassed);
|
||||
|
||||
self.clickZones.push({
|
||||
type: "itemToggle",
|
||||
itemType: item.type,
|
||||
id: item.id,
|
||||
x: zones.toggle.x,
|
||||
y: zones.toggle.y,
|
||||
w: zones.toggle.w,
|
||||
h: zones.toggle.h
|
||||
});
|
||||
|
||||
self.clickZones.push({
|
||||
type: "remove",
|
||||
itemType: item.type,
|
||||
id: item.id,
|
||||
x: zones.remove.x,
|
||||
y: zones.remove.y,
|
||||
w: zones.remove.w,
|
||||
h: zones.remove.h
|
||||
});
|
||||
});
|
||||
|
||||
const bypassedCount = bypassedItems.length;
|
||||
if (self._lastBypassedCount !== bypassedCount) {
|
||||
self._lastBypassedCount = bypassedCount;
|
||||
const currentCount = displayItems.length;
|
||||
if (self._lastBypassedCount !== currentCount) {
|
||||
self._lastBypassedCount = currentCount;
|
||||
self._rs_updateUI();
|
||||
}
|
||||
};
|
||||
@@ -180,6 +383,9 @@ app.registerExtension({
|
||||
return;
|
||||
}
|
||||
|
||||
// Синхронизация перед открытием меню
|
||||
self._rs_syncFromExternal();
|
||||
|
||||
const existingMenu = document.getElementById("rs-bypass-menu");
|
||||
if (existingMenu) existingMenu.remove();
|
||||
|
||||
@@ -242,21 +448,21 @@ app.registerExtension({
|
||||
const title = group.title || "Group " + group.id;
|
||||
if (query && !title.toLowerCase().includes(query)) return;
|
||||
|
||||
const bypassedCount = groupNodes.filter(n => n.mode === 4).length;
|
||||
const isAllBypassed = bypassedCount === groupNodes.length;
|
||||
const isPartialBypassed = bypassedCount > 0 && !isAllBypassed;
|
||||
// Проверяем, есть ли уже группа в кэше
|
||||
const cachedGroup = self.data.bypassedGroups.find(item => item.id === group.id);
|
||||
const isAllBypassed = cachedGroup ? cachedGroup.enabled : false;
|
||||
const isPartialBypassed = false; // упростим
|
||||
const isExpanded = self.data.expandedGroups[group.id] || false;
|
||||
|
||||
let groupColor = "#ddd";
|
||||
if (isAllBypassed) groupColor = "#ff4444";
|
||||
else if (isPartialBypassed) groupColor = "#ff9800";
|
||||
|
||||
const groupItem = document.createElement("div");
|
||||
groupItem.style.cssText = "padding:10px 12px;cursor:pointer;color:" + groupColor + ";border-bottom:1px solid #333;font-size:12px;display:flex;align-items:center;transition:background-color 0.15s;";
|
||||
|
||||
const arrow = document.createElement("span");
|
||||
arrow.textContent = isExpanded ? "▼ " : "▶ ";
|
||||
arrow.style.cssText = "margin-right:8px;font-size:10px;";
|
||||
arrow.style.cssText = "margin-right:8px;font-size:10px;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border:1px solid #555;border-radius:4px;";
|
||||
arrow.onclick = (ev) => {
|
||||
ev.stopPropagation();
|
||||
self.data.expandedGroups[group.id] = !isExpanded;
|
||||
@@ -266,19 +472,21 @@ app.registerExtension({
|
||||
|
||||
const groupText = document.createElement("span");
|
||||
groupText.textContent = " " + title;
|
||||
groupText.style.cssText = "flex:1;";
|
||||
groupText.style.cssText = "flex:1;margin-left:4px;";
|
||||
groupText.onclick = (ev) => {
|
||||
ev.stopPropagation();
|
||||
groupNodes.forEach(n => setNodeBypass(n, !isAllBypassed));
|
||||
|
||||
if (!isAllBypassed) {
|
||||
if (!self.data.bypassedGroups.includes(group.id)) {
|
||||
self.data.bypassedGroups.push(group.id);
|
||||
}
|
||||
// Добавляем или удаляем группу из кэша
|
||||
let entry = self.data.bypassedGroups.find(item => item.id === group.id);
|
||||
if (entry) {
|
||||
// Если уже есть, переключаем enabled
|
||||
entry.enabled = !entry.enabled;
|
||||
} else {
|
||||
self.data.bypassedGroups = self.data.bypassedGroups.filter(id => id !== group.id);
|
||||
// Добавляем с enabled: true
|
||||
entry = { id: group.id, enabled: true };
|
||||
self.data.bypassedGroups.push(entry);
|
||||
}
|
||||
|
||||
// Применяем байпас ко всем нодам группы
|
||||
groupNodes.forEach(n => setNodeBypass(n, entry.enabled));
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
renderContent();
|
||||
@@ -296,7 +504,8 @@ app.registerExtension({
|
||||
const nodeTitle = n.title || n.type;
|
||||
if (query && !nodeTitle.toLowerCase().includes(query)) return;
|
||||
|
||||
const isNodeBypassed = n.mode === 4;
|
||||
const cachedNode = self.data.bypassedNodes.find(item => item.id === n.id);
|
||||
const isNodeBypassed = cachedNode ? cachedNode.enabled : false;
|
||||
const nodeColor = isNodeBypassed ? "#ff4444" : "#ddd";
|
||||
|
||||
const nodeItem = document.createElement("div");
|
||||
@@ -306,16 +515,14 @@ app.registerExtension({
|
||||
nodeItem.onmouseout = () => nodeItem.style.background = "#1a1a1a";
|
||||
nodeItem.onclick = (ev) => {
|
||||
ev.stopPropagation();
|
||||
setNodeBypass(n, !isNodeBypassed);
|
||||
|
||||
if (!isNodeBypassed) {
|
||||
if (!self.data.bypassedNodes.includes(n.id)) {
|
||||
self.data.bypassedNodes.push(n.id);
|
||||
}
|
||||
let entry = self.data.bypassedNodes.find(item => item.id === n.id);
|
||||
if (entry) {
|
||||
entry.enabled = !entry.enabled;
|
||||
} else {
|
||||
self.data.bypassedNodes = self.data.bypassedNodes.filter(id => id !== n.id);
|
||||
entry = { id: n.id, enabled: true };
|
||||
self.data.bypassedNodes.push(entry);
|
||||
}
|
||||
|
||||
setNodeBypass(n, entry.enabled);
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
renderContent();
|
||||
@@ -330,7 +537,8 @@ app.registerExtension({
|
||||
const title = n.title || n.type;
|
||||
if (query && !title.toLowerCase().includes(query)) return;
|
||||
|
||||
const isBypassed = n.mode === 4;
|
||||
const cachedNode = self.data.bypassedNodes.find(item => item.id === n.id);
|
||||
const isBypassed = cachedNode ? cachedNode.enabled : false;
|
||||
const nodeColor = isBypassed ? "#ff4444" : "#ddd";
|
||||
|
||||
const item = document.createElement("div");
|
||||
@@ -340,16 +548,14 @@ app.registerExtension({
|
||||
item.onmouseout = () => item.style.background = "#1a1a1a";
|
||||
item.onclick = (ev) => {
|
||||
ev.stopPropagation();
|
||||
setNodeBypass(n, !isBypassed);
|
||||
|
||||
if (!isBypassed) {
|
||||
if (!self.data.bypassedNodes.includes(n.id)) {
|
||||
self.data.bypassedNodes.push(n.id);
|
||||
}
|
||||
let entry = self.data.bypassedNodes.find(item => item.id === n.id);
|
||||
if (entry) {
|
||||
entry.enabled = !entry.enabled;
|
||||
} else {
|
||||
self.data.bypassedNodes = self.data.bypassedNodes.filter(id => id !== n.id);
|
||||
entry = { id: n.id, enabled: true };
|
||||
self.data.bypassedNodes.push(entry);
|
||||
}
|
||||
|
||||
setNodeBypass(n, entry.enabled);
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
renderContent();
|
||||
@@ -404,20 +610,86 @@ app.registerExtension({
|
||||
self.showBypassMenu(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (zone.type === "toggleAll") {
|
||||
self.data.toggleAllOn = !self.data.toggleAllOn;
|
||||
const newState = self.data.toggleAllOn;
|
||||
|
||||
// Меняем enabled у всех элементов в кэше
|
||||
self.data.bypassedGroups.forEach(item => item.enabled = newState);
|
||||
self.data.bypassedNodes.forEach(item => item.enabled = newState);
|
||||
|
||||
// Применяем байпас
|
||||
const nodes = app.graph._nodes || [];
|
||||
const groups = app.graph._groups || [];
|
||||
self.data.bypassedGroups.forEach(item => {
|
||||
const group = groups.find(g => g.id === item.id);
|
||||
if (group) {
|
||||
const groupNodes = nodes.filter(n => isNodeInGroup(n, group));
|
||||
groupNodes.forEach(n => setNodeBypass(n, newState));
|
||||
}
|
||||
});
|
||||
self.data.bypassedNodes.forEach(item => {
|
||||
const targetNode = nodes.find(n => n.id === item.id);
|
||||
if (targetNode) {
|
||||
// Проверяем, не входит ли нода в группу из кэша
|
||||
const inGroup = self.data.bypassedGroups.some(gItem => {
|
||||
const group = groups.find(g => g.id === gItem.id);
|
||||
return group && isNodeInGroup(targetNode, group);
|
||||
});
|
||||
if (!inGroup) setNodeBypass(targetNode, newState);
|
||||
}
|
||||
});
|
||||
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (zone.type === "itemToggle") {
|
||||
if (zone.itemType === "group") {
|
||||
const group = app.graph._groups.find(g => g.id === zone.id);
|
||||
if (group) {
|
||||
const groupNodes = app.graph._nodes.filter(n => isNodeInGroup(n, group));
|
||||
let entry = self.data.bypassedGroups.find(item => item.id === zone.id);
|
||||
if (!entry) {
|
||||
entry = { id: zone.id, enabled: false };
|
||||
self.data.bypassedGroups.push(entry);
|
||||
}
|
||||
entry.enabled = !entry.enabled;
|
||||
groupNodes.forEach(n => setNodeBypass(n, entry.enabled));
|
||||
}
|
||||
} else {
|
||||
const targetNode = app.graph._nodes.find(n => n.id === zone.id);
|
||||
if (targetNode) {
|
||||
let entry = self.data.bypassedNodes.find(item => item.id === zone.id);
|
||||
if (!entry) {
|
||||
entry = { id: zone.id, enabled: false };
|
||||
self.data.bypassedNodes.push(entry);
|
||||
}
|
||||
entry.enabled = !entry.enabled;
|
||||
setNodeBypass(targetNode, entry.enabled);
|
||||
}
|
||||
}
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (zone.type === "remove") {
|
||||
if (zone.itemType === "group") {
|
||||
const group = app.graph._groups.find(g => g.id === zone.id);
|
||||
if (group) {
|
||||
const groupNodes = app.graph._nodes.filter(n => isNodeInGroup(n, group));
|
||||
groupNodes.forEach(n => setNodeBypass(n, false));
|
||||
self.data.bypassedGroups = self.data.bypassedGroups.filter(id => id !== zone.id);
|
||||
}
|
||||
self.data.bypassedGroups = self.data.bypassedGroups.filter(item => item.id !== zone.id);
|
||||
} else {
|
||||
const targetNode = app.graph._nodes.find(n => n.id === zone.id);
|
||||
if (targetNode) {
|
||||
setNodeBypass(targetNode, false);
|
||||
self.data.bypassedNodes = self.data.bypassedNodes.filter(id => id !== zone.id);
|
||||
}
|
||||
self.data.bypassedNodes = self.data.bypassedNodes.filter(item => item.id !== zone.id);
|
||||
}
|
||||
self._rs_syncData();
|
||||
self._rs_updateUI();
|
||||
@@ -432,12 +704,17 @@ app.registerExtension({
|
||||
const pad = self.padding;
|
||||
const rowH = self.rowHeight;
|
||||
const bypassedItemsCount = self._lastBypassedCount >= 0 ? self._lastBypassedCount : (self.data.bypassedGroups.length + self.data.bypassedNodes.length);
|
||||
const hasItems = bypassedItemsCount > 0;
|
||||
|
||||
let y = 5;
|
||||
y += rowH;
|
||||
y += 10;
|
||||
if (hasItems) {
|
||||
y += rowH;
|
||||
y += 10;
|
||||
}
|
||||
y += (bypassedItemsCount * rowH);
|
||||
y += 20;
|
||||
y += 8;
|
||||
|
||||
const minHeight = 80;
|
||||
const minWidth = 220;
|
||||
@@ -455,19 +732,24 @@ app.registerExtension({
|
||||
const nodes = app.graph._nodes || [];
|
||||
const groups = app.graph._groups || [];
|
||||
|
||||
self.data.bypassedGroups.forEach(groupId => {
|
||||
const group = groups.find(g => g.id === groupId);
|
||||
// Включаем байпас только для элементов с enabled === true
|
||||
self.data.bypassedGroups.forEach(item => {
|
||||
if (!item.enabled) return;
|
||||
const group = groups.find(g => g.id === item.id);
|
||||
if (group) {
|
||||
const groupNodes = nodes.filter(n => isNodeInGroup(n, group));
|
||||
groupNodes.forEach(n => setNodeBypass(n, true));
|
||||
}
|
||||
});
|
||||
|
||||
self.data.bypassedNodes.forEach(nodeId => {
|
||||
const targetNode = nodes.find(n => n.id === nodeId);
|
||||
self.data.bypassedNodes.forEach(item => {
|
||||
if (!item.enabled) return;
|
||||
const targetNode = nodes.find(n => n.id === item.id);
|
||||
if (targetNode) {
|
||||
const inBypassedGroup = self.data.bypassedGroups.some(groupId => {
|
||||
const group = groups.find(g => g.id === groupId);
|
||||
// Проверяем, не входит ли нода в уже забайпашенную группу
|
||||
const inBypassedGroup = self.data.bypassedGroups.some(gItem => {
|
||||
if (!gItem.enabled) return false;
|
||||
const group = groups.find(g => g.id === gItem.id);
|
||||
return group && isNodeInGroup(targetNode, group);
|
||||
});
|
||||
if (!inBypassedGroup) {
|
||||
@@ -481,26 +763,34 @@ app.registerExtension({
|
||||
const nodes = app.graph._nodes || [];
|
||||
const groups = app.graph._groups || [];
|
||||
|
||||
// 1. Полностью забайпашенные группы
|
||||
groups.forEach(group => {
|
||||
if (!group || !group.bounding && !group._bounding) return;
|
||||
const groupNodes = nodes.filter(n => n.comfyClass !== "RS_Bypass" && isNodeInGroup(n, group));
|
||||
if (groupNodes.length > 0 && groupNodes.every(n => n.mode === 4)) {
|
||||
if (!self.data.bypassedGroups.includes(group.id)) {
|
||||
self.data.bypassedGroups.push(group.id);
|
||||
// Добавляем группу в кэш, если её там нет
|
||||
if (!self.data.bypassedGroups.some(item => item.id === group.id)) {
|
||||
self.data.bypassedGroups.push({ id: group.id, enabled: true });
|
||||
} else {
|
||||
// Обновляем enabled
|
||||
const entry = self.data.bypassedGroups.find(item => item.id === group.id);
|
||||
if (entry) entry.enabled = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 2. Отдельные ноды с mode=4, не входящие ни в какую группу
|
||||
nodes.forEach(n => {
|
||||
if (n.comfyClass === "RS_Bypass") return;
|
||||
if (n.mode === 4) {
|
||||
const inBypassedGroup = self.data.bypassedGroups.some(groupId => {
|
||||
const group = groups.find(g => g.id === groupId);
|
||||
return group && isNodeInGroup(n, group);
|
||||
});
|
||||
|
||||
if (!inBypassedGroup && !self.data.bypassedNodes.includes(n.id)) {
|
||||
self.data.bypassedNodes.push(n.id);
|
||||
const inAnyGroup = groups.some(g => g && (g.bounding || g._bounding) && isNodeInGroup(n, g));
|
||||
if (!inAnyGroup) {
|
||||
if (!self.data.bypassedNodes.some(item => item.id === n.id)) {
|
||||
self.data.bypassedNodes.push({ id: n.id, enabled: true });
|
||||
} else {
|
||||
const entry = self.data.bypassedNodes.find(item => item.id === n.id);
|
||||
if (entry) entry.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -510,7 +800,8 @@ app.registerExtension({
|
||||
if (stateWidget) {
|
||||
stateWidget.value = JSON.stringify({
|
||||
nodes: self.data.bypassedNodes,
|
||||
groups: self.data.bypassedGroups
|
||||
groups: self.data.bypassedGroups,
|
||||
toggleAllOn: self.data.toggleAllOn
|
||||
});
|
||||
}
|
||||
if (self.graph) {
|
||||
@@ -536,8 +827,22 @@ app.registerExtension({
|
||||
try {
|
||||
const restoredData = JSON.parse(stateWidget.value);
|
||||
if (restoredData) {
|
||||
if (restoredData.nodes) self.data.bypassedNodes = restoredData.nodes;
|
||||
if (restoredData.groups) self.data.bypassedGroups = restoredData.groups;
|
||||
// Преобразование при необходимости
|
||||
if (Array.isArray(restoredData.nodes)) {
|
||||
if (restoredData.nodes.length && typeof restoredData.nodes[0] === 'number') {
|
||||
self.data.bypassedNodes = restoredData.nodes.map(id => ({ id, enabled: true }));
|
||||
} else {
|
||||
self.data.bypassedNodes = restoredData.nodes;
|
||||
}
|
||||
}
|
||||
if (Array.isArray(restoredData.groups)) {
|
||||
if (restoredData.groups.length && typeof restoredData.groups[0] === 'number') {
|
||||
self.data.bypassedGroups = restoredData.groups.map(id => ({ id, enabled: true }));
|
||||
} else {
|
||||
self.data.bypassedGroups = restoredData.groups;
|
||||
}
|
||||
}
|
||||
if (restoredData.toggleAllOn !== undefined) self.data.toggleAllOn = restoredData.toggleAllOn;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Rayko] Error restoring data:", e);
|
||||
@@ -567,4 +872,4 @@ app.registerExtension({
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user