Changeset 57346 in webkit


Ignore:
Timestamp:
Apr 9, 2010 11:03:06 AM (14 years ago)
Author:
tkent@chromium.org
Message:

Implement interactive validation for forms.
https://bugs.webkit.org/show_bug.cgi?id=34930

Reviewed by Darin Adler.

WebCore:

  • HTMLFormControlElement::checkValidity() supports unhandled invalid control list
  • HTMLFormElement::validateInteractively() called from prepareSubmit() prevents the submission if neither noValidate nor formNoValidate is specified, and focuses on the first invalid control of which "invalid" event is not canceled.

Tests: fast/forms/checkValidity-cancel.html

fast/forms/interactive-validation-cancel.html
fast/forms/interactive-validation-formnovalidate.html
fast/forms/interactive-validation-novalidate.html
fast/forms/interactive-validation-prevented.html
fast/forms/interactive-validation-remove-node-in-handler.html

  • html/HTMLFormControlElement.cpp:

(WebCore::HTMLFormControlElement::checkValidity):

If the control is invalid and the "invalid" is not canceled,
push the control to the specified vector.

  • html/HTMLFormControlElement.h:
  • html/HTMLFormElement.cpp:

(WebCore::HTMLFormElement::validateInteractively):

The main part of the interactive validation.

(WebCore::HTMLFormElement::prepareSubmit):

Calls validateInteractively().

(WebCore::HTMLFormElement::checkValidity):

Uses collectUnhandledInvalidControls().

(WebCore::HTMLFormElement::collectUnhandledInvalidControls):

  • html/HTMLFormElement.h:

LayoutTests:

Add tests for "invalid" event and interactive validation.

  • fast/forms/checkValidity-cancel-expected.txt: Added.
  • fast/forms/checkValidity-cancel.html: Added.
  • fast/forms/interactive-validation-cancel-expected.txt: Added.
  • fast/forms/interactive-validation-cancel.html: Added.
  • fast/forms/interactive-validation-formnovalidate-expected.txt: Added.
  • fast/forms/interactive-validation-formnovalidate.html: Added.
  • fast/forms/interactive-validation-novalidate-expected.txt: Added.
  • fast/forms/interactive-validation-novalidate.html: Added.
  • fast/forms/interactive-validation-prevented-expected.txt: Added.
  • fast/forms/interactive-validation-prevented.html: Added.
  • fast/forms/interactive-validation-remove-node-in-handler-expected.txt: Added.
  • fast/forms/interactive-validation-remove-node-in-handler.html: Added.
  • fast/forms/script-tests/checkValidity-cancel.js: Added.
Location:
trunk
Files:
13 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r57345 r57346  
     12010-04-09  Kent Tamura  <tkent@chromium.org>
     2
     3        Reviewed by Darin Adler.
     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/interactive-validation-remove-node-in-handler-expected.txt: Added.
     21        * fast/forms/interactive-validation-remove-node-in-handler.html: Added.
     22        * fast/forms/script-tests/checkValidity-cancel.js: Added.
     23
    1242010-04-09  Gustavo Noronha Silva  <gns@gnome.org>
    225
  • trunk/WebCore/ChangeLog

    r57344 r57346  
     12010-04-09  Kent Tamura  <tkent@chromium.org>
     2
     3        Reviewed by Darin Adler.
     4
     5        Implement interactive validation for forms.
     6        https://bugs.webkit.org/show_bug.cgi?id=34930
     7
     8        - HTMLFormControlElement::checkValidity() supports unhandled invalid control list
     9        - HTMLFormElement::validateInteractively() called from prepareSubmit()
     10          prevents the submission if neither noValidate nor formNoValidate is
     11          specified, and focuses on the first invalid control of which "invalid"
     12          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               fast/forms/interactive-validation-remove-node-in-handler.html
     20
     21        * html/HTMLFormControlElement.cpp:
     22        (WebCore::HTMLFormControlElement::checkValidity):
     23          If the control is invalid and the "invalid" is not canceled,
     24          push the control to the specified vector.
     25        * html/HTMLFormControlElement.h:
     26        * html/HTMLFormElement.cpp:
     27        (WebCore::HTMLFormElement::validateInteractively):
     28         The main part of the interactive validation.
     29        (WebCore::HTMLFormElement::prepareSubmit):
     30         Calls validateInteractively().
     31        (WebCore::HTMLFormElement::checkValidity):
     32         Uses collectUnhandledInvalidControls().
     33        (WebCore::HTMLFormElement::collectUnhandledInvalidControls):
     34        * html/HTMLFormElement.h:
     35
    1362010-04-09  Sam Weinig  <sam@webkit.org>
    237
  • trunk/WebCore/html/HTMLFormControlElement.cpp

    r57274 r57346  
    330330}
    331331
    332 bool HTMLFormControlElement::checkValidity()
    333 {
    334     if (willValidate() && !isValidFormControlElement()) {
    335         dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
    336         return false;
    337     }
    338 
    339     return true;
     332bool HTMLFormControlElement::checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls)
     333{
     334    if (!willValidate() || isValidFormControlElement())
     335        return true;
     336    // An event handler can deref this object.
     337    RefPtr<HTMLFormControlElement> protector(this);
     338    RefPtr<Document> originalDocument(document());
     339    bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
     340    if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
     341        unhandledInvalidControls->append(this);
     342    return false;
    340343}
    341344
  • trunk/WebCore/html/HTMLFormControlElement.h

    r57274 r57346  
    109109    virtual bool willValidate() const;
    110110    String validationMessage();
    111     bool checkValidity();
     111    bool checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls = 0);
    112112    // This must be called when a validation constraint or control value is changed.
    113113    void setNeedsValidityCheck();
  • trunk/WebCore/html/HTMLFormElement.cpp

    r55821 r57346  
    2828#include "CSSHelper.h"
    2929#include "DOMFormData.h"
     30#include "DOMWindow.h"
    3031#include "Document.h"
    3132#include "Event.h"
     
    220221}
    221222
     223static inline HTMLFormControlElement* submitElementFromEvent(const Event* event)
     224{
     225    Node* targetNode = event->target()->toNode();
     226    if (!targetNode || !targetNode->isElementNode())
     227        return 0;
     228    Element* targetElement = static_cast<Element*>(targetNode);
     229    if (!targetElement->isFormControlElement())
     230        return 0;
     231    return static_cast<HTMLFormControlElement*>(targetElement);
     232}
     233
     234bool HTMLFormElement::validateInteractively(Event* event)
     235{
     236    ASSERT(event);
     237    if (noValidate())
     238        return true;
     239
     240    HTMLFormControlElement* submitElement = submitElementFromEvent(event);
     241    if (submitElement && submitElement->formNoValidate())
     242        return true;
     243
     244    Vector<RefPtr<HTMLFormControlElement> > unhandledInvalidControls;
     245    collectUnhandledInvalidControls(unhandledInvalidControls);
     246    if (unhandledInvalidControls.isEmpty())
     247        return true;
     248    // If the form has invalid controls, abort submission.
     249
     250    RefPtr<HTMLFormElement> protector(this);
     251    // Focus on the first focusable control.
     252    for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
     253        HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get();
     254        if (unhandled->isFocusable() && unhandled->inDocument()) {
     255            RefPtr<Document> originalDocument(unhandled->document());
     256            unhandled->scrollIntoViewIfNeeded(false);
     257            // scrollIntoViewIfNeeded() dispatches events, so the state
     258            // of 'unhandled' might be changed so it's no longer focusable or
     259            // moved to another document.
     260            if (unhandled->isFocusable() && unhandled->inDocument() && originalDocument == unhandled->document()) {
     261                unhandled->focus();
     262                break;
     263            }
     264        }
     265    }
     266    // Warn about all of unfocusable controls.
     267    if (Frame* frame = document()->frame()) {
     268        for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) {
     269            HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get();
     270            if (unhandled->isFocusable() && unhandled->inDocument())
     271                continue;
     272            String message("An invalid form control with name='%name' is not focusable.");
     273            message.replace("%name", unhandled->name());
     274            frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string());
     275        }
     276    }
     277    m_insubmit = false;
     278    return false;
     279}
     280
    222281bool HTMLFormElement::prepareSubmit(Event* event)
    223282{
     
    228287    m_insubmit = true;
    229288    m_doingsubmit = false;
     289
     290    // Interactive validation must be done before dispatching the submit event.
     291    if (!validateInteractively(event))
     292        return false;
    230293
    231294    if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit)
     
    542605bool HTMLFormElement::checkValidity()
    543606{
    544     // TODO: Check for unhandled invalid controls, see #27452 for tips.
    545 
    546     bool hasOnlyValidControls = true;
    547     for (unsigned i = 0; i < formElements.size(); ++i) {
    548         HTMLFormControlElement* control = formElements[i];
    549         if (!control->checkValidity())
    550             hasOnlyValidControls = false;
    551     }
    552 
    553     return hasOnlyValidControls;
     607    Vector<RefPtr<HTMLFormControlElement> > controls;
     608    collectUnhandledInvalidControls(controls);
     609    return controls.isEmpty();
     610}
     611
     612void HTMLFormElement::collectUnhandledInvalidControls(Vector<RefPtr<HTMLFormControlElement> >& unhandledInvalidControls)
     613{
     614    RefPtr<HTMLFormElement> protector(this);
     615    // Copy formElements because event handlers called from
     616    // HTMLFormControlElement::checkValidity() might change formElements.
     617    Vector<RefPtr<HTMLFormControlElement> > elements;
     618    elements.reserveCapacity(formElements.size());
     619    for (unsigned i = 0; i < formElements.size(); ++i)
     620        elements.append(formElements[i]);
     621    for (unsigned i = 0; i < elements.size(); ++i) {
     622        if (elements[i]->form() == this)
     623            elements[i]->checkValidity(&unhandledInvalidControls);
     624    }
    554625}
    555626
  • trunk/WebCore/html/HTMLFormElement.h

    r55821 r57346  
    138138    PassRefPtr<FormData> createFormData();
    139139    unsigned formElementIndex(HTMLFormControlElement*);
     140    // Returns true if the submission should be proceeded.
     141    bool validateInteractively(Event*);
     142    // Validates each of the controls, and stores controls of which 'invalid'
     143    // event was not canceled to the specified vector.
     144    void collectUnhandledInvalidControls(Vector<RefPtr<HTMLFormControlElement> >&);
    140145
    141146    friend class HTMLFormCollection;
Note: See TracChangeset for help on using the changeset viewer.