mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 19:45:12 +00:00
Merge 3b14066bc4
into 629cd3c42a
This commit is contained in:
commit
8edd4a29aa
9 changed files with 292 additions and 10 deletions
|
@ -46,6 +46,168 @@ GC::Ptr<DOM::ShadowRoot> ElementInternals::shadow_root() const
|
|||
return shadow;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/custom-elements.html#dom-elementinternals-setformvalue
|
||||
WebIDL::ExceptionOr<void> ElementInternals::set_form_value(Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>> value, Optional<Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>>> state)
|
||||
{
|
||||
// 1. Let element be this's target element.
|
||||
auto element = m_target_element;
|
||||
|
||||
// 2. If element is not a form-associated custom element, then throw a "NotSupportedError" DOMException.
|
||||
if (!element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
(void)value;
|
||||
(void)state;
|
||||
|
||||
// FIXME: 3. Set target element's submission value to value if value is not a FormData object, or to a clone of value's entry list otherwise.
|
||||
|
||||
// FIXME: 4. If the state argument of the function is omitted, set element's state to its submission value.
|
||||
|
||||
// FIXME: 5. Otherwise, if state is a FormData object, set element's state to a clone of state's entry list.
|
||||
|
||||
// FIXME: 6. Otherwise, set element's state to state.
|
||||
|
||||
dbgln("FIXME: ElementInternals::set_form_value()");
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-elementinternals-form
|
||||
WebIDL::ExceptionOr<GC::Ptr<HTMLFormElement>> ElementInternals::form() const
|
||||
{
|
||||
// Form-associated custom elements don't have form IDL attribute. Instead, their ElementInternals object has a form IDL attribute.
|
||||
// On getting, it must throw a "NotSupportedError" DOMException if the target element is not a form-associated custom element.
|
||||
// Otherwise, it must return the element's form owner, or null if there isn't one.
|
||||
if (!m_target_element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
dbgln("FIXME: ElementInternals::form()");
|
||||
return WebIDL::NotFoundError::create(realm(), "FIXME: ElementInternals::form()"_string);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/custom-elements.html#dom-elementinternals-setvalidity
|
||||
WebIDL::ExceptionOr<void> ElementInternals::set_validity(ValidityStateFlags flags, Optional<String> message, Optional<GC::Ptr<HTMLElement>> anchor)
|
||||
{
|
||||
// 1. Let element be this's target element.
|
||||
auto element = m_target_element;
|
||||
|
||||
// 2. If element is not a form-associated custom element, then throw a "NotSupportedError" DOMException.
|
||||
if (!element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
// 3. If flags contains one or more true values and message is not given or is the empty string, then throw a TypeError.
|
||||
if (!(flags.value_missing || flags.type_mismatch || flags.pattern_mismatch || flags.too_long || flags.too_short
|
||||
|| flags.range_underflow || flags.range_overflow || flags.step_mismatch || flags.bad_input || flags.custom_error)
|
||||
&& (!message.has_value() || message->is_empty()))
|
||||
return WebIDL::SimpleException {
|
||||
WebIDL::SimpleExceptionType::TypeError,
|
||||
"Invalid flag(s) and empty message"sv
|
||||
};
|
||||
|
||||
// FIXME: 4. For each entry flag → value of flags, set element's validity flag with the name flag to value.
|
||||
|
||||
// FIXME: 5. Set element's validation message to the empty string if message is not given or all of element's validity flags are false, or to message otherwise.
|
||||
|
||||
// FIXME: 6. If element's customError validity flag is true, then set element's custom validity error message to element's validation message. Otherwise, set element's custom validity error message to the empty string.
|
||||
|
||||
// FIXME: 7. Set element's validation anchor to null if anchor is not given. Otherwise, if anchor is not a shadow-including descendant of element, then throw a "NotFoundError" DOMException. Otherwise, set element's validation anchor to anchor.
|
||||
if (!anchor.has_value() || !anchor.value().ptr()) {
|
||||
|
||||
} else if (!anchor.value()->is_shadow_including_descendant_of(element)) {
|
||||
return WebIDL::NotFoundError::create(realm(), "Anchor is not a shadow-including descendant of element"_string);
|
||||
} else {
|
||||
}
|
||||
|
||||
dbgln("FIXME: ElementInternals::set_validity()");
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-elementinternals-willvalidate
|
||||
WebIDL::ExceptionOr<bool> ElementInternals::will_validate() const
|
||||
{
|
||||
// The willValidate attribute of ElementInternals interface, on getting, must throw a "NotSupportedError" DOMException if
|
||||
// the target element is not a form-associated custom element. Otherwise, it must return true if the target element is a
|
||||
// candidate for constraint validation, and false otherwise.
|
||||
if (!m_target_element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
dbgln("FIXME: ElementInternals::will_validate()");
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-elementinternals-validity
|
||||
WebIDL::ExceptionOr<GC::Ref<ValidityState const>> ElementInternals::validity() const
|
||||
{
|
||||
// The validity attribute of ElementInternals interface, on getting, must throw a "NotSupportedError" DOMException if
|
||||
// the target element is not a form-associated custom element. Otherwise, it must return a ValidityState object that
|
||||
// represents the validity states of the target element. This object is live.
|
||||
if (!m_target_element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
dbgln("FIXME: ElementInternals::validity()");
|
||||
return WebIDL::NotSupportedError::create(realm(), "FIXME: ElementInternals::validity()"_string);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/custom-elements.html#dom-elementinternals-validationmessage
|
||||
WebIDL::ExceptionOr<String> ElementInternals::validation_message() const
|
||||
{
|
||||
// 1. Let element be this's target element.
|
||||
auto element = m_target_element;
|
||||
|
||||
// 2. If element is not a form-associated custom element, then throw a "NotSupportedError" DOMException.
|
||||
if (!element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
// FIXME: 3. Return element's validation message.
|
||||
|
||||
dbgln("FIXME: ElementInternals::validation_message()");
|
||||
return "FIXME: ElementInternals::validation_message()"_string;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-elementinternals-checkvalidity
|
||||
WebIDL::ExceptionOr<bool> ElementInternals::check_validity() const
|
||||
{
|
||||
// 1. Let element be this ElementInternals's target element.
|
||||
auto element = m_target_element;
|
||||
|
||||
// 2. If element is not a form-associated custom element, then throw a "NotSupportedError" DOMException.
|
||||
if (!element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
// FIXME: 3. Run the check validity steps on element.
|
||||
|
||||
dbgln("FIXME: ElementInternals::check_validity()");
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-elementinternals-reportvalidity
|
||||
WebIDL::ExceptionOr<bool> ElementInternals::report_validity() const
|
||||
{
|
||||
// 1. Let element be this ElementInternals's target element
|
||||
auto element = m_target_element;
|
||||
|
||||
// 2. If element is not a form-associated custom element, then throw a "NotSupportedError" DOMException.
|
||||
if (!element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
// FIXME: 3. Run the report validity steps on element.
|
||||
|
||||
dbgln("FIXME: ElementInternals::report_validity()");
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#dom-elementinternals-labels
|
||||
WebIDL::ExceptionOr<GC::Ptr<DOM::NodeList>> ElementInternals::labels()
|
||||
{
|
||||
// Form-associated custom elements don't have a labels IDL attribute. Instead, their ElementInternals object has a labels IDL attribute.
|
||||
// On getting, it must throw a "NotSupportedError" DOMException if the target element is not a form-associated custom element.
|
||||
// Otherwise, it must return that NodeList object, and that same value must always be returned.
|
||||
if (!m_target_element->form_associated())
|
||||
return WebIDL::NotSupportedError::create(realm(), "Element is not a form-associated custom element"_string);
|
||||
|
||||
dbgln("FIXME: ElementInternals::labels()");
|
||||
return WebIDL::NotSupportedError::create(realm(), "FIXME: ElementInternals::labels()"_string);
|
||||
}
|
||||
|
||||
void ElementInternals::initialize(JS::Realm& realm)
|
||||
{
|
||||
Base::initialize(realm);
|
||||
|
|
|
@ -9,10 +9,27 @@
|
|||
#include <AK/WeakPtr.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/DOM/NodeList.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
#include <LibWeb/HTML/HTMLFormElement.h>
|
||||
#include <LibWeb/HTML/ValidityState.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
struct ValidityStateFlags {
|
||||
bool value_missing = false;
|
||||
bool type_mismatch = false;
|
||||
bool pattern_mismatch = false;
|
||||
bool too_long = false;
|
||||
bool too_short = false;
|
||||
bool range_underflow = false;
|
||||
bool range_overflow = false;
|
||||
bool step_mismatch = false;
|
||||
bool bad_input = false;
|
||||
bool custom_error = false;
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/custom-elements.html#elementinternals
|
||||
class ElementInternals final : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(ElementInternals, Bindings::PlatformObject);
|
||||
|
@ -23,6 +40,19 @@ public:
|
|||
|
||||
GC::Ptr<DOM::ShadowRoot> shadow_root() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_form_value(Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>> value, Optional<Variant<GC::Root<FileAPI::File>, String, GC::Root<XHR::FormData>>> state);
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ptr<HTMLFormElement>> form() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_validity(ValidityStateFlags flags, Optional<String> message, Optional<GC::Ptr<HTMLElement>> anchor);
|
||||
WebIDL::ExceptionOr<bool> will_validate() const;
|
||||
WebIDL::ExceptionOr<GC::Ref<ValidityState const>> validity() const;
|
||||
WebIDL::ExceptionOr<String> validation_message() const;
|
||||
WebIDL::ExceptionOr<bool> check_validity() const;
|
||||
WebIDL::ExceptionOr<bool> report_validity() const;
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ptr<DOM::NodeList>> labels();
|
||||
|
||||
private:
|
||||
explicit ElementInternals(JS::Realm&, HTMLElement& target_element);
|
||||
|
||||
|
|
|
@ -7,21 +7,21 @@ interface ElementInternals {
|
|||
readonly attribute ShadowRoot? shadowRoot;
|
||||
|
||||
// Form-associated custom elements
|
||||
[FIXME] undefined setFormValue((File or USVString or FormData)? value,
|
||||
undefined setFormValue((File or USVString or FormData)? value,
|
||||
optional (File or USVString or FormData)? state);
|
||||
|
||||
[FIXME] readonly attribute HTMLFormElement? form;
|
||||
readonly attribute HTMLFormElement? form;
|
||||
|
||||
[FIXME] undefined setValidity(optional ValidityStateFlags flags = {},
|
||||
undefined setValidity(optional ValidityStateFlags flags = {},
|
||||
optional DOMString message,
|
||||
optional HTMLElement anchor);
|
||||
[FIXME] readonly attribute boolean willValidate;
|
||||
[FIXME] readonly attribute ValidityState validity;
|
||||
[FIXME] readonly attribute DOMString validationMessage;
|
||||
[FIXME] boolean checkValidity();
|
||||
[FIXME] boolean reportValidity();
|
||||
readonly attribute boolean willValidate;
|
||||
readonly attribute ValidityState validity;
|
||||
readonly attribute DOMString validationMessage;
|
||||
boolean checkValidity();
|
||||
boolean reportValidity();
|
||||
|
||||
[FIXME] readonly attribute NodeList labels;
|
||||
readonly attribute NodeList labels;
|
||||
|
||||
// Custom state pseudo-class
|
||||
[FIXME, SameObject] readonly attribute CustomStateSet states;
|
||||
|
|
|
@ -832,6 +832,12 @@ void HTMLElement::click()
|
|||
m_click_in_progress = false;
|
||||
}
|
||||
|
||||
bool HTMLElement::form_associated()
|
||||
{
|
||||
auto definition = document().lookup_custom_element_definition(namespace_uri(), local_name(), is_value());
|
||||
return definition->form_associated();
|
||||
}
|
||||
|
||||
Optional<ARIA::Role> HTMLElement::default_role() const
|
||||
{
|
||||
// https://www.w3.org/TR/html-aria/#el-address
|
||||
|
@ -1022,7 +1028,7 @@ WebIDL::ExceptionOr<GC::Ref<ElementInternals>> HTMLElement::attach_internals()
|
|||
{
|
||||
// 1. If this's is value is not null, then throw a "NotSupportedError" DOMException.
|
||||
if (is_value().has_value())
|
||||
return WebIDL::NotSupportedError::create(realm(), "ElementInternals cannot be attached to a customized build-in element"_string);
|
||||
return WebIDL::NotSupportedError::create(realm(), "ElementInternals cannot be attached to a customized built-in element"_string);
|
||||
|
||||
// 2. Let definition be the result of looking up a custom element definition given this's node document, its namespace, its local name, and null as the is value.
|
||||
auto definition = document().lookup_custom_element_definition(namespace_uri(), local_name(), is_value());
|
||||
|
|
|
@ -151,6 +151,8 @@ public:
|
|||
|
||||
bool is_inert() const { return m_inert; }
|
||||
|
||||
bool form_associated();
|
||||
|
||||
protected:
|
||||
HTMLElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass Form-related operations and attributes should throw NotSupportedErrors for non-form-associated custom elements.
|
|
@ -0,0 +1,7 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 2 tests
|
||||
|
||||
2 Pass
|
||||
Pass ElementInternals.setFormValue(null) clears submission value
|
||||
Pass ElementInternals.setFormValue(undefined) clears submission value
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<body>
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
class NotFormAssociatedElement extends HTMLElement {}
|
||||
customElements.define('my-element1', NotFormAssociatedElement);
|
||||
const element = new NotFormAssociatedElement();
|
||||
const i = element.attachInternals();
|
||||
|
||||
assert_throws_dom('NotSupportedError', () => i.setFormValue(''));
|
||||
assert_throws_dom('NotSupportedError', () => i.form);
|
||||
assert_throws_dom('NotSupportedError', () => i.setValidity({}));
|
||||
assert_throws_dom('NotSupportedError', () => i.willValidate);
|
||||
assert_throws_dom('NotSupportedError', () => i.validity);
|
||||
assert_throws_dom('NotSupportedError', () => i.validationMessage);
|
||||
assert_throws_dom('NotSupportedError', () => i.checkValidity());
|
||||
assert_throws_dom('NotSupportedError', () => i.reportValidity());
|
||||
assert_throws_dom('NotSupportedError', () => i.labels);
|
||||
}, 'Form-related operations and attributes should throw NotSupportedErrors' +
|
||||
' for non-form-associated custom elements.');
|
||||
</script>
|
||||
</body>
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ElementInternals.setFormValue(nullish value) should clear submission value</title>
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/custom-elements.html#dom-elementinternals-setformvalue">
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
customElements.define("test-form-element", class extends HTMLElement {
|
||||
static formAssociated = true;
|
||||
constructor() {
|
||||
super();
|
||||
this.i = this.attachInternals();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form id="form-null">
|
||||
<test-form-element id="input-null" name="input-null"></test-form-element>
|
||||
</form>
|
||||
|
||||
<form id="form-undefined">
|
||||
<test-form-element id="input-undefined" name="input-undefined"></test-form-element>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
test(() => {
|
||||
const input = document.getElementById("input-null");
|
||||
input.i.setFormValue("fail");
|
||||
input.i.setFormValue(null);
|
||||
const formData = new FormData(document.getElementById("form-null"));
|
||||
assert_false(formData.has("input-null"));
|
||||
}, "ElementInternals.setFormValue(null) clears submission value");
|
||||
|
||||
test(() => {
|
||||
const input = document.getElementById("input-undefined");
|
||||
input.i.setFormValue("fail");
|
||||
input.i.setFormValue(undefined);
|
||||
const formData = new FormData(document.getElementById("form-undefined"));
|
||||
assert_false(formData.has("input-undefined"));
|
||||
}, "ElementInternals.setFormValue(undefined) clears submission value");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue