mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-21 20:52:12 -03:00
Enable cross-workflow node duplication with layers
Store canvas state in IndexedDB clipboard on copy, allowing nodes to be duplicated with their layers preserved across different workflows. When copying a node, the canvas state is stored in a special '__clipboard__' entry that persists across workflow switches. On paste, if the source node doesn't exist (indicating cross-workflow paste), the system falls back to loading from the clipboard entry.
This commit is contained in:
@@ -1126,14 +1126,19 @@ app.registerExtension({
|
|||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const { getCanvasState, setCanvasState } = await import('./db.js');
|
const { getCanvasState, setCanvasState } = await import('./db.js');
|
||||||
const sourceState = await getCanvasState(String(sourceNodeId));
|
let sourceState = await getCanvasState(String(sourceNodeId));
|
||||||
|
// If source node doesn't exist (cross-workflow paste), try clipboard
|
||||||
if (!sourceState) {
|
if (!sourceState) {
|
||||||
log.debug(`No canvas state found for source node ${sourceNodeId}`);
|
log.debug(`No canvas state found for source node ${sourceNodeId}, checking clipboard`);
|
||||||
|
sourceState = await getCanvasState('__clipboard__');
|
||||||
|
}
|
||||||
|
if (!sourceState) {
|
||||||
|
log.debug(`No canvas state found in clipboard either`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await setCanvasState(String(this.id), sourceState);
|
await setCanvasState(String(this.id), sourceState);
|
||||||
await canvasWidget.canvas.loadInitialState();
|
await canvasWidget.canvas.loadInitialState();
|
||||||
log.info(`Canvas state copied successfully from node ${sourceNodeId} to node ${this.id}`);
|
log.info(`Canvas state copied successfully to node ${this.id}`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
log.error(`Error copying canvas state:`, error);
|
log.error(`Error copying canvas state:`, error);
|
||||||
@@ -1312,6 +1317,22 @@ app.registerExtension({
|
|||||||
// Store a reference to the source node ID so we can copy layer data
|
// Store a reference to the source node ID so we can copy layer data
|
||||||
data.sourceNodeId = this.id;
|
data.sourceNodeId = this.id;
|
||||||
log.debug(`Serializing node ${this.id} for copy`);
|
log.debug(`Serializing node ${this.id} for copy`);
|
||||||
|
// Store canvas state in a clipboard entry for cross-workflow paste
|
||||||
|
// This happens async but that's fine since paste happens later
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const { getCanvasState, setCanvasState } = await import('./db.js');
|
||||||
|
const sourceState = await getCanvasState(String(this.id));
|
||||||
|
if (sourceState) {
|
||||||
|
// Store in a special "clipboard" entry
|
||||||
|
await setCanvasState('__clipboard__', sourceState);
|
||||||
|
log.debug(`Stored canvas state in clipboard for node ${this.id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
log.error('Error storing canvas state to clipboard:', error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
// Handle copy/paste - load canvas state from source node when pasting
|
// Handle copy/paste - load canvas state from source node when pasting
|
||||||
|
|||||||
@@ -1299,16 +1299,22 @@ app.registerExtension({
|
|||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const { getCanvasState, setCanvasState } = await import('./db.js');
|
const { getCanvasState, setCanvasState } = await import('./db.js');
|
||||||
const sourceState = await getCanvasState(String(sourceNodeId));
|
let sourceState = await getCanvasState(String(sourceNodeId));
|
||||||
|
|
||||||
|
// If source node doesn't exist (cross-workflow paste), try clipboard
|
||||||
|
if (!sourceState) {
|
||||||
|
log.debug(`No canvas state found for source node ${sourceNodeId}, checking clipboard`);
|
||||||
|
sourceState = await getCanvasState('__clipboard__');
|
||||||
|
}
|
||||||
|
|
||||||
if (!sourceState) {
|
if (!sourceState) {
|
||||||
log.debug(`No canvas state found for source node ${sourceNodeId}`);
|
log.debug(`No canvas state found in clipboard either`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await setCanvasState(String(this.id), sourceState);
|
await setCanvasState(String(this.id), sourceState);
|
||||||
await canvasWidget.canvas.loadInitialState();
|
await canvasWidget.canvas.loadInitialState();
|
||||||
log.info(`Canvas state copied successfully from node ${sourceNodeId} to node ${this.id}`);
|
log.info(`Canvas state copied successfully to node ${this.id}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error copying canvas state:`, error);
|
log.error(`Error copying canvas state:`, error);
|
||||||
}
|
}
|
||||||
@@ -1507,6 +1513,22 @@ app.registerExtension({
|
|||||||
data.sourceNodeId = this.id;
|
data.sourceNodeId = this.id;
|
||||||
log.debug(`Serializing node ${this.id} for copy`);
|
log.debug(`Serializing node ${this.id} for copy`);
|
||||||
|
|
||||||
|
// Store canvas state in a clipboard entry for cross-workflow paste
|
||||||
|
// This happens async but that's fine since paste happens later
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const { getCanvasState, setCanvasState } = await import('./db.js');
|
||||||
|
const sourceState = await getCanvasState(String(this.id));
|
||||||
|
if (sourceState) {
|
||||||
|
// Store in a special "clipboard" entry
|
||||||
|
await setCanvasState('__clipboard__', sourceState);
|
||||||
|
log.debug(`Stored canvas state in clipboard for node ${this.id}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
log.error('Error storing canvas state to clipboard:', error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user