Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag and drop from finder to WebView

I'm using a WebView in edit mode. I have implemented this method from WebUIDelegate Procotol:

- (void)webView:(WebView *)sender willPerformDragDestinationAction:(WebDragDestinationAction)action forDraggingInfo:(id < NSDraggingInfo >)draggingInfo

and use it to catch the drops of elements on my WebView. When I detect a file being dragged from outside my app, and containing a picture, I build in this method the img DOM element and add it to my document.

This works fine, but as the method's name implies, I am only informed that the drag will happen, and I have no control over it.

As the Finder always does file drag operation, what normally happens when dropping a file on a WebView in editing mode is the webview displays the path of the file.

I end up having the file path string added to my webview, and the image too, but I would like to prevent the text from being added.

Is there any way to configure this without subclassing webview?

I tried it and while it works, it breaks plenty of other things like caret moving for the drop and such.

like image 909
Olivier Pallière Avatar asked Oct 05 '12 08:10

Olivier Pallière


2 Answers

Answering this myself for a change!

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{

    if ([sender draggingSource] == nil)
    {

        NSPasteboard *pboard = [sender draggingPasteboard];

        if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
            NSURL* fileURL;
            fileURL=[NSURL URLFromPasteboard: [sender draggingPasteboard]];

            NSArray *dragTypes = [NSArray arrayWithObject:NSFileContentsPboardType];
            [[sender draggingPasteboard] declareTypes:dragTypes owner:nil];

            NSImage *content = [[NSImage alloc] initWithContentsOfURL:fileURL];
            [[sender draggingPasteboard] setData:[content TIFFRepresentation] forType:NSPasteboardTypeTIFF];
        }
    }

    return [super performDragOperation:sender];


}

Actually, what I did was indeed to subclass the WebView and intercept the performDragOperation to change the content of the dragging pasteboard, if the dragging source is outside of my app and doesn't contain already an image but only a filename.

like image 165
Olivier Pallière Avatar answered Oct 18 '22 13:10

Olivier Pallière


I ran into the same issue.

What I found is that subclassing the view is the best place for this to insert the image data into the pasteboard. Here is how I am doing it for multiple files:

- (BOOL) performDragOperation:(id<NSDraggingInfo>)sender {

    if ( [sender draggingSource] == nil ) {

        NSPasteboard *pboard = [sender draggingPasteboard];

        NSArray *classes = @[ [NSURL class] ];
        NSDictionary *options = @{ NSPasteboardURLReadingFileURLsOnlyKey: [NSNumber numberWithBool:YES],
                                   NSPasteboardURLReadingContentsConformToTypesKey: [NSImage imageTypes] };

        NSArray *fileURLs = [pboard readObjectsForClasses:classes options:options];

        if ( fileURLs ) {

            NSMutableArray *images = [NSMutableArray arrayWithCapacity:[fileURLs count]];

            for ( NSURL *fileURL in fileURLs )
                [images addObject:[[NSImage alloc] initWithContentsOfURL:fileURL]];

            [pboard declareTypes:[NSImage imageTypes] owner:nil];
            [pboard clearContents]; [pboard writeObjects:images];           
        }

    } return [super performDragOperation:sender];
}

What I noticed is the following sequence:
1. WebView captures drag operation.
2. Internal WebCore created document fragment
3. Node is inserted into a DOMRange
4. Editing Delegate is called
5. Lastly UI Delegate is called where it is too late to do anything

Also, I suggest setting the following via the UI Delegate:

- (NSUInteger) webView:(WebView *)webView dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo {

    return WebDragDestinationActionEdit;
}

Ok, now the ISSUE I am running into and I really hope you might have an answer for me. When I select one file no problem. When I select multiple files, I get them and add all of them into the pasteboard properly. Even when I get to (5) for the UIDelegate and inspect the draggingPasteboard for its count I get what is expected. But unfortunately the document fragment is only being created once and likewise only one node gets inserted.

Any ideas how to get multiple fragments to be created so that they can all be inserted?

Thank you in advance.

like image 25
Arvin Avatar answered Oct 18 '22 13:10

Arvin