Commit 222ce095 authored by morrita@google.com's avatar morrita@google.com

2010-08-13 MORITA Hajime <morrita@google.com>

        Reviewed by Tony Chang.

        https://bugs.webkit.org/show_bug.cgi?id=43778
        Dropping should fire textInput event.

        * editing/pasteboard/drop-text-events-expected.txt: Added.
        * editing/pasteboard/drop-text-events-sideeffect-expected.txt: Added.
        * editing/pasteboard/drop-text-events-sideeffect.html: Added.
        * editing/pasteboard/drop-text-events.html: Added.
        * editing/pasteboard/script-tests/drop-text-events-sideeffect.js: Added.
        * editing/pasteboard/script-tests/drop-text-events.js: Added.
2010-08-13  MORITA Hajime  <morrita@google.com>

        Reviewed by Tony Chang.

        https://bugs.webkit.org/show_bug.cgi?id=43778
        Dropping should fire textInput event

        This change:
        - added TextEvent::m_isDrop to distinguish drop-initiated events.
        - added to dispatch TextEvent from DragController before making a side effect
          and cancel the side effect if the event prevents default

        Tests: editing/pasteboard/drop-text-events-sideeffect.html
               editing/pasteboard/drop-text-events.html

        * dom/TextEvent.cpp:
        (WebCore::TextEvent::createForDrop): Added.
        (WebCore::TextEvent::TextEvent):
        * dom/TextEvent.h:
        (WebCore::TextEvent::isDrop): Added.
        * editing/Editor.cpp:
        (WebCore::Editor::handleTextEvent):
        (WebCore::Editor::findEventTargetFrom): Extracted from findEventTargetFromSelection().
        (WebCore::Editor::findEventTargetFromSelection):
        * editing/Editor.h:
        * page/DragController.cpp:
        (WebCore::DragController::dispatchTextInputEventFor): Added.
        (WebCore::DragController::concludeEditDrag): Added an event dispatch path.
        * page/DragController.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@65395 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 5f641286
