mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 20:29:18 +00:00
LibWeb: Implement 'no-validate state' concept
This commit is contained in:
parent
edfae02680
commit
8ca956e6f1
Notes:
github-actions[bot]
2025-07-07 19:15:00 +00:00
Author: https://github.com/edvwib 🔰
Commit: 8ca956e6f1
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4592
Reviewed-by: https://github.com/tcl3
7 changed files with 109 additions and 5 deletions
|
@ -350,6 +350,27 @@ bool FormAssociatedElement::satisfies_its_constraints() const
|
|||
suffering_from_being_missing() || suffering_from_a_type_mismatch() || suffering_from_a_pattern_mismatch() || suffering_from_being_too_long() || suffering_from_being_too_short() || suffering_from_an_underflow() || suffering_from_an_overflow() || suffering_from_a_step_mismatch() || suffering_from_bad_input() || suffering_from_a_custom_error());
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fs-novalidate
|
||||
bool FormAssociatedElement::novalidate_state() const
|
||||
{
|
||||
// The no-validate state of an element is true if the element is a submit button ...
|
||||
if (!is_submit_button())
|
||||
return false;
|
||||
|
||||
// ..., and the element's formnovalidate attribute is present, ...
|
||||
auto const& html_element = form_associated_element_to_html_element();
|
||||
if (html_element.has_attribute(HTML::AttributeNames::formnovalidate))
|
||||
return true;
|
||||
|
||||
// ... or if the element's form owner's novalidate attribute is present, ...
|
||||
auto* form = this->form();
|
||||
if (form && form->has_attribute(HTML::AttributeNames::novalidate))
|
||||
return true;
|
||||
|
||||
// ... and false otherwise.
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#limiting-user-input-length%3A-the-maxlength-attribute%3Asuffering-from-being-too-long
|
||||
bool FormAssociatedElement::suffering_from_being_too_long() const
|
||||
{
|
||||
|
|
|
@ -110,6 +110,9 @@ public:
|
|||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fv-valid
|
||||
bool satisfies_its_constraints() const;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fs-novalidate
|
||||
bool novalidate_state() const;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure/#definitions
|
||||
virtual bool suffering_from_being_missing() const { return false; }
|
||||
virtual bool suffering_from_a_type_mismatch() const { return false; }
|
||||
|
|
|
@ -139,11 +139,20 @@ WebIDL::ExceptionOr<void> HTMLFormElement::submit_form(GC::Ref<HTMLElement> subm
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: 4. If the submitter element's no-validate state is false, then interactively validate the constraints
|
||||
// of form and examine the result. If the result is negative (i.e., the constraint validation concluded
|
||||
// that there were invalid fields and probably informed the user of this), then:
|
||||
// 1. Set form's firing submission events to false.
|
||||
// 2. Return.
|
||||
// 4. If the submitter element's no-validate state is false, then interactively validate the constraints
|
||||
// of form and examine the result. If the result is negative (i.e., the constraint validation concluded
|
||||
// that there were invalid fields and probably informed the user of this), then:
|
||||
auto* form_associated_element = as_if<FormAssociatedElement>(*submitter);
|
||||
if (form_associated_element && !form_associated_element->novalidate_state()) {
|
||||
auto validation_result = interactively_validate_constraints();
|
||||
if (!validation_result) {
|
||||
// 1. Set form's firing submission events to false.
|
||||
m_firing_submission_events = false;
|
||||
|
||||
// 2. Return.
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Let submitterButton be null if submitter is form. Otherwise, let submitterButton be submitter.
|
||||
GC::Ptr<HTMLElement> submitter_button;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass invalid event is only supported for form controls
|
|
@ -0,0 +1,8 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
|
||||
<script src="../../../../resources/testharness.js"></script>
|
||||
<script src="../../../../resources/testharnessreport.js"></script>
|
||||
<script src="./resources/targetted-form.js"></script>
|
||||
<div id=log></div>
|
||||
<script src="../../../../html/semantics/forms/form-submission-0/historical.window.js"></script>
|
|
@ -0,0 +1,19 @@
|
|||
// META: script=./resources/targetted-form.js
|
||||
|
||||
test(t => {
|
||||
const form = populateForm('<input required><input type=submit>');
|
||||
t.add_cleanup(() => {
|
||||
form.previousElementSibling.remove();
|
||||
form.remove();
|
||||
});
|
||||
const submitter = form.querySelector('input[type=submit]');
|
||||
let invalid = form.querySelector('[required]');
|
||||
let targets = [];
|
||||
const listener = e => targets.push(e.target.localName);
|
||||
form.addEventListener("invalid", t.step_func(listener));
|
||||
form.oninvalid = t.step_func(listener);
|
||||
invalid.addEventListener("invalid", t.step_func(listener));
|
||||
invalid.oninvalid = t.step_func(listener);
|
||||
submitter.click();
|
||||
assert_array_equals(targets, ["input", "input"]);
|
||||
}, "invalid event is only supported for form controls");
|
|
@ -0,0 +1,38 @@
|
|||
let frameCounter = 0;
|
||||
|
||||
function populateForm(optionalContentHtml) {
|
||||
if (!optionalContentHtml)
|
||||
optionalContentHtml = '';
|
||||
const frameName = "form-test-target-" + frameCounter++;
|
||||
document.body.insertAdjacentHTML(
|
||||
'afterbegin',
|
||||
`<iframe name="${frameName}"></iframe>` +
|
||||
`<form action="/common/blank.html" target="` +
|
||||
`${frameName}">${optionalContentHtml}</form>`);
|
||||
return document.getElementsByName(frameName)[0].nextSibling;
|
||||
}
|
||||
|
||||
function submitPromise(form, iframe) {
|
||||
return new Promise((resolve, reject) => {
|
||||
iframe.onload = () => resolve(iframe.contentWindow.location.search);
|
||||
iframe.onerror = () => reject(new Error('iframe onerror fired'));
|
||||
form.submit();
|
||||
});
|
||||
}
|
||||
|
||||
function loadPromise(iframe) {
|
||||
return new Promise((resolve, reject) => {
|
||||
iframe.onload = function() {
|
||||
// The initial about:blank load event can be fired before the form navigation occurs.
|
||||
// See https://github.com/whatwg/html/issues/490 for more information.
|
||||
if (iframe.contentWindow.location == "about:blank") { return; }
|
||||
resolve();
|
||||
};
|
||||
iframe.onerror = () => reject(new Error('iframe onerror fired'));
|
||||
});
|
||||
}
|
||||
|
||||
function getParamValue(iframe, paramName) {
|
||||
let params = (new URL(iframe.contentWindow.location)).searchParams;
|
||||
return params.get(paramName);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue