| Differences between
and this patch
- a/LayoutTests/ChangeLog +21 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2010-04-06  Kent Tamura  <tkent@chromium.org>
2
3
        Reviewed by NOBODY (OOPS!).
4
5
        Implement interactive validation for forms.
6
        https://bugs.webkit.org/show_bug.cgi?id=34930
7
8
        Add tests for "invalid" event and interactive validation.
9
10
        * fast/forms/checkValidity-cancel-expected.txt: Added.
11
        * fast/forms/checkValidity-cancel.html: Added.
12
        * fast/forms/interactive-validation-cancel-expected.txt: Added.
13
        * fast/forms/interactive-validation-cancel.html: Added.
14
        * fast/forms/interactive-validation-formnovalidate-expected.txt: Added.
15
        * fast/forms/interactive-validation-formnovalidate.html: Added.
16
        * fast/forms/interactive-validation-novalidate-expected.txt: Added.
17
        * fast/forms/interactive-validation-novalidate.html: Added.
18
        * fast/forms/interactive-validation-prevented-expected.txt: Added.
19
        * fast/forms/interactive-validation-prevented.html: Added.
20
        * fast/forms/script-tests/checkValidity-cancel.js: Added.
21
1
2010-04-06  Pavel Feldman  <pfeldman@chromium.org>
22
2010-04-06  Pavel Feldman  <pfeldman@chromium.org>
2
23
3
        Not reviewed: rebaselining Chromium layout test expectations.
24
        Not reviewed: rebaselining Chromium layout test expectations.
- a/LayoutTests/fast/forms/checkValidity-cancel-expected.txt +16 lines
Line 0 a/LayoutTests/fast/forms/checkValidity-cancel-expected.txt_sec1
1
Tests for checkValidity() with invalid evnet canceling
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
"invalid" event is not canceled.
7
PASS input.addEventListener("invalid", nothingListener, false); !input.checkValidity() && invalidFired is true
8
PASS invalidFired = false; !form.checkValidity() && invalidFired is true
9
10
"invalid" event is canceled.
11
PASS input.addEventListener("invalid", cancelListener, false); !input.checkValidity() && invalidFired is true
12
PASS invalidFired = false; form.checkValidity() && invalidFired is true
13
PASS successfullyParsed is true
14
15
TEST COMPLETE
16
- a/LayoutTests/fast/forms/checkValidity-cancel.html +13 lines
Line 0 a/LayoutTests/fast/forms/checkValidity-cancel.html_sec1
1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2
<html>
3
<head>
4
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
5
<script src="../../fast/js/resources/js-test-pre.js"></script>
6
</head>
7
<body>
8
<p id="description"></p>
9
<div id="console"></div>
10
<script src="script-tests/checkValidity-cancel.js"></script>
11
<script src="../../fast/js/resources/js-test-post.js"></script>
12
</body>
13
</html>
- a/LayoutTests/fast/forms/interactive-validation-cancel-expected.txt +9 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-cancel-expected.txt_sec1
1
Test if the form is submitted when an "invalid" evnet for a control is canceled.
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
PASS The form should not be submitted.
7
PASS location.search.indexOf("i0=") != -1 is true
8
TEST COMPLETE
9
 
- a/LayoutTests/fast/forms/interactive-validation-cancel.html +43 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-cancel.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
5
<script src="../../fast/js/resources/js-test-pre.js"></script>
6
</head>
7
<body>
8
<p id="description"></p>
9
<div id="console"></div>
10
<form id=f action="interactive-validation-cancel.html">
11
<input type=hidden name=submitted value="true">
12
<input name=i0 required id="i0">
13
<input type=submit id="s">
14
</form>
15
<script>
16
description('Test if the form is submitted when an "invalid" evnet for a control is canceled.');
17
18
function cancel(event) {
19
    event.preventDefault();
20
}
21
22
function startOrVerify() {
23
    var query = window.location.search;
24
    if (query.indexOf('submitted=true') != -1) {
25
        testPassed('The form should not be submitted.');
26
        shouldBeTrue('location.search.indexOf("i0=") != -1');
27
        debug('TEST COMPLETE');
28
        if (window.layoutTestController)
29
            layoutTestController.notifyDone();
30
    } else {
31
        document.getElementById('i0').addEventListener('invalid', cancel, false);
32
        // HTMLFormElement::submit() skips validation. Use the submit button.
33
        document.getElementById('s').click();
34
        testFailed('The form was not submitted.');
35
    }
36
}
37
38
if (window.layoutTestController)
39
    layoutTestController.waitUntilDone();
40
window.onload = startOrVerify;
41
</script>
42
</body>
43
</html>
- a/LayoutTests/fast/forms/interactive-validation-formnovalidate-expected.txt +9 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-formnovalidate-expected.txt_sec1
1
Test if the form is submitted with a submit button with formnovalidate.
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
PASS The form should not be submitted.
7
PASS location.search.indexOf("i0=") != -1 is true
8
TEST COMPLETE
9
 
- a/LayoutTests/fast/forms/interactive-validation-formnovalidate.html +38 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-formnovalidate.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
5
<script src="../../fast/js/resources/js-test-pre.js"></script>
6
</head>
7
<body>
8
<p id="description"></p>
9
<div id="console"></div>
10
<form id=f action="interactive-validation-formnovalidate.html">
11
<input type=hidden name=submitted value="true">
12
<input name=i0 required id="i0">
13
<input type=submit id="s" formnovalidate>
14
</form>
15
<script>
16
description('Test if the form is submitted with a submit button with formnovalidate.');
17
18
function startOrVerify() {
19
    var query = window.location.search;
20
    if (query.indexOf('submitted=true') != -1) {
21
        testPassed('The form should not be submitted.');
22
        shouldBeTrue('location.search.indexOf("i0=") != -1');
23
        debug('TEST COMPLETE');
24
        if (window.layoutTestController)
25
            layoutTestController.notifyDone();
26
    } else {
27
        // HTMLFormElement::submit() skips validation. Use the submit button.
28
        document.getElementById('s').click();
29
        testFailed('The form was not submitted.');
30
    }
31
}
32
33
if (window.layoutTestController)
34
    layoutTestController.waitUntilDone();
35
window.onload = startOrVerify;
36
</script>
37
</body>
38
</html>
- a/LayoutTests/fast/forms/interactive-validation-novalidate-expected.txt +9 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-novalidate-expected.txt_sec1
1
Test if the form with novalidate is submitted.
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
PASS The form should not be submitted.
7
PASS location.search.indexOf("i0=") != -1 is true
8
TEST COMPLETE
9
 
- a/LayoutTests/fast/forms/interactive-validation-novalidate.html +38 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-novalidate.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
5
<script src="../../fast/js/resources/js-test-pre.js"></script>
6
</head>
7
<body>
8
<p id="description"></p>
9
<div id="console"></div>
10
<form id=f action="interactive-validation-novalidate.html" novalidate>
11
<input type=hidden name=submitted value="true">
12
<input name=i0 required id="i0">
13
<input type=submit id="s">
14
</form>
15
<script>
16
description('Test if the form with novalidate is submitted.');
17
18
function startOrVerify() {
19
    var query = window.location.search;
20
    if (query.indexOf('submitted=true') != -1) {
21
        testPassed('The form should not be submitted.');
22
        shouldBeTrue('location.search.indexOf("i0=") != -1');
23
        debug('TEST COMPLETE');
24
        if (window.layoutTestController)
25
            layoutTestController.notifyDone();
26
    } else {
27
        // HTMLFormElement::submit() skips validation. Use the submit button.
28
        document.getElementById('s').click();
29
        testFailed('The form was not submitted.');
30
    }
31
}
32
33
if (window.layoutTestController)
34
    layoutTestController.waitUntilDone();
35
window.onload = startOrVerify;
36
</script>
37
</body>
38
</html>
- a/LayoutTests/fast/forms/interactive-validation-prevented-expected.txt +9 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-prevented-expected.txt_sec1
1
Test if an invalid control prevents interactive form submission, and the first invalid focusable control gets focus.
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
PASS The form was not submitted
7
PASS document.activeElement is document.getElementById("i2")
8
TEST COMPLETE
9
   
- a/LayoutTests/fast/forms/interactive-validation-prevented.html +43 lines
Line 0 a/LayoutTests/fast/forms/interactive-validation-prevented.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
5
<script src="../../fast/js/resources/js-test-pre.js"></script>
6
</head>
7
<body>
8
<p id="description"></p>
9
<div id="console"></div>
10
<form id=f action="interactive-validation-prevented.html">
11
<input type=hidden name=submitted value=true>
12
<input name=i0 required id=i0 value="abc">
13
<input name=i1 required id=i1 style="display:none">
14
<input name=i2 required id=i2>
15
<input type=submit id=s>
16
</form>
17
<script>
18
description('Test if an invalid control prevents interactive form submission, and the first invalid focusable control gets focus.');
19
20
function startOrVerify() {
21
    var query = window.location.search;
22
    if (query.indexOf('submitted=true') != -1) {
23
        testFailed('The form should not be submitted.');
24
    } else {
25
        // Force to render the form.
26
        document.getElementById("f").offsetWidth;
27
        // HTMLFormElement::submit() skips validation. Use the submit button.
28
        document.getElementById('s').click();
29
        testPassed('The form was not submitted');
30
        shouldBe('document.activeElement', 'document.getElementById("i2")');
31
        debug('TEST COMPLETE');
32
    }
33
34
    if (window.layoutTestController)
35
        layoutTestController.notifyDone();
36
}
37
38
if (window.layoutTestController)
39
    layoutTestController.waitUntilDone();
40
window.onload = startOrVerify;
41
</script>
42
</body>
43
</html>
- a/LayoutTests/fast/forms/script-tests/checkValidity-cancel.js +32 lines
Line 0 a/LayoutTests/fast/forms/script-tests/checkValidity-cancel.js_sec1
1
description('Tests for checkValidity() with invalid evnet canceling');
2
3
var parent = document.createElement('div');
4
document.body.appendChild(parent);
5
parent.innerHTML = '<form><input name=i required></form>';
6
var form = parent.firstChild;
7
var input = form.firstChild;
8
9
debug('"invalid" event is not canceled.');
10
var invalidFired  = false;
11
var nothingListener = {};
12
nothingListener.handleEvent = function(event) {
13
    invalidFired = true;
14
};
15
shouldBeTrue('input.addEventListener("invalid", nothingListener, false); !input.checkValidity() && invalidFired');
16
shouldBeTrue('invalidFired = false; !form.checkValidity() && invalidFired');
17
input.removeEventListener('invalid', nothingListener, false);
18
19
debug('');
20
debug('"invalid" event is canceled.');
21
invalidFired = false;
22
var cancelListener = {};
23
cancelListener.handleEvent = function(event) {
24
    invalidFired = true;
25
    event.preventDefault();
26
};
27
// Even if 'invalid' is canceled, the input.checkValidity() result is still false.
28
shouldBeTrue('input.addEventListener("invalid", cancelListener, false); !input.checkValidity() && invalidFired');
29
// form.checkValidity() should be true.
30
shouldBeTrue('invalidFired = false; form.checkValidity() && invalidFired');
31
32
var successfullyParsed = true;
- a/WebCore/ChangeLog +36 lines
Lines 1-3 a/WebCore/ChangeLog_sec1
1
2010-04-06  Kent Tamura  <tkent@chromium.org>
2
3
        Reviewed by NOBODY (OOPS!).
4
5
        Implement interactive validation for forms.
6
        https://bugs.webkit.org/show_bug.cgi?id=34930
7
8
        - Pass a submit button information to HTMLFormElement::prepareSubmit()
9
        - checkValidity() supports unhandled invalid control list
10
        - prepareSubmit() prevents the submission if neither noValidate
11
          nor formNoValidate is specified, and focuses on the first invalid
12
          control of which "invalid" event is not canceled.
13
14
        Tests: fast/forms/checkValidity-cancel.html
15
               fast/forms/interactive-validation-cancel.html
16
               fast/forms/interactive-validation-formnovalidate.html
17
               fast/forms/interactive-validation-novalidate.html
18
               fast/forms/interactive-validation-prevented.html
19
20
        * html/HTMLButtonElement.cpp:
21
        (WebCore::HTMLButtonElement::defaultEventHandler):
22
          Pass the button instance to prepareSubmit() to check formNoValidate.
23
        * html/HTMLFormControlElement.cpp:
24
        (WebCore::HTMLFormControlElement::checkValidity):
25
          If the control is invalid and the "invalid" is not canceled,
26
          push the control to the specified vector.
27
        * html/HTMLFormControlElement.h:
28
        * html/HTMLFormElement.cpp:
29
        (WebCore::HTMLFormElement::submitClick):
30
        (WebCore::HTMLFormElement::prepareSubmit):
31
        (WebCore::HTMLFormElement::checkValidity):
32
        * html/HTMLFormElement.h:
33
        * html/HTMLInputElement.cpp:
34
        (WebCore::HTMLInputElement::defaultEventHandler):
35
          Pass the button instance to prepareSubmit() to check formNoValidate.
36
1
2010-04-06  Mattias Nissler  <mnissler@chromium.org>
37
2010-04-06  Mattias Nissler  <mnissler@chromium.org>
2
38
3
        Reviewed by Pavel Feldman.
39
        Reviewed by Pavel Feldman.
- a/WebCore/html/HTMLButtonElement.cpp -1 / +1 lines
Lines 99-105 void HTMLButtonElement::defaultEventHandler(Event* evt) a/WebCore/html/HTMLButtonElement.cpp_sec1
99
    if (evt->type() == eventNames().DOMActivateEvent && !disabled()) {
99
    if (evt->type() == eventNames().DOMActivateEvent && !disabled()) {
100
        if (form() && m_type == SUBMIT) {
100
        if (form() && m_type == SUBMIT) {
101
            m_activeSubmit = true;
101
            m_activeSubmit = true;
102
            form()->prepareSubmit(evt);
102
            form()->prepareSubmit(evt, this);
103
            m_activeSubmit = false; // in case we were canceled
103
            m_activeSubmit = false; // in case we were canceled
104
        }
104
        }
105
        if (form() && m_type == RESET)
105
        if (form() && m_type == RESET)
- a/WebCore/html/HTMLFormControlElement.cpp -2 / +4 lines
Lines 331-340 String HTMLFormControlElement::validationMessage() a/WebCore/html/HTMLFormControlElement.cpp_sec1
331
    return validity()->validationMessage();
331
    return validity()->validationMessage();
332
}
332
}
333
333
334
bool HTMLFormControlElement::checkValidity()
334
bool HTMLFormControlElement::checkValidity(Vector<HTMLFormControlElement*>* unhandledInvalidControls)
335
{
335
{
336
    if (willValidate() && !isValidFormControlElement()) {
336
    if (willValidate() && !isValidFormControlElement()) {
337
        dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
337
        bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
338
        if (needsDefaultAction && unhandledInvalidControls)
339
            unhandledInvalidControls->append(this);
338
        return false;
340
        return false;
339
    }
341
    }
340
342
- a/WebCore/html/HTMLFormControlElement.h -1 / +1 lines
Lines 108-114 public: a/WebCore/html/HTMLFormControlElement.h_sec1
108
108
109
    bool willValidate() const;
109
    bool willValidate() const;
110
    String validationMessage();
110
    String validationMessage();
111
    bool checkValidity();
111
    bool checkValidity(Vector<HTMLFormControlElement*>* unhandledInvalidControls = 0);
112
    // This must be called when a validation constraint or control value is changed.
112
    // This must be called when a validation constraint or control value is changed.
113
    void setNeedsValidityCheck();
113
    void setNeedsValidityCheck();
114
    void setCustomValidity(const String&);
114
    void setCustomValidity(const String&);
- a/WebCore/html/HTMLFormElement.cpp -8 / +39 lines
Lines 27-32 a/WebCore/html/HTMLFormElement.cpp_sec1
27
27
28
#include "CSSHelper.h"
28
#include "CSSHelper.h"
29
#include "DOMFormData.h"
29
#include "DOMFormData.h"
30
#include "DOMWindow.h"
30
#include "Document.h"
31
#include "Document.h"
31
#include "Event.h"
32
#include "Event.h"
32
#include "EventNames.h"
33
#include "EventNames.h"
Lines 188-194 void HTMLFormElement::submitClick(Event* event) a/WebCore/html/HTMLFormElement.cpp_sec2
188
        }
189
        }
189
    }
190
    }
190
    if (!submitFound) // submit the form without a submit or image input
191
    if (!submitFound) // submit the form without a submit or image input
191
        prepareSubmit(event);
192
        prepareSubmit(event, 0);
192
}
193
}
193
194
194
TextEncoding HTMLFormElement::dataEncoding() const
195
TextEncoding HTMLFormElement::dataEncoding() const
Lines 219-225 bool HTMLFormElement::isMailtoForm() const a/WebCore/html/HTMLFormElement.cpp_sec3
219
    return protocolIs(m_url, "mailto");
220
    return protocolIs(m_url, "mailto");
220
}
221
}
221
222
222
bool HTMLFormElement::prepareSubmit(Event* event)
223
bool HTMLFormElement::prepareSubmit(Event* event, HTMLFormControlElement* submitElement)
223
{
224
{
224
    Frame* frame = document()->frame();
225
    Frame* frame = document()->frame();
225
    if (m_insubmit || !frame)
226
    if (m_insubmit || !frame)
Lines 228-233 bool HTMLFormElement::prepareSubmit(Event* event) a/WebCore/html/HTMLFormElement.cpp_sec4
228
    m_insubmit = true;
229
    m_insubmit = true;
229
    m_doingsubmit = false;
230
    m_doingsubmit = false;
230
231
232
    // Interactive validation must be done before dispatching the submit event.
233
    if (!noValidate() && (!submitElement || !submitElement->formNoValidate())) {
234
        Vector<HTMLFormControlElement*> unhandledInvalidControls;
235
        // If the form has invalid controls, abort submission.
236
        if (!checkValidity(unhandledInvalidControls)) {
237
            // Focus on the first forcusable control.
238
            for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
239
                HTMLFormControlElement* unhandled = unhandledInvalidControls[i];
240
                if (unhandled->isFocusable()) {
241
                    unhandled->scrollIntoViewIfNeeded(false);
242
                    unhandled->focus();
243
                    break;
244
                }
245
            }
246
            // Warn about all of unforcusable controls.
247
            Frame* frame = document()->frame();
248
            for (unsigned i = 0; frame && i < unhandledInvalidControls.size(); ++i) {
249
                HTMLFormControlElement* unhandled = unhandledInvalidControls[i];
250
                if (unhandled->isFocusable())
251
                    continue;
252
                String message("An invalid form control with name='%name' is not user-editable.");
253
                message.replace("%name", unhandled->name());
254
                frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string());
255
            }
256
            m_insubmit = false;
257
            return false;
258
        }
259
    }
260
231
    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
261
    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
232
        m_doingsubmit = true;
262
        m_doingsubmit = true;
233
263
Lines 541-556 HTMLFormControlElement* HTMLFormElement::defaultButton() const a/WebCore/html/HTMLFormElement.cpp_sec5
541
571
542
bool HTMLFormElement::checkValidity()
572
bool HTMLFormElement::checkValidity()
543
{
573
{
544
    // TODO: Check for unhandled invalid controls, see #27452 for tips.
574
    Vector<HTMLFormControlElement*> unhandled;
575
    return checkValidity(unhandled);
576
}
545
577
546
    bool hasOnlyValidControls = true;
578
bool HTMLFormElement::checkValidity(Vector<HTMLFormControlElement*>& unhandledInvalidControls)
579
{
547
    for (unsigned i = 0; i < formElements.size(); ++i) {
580
    for (unsigned i = 0; i < formElements.size(); ++i) {
548
        HTMLFormControlElement* control = formElements[i];
581
        HTMLFormControlElement* control = formElements[i];
549
        if (!control->checkValidity())
582
        control->checkValidity(&unhandledInvalidControls);
550
            hasOnlyValidControls = false;
551
    }
583
    }
552
584
    return !unhandledInvalidControls.size();
553
    return hasOnlyValidControls;
554
}
585
}
555
586
556
PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias)
587
PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias)
- a/WebCore/html/HTMLFormElement.h -1 / +2 lines
Lines 78-84 public: a/WebCore/html/HTMLFormElement.h_sec1
78
    void registerImgElement(HTMLImageElement*);
78
    void registerImgElement(HTMLImageElement*);
79
    void removeImgElement(HTMLImageElement*);
79
    void removeImgElement(HTMLImageElement*);
80
80
81
    bool prepareSubmit(Event*);
81
    bool prepareSubmit(Event*, HTMLFormControlElement*);
82
    void submit(Frame* javaScriptActiveFrame = 0);
82
    void submit(Frame* javaScriptActiveFrame = 0);
83
    void reset();
83
    void reset();
84
84
Lines 137-142 private: a/WebCore/html/HTMLFormElement.h_sec2
137
    TextEncoding dataEncoding() const;
137
    TextEncoding dataEncoding() const;
138
    PassRefPtr<FormData> createFormData();
138
    PassRefPtr<FormData> createFormData();
139
    unsigned formElementIndex(HTMLFormControlElement*);
139
    unsigned formElementIndex(HTMLFormControlElement*);
140
    bool checkValidity(Vector<HTMLFormControlElement*>&);
140
141
141
    friend class HTMLFormCollection;
142
    friend class HTMLFormCollection;
142
143
- a/WebCore/html/HTMLInputElement.cpp -1 / +1 lines
Lines 2133-2139 void HTMLInputElement::defaultEventHandler(Event* evt) a/WebCore/html/HTMLInputElement.cpp_sec1
2133
                // event (if any) here instead of relying on the variables set above when
2133
                // event (if any) here instead of relying on the variables set above when
2134
                // processing the click event. Even better, appendFormData could pass the
2134
                // processing the click event. Even better, appendFormData could pass the
2135
                // event in, and then we could get rid of m_xPos and m_yPos altogether!
2135
                // event in, and then we could get rid of m_xPos and m_yPos altogether!
2136
                if (!form()->prepareSubmit(evt)) {
2136
                if (!form()->prepareSubmit(evt, this)) {
2137
                    m_xPos = 0;
2137
                    m_xPos = 0;
2138
                    m_yPos = 0;
2138
                    m_yPos = 0;
2139
                }
2139
                }

Return to Bug 34930