2010-08-13 MORITA Hajime <morrita@google.com>
Reviewed by Tony Chang.
https://bugs.webkit.org/show_bug.cgi?id=43778
Dropping should fire textInput event.
* editing/pasteboard/drop-text-events-expected.txt: Added.
* editing/pasteboard/drop-text-events-sideeffect-expected.txt: Added.
* editing/pasteboard/drop-text-events-sideeffect.html: Added.
* editing/pasteboard/drop-text-events.html: Added.
* editing/pasteboard/script-tests/drop-text-events-sideeffect.js: Added.
* editing/pasteboard/script-tests/drop-text-events.js: Added.
2010-08-15 Ariya Hidayat <ariya@sencha.com>
Reviewed by Antonio Gomes.
This tests that Drag drop fires textInput events.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS event.data is 'PlainHello'
PASS testTargetTextarea.value is 'PlainHello'
PASS event.data is 'PlainHello'
PASS testTargetInput.value is 'PlainHello'
PASS event.data is ''
PASS 0 <= testTargetEditable.innerHTML.indexOf('PlainHello') is true
PASS event.data is 'RichHello'
PASS testTargetTextarea.value is 'RichHello'
PASS event.data is 'RichHello'
PASS testTargetInput.value is 'RichHello'
PASS event.data is ''
PASS 0 <= testTargetEditable.innerHTML.indexOf('<b>Rich</b>Hello') is true
PASS textInputCount is proceedingTestCases.length
PASS event.data is 'PlainHello'
PASS testTargetTextarea.value is ''
PASS event.data is 'PlainHello'
PASS testTargetInput.value is ''
PASS event.data is ''
PASS testTargetEditable.innerHTML is 'placeholder'
PASS event.data is 'RichHello'
PASS testTargetTextarea.value is ''
PASS event.data is 'RichHello'
PASS testTargetInput.value is ''
PASS event.data is ''
PASS testTargetEditable.innerHTML is 'placeholder'
PASS textInputCount is cancelingTestCases.length
PASS successfullyParsed is true
TEST COMPLETE
Ensure safety on side-effect on drop-initiated TextEvent.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS testTargetEditable.innerHTML is 'initialValue'
PASS testTargetIFrameDocument.body.innerHTML is 'initialBody'
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
<script src="../../fast/js/resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="script-tests/drop-text-events-sideeffect.js"></script>
<script src="../../fast/js/resources/js-test-post.js"></script>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
<script src="../../fast/js/resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="script-tests/drop-text-events.js"></script>
<script src="../../fast/js/resources/js-test-post.js"></script>
</body>
</html>
description('Ensure safety on side-effect on drop-initiated TextEvent.');
function toStringLiteral(str)
{
return "'" + str + "'";
}
var testSourceRoot = document.createElement("div");
document.body.appendChild(testSourceRoot);
var testTargetRoot = document.createElement("div");
testTargetRoot.innerHTML += "<div><span id='targetEditable' contentEditable>initialValue</span></div>";
testTargetRoot.innerHTML += "<iframe id='targetIFrame' src='data:text/html;charset=utf-8," + encodeURI("<html></html>") + "'></iframe>";
document.body.appendChild(testTargetRoot);
testTargetEditable = document.getElementById("targetEditable");
testTargetIFrame = document.getElementById("targetIFrame");
testTargetIFrameDocument = testTargetIFrame.contentDocument;
testTargetIFrameDocument.body.innerHTML = "initialBody";
testTargetIFrameDocument.designMode = "on";
function handlerRemovingTarget(event)
{
event.target.parentNode.removeChild(event.target);
}
function handlerRemovingIFrame(event)
{
testTargetIFrame.parentNode.removeChild(testTargetIFrame);
}
function dragFrom(element)
{
var x = element.offsetLeft + element.offsetWidth / 2;
var y = element.offsetTop + element.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseDown();
// Makes drag happen
var meaninglessDelta = 10;
eventSender.leapForward(500);
eventSender.mouseMoveTo(x + meaninglessDelta , y + meaninglessDelta);
}
function dropTo(element)
{
var x = element.offsetLeft + element.offsetWidth / 2;
var y = element.offsetTop + element.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseUp();
}
function dragPlainText()
{
var selection = window.getSelection();
testSourceRoot.innerHTML = "<input type='text' value='PlainHello' id='src' />";
var input = document.getElementById("src");
input.focus();
selection.modify("extend", "forward", "line");
dragFrom(input);
}
function dropToTargetEditable()
{
dropTo(testTargetEditable);
}
function dropToTargetIFrame()
{
dropTo(testTargetIFrame);
}
testTargetEditable.addEventListener("textInput", handlerRemovingTarget);
dragPlainText();
dropToTargetEditable();
// detached node shouldn't get dropped value
shouldBe("testTargetEditable.innerHTML", toStringLiteral("initialValue"));
testTargetIFrameDocument.body.addEventListener("textInput", handlerRemovingIFrame);
dragPlainText();
dropToTargetIFrame();
// detached frame shouldn't get dropped value
shouldBe("testTargetIFrameDocument.body.innerHTML", toStringLiteral("initialBody"));
// Hides dataset to make dump clean.
testTargetRoot.style.display = "none";
testSourceRoot.style.display = "none";
var successfullyParsed = true;
\ No newline at end of file
description('This tests that Drag drop fires textInput events.');
function toStringLiteral(str)
{
return "'" + str + "'";
}
var willCancelTextInput = false;
var textInputCount = 0;
var expectedTextEventData = "";
function droppingTextInputHandler(evt)
{
shouldBe("event.data", toStringLiteral(expectedTextEventData));
textInputCount++;
if (willCancelTextInput)
evt.preventDefault();
}
var testSourceRoot = document.createElement("div");
document.body.appendChild(testSourceRoot);
var testTargetRoot = document.createElement("div");
testTargetRoot.innerHTML += "<input type='text' id='targetInput' value=''>";
testTargetRoot.innerHTML += "<div><span id='targetEditable' contentEditable></span></div>";
testTargetRoot.innerHTML += "<textarea id='targetTextarea' ></textarea>";
document.body.appendChild(testTargetRoot);
testTargetEditable = document.getElementById("targetEditable");
testTargetEditable.addEventListener("textInput", droppingTextInputHandler);
testTargetInput = document.getElementById("targetInput");
testTargetInput.addEventListener("textInput", droppingTextInputHandler);
testTargetTextarea = document.getElementById("targetTextarea");
testTargetTextarea.addEventListener("textInput", droppingTextInputHandler);
var selection = window.getSelection();
function clearTargets()
{
testTargetEditable.innerHTML = "placeholder"; // give some text to have an area to drop
testTargetInput.value = "";
testTargetTextarea.value = "";
}
function dragFrom(element)
{
var x = element.offsetLeft + element.offsetWidth / 2;
var y = element.offsetTop + element.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseDown();
// Makes drag happen
var meaninglessDelta = 10;
eventSender.leapForward(500);
eventSender.mouseMoveTo(x + meaninglessDelta , y + meaninglessDelta);
}
function dropTo(element)
{
var x = element.offsetLeft + element.offsetWidth / 2;
var y = element.offsetTop + element.offsetHeight / 2;
eventSender.mouseMoveTo(x, y);
eventSender.mouseUp();
}
function dragPlainText()
{
testSourceRoot.innerHTML = "<input type='text' value='PlainHello' id='src' />";
var input = document.getElementById("src");
input.focus();
selection.modify("extend", "forward", "line");
dragFrom(input);
}
function dragRichText()
{
testSourceRoot.innerHTML = "<div id='src' contentEditable><b>Rich</b>Hello</div>";
var editable = document.getElementById("src");
selection.setBaseAndExtent(editable, 0, editable, 0);
selection.modify("extend", "forward", "line");
dragFrom(editable);
}
function dropToTargetEditable()
{
var editable = testTargetEditable;
dropTo(editable);
}
function targetEditableShouldHave(value)
{
shouldBeTrue("0 <= testTargetEditable.innerHTML.indexOf(" + toStringLiteral(value) + ")");
}
function targetEditableShouldStayAsIs()
{
shouldBe("testTargetEditable.innerHTML", toStringLiteral("placeholder"));
}
function dropToTargetInput()
{
var input = testTargetInput;
dropTo(input);
}
function targetInputShouldHave(value)
{
shouldBe("testTargetInput.value", toStringLiteral(value));
}
function dropToTargetTextarea()
{
var textarea = testTargetTextarea;
dropTo(textarea);
}
function targetTextareaShouldHave(value)
{
shouldBe("testTargetTextarea.value", toStringLiteral(value));
}
var proceedingTestCases = [
[dragPlainText, dropToTargetTextarea, targetTextareaShouldHave, "PlainHello", "PlainHello"],
[dragPlainText, dropToTargetInput, targetInputShouldHave, "PlainHello", "PlainHello"],
[dragPlainText, dropToTargetEditable, targetEditableShouldHave, "PlainHello", ""],
[dragRichText, dropToTargetTextarea, targetTextareaShouldHave, "RichHello", "RichHello"],
[dragRichText, dropToTargetInput, targetInputShouldHave, "RichHello", "RichHello"],
[dragRichText, dropToTargetEditable, targetEditableShouldHave, "<b>Rich</b>Hello", ""],
];
var cancelingTestCases = [
[dragPlainText, dropToTargetTextarea, targetTextareaShouldHave, "", "PlainHello"],
[dragPlainText, dropToTargetInput, targetInputShouldHave, "", "PlainHello"],
[dragPlainText, dropToTargetEditable, targetEditableShouldStayAsIs, "", ""],
[dragRichText, dropToTargetTextarea, targetTextareaShouldHave, "", "RichHello"],
[dragRichText, dropToTargetInput, targetInputShouldHave, "", "RichHello"],
[dragRichText, dropToTargetEditable, targetEditableShouldStayAsIs, "", ""],
];
function runSingleTest(caseData)
{
var drag = caseData[0];
var drop = caseData[1];
var verifyFunction = caseData[2];
var verifyParameter = caseData[3];
expectedTextEventData = caseData[4];
clearTargets();
drag();
drop();
verifyFunction(verifyParameter);
}
eventSender.dragMode = false;
textInputCount = 0;
willCancelTextInput = false;
for (var i = 0; i < proceedingTestCases.length; ++i)
runSingleTest(proceedingTestCases[i]);
shouldBe("textInputCount", "proceedingTestCases.length");
textInputCount = 0;
willCancelTextInput = true;
for (var i = 0; i < cancelingTestCases.length; ++i)
runSingleTest(cancelingTestCases[i]);
shouldBe("textInputCount", "cancelingTestCases.length");
// Hides dataset to make dump clean.
testTargetRoot.style.display = "none";
testSourceRoot.style.display = "none";
var successfullyParsed = true;
2010-08-13 MORITA Hajime <morrita@google.com>
Reviewed by Tony Chang.
https://bugs.webkit.org/show_bug.cgi?id=43778
Dropping should fire textInput event
This change:
- added TextEvent::m_isDrop to distinguish drop-initiated events.
- added to dispatch TextEvent from DragController before making a side effect
and cancel the side effect if the event prevents default
Tests: editing/pasteboard/drop-text-events-sideeffect.html
editing/pasteboard/drop-text-events.html
* dom/TextEvent.cpp:
(WebCore::TextEvent::createForDrop): Added.
(WebCore::TextEvent::TextEvent):
* dom/TextEvent.h:
(WebCore::TextEvent::isDrop): Added.
* editing/Editor.cpp:
(WebCore::Editor::handleTextEvent):
(WebCore::Editor::findEventTargetFrom): Extracted from findEventTargetFromSelection().
(WebCore::Editor::findEventTargetFromSelection):
* editing/Editor.h:
* page/DragController.cpp:
(WebCore::DragController::dispatchTextInputEventFor): Added.
(WebCore::DragController::concludeEditDrag): Added an event dispatch path.
* page/DragController.h:
2010-08-15 Ariya Hidayat <ariya@sencha.com>
Unreviewed, rolling out r65393.
......@@ -60,6 +60,11 @@ PassRefPtr<TextEvent> TextEvent::createForFragmentPaste(PassRefPtr<AbstractView>
return adoptRef(new TextEvent(view, "", data, shouldSmartReplace, shouldMatchStyle));
}
PassRefPtr<TextEvent> TextEvent::createForDrop(PassRefPtr<AbstractView> view, const String& data)
{
return adoptRef(new TextEvent(view, data, TextEvent::InputTypeDrop));
}
TextEvent::TextEvent()
: m_inputType(TextEvent::InputTypeKeyboard)
, m_shouldSmartReplace(false)
......
......@@ -38,7 +38,8 @@ namespace WebCore {
InputTypeKeyboard, // any newline characters in the text are line breaks only, not paragraph separators.
InputTypeLineBreak, // any tab characters in the text are backtabs.
InputTypeBackTab,
InputTypePaste
InputTypePaste,
InputTypeDrop,
};
static InputType selectInputType(bool isLineBreak, bool isBackTab);
......@@ -46,6 +47,7 @@ namespace WebCore {
static PassRefPtr<TextEvent> create(PassRefPtr<AbstractView> view, const String& data, InputType = InputTypeKeyboard);
static PassRefPtr<TextEvent> createForPlainTextPaste(PassRefPtr<AbstractView> view, const String& data, bool shouldSmartReplace);
static PassRefPtr<TextEvent> createForFragmentPaste(PassRefPtr<AbstractView> view, PassRefPtr<DocumentFragment> data, bool shouldSmartReplace, bool shouldMatchStyle);
static PassRefPtr<TextEvent> createForDrop(PassRefPtr<AbstractView> view, const String& data);
virtual ~TextEvent();
......@@ -58,6 +60,7 @@ namespace WebCore {
bool isLineBreak() const { return m_inputType == InputTypeLineBreak; }
bool isBackTab() const { return m_inputType == InputTypeBackTab; }
bool isPaste() const { return m_inputType == InputTypePaste; }
bool isDrop() const { return m_inputType == InputTypeDrop; }
bool shouldSmartReplace() const { return m_shouldSmartReplace; }
bool shouldMatchStyle() const { return m_shouldMatchStyle; }
......@@ -65,9 +68,11 @@ namespace WebCore {
private:
TextEvent();
TextEvent(PassRefPtr<AbstractView>, const String& data, InputType = InputTypeKeyboard);
TextEvent(PassRefPtr<AbstractView>, const String& data, PassRefPtr<DocumentFragment>,
bool shouldSmartReplace, bool shouldMatchStyle);
InputType m_inputType;
String m_data;
......
......@@ -130,6 +130,11 @@ void Editor::handleInputMethodKeydown(KeyboardEvent* event)
bool Editor::handleTextEvent(TextEvent* event)
{
// Default event handling for Drag and Drop will be handled by DragController
// so we leave the event for it.
if (event->isDrop())
return false;
if (event->isPaste()) {
if (event->pastingFragment())
replaceSelectionWithFragment(event->pastingFragment(), false, event->shouldSmartReplace(), event->shouldMatchStyle());
......@@ -762,14 +767,20 @@ bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPoli
return !noDefaultProcessing;
}
Node* Editor::findEventTargetFromSelection() const
Node* Editor::findEventTargetFrom(const VisibleSelection& selection) const
{
Node* target = m_frame->selection()->start().element();
Node* target = selection.start().element();
if (!target)
target = m_frame->document()->body();
if (!target)
return 0;
return target->shadowAncestorNode();
}
Node* Editor::findEventTargetFromSelection() const
{
return findEventTargetFrom(m_frame->selection()->selection());
}
void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
......
......@@ -299,6 +299,7 @@ public:
void pasteAsFragment(PassRefPtr<DocumentFragment>, bool smartReplace, bool matchStyle);
void pasteAsPlainText(const String&, bool smartReplace);
Node* findEventTargetFrom(const VisibleSelection& selection) const;
private:
Frame* m_frame;
OwnPtr<DeleteButtonController> m_deleteButtonController;
......
......@@ -63,6 +63,7 @@
#include "SelectionController.h"
#include "Settings.h"
#include "Text.h"
#include "TextEvent.h"
#include "htmlediting.h"
#include "markup.h"
#include <wtf/CurrentTime.h>
......@@ -363,6 +364,15 @@ static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& dragCaret, R
return !frame->selection()->isNone() && frame->selection()->isContentEditable();
}
bool DragController::dispatchTextInputEventFor(Frame* innerFrame, DragData* dragData)
{
VisibleSelection dragCaret(m_page->dragCaretController()->selection());
String text = dragCaret.isContentRichlyEditable() ? "" : dragData->asPlainText();
Node* target = innerFrame->editor()->findEventTargetFrom(dragCaret);
ExceptionCode ec = 0;
return target->dispatchEvent(TextEvent::createForDrop(innerFrame->domWindow(), text), ec);
}
bool DragController::concludeEditDrag(DragData* dragData)
{
ASSERT(dragData);
......@@ -376,12 +386,13 @@ bool DragController::concludeEditDrag(DragData* dragData)
Frame* innerFrame = element->ownerDocument()->frame();
ASSERT(innerFrame);
if (!dispatchTextInputEventFor(innerFrame, dragData))
return true;
if (dragData->containsColor()) {
Color color = dragData->asColor();
if (!color.isValid())
return false;
if (!innerFrame)
return false;
RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange();
RefPtr<CSSStyleDeclaration> style = m_documentUnderMouse->createCSSStyleDeclaration();
ExceptionCode ec;
......
......@@ -90,6 +90,7 @@ namespace WebCore {
static const float DragImageAlpha;
private:
bool dispatchTextInputEventFor(Frame*, DragData*);
bool canProcessDrag(DragData*);
bool concludeEditDrag(DragData*);
DragOperation dragEnteredOrUpdated(DragData*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment