fix: skip node metadata paste when media node is selected (#9773)

## Summary

- When a media node (LoadImage/LoadAudio/LoadVideo) is selected and the
clipboard contains stale node metadata from a prior Ctrl+C, pasting
skips the node-metadata deserialization so that the paste falls through
to litegraph's default handler instead of incorrectly pasting the old
copied node.
- Fixes Comfy-Org/ComfyUI#12896

## Root Cause

The paste handler in `usePaste.ts` checks clipboard `text/html` for
`data-metadata` (serialized node data) **before** falling through to
litegraph's default paste. When a user copies a node, then copies a web
image, the browser clipboard may retain the old `data-metadata` in
`text/html` while the image data is not available as a
`DataTransferItem` file. This causes the stale node to be pasted instead
of the image.

## Fix

Skip `pasteClipboardItems()` when a media node is selected, allowing the
paste to fall through to litegraph's default handler which can handle
the clipboard content appropriately.

## Test plan

- [x] Added unit test verifying node metadata paste is skipped when
media node is selected
- [x] Manual: Copy a node → copy a web image → select LoadImage node →
Ctrl+V → verify image is pasted, not the node


## AS IS 


https://github.com/user-attachments/assets/210d77d3-5c49-4e38-91b7-b9d9ea0e7ca0



## TO BE



https://github.com/user-attachments/assets/b68e4582-0c57-48b8-9ed9-0b3243bb1554




🤖 Generated with [Claude Code](https://claude.com/claude-code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9773-fix-skip-node-metadata-paste-when-media-node-is-selected-3216d73d3650814d92dadcd0c0ec79c7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Dante
2026-03-13 00:44:11 +09:00
committed by GitHub
parent ef477d0381
commit 39ce4a23cc
4 changed files with 137 additions and 1 deletions

View File

@@ -595,6 +595,34 @@ describe('usePaste', () => {
)
})
})
it('should skip node metadata paste when a media node is selected', async () => {
const mockNode = createMockLGraphNode({
is_selected: true,
pasteFile: vi.fn(),
pasteFiles: vi.fn()
})
mockCanvas.current_node = mockNode
vi.mocked(isImageNode).mockReturnValue(true)
usePaste()
const nodeData = { nodes: [{ type: 'KSampler' }] }
const encoded = btoa(JSON.stringify(nodeData))
const html = `<div data-metadata="${encoded}"></div>`
const dataTransfer = new DataTransfer()
dataTransfer.setData('text/html', html)
dataTransfer.setData('text/plain', 'some text')
const event = new ClipboardEvent('paste', { clipboardData: dataTransfer })
document.dispatchEvent(event)
await vi.waitFor(() => {
expect(mockCanvas._deserializeItems).not.toHaveBeenCalled()
expect(mockCanvas.pasteFromClipboard).toHaveBeenCalled()
})
})
})
describe('cloneDataTransfer', () => {

View File

@@ -229,7 +229,10 @@ export const usePaste = () => {
return
}
}
if (pasteClipboardItems(data)) return
const isMediaNodeSelected =
isImageNodeSelected || isVideoNodeSelected || isAudioNodeSelected
if (!isMediaNodeSelected && pasteClipboardItems(data)) return
// No image found. Look for node data
data = data.getData('text/plain')