Changeset 21437 in webkit


Ignore:
Timestamp:
May 12, 2007 10:15:05 PM (17 years ago)
Author:
oliver
Message:

2007-05-12 Oliver Hunt <oliver@apple.com>

LayoutTests:

Reviewed by Hyatt.


Add test to verify files can be dragged to <input type="file">

  • fast/forms/dragging-to-file-input-expected.txt: Added.
  • fast/forms/dragging-to-file-input.html: Added.

WebCore:

Reviewed by Hyatt.

<rdar://problem/4728842> Can't drag-and-drop files onto <input type="file">


This patch allows a file to be dropped on to a file input field. There
are a few changes for data handling and a few to allow the data to be
threaded to the appropriate places.

  • page/DragController.cpp: (WebCore::asFileInput):

When dropping a file onto a file input we may mouse over either
the element itself, or the contained button element. This method
returns the base element for the file input in either of these
cases.

(WebCore::DragController::tryDocumentDrag):

Don't try to set the drag caret to a file input.

(WebCore::DragController::concludeDrag):

Handle dropping onto a file input element.

(WebCore::DragController::canProcessDrag):

We can now process a file being dragged onto a file input element.


  • platform/DragData.h:

New accessors


  • platform/gdk/DragDataGdk.cpp: (WebCore::DragData::containsFiles): (WebCore::DragData::asFilenames):

Link stubs.


  • platform/mac/DragDataMac.mm: (WebCore::DragData::containsFiles): (WebCore::DragData::asFilenames):

Implement new accessors

(WebCore::DragData::containsCompatibleContent):

Update containsCompatibleContent to allow standalone files.


  • platform/qt/DragDataQt.cpp: (WebCore::DragData::containsFiles): (WebCore::DragData::asFilenames):

Link stubs


  • rendering/RenderFileUploadControl.cpp: (WebCore::RenderFileUploadControl::receiveDroppedFile):
  • rendering/RenderFileUploadControl.h:

For security reasons we don't have an api to allow us to set
a value directly on a file input -- attempts to do so are
blocked. By adding a method to set the target through the
render we bypass such restrictions, and ensure the renderer
is updated correctly.

WebKitTools:

Reviewed by Hyatt.


