diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp index c2a3444bf2e..0887c8824e7 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.cpp +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.cpp @@ -226,6 +226,20 @@ WebIDL::ExceptionOr FormAssociatedElement::set_form_action(String const& v return html_element.set_attribute(HTML::AttributeNames::formaction, value); } +// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#check-validity-steps +bool FormAssociatedElement::check_validity_steps() +{ + // 1. If element is a candidate for constraint validation and does not satisfy its constraints + if (is_candidate_for_constraint_validation() && !satisfies_its_constraints()) { + auto& element = form_associated_element_to_html_element(); + // 1. Fire an event named invalid at element, with the cancelable attribute initialized to true + element.dispatch_event(DOM::Event::create(element.realm(), EventNames::invalid, { .cancelable = true })); + // 2. Return false. + return false; + } + return true; +} + // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#candidate-for-constraint-validation bool FormAssociatedElement::is_candidate_for_constraint_validation() const { diff --git a/Libraries/LibWeb/HTML/FormAssociatedElement.h b/Libraries/LibWeb/HTML/FormAssociatedElement.h index 938e809a1e5..6536283174e 100644 --- a/Libraries/LibWeb/HTML/FormAssociatedElement.h +++ b/Libraries/LibWeb/HTML/FormAssociatedElement.h @@ -91,6 +91,9 @@ public: // https://html.spec.whatwg.org/multipage/forms.html#concept-submit-button virtual bool is_submit_button() const { return false; } + // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#check-validity-steps + bool check_validity_steps(); + // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#candidate-for-constraint-validation bool is_candidate_for_constraint_validation() const; diff --git a/Libraries/LibWeb/HTML/HTMLFormElement.cpp b/Libraries/LibWeb/HTML/HTMLFormElement.cpp index 7d17382c896..4452a10107a 100644 --- a/Libraries/LibWeb/HTML/HTMLFormElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLFormElement.cpp @@ -561,11 +561,48 @@ unsigned HTMLFormElement::length() const return elements()->length(); } +// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#statically-validate-the-constraints +HTMLFormElement::StaticValidationResult HTMLFormElement::statically_validate_constraints() +{ + // 1. Let controls be a list of all the submittable elements whose form owner is form, in tree order. + auto controls = get_submittable_elements(); + // 2. Let invalid controls be an initially empty list of elements. + GC::RootVector> invalid_controls(realm().heap()); + // 3. For each element field in controls, in tree order: + for (auto& element : controls) { + auto& field = as(*element); + // 1. If field is not a candidate for constraint validation, then move on to the next element. + if (!field.is_candidate_for_constraint_validation()) + continue; + // 2. Otherwise, if field satisfies its constraints, then move on to the next element. + if (field.satisfies_its_constraints()) + continue; + // 3. Otherwise, add field to invalid controls. + invalid_controls.append(field.form_associated_element_to_html_element()); + } + // 4. If invalid controls is empty, then return a positive result. + if (invalid_controls.is_empty()) + return { true, invalid_controls }; + // 5. Let unhandled invalid controls be an initially empty list of elements. + GC::RootVector> unhandled_invalid_controls(realm().heap()); + // 6. For each element field in invalid controls, if any, in tree order: + for (auto& field : invalid_controls) { + // 1. Let notCanceled be the result of firing an event named invalid at field, with the cancelable attribute + // initialized to true. + auto not_canceled = field->dispatch_event(DOM::Event::create(this->realm(), + EventNames::invalid, { .cancelable = true })); + // 2. If notCanceled is true, then add field to unhandled invalid controls. + if (not_canceled) + unhandled_invalid_controls.append(field); + } + // 7. Return a negative result with the list of elements in the unhandled invalid controls list. + return { false, unhandled_invalid_controls }; +} + // https://html.spec.whatwg.org/multipage/forms.html#dom-form-checkvalidity WebIDL::ExceptionOr HTMLFormElement::check_validity() { - dbgln("(STUBBED) HTMLFormElement::check_validity(). Called on: {}", debug_description()); - return true; + return statically_validate_constraints().result; } // https://html.spec.whatwg.org/multipage/forms.html#dom-form-reportvalidity diff --git a/Libraries/LibWeb/HTML/HTMLFormElement.h b/Libraries/LibWeb/HTML/HTMLFormElement.h index 7795142167e..c24fed3253c 100644 --- a/Libraries/LibWeb/HTML/HTMLFormElement.h +++ b/Libraries/LibWeb/HTML/HTMLFormElement.h @@ -78,6 +78,12 @@ public: GC::Ref elements() const; unsigned length() const; + struct StaticValidationResult { + bool result; + GC::RootVector> unhandled_invalid_controls; + }; + + StaticValidationResult statically_validate_constraints(); WebIDL::ExceptionOr check_validity(); WebIDL::ExceptionOr report_validity();