-
Notifications
You must be signed in to change notification settings - Fork 643
Batch Drag & Drop Images #8282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Batch Drag & Drop Images #8282
Changes from 11 commits
dfb6b6b
44c4ebc
2fc4305
7904320
55d38e8
bd6df61
e26c0db
5bb3550
7c00888
1f8d5fa
3e69806
d64df32
55634e4
7f7f3b8
daed3cb
373af13
758ed36
2ca9850
4252d58
6c6f0db
7c1960f
939c2f5
0600af4
e30b081
afc6ec8
98fc6c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,9 +6,41 @@ import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/w | |
| import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' | ||
| import { app } from '@/scripts/app' | ||
| import { useWorkspaceStore } from '@/stores/workspaceStore' | ||
| import { isAudioNode, isImageNode, isVideoNode } from '@/utils/litegraphUtil' | ||
| import { | ||
| createNode, | ||
| isAudioNode, | ||
| isImageNode, | ||
| isVideoNode | ||
| } from '@/utils/litegraphUtil' | ||
| import { shouldIgnoreCopyPaste } from '@/workbench/eventHelpers' | ||
|
|
||
| export function cloneDataTransfer(original: DataTransfer): DataTransfer { | ||
| const persistent = new DataTransfer() | ||
|
|
||
| // Copy string data | ||
| for (const type of original.types) { | ||
| const data = original.getData(type) | ||
| if (data) { | ||
| persistent.setData(type, data) | ||
| } | ||
| } | ||
|
|
||
| for (const item of original.items) { | ||
| if (item.kind === 'file') { | ||
| const file = item.getAsFile() | ||
| if (file) { | ||
| persistent.items.add(file) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Preserve dropEffect and effectAllowed | ||
| persistent.dropEffect = original.dropEffect | ||
| persistent.effectAllowed = original.effectAllowed | ||
|
|
||
| return persistent | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| function pasteClipboardItems(data: DataTransfer): boolean { | ||
| const rawData = data.getData('text/html') | ||
| const match = rawData.match(/data-metadata="([A-Za-z0-9+/=]+)"/)?.[1] | ||
|
|
@@ -48,27 +80,37 @@ function pasteItemsOnNode( | |
| ) | ||
| } | ||
|
|
||
| export function pasteImageNode( | ||
| export async function pasteImageNode( | ||
| canvas: LGraphCanvas, | ||
| items: DataTransferItemList, | ||
| imageNode: LGraphNode | null = null | ||
| ): void { | ||
| const { | ||
| graph, | ||
| graph_mouse: [posX, posY] | ||
| } = canvas | ||
|
|
||
| ): Promise<LGraphNode | null> { | ||
| // No image node selected: add a new one | ||
| if (!imageNode) { | ||
| // No image node selected: add a new one | ||
| const newNode = LiteGraph.createNode('LoadImage') | ||
| if (newNode) { | ||
| newNode.pos = [posX, posY] | ||
| imageNode = graph?.add(newNode) ?? null | ||
| } | ||
| graph?.change() | ||
| imageNode = await createNode(canvas, 'LoadImage') | ||
| } | ||
|
|
||
| pasteItemsOnNode(items, imageNode, 'image') | ||
| return imageNode | ||
| } | ||
|
|
||
| export async function pasteImageNodes( | ||
| canvas: LGraphCanvas, | ||
| fileList: FileList | ||
| ): Promise<LGraphNode[]> { | ||
| const nodes: LGraphNode[] = [] | ||
|
|
||
| for (const file of fileList) { | ||
| const transfer = new DataTransfer() | ||
| transfer.items.add(file) | ||
| const imageNode = await pasteImageNode(canvas, transfer.items) | ||
|
|
||
| if (imageNode) { | ||
| nodes.push(imageNode) | ||
| } | ||
| } | ||
|
|
||
| return nodes | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| /** | ||
|
|
@@ -93,6 +135,7 @@ export const usePaste = () => { | |
| const { graph } = canvas | ||
| let data: DataTransfer | string | null = e.clipboardData | ||
| if (!data) throw new Error('No clipboard data on clipboard event') | ||
| data = cloneDataTransfer(data) | ||
|
|
||
| const { items } = data | ||
|
|
||
|
|
@@ -114,7 +157,7 @@ export const usePaste = () => { | |
| // Look for image paste data | ||
| for (const item of items) { | ||
| if (item.type.startsWith('image/')) { | ||
| pasteImageNode(canvas as LGraphCanvas, items, imageNode) | ||
| await pasteImageNode(canvas as LGraphCanvas, items, imageNode) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I know it's not introduced here, but can we clean up the type assertion?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was planning on cleaning up all the type assertion when I got to the audio/video story as it's the last drag and drop / copy & paste task. Unless there is some other type beyond that I should add to that task. I already have another task waiting with the text drag/drop/copy/paste |
||
| return | ||
| } else if (item.type.startsWith('video/')) { | ||
| if (!videoNode) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.