Add new api to DRT to allow us to test a file being dragged
onto <input type="file">

  • DumpRenderTree/DumpRenderTree.h:
  • DumpRenderTree/DumpRenderTree.m: (+[LayoutTestController isSelectorExcludedFromWebScript:]): (-[LayoutTestController addFileToPasteboardOnDrag]): (runTest):
  • DumpRenderTree/UIDelegate.m: (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r21436 r21437  
     12007-05-12  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Hyatt.
     4       
     5        Add test to verify files can be dragged to <input type="file">
     6
     7        * fast/forms/dragging-to-file-input-expected.txt: Added.
     8        * fast/forms/dragging-to-file-input.html: Added.
     9
    1102007-05-12  Mitz Pettel  <mitz@webkit.org>
    211
  • trunk/WebCore/ChangeLog

    r21436 r21437  
     12007-05-12  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Hyatt.
     4
     5        <rdar://problem/4728842> Can't drag-and-drop files onto <input type="file">
     6       
     7        This patch allows a file to be dropped on to a file input field.  There
     8        are a few changes for data handling and a  few to allow the data to be
     9        threaded to the appropriate places.
     10
     11        * page/DragController.cpp:
     12        (WebCore::asFileInput):
     13           When dropping a file onto a file input we may mouse over either
     14           the element itself, or the contained button element.  This method
     15           returns the base element for the file input in either of these
     16           cases.
     17        (WebCore::DragController::tryDocumentDrag):
     18           Don't try to set the drag caret to a file input.
     19        (WebCore::DragController::concludeDrag):
     20           Handle dropping onto a file input element.
     21        (WebCore::DragController::canProcessDrag):
     22           We can now process a file being dragged onto a file input element.
     23           
     24        * platform/DragData.h:
     25           New accessors
     26           
     27        * platform/gdk/DragDataGdk.cpp:
     28        (WebCore::DragData::containsFiles):
     29        (WebCore::DragData::asFilenames):
     30           Link stubs.
     31           
     32        * platform/mac/DragDataMac.mm:
     33        (WebCore::DragData::containsFiles):
     34        (WebCore::DragData::asFilenames):
     35           Implement new accessors
     36        (WebCore::DragData::containsCompatibleContent):
     37           Update containsCompatibleContent to allow standalone files.
     38         
     39        * platform/qt/DragDataQt.cpp:
     40        (WebCore::DragData::containsFiles):
     41        (WebCore::DragData::asFilenames):
     42           Link stubs
     43                     
     44        * rendering/RenderFileUploadControl.cpp:
     45        (WebCore::RenderFileUploadControl::receiveDroppedFile):
     46        * rendering/RenderFileUploadControl.h:
     47           For security reasons we don't have an api to allow us to set
     48           a value directly on a file input -- attempts to do so are
     49           blocked.  By adding a method to set the target through the
     50           render we bypass such restrictions, and ensure the renderer
     51           is updated correctly.
     52
    1532007-05-12  Mitz Pettel  <mitz@webkit.org>
    254
  • trunk/WebCore/page/DragController.cpp

    r21387 r21437  
    4545#include "FrameView.h"
    4646#include "HTMLAnchorElement.h"
     47#include "HTMLInputElement.h"
     48#include "HTMLNames.h"
    4749#include "Image.h"
    4850#include "markup.h"
     
    5153#include "Page.h"
    5254#include "PlugInInfoStore.h"
     55#include "RenderFileUploadControl.h"
    5356#include "RenderImage.h"
    5457#include "ReplaceSelectionCommand.h"
     
    249252    return operation;
    250253}
     254
     255static HTMLInputElement* asFileInput(Node* node)
     256{
     257    ASSERT(node);
     258   
     259    // The button for a FILE input is a sub element with no set input type
     260    // In order to get around this problem we assume any non-FILE input element
     261    // is this internal button, and try querying the shadow parent node.
     262    if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE)
     263      node = node->shadowParentNode();
     264   
     265    if (!node || !node->hasTagName(HTMLNames::inputTag))
     266        return 0;
     267   
     268    HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node);
     269    if (inputElem->inputType() == HTMLInputElement::FILE)
     270        return inputElem;
     271   
     272    return 0;
     273}
    251274   
    252275DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask)
     
    272295        IntPoint dragPos = dragData->clientPosition();
    273296        IntPoint point = frameView->windowToContents(dragPos);
    274         Selection dragCaret(visiblePositionForPoint(m_document->frame(), point));
    275         m_page->dragCaretController()->setSelection(dragCaret);
    276297        Element* element = m_document->elementFromPoint(point.x(), point.y());
    277298        ASSERT(element);
    278299        Frame* innerFrame = element->document()->frame();
    279300        ASSERT(innerFrame);
     301        if (!asFileInput(element)) {
     302            Selection dragCaret(visiblePositionForPoint(m_document->frame(), point));
     303            m_page->dragCaretController()->setSelection(dragCaret);
     304        }
     305       
    280306        return dragIsMove(innerFrame->selectionController(), dragData) ? DragOperationMove : DragOperationCopy;
    281307    }
     
    342368        return true;
    343369    }
    344 
     370   
    345371    if (!m_page->dragController()->canProcessDrag(dragData)) {
    346372        m_page->dragCaretController()->clear();
    347373        return false;
     374    }
     375   
     376    if (HTMLInputElement* fileInput = asFileInput(element)) {
     377        if (!dragData->containsFiles())
     378            return false;
     379       
     380        Vector<String> filenames;
     381        dragData->asFilenames(filenames);
     382        if (filenames.isEmpty())
     383            return false;
     384       
     385        // Ugly.  For security none of the API's available to us to set the input value
     386        // on file inputs.  Even forcing a change in HTMLInputElement doesn't work as
     387        // RenderFileUploadControl clears the file when doing updateFromElement()
     388        RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl*>(fileInput->renderer());
     389       
     390        if (!renderer)
     391            return false;
     392       
     393        // Only take the first filename as <input type="file" /> can only accept one
     394        renderer->receiveDroppedFile(filenames[0]);
     395        return true;
    348396    }
    349397
     
    401449
    402450    result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true);
    403     if (!result.innerNonSharedNode() || !result.innerNonSharedNode()->isContentEditable())
    404         return false;
    405 
     451   
     452    if (!result.innerNonSharedNode())
     453        return false;
     454   
     455    if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode()))
     456        return true;
     457       
     458    if (!result.innerNonSharedNode()->isContentEditable())
     459        return false;
     460       
    406461    if (m_didInitiateDrag && m_document == m_dragInitiator && result.isSelected())
    407462        return false;
  • trunk/WebCore/platform/DragData.h

    r21180 r21437  
    3333
    3434#include <wtf/Forward.h>
     35#include <wtf/Vector.h>
    3536
    3637#if PLATFORM(MAC)
     
    8687        String asURL(String* title = 0) const;
    8788        String asPlainText() const;
     89        void asFilenames(Vector<String>&) const;
    8890        Color asColor() const;
    8991        PassRefPtr<DocumentFragment> asFragment(Document*) const;
    9092        bool canSmartReplace() const;
    9193        bool containsColor() const;
    92        
     94        bool containsFiles() const;
    9395    private:
    9496        IntPoint m_clientPosition;
  • trunk/WebCore/platform/gdk/DragDataGdk.cpp

    r19477 r21437  
    4040{
    4141    return false;
     42}
     43
     44bool DragData::containsFiles() const
     45{
     46    return false;
     47}
     48
     49void DragData::asFilenames(Vector<String>& result) const
     50{
    4251}
    4352
  • trunk/WebCore/platform/mac/DragDataMac.mm

    r19832 r21437  
    5656    return [[[m_platformDragData draggingPasteboard] types] containsObject:WebSmartPastePboardType];
    5757}
    58    
     58
    5959bool DragData::containsColor() const
    6060{
    6161    return [[[m_platformDragData draggingPasteboard] types] containsObject:NSColorPboardType];
     62}
     63
     64bool DragData::containsFiles() const
     65{
     66    return [[[m_platformDragData draggingPasteboard] types] containsObject:NSFilenamesPboardType];
     67}
     68
     69void DragData::asFilenames(Vector<String>& result) const
     70{
     71    NSArray *filenames = [[m_platformDragData draggingPasteboard] propertyListForType:NSFilenamesPboardType];
     72    NSEnumerator *fileEnumerator = [filenames objectEnumerator];
     73   
     74    while (NSString *filename = [fileEnumerator nextObject])
     75        result.append(filename);
    6276}
    6377
     
    91105}
    92106
    93 static bool imageExistsAtPaths(NSArray* paths)
    94 {
    95     NSEnumerator *enumerator = [paths objectEnumerator];
    96     NSString *path;
    97    
    98     while ((path = [enumerator nextObject]) != nil)
    99         if (MimeTypeRegistry::isSupportedImageResourceMIMEType(MimeTypeRegistry::getMIMETypeForExtension([path pathExtension])))
    100             return true;
    101    
    102     return false;
    103 }
    104    
    105107bool DragData::containsCompatibleContent() const
    106108{
     
    109111    NSMutableSet *types = [NSMutableSet setWithArray:[pasteboard types]];
    110112    [types intersectSet:[NSSet setWithArray:m_pasteboardHelper->insertablePasteboardTypes()]];
    111     if ([types count] == 0)
    112         return false;
    113     return !([types count] == 1 && [types containsObject:NSFilenamesPboardType] &&
    114         !imageExistsAtPaths([pasteboard propertyListForType:NSFilenamesPboardType]));
     113    return [types count] != 0;
    115114}
    116115   
  • trunk/WebCore/platform/qt/DragDataQt.cpp

    r21180 r21437  
    4949    notImplemented();
    5050    return false;
     51}
     52
     53bool DragData::containsFiles() const
     54{
     55    notImplemented();
     56    return false;
     57}
     58
     59void DragData::asFilenames(Vector<String>& result) const
     60{
    5161}
    5262
  • trunk/WebCore/rendering/RenderFileUploadControl.cpp

    r21093 r21437  
    267267}
    268268
     269void RenderFileUploadControl::receiveDroppedFile(const String& filename)
     270{
     271    m_fileChooser->chooseFile(filename);
     272}
     273
    269274HTMLFileUploadInnerButtonElement::HTMLFileUploadInnerButtonElement(Document* doc, Node* shadowParent)
    270275    : HTMLInputElement(doc)
  • trunk/WebCore/rendering/RenderFileUploadControl.h

    r21079 r21437  
    4848
    4949    void valueChanged();
     50   
     51    void receiveDroppedFile(const String&);
    5052
    5153private:
  • trunk/WebKitTools/ChangeLog

    r21416 r21437  
     12007-05-12  Oliver Hunt  <oliver@apple.com>
     2
     3        Reviewed by Hyatt.
     4       
     5        Add new api to DRT to allow us to test a file being dragged
     6        onto <input type="file">
     7
     8        * DumpRenderTree/DumpRenderTree.h:
     9        * DumpRenderTree/DumpRenderTree.m:
     10        (+[LayoutTestController isSelectorExcludedFromWebScript:]):
     11        (-[LayoutTestController addFileToPasteboardOnDrag]):
     12        (runTest):
     13        * DumpRenderTree/UIDelegate.m:
     14        (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
     15
    1162007-05-11  Holger Hans Peter Freyther  <zecke@selfish.org>
    217
  • trunk/WebKitTools/DumpRenderTree/DumpRenderTree.h

    r20742 r21437  
    4040extern BOOL canOpenWindows;
    4141extern BOOL closeWebViews;
     42extern BOOL addFileToPasteboardOnDrag;
    4243
    4344WebView *createWebView();
  • trunk/WebKitTools/DumpRenderTree/DumpRenderTree.m

    r21413 r21437  
    111111BOOL closeWebViews;
    112112BOOL closeRemainingWindowsWhenComplete = YES;
     113BOOL addFileToPasteboardOnDrag = NO;
    113114
    114115static void runTest(const char *pathOrURL);
     
    10691070            || aSelector == @selector(setCallCloseOnWebViews:)
    10701071            || aSelector == @selector(setCloseRemainingWindowsWhenComplete:)
    1071             || aSelector == @selector(setUseDashboardCompatibilityMode:))
    1072         return NO;
     1072            || aSelector == @selector(setUseDashboardCompatibilityMode:)
     1073            || aSelector == @selector(addFileToPasteboardOnDrag))
     1074            return NO;
    10731075    return YES;
    10741076}
     
    11791181}
    11801182
     1183- (void)addFileToPasteboardOnDrag
     1184{
     1185    addFileToPasteboardOnDrag = YES;
     1186}
     1187
    11811188- (void)addDisallowedURL:(NSString *)urlString
    11821189{
     
    14691476        return;
    14701477    }
    1471 
     1478   
    14721479    CFURLRef URL;
    14731480    if (CFStringHasPrefix(pathOrURLString, CFSTR("http://")))
     
    14991506    canOpenWindows = NO;
    15001507    closeWebViews = YES;
     1508    addFileToPasteboardOnDrag = NO;
    15011509    [[frame webView] _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:NO];
    15021510    testRepaint = testRepaintDefault;
  • trunk/WebKitTools/DumpRenderTree/UIDelegate.m

    r20742 r21437  
    5757{
    5858     assert(!draggingInfo);
     59     if (addFileToPasteboardOnDrag) {
     60         [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
     61         [pboard setPropertyList:[NSArray arrayWithObject:@"DRTFakeFile"] forType:NSFilenamesPboardType];
     62     }
    5963     draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj];
    6064     [EventSendingController replaySavedEvents];
Note: See TracChangeset for help on using the changeset viewer.