2011-03-25 Emil A Eklund <eae@chromium.org>
authoreae@chromium.org <eae@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Mar 2011 19:08:27 +0000 (19:08 +0000)
committereae@chromium.org <eae@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Mar 2011 19:08:27 +0000 (19:08 +0000)
        Reviewed by Dimitri Glazkov.

        Text field "onchange" event is triggered if actual value unchanged
        https://bugs.webkit.org/show_bug.cgi?id=36314

        Add tests for text field change events.

        * fast/events/onchange-text-form-field-expected.txt: Added.
        * fast/events/onchange-text-form-field.html: Added.
2011-03-25  Emil A Eklund  <eae@chromium.org>

        Reviewed by Dimitri Glazkov.

        Text field "onchange" event is triggered if actual value unchanged
        https://bugs.webkit.org/show_bug.cgi?id=36314

        Change RenderTextControl::subtreeHasChanged to only return true if the
        subtree has changed since the last event was triggered.

        * html/HTMLFormControlElement.cpp:
        (WebCore::HTMLTextFormControlElement::insertedIntoDocument):
        (WebCore::HTMLTextFormControlElement::dispatchFormControlChangeEvent):
        * html/HTMLFormControlElement.h:
        (WebCore::HTMLTextFormControlElement::setTextAsOfLastFormControlChangeEvent):
        * html/HTMLInputElement.cpp:
        (WebCore::HTMLInputElement::setChecked):
        (WebCore::HTMLInputElement::setValue):
        * html/HTMLTextAreaElement.cpp:
        (WebCore::HTMLTextAreaElement::setValue):
        (WebCore::HTMLTextAreaElement::setNonDirtyValue):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@81978 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/events/onchange-text-form-field-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/onchange-text-form-field.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLFormControlElement.cpp
Source/WebCore/html/HTMLFormControlElement.h
Source/WebCore/html/HTMLInputElement.cpp
Source/WebCore/html/HTMLTextAreaElement.cpp

index 1bb29cd..7ebd1cc 100644 (file)
@@ -1,3 +1,15 @@
+2011-03-25  Emil A Eklund  <eae@chromium.org>
+
+        Reviewed by Dimitri Glazkov.
+
+        Text field "onchange" event is triggered if actual value unchanged
+        https://bugs.webkit.org/show_bug.cgi?id=36314
+
+        Add tests for text field change events.
+
+        * fast/events/onchange-text-form-field-expected.txt: Added.
+        * fast/events/onchange-text-form-field.html: Added.
+
 2011-03-25  Jessie Berlin  <jberlin@apple.com>
 
         Websockets tests sometimes time out on apple-windows-5
diff --git a/LayoutTests/fast/events/onchange-text-form-field-expected.txt b/LayoutTests/fast/events/onchange-text-form-field-expected.txt
new file mode 100644 (file)
index 0000000..6caa63a
--- /dev/null
@@ -0,0 +1,26 @@
+      
+PASS simulateTextEntry(elements[0], '', true); is false
+PASS simulateTextEntry(elements[0], 'fo', true); is true
+PASS simulateTextEntry(elements[0], 'o', false); is true
+PASS simulateTextEntry(elements[0], 'foo', true); is false
+PASS simulateTextEntry(elements[0], 'foo', true); is false
+PASS simulateTextEntry(elements[0], ' ', false); is true
+PASS simulateTextEntry(elements[0], 'foo bar', true); is true
+PASS simulateTextEntry(elements[0], 'foo bar', true); is false
+PASS setTextValue(elements[0], 'foo'); is false
+PASS simulateTextEntry(elements[0], 'foo bar', true); is true
+PASS simulateTextEntry(elements[1], '', true); is true
+PASS simulateTextEntry(elements[1], 'fo', true); is true
+PASS simulateTextEntry(elements[1], 'o', false); is true
+PASS simulateTextEntry(elements[1], 'foo', true); is false
+PASS simulateTextEntry(elements[2], '', true); is false
+PASS simulateTextEntry(elements[2], 'fo', true); is true
+PASS simulateTextEntry(elements[2], 'o', false); is true
+PASS simulateTextEntry(elements[2], 'foo', true); is false
+PASS simulateTextEntry(elements[3], 'foo', true); is false
+PASS simulateTextEntry(elements[3], 'foo', true); is false
+PASS setTextValue(elements[3], ''); is false
+PASS simulateTextEntry(elements[3], 'fo', true); is true
+PASS simulateTextEntry(elements[3], 'o', false); is true
+PASS simulateTextEntry(elements[3], 'foo', true); is false
+
diff --git a/LayoutTests/fast/events/onchange-text-form-field.html b/LayoutTests/fast/events/onchange-text-form-field.html
new file mode 100644 (file)
index 0000000..b2517d1
--- /dev/null
@@ -0,0 +1,81 @@
+<html>
+<head>
+<script src="../js/resources/js-test-pre.js"></script>
+<body>
+    <div id="test">
+        <input type="text">
+        <input type="text"value="foo">
+        <textarea></textarea>
+        <textarea>foo</textarea>
+    </div>
+    <div id="console"></div>
+</body>
+<script>
+
+    function simulateTextEntry(element, text, opt_clear) {
+        if (!window.eventSender)
+            return null;
+            
+        var firedEvent = false;
+        function listener(event) {
+            firedEvent = true;
+        }
+        element.addEventListener('change', listener, false);
+        element.focus();
+        if (opt_clear) {
+            element.select();
+            eventSender.keyDown('delete');
+        }
+        for (var i = 0; i < text.length; i++) {
+            eventSender.keyDown(text.charAt(i));
+        }
+        element.blur();
+        element.removeEventListener('change', listener, false);
+        return firedEvent;
+    }
+
+
+    function setTextValue(element, text) {
+        var firedEvent = false;
+        function listener(event) {
+            firedEvent = true;
+        }
+        element.addEventListener('change', listener, false);
+        element.focus();
+        element.value = text;
+        element.blur();
+        element.removeEventListener('change', listener, false);
+        return firedEvent;
+    }
+
+    var elements = document.getElementById('test').getElementsByTagName('*');
+
+    shouldBe("simulateTextEntry(elements[0], '', true);", "false");
+    shouldBe("simulateTextEntry(elements[0], 'fo', true);", "true");
+    shouldBe("simulateTextEntry(elements[0], 'o', false);", "true");
+    shouldBe("simulateTextEntry(elements[0], 'foo', true); ", "false");
+    shouldBe("simulateTextEntry(elements[0], 'foo', true); ", "false");
+    shouldBe("simulateTextEntry(elements[0], ' ', false); ", "true");
+    shouldBe("simulateTextEntry(elements[0], 'foo bar', true); ", "true");
+    shouldBe("simulateTextEntry(elements[0], 'foo bar', true); ", "false");
+    shouldBe("setTextValue(elements[0], 'foo'); ", "false");
+    shouldBe("simulateTextEntry(elements[0], 'foo bar', true);", "true");
+
+    shouldBe("simulateTextEntry(elements[1], '', true);", "true");
+    shouldBe("simulateTextEntry(elements[1], 'fo', true);", "true");
+    shouldBe("simulateTextEntry(elements[1], 'o', false);", "true");
+    shouldBe("simulateTextEntry(elements[1], 'foo', true); ", "false");
+
+    shouldBe("simulateTextEntry(elements[2], '', true);", "false");
+    shouldBe("simulateTextEntry(elements[2], 'fo', true);", "true");
+    shouldBe("simulateTextEntry(elements[2], 'o', false);", "true");
+    shouldBe("simulateTextEntry(elements[2], 'foo', true); ", "false");
+
+    shouldBe("simulateTextEntry(elements[3], 'foo', true);", "false");
+    shouldBe("simulateTextEntry(elements[3], 'foo', true);", "false");
+    shouldBe("setTextValue(elements[3], ''); ", "false");
+    shouldBe("simulateTextEntry(elements[3], 'fo', true);", "true");
+    shouldBe("simulateTextEntry(elements[3], 'o', false);", "true");
+    shouldBe("simulateTextEntry(elements[3], 'foo', true); ", "false");
+</script>
+</html> 
index 0856eae..7e748e3 100644 (file)
@@ -1,3 +1,25 @@
+2011-03-25  Emil A Eklund  <eae@chromium.org>
+
+        Reviewed by Dimitri Glazkov.
+
+        Text field "onchange" event is triggered if actual value unchanged
+        https://bugs.webkit.org/show_bug.cgi?id=36314
+
+        Change RenderTextControl::subtreeHasChanged to only return true if the
+        subtree has changed since the last event was triggered.
+
+        * html/HTMLFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::insertedIntoDocument):
+        (WebCore::HTMLTextFormControlElement::dispatchFormControlChangeEvent):
+        * html/HTMLFormControlElement.h:
+        (WebCore::HTMLTextFormControlElement::setTextAsOfLastFormControlChangeEvent):
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::setChecked):
+        (WebCore::HTMLInputElement::setValue):
+        * html/HTMLTextAreaElement.cpp:
+        (WebCore::HTMLTextAreaElement::setValue):
+        (WebCore::HTMLTextAreaElement::setNonDirtyValue):
+
 2011-03-25  Brent Fulgham  <bfulgham@webkit.org>
 
         Reviewed by David Hyatt.
index f33c5ba..af061fe 100644 (file)
@@ -547,6 +547,12 @@ HTMLTextFormControlElement::~HTMLTextFormControlElement()
 {
 }
 
+void HTMLTextFormControlElement::insertedIntoDocument()
+{
+    HTMLFormControlElement::insertedIntoDocument();
+    setTextAsOfLastFormControlChangeEvent(value());
+}
+
 void HTMLTextFormControlElement::dispatchFocusEvent()
 {
     if (supportsPlaceholder())
@@ -629,6 +635,15 @@ void HTMLTextFormControlElement::select()
     setSelectionRange(0, numeric_limits<int>::max());
 }
 
+void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
+{
+    if (m_textAsOfLastFormControlChangeEvent != value()) {
+        HTMLElement::dispatchChangeEvents();
+        setTextAsOfLastFormControlChangeEvent(value());
+    }
+    setChangedSinceLastFormControlChangeEvent(false);
+}
+
 void HTMLTextFormControlElement::setSelectionRange(int start, int end)
 {
     WebCore::setSelectionRange(this, start, end);
index 120313d..ede3299 100644 (file)
@@ -194,6 +194,8 @@ public:
 
     virtual ~HTMLTextFormControlElement();
 
+    virtual void insertedIntoDocument();
+
     // The derived class should return true if placeholder processing is needed.
     virtual bool supportsPlaceholder() const = 0;
     String strippedPlaceholder() const;
@@ -207,6 +209,8 @@ public:
     void setSelectionRange(int start, int end);
     PassRefPtr<Range> selection() const;
 
+    virtual void dispatchFormControlChangeEvent();
+
     virtual int maxLength() const = 0;
     virtual String value() const = 0;
 
@@ -216,6 +220,7 @@ protected:
     void updatePlaceholderVisibility(bool);
 
     virtual void parseMappedAttribute(Attribute*);
+    virtual void setTextAsOfLastFormControlChangeEvent(String text) { m_textAsOfLastFormControlChangeEvent = text; }
 
 private:
     virtual void dispatchFocusEvent();
@@ -236,6 +241,8 @@ private:
     virtual void handleBlurEvent() { }
 
     RenderTextControl* textRendererAfterUpdateLayout();
+
+    String m_textAsOfLastFormControlChangeEvent;
 };
 
 } // namespace
index 9b2c433..55e636f 100644 (file)
@@ -790,8 +790,10 @@ void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent)
     // unchecked to match other browsers. DOM is not a useful standard for this
     // because it says only to fire change events at "lose focus" time, which is
     // definitely wrong in practice for these types of elements.
-    if (sendChangeEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged())
+    if (sendChangeEvent && inDocument() && m_inputType->shouldSendChangeEventAfterCheckedChanged()) {
+        setTextAsOfLastFormControlChangeEvent(String());
         dispatchFormControlChangeEvent();
+    }
 }
 
 void HTMLInputElement::setIndeterminate(bool newValue)
@@ -912,6 +914,9 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
             dispatchFormControlChangeEvent();
     }
 
+    if (isText() && (!focused() || !sendChangeEvent))
+        setTextAsOfLastFormControlChangeEvent(value);
+
     InputElement::notifyFormStateChanged(this);
 }
 
index 2cb085c..043281c 100644 (file)
@@ -291,6 +291,7 @@ void HTMLTextAreaElement::setValue(const String& value)
     setValueCommon(value);
     m_isDirty = true;
     setNeedsValidityCheck();
+    setTextAsOfLastFormControlChangeEvent(value);
 }
 
 void HTMLTextAreaElement::setNonDirtyValue(const String& value)
@@ -298,6 +299,7 @@ void HTMLTextAreaElement::setNonDirtyValue(const String& value)
     setValueCommon(value);
     m_isDirty = false;
     setNeedsValidityCheck();
+    setTextAsOfLastFormControlChangeEvent(value);
 }
 
 void HTMLTextAreaElement::setValueCommon(const String& value)