Changeset 105396 in webkit


Ignore:
Timestamp:
Jan 19, 2012 2:16:35 AM (12 years ago)
Author:
rniwa@webkit.org
Message:

drop event isn't fired for contentEditable in edit drag
https://bugs.webkit.org/show_bug.cgi?id=57185

Reviewed by Adam Barth.

Source/WebCore:

Dispatch drop and dragend events after edit drag per HTML5 spec:
http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model

There are two major differences between the spec and WebKit's new behavior:

While the spec says we have to insert the dragged contents immediately after dispatching drop event
and delete the source in the default event handler of dragend event, doing so in WebKit is extremely
difficult because of the way we manage the selection. Instead, we continue to delete the source
and insert the dragged contents immediately after the drop event; this behavior matches that of Firefox 9.

When the dragged contents and the destination of the move is in the same text node, ReplaceSelectionCommand
may end up replacing it with a new text node. But this removal causes a problem when EventHandler uses
the node to dispatch dragend event because the node is "orphaned" from its parent at that point. To mitigate
this issue, we update the dragState's m_dragSrc when the node is orphaned by the edit drag. While this behavior
may differ from the spec and other browsers, not delivering dragend to the editing host seems strictly worse than
dispatching it at the slightly wrong target.

Tests: fast/events/moving-text-should-fire-drop-and-dragend-events-2.html

fast/events/moving-text-should-fire-drop-and-dragend-events.html

  • page/DragController.cpp:

(WebCore::DragController::performDrag): Dispatch drop event even when m_isHandlingDrag is true as long
as DragDestinationActionDHTML is an acceptable action.
(WebCore::DragController::concludeEditDrag): Call updateDragStateAfterEditDragIfNeeded after inserting
the dragged contents. This is necessary when ReplaceSelectionCommand or MoveSelectionCommand modifies
the source node while inserting the dragged contents.

  • page/EventHandler.cpp:

(WebCore::EventHandler::performDragAndDrop): Clear the drag state only if drop event's default action
was prevented so that we dispatch dragevent event later.
(WebCore::EventHandler::updateDragStateAfterEditDragIfNeeded): Update dragState's m_dragSrc when the node
is orphaned. See above for the rationale.

  • page/EventHandler.h:

LayoutTests:

Added tests ensure moving text in contenteditable regions fire dragstart, drop, and dragend events.

  • fast/events/moving-text-should-fire-drop-and-dragend-events-2-expected.txt: Added.
  • fast/events/moving-text-should-fire-drop-and-dragend-events-2.html: Added.
  • fast/events/moving-text-should-fire-drop-and-dragend-events-expected.txt: Added.
  • fast/events/moving-text-should-fire-drop-and-dragend-events.html: Added.
Location:
trunk
Files:
4 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r105392 r105396  
     12012-01-19  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        drop event isn't fired for contentEditable in edit drag
     4        https://bugs.webkit.org/show_bug.cgi?id=57185
     5
     6        Reviewed by Adam Barth.
     7
     8        Added tests ensure moving text in contenteditable regions fire dragstart, drop, and dragend events.
     9
     10        * fast/events/moving-text-should-fire-drop-and-dragend-events-2-expected.txt: Added.
     11        * fast/events/moving-text-should-fire-drop-and-dragend-events-2.html: Added.
     12        * fast/events/moving-text-should-fire-drop-and-dragend-events-expected.txt: Added.
     13        * fast/events/moving-text-should-fire-drop-and-dragend-events.html: Added.
     14
    1152012-01-19  Dominic Mazzoni  <dmazzoni@google.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r105395 r105396  
     12012-01-19  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        drop event isn't fired for contentEditable in edit drag
     4        https://bugs.webkit.org/show_bug.cgi?id=57185
     5
     6        Reviewed by Adam Barth.
     7
     8        Dispatch drop and dragend events after edit drag per HTML5 spec:
     9        http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
     10
     11        There are two major differences between the spec and WebKit's new behavior:
     12
     13        While the spec says we have to insert the dragged contents immediately after dispatching drop event
     14        and delete the source in the default event handler of dragend event, doing so in WebKit is extremely
     15        difficult because of the way we manage the selection. Instead, we continue to delete the source
     16        and insert the dragged contents immediately after the drop event; this behavior matches that of Firefox 9.
     17
     18        When the dragged contents and the destination of the move is in the same text node, ReplaceSelectionCommand
     19        may end up replacing it with a new text node. But this removal causes a problem when EventHandler uses
     20        the node to dispatch dragend event because the node is "orphaned" from its parent at that point. To mitigate
     21        this issue, we update the dragState's m_dragSrc when the node is orphaned by the edit drag. While this behavior
     22        may differ from the spec and other browsers, not delivering dragend to the editing host seems strictly worse than
     23        dispatching it at the slightly wrong target.
     24
     25        Tests: fast/events/moving-text-should-fire-drop-and-dragend-events-2.html
     26               fast/events/moving-text-should-fire-drop-and-dragend-events.html
     27
     28        * page/DragController.cpp:
     29        (WebCore::DragController::performDrag): Dispatch drop event even when m_isHandlingDrag is true as long
     30        as DragDestinationActionDHTML is an acceptable action.
     31        (WebCore::DragController::concludeEditDrag): Call updateDragStateAfterEditDragIfNeeded after inserting
     32        the dragged contents. This is necessary when ReplaceSelectionCommand or MoveSelectionCommand modifies
     33        the source node while inserting the dragged contents.
     34        * page/EventHandler.cpp:
     35        (WebCore::EventHandler::performDragAndDrop): Clear the drag state only if drop event's default action
     36        was prevented so that we dispatch dragevent event later.
     37        (WebCore::EventHandler::updateDragStateAfterEditDragIfNeeded): Update dragState's m_dragSrc when the node
     38        is orphaned. See above for the rationale.
     39        * page/EventHandler.h:
     40
    1412012-01-18  Kinuko Yasuda  <kinuko@chromium.org>
    242
  • trunk/Source/WebCore/page/DragController.cpp

    r104552 r105396  
    202202    ASSERT(dragData);
    203203    m_documentUnderMouse = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
    204     if (m_isHandlingDrag) {
    205         ASSERT(m_dragDestinationAction & DragDestinationActionDHTML);
     204    if (m_dragDestinationAction & DragDestinationActionDHTML) {
    206205        m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData);
    207206        RefPtr<Frame> mainFrame = m_page->mainFrame();
     207        bool preventedDefault = false;
    208208        if (mainFrame->view()) {
    209209            // Sending an event can result in the destruction of the view and part.
    210210            RefPtr<Clipboard> clipboard = Clipboard::create(ClipboardReadable, dragData, mainFrame.get());
    211211            clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
    212             mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
    213             clipboard->setAccessPolicy(ClipboardNumb);    // invalidate clipboard here for security
    214         }
    215         m_documentUnderMouse = 0;
    216         return true;
     212            preventedDefault = mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
     213            clipboard->setAccessPolicy(ClipboardNumb); // Invalidate clipboard here for security
     214        }
     215        if (m_isHandlingDrag || preventedDefault) {
     216            m_documentUnderMouse = 0;
     217            return true;
     218        }
    217219    }
    218220
     
    478480    m_page->dragCaretController()->clear();
    479481    RefPtr<Range> range = dragCaret.toNormalizedRange();
     482    RefPtr<Element> rootEditableElement = innerFrame->selection()->rootEditableElement();
    480483
    481484    // For range to be null a WebKit client must have done something bad while
     
    518521        if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
    519522            applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), createFragmentFromText(range.get(), text),  ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting));
     523    }
     524
     525    if (rootEditableElement) {
     526        if (Frame* frame = rootEditableElement->document()->frame())
     527            frame->eventHandler()->updateDragStateAfterEditDragIfNeeded(rootEditableElement.get());
    520528    }
    521529
  • trunk/Source/WebCore/page/EventHandler.cpp

    r105212 r105396  
    19121912}
    19131913
    1914 void EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
     1914bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
    19151915{
    19161916    Frame* targetFrame;
     1917    bool preventedDefault = false;
    19171918    if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
    19181919        if (targetFrame)
    1919             targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
     1920            preventedDefault = targetFrame->eventHandler()->performDragAndDrop(event, clipboard);
    19201921    } else if (m_dragTarget.get())
    1921         dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
    1922     clearDragState();
     1922        preventedDefault = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
     1923    if (preventedDefault)
     1924        clearDragState();
     1925    return preventedDefault;
    19231926}
    19241927
     
    27842787    m_mouseDownMayStartDrag = false;
    27852788}
    2786    
     2789
     2790void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
     2791{
     2792    // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
     2793    if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
     2794        dragState().m_dragSrc = rootEditableElement;
     2795}
     2796
    27872797// returns if we should continue "default processing", i.e., whether eventhandler canceled
    27882798bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
  • trunk/Source/WebCore/page/EventHandler.h

    r104773 r105396  
    128128    bool updateDragAndDrop(const PlatformMouseEvent&, Clipboard*);
    129129    void cancelDragAndDrop(const PlatformMouseEvent&, Clipboard*);
    130     void performDragAndDrop(const PlatformMouseEvent&, Clipboard*);
     130    bool performDragAndDrop(const PlatformMouseEvent&, Clipboard*);
     131    void updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement);
    131132#endif
    132133
Note: See TracChangeset for help on using the changeset viewer.