mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:48:12 +00:00
LibWeb: Reset form association when the element's form attribute changes
This commit is contained in:
parent
23fb1209af
commit
960dcf0e56
12 changed files with 75 additions and 40 deletions
|
@ -1,4 +1,4 @@
|
||||||
== Elements and Names ==
|
== Elements and Names ==
|
||||||
formy.length: 12
|
formy.length: 12
|
||||||
elements.length: 12
|
elements.length: 12
|
||||||
elements[0] === form.foo
|
elements[0] === form.foo
|
||||||
|
@ -32,3 +32,9 @@ Can we still use the same name?: true
|
||||||
new hello is goodbye? false
|
new hello is goodbye? false
|
||||||
new hello is old hello? false
|
new hello is old hello? false
|
||||||
new hello is newInput? true
|
new hello is newInput? true
|
||||||
|
== Changing form attribute ==
|
||||||
|
elements in changeForFormAttribute: 0
|
||||||
|
elements in changeForFormAttribute: 1
|
||||||
|
elements in changeForFormAttribute: 0
|
||||||
|
elements in changeForFormAttribute: 1
|
||||||
|
elements in changeForFormAttribute: 0
|
||||||
|
|
|
@ -60,6 +60,9 @@
|
||||||
<input type="text" name="hello">
|
<input type="text" name="hello">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<form id="changeForFormAttribute"></form>
|
||||||
|
<input id="changeForFormAttributeInput" type="text" name="changeForFormAttribute" />
|
||||||
|
|
||||||
<script src="../include.js"></script>
|
<script src="../include.js"></script>
|
||||||
<script>
|
<script>
|
||||||
test(() => {
|
test(() => {
|
||||||
|
@ -117,5 +120,23 @@
|
||||||
println(`new hello is goodbye? ${changy.hello === goodbye}`);
|
println(`new hello is goodbye? ${changy.hello === goodbye}`);
|
||||||
println(`new hello is old hello? ${changy.hello === hello}`);
|
println(`new hello is old hello? ${changy.hello === hello}`);
|
||||||
println(`new hello is newInput? ${changy.hello === newInput}`);
|
println(`new hello is newInput? ${changy.hello === newInput}`);
|
||||||
|
|
||||||
|
println("== Changing form attribute ==");
|
||||||
|
let changeForFormAttribute = document.getElementById("changeForFormAttribute");
|
||||||
|
let changeForFormAttributeInput = document.getElementById("changeForFormAttributeInput");
|
||||||
|
|
||||||
|
println(`elements in changeForFormAttribute: ${changeForFormAttribute.elements.length}`);
|
||||||
|
|
||||||
|
changeForFormAttributeInput.setAttribute("form", "changeForFormAttribute");
|
||||||
|
println(`elements in changeForFormAttribute: ${changeForFormAttribute.elements.length}`);
|
||||||
|
|
||||||
|
changeForFormAttributeInput.setAttribute("form", "hakuna matata");
|
||||||
|
println(`elements in changeForFormAttribute: ${changeForFormAttribute.elements.length}`);
|
||||||
|
|
||||||
|
changeForFormAttributeInput.setAttribute("form", "changeForFormAttribute");
|
||||||
|
println(`elements in changeForFormAttribute: ${changeForFormAttribute.elements.length}`);
|
||||||
|
|
||||||
|
changeForFormAttributeInput.removeAttribute("form");
|
||||||
|
println(`elements in changeForFormAttribute: ${changeForFormAttribute.elements.length}`);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -72,13 +72,22 @@ void FormAssociatedElement::form_node_was_removed()
|
||||||
reset_form_owner();
|
reset_form_owner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#association-of-controls-and-forms:category-listed-3
|
||||||
|
void FormAssociatedElement::form_node_attribute_changed(FlyString const& name, Optional<String> const&)
|
||||||
|
{
|
||||||
|
// When a listed form-associated element's form attribute is set, changed, or removed, then the user agent must
|
||||||
|
// reset the form owner of that element.
|
||||||
|
if (name == HTML::AttributeNames::form) {
|
||||||
|
reset_form_owner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#reset-the-form-owner
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#reset-the-form-owner
|
||||||
void FormAssociatedElement::reset_form_owner()
|
void FormAssociatedElement::reset_form_owner()
|
||||||
{
|
{
|
||||||
auto& html_element = form_associated_element_to_html_element();
|
auto& html_element = form_associated_element_to_html_element();
|
||||||
|
|
||||||
// Although these aren't in the "reset form owner" algorithm, these here as they are triggers for this algorithm:
|
// Although these aren't in the "reset form owner" algorithm, these here as they are triggers for this algorithm:
|
||||||
// FIXME: When a listed form-associated element's form attribute is set, changed, or removed, then the user agent must reset the form owner of that element.
|
|
||||||
// FIXME: When a listed form-associated element has a form attribute and the ID of any of the elements in the tree changes, then the user agent must reset the form owner of that form-associated element.
|
// FIXME: When a listed form-associated element has a form attribute and the ID of any of the elements in the tree changes, then the user agent must reset the form owner of that form-associated element.
|
||||||
// FIXME: When a listed form-associated element has a form attribute and an element with an ID is inserted into or removed from the Document, then the user agent must reset the form owner of that form-associated element.
|
// FIXME: When a listed form-associated element has a form attribute and an element with an ID is inserted into or removed from the Document, then the user agent must reset the form owner of that form-associated element.
|
||||||
|
|
||||||
|
|
|
@ -19,26 +19,33 @@ namespace Web::HTML {
|
||||||
// HTMLElement::inserted() -> Use form_associated_element_was_inserted()
|
// HTMLElement::inserted() -> Use form_associated_element_was_inserted()
|
||||||
// HTMLElement::removed_from() -> Use form_associated_element_was_removed()
|
// HTMLElement::removed_from() -> Use form_associated_element_was_removed()
|
||||||
//
|
//
|
||||||
#define FORM_ASSOCIATED_ELEMENT(ElementBaseClass, ElementClass) \
|
#define FORM_ASSOCIATED_ELEMENT(ElementBaseClass, ElementClass) \
|
||||||
private: \
|
private: \
|
||||||
virtual HTMLElement& form_associated_element_to_html_element() override \
|
virtual HTMLElement& form_associated_element_to_html_element() override \
|
||||||
{ \
|
{ \
|
||||||
static_assert(IsBaseOf<HTMLElement, ElementClass>); \
|
static_assert(IsBaseOf<HTMLElement, ElementClass>); \
|
||||||
return *this; \
|
return *this; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
virtual void inserted() override \
|
virtual void inserted() override \
|
||||||
{ \
|
{ \
|
||||||
ElementBaseClass::inserted(); \
|
ElementBaseClass::inserted(); \
|
||||||
form_node_was_inserted(); \
|
form_node_was_inserted(); \
|
||||||
form_associated_element_was_inserted(); \
|
form_associated_element_was_inserted(); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
virtual void removed_from(DOM::Node* node) override \
|
virtual void removed_from(DOM::Node* node) override \
|
||||||
{ \
|
{ \
|
||||||
ElementBaseClass::removed_from(node); \
|
ElementBaseClass::removed_from(node); \
|
||||||
form_node_was_removed(); \
|
form_node_was_removed(); \
|
||||||
form_associated_element_was_removed(node); \
|
form_associated_element_was_removed(node); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
virtual void attribute_changed(FlyString const& name, Optional<String> const& value) override \
|
||||||
|
{ \
|
||||||
|
ElementBaseClass::attribute_changed(name, value); \
|
||||||
|
form_node_attribute_changed(name, value); \
|
||||||
|
form_associated_element_attribute_changed(name, value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
class FormAssociatedElement {
|
class FormAssociatedElement {
|
||||||
|
@ -83,9 +90,11 @@ protected:
|
||||||
|
|
||||||
virtual void form_associated_element_was_inserted() { }
|
virtual void form_associated_element_was_inserted() { }
|
||||||
virtual void form_associated_element_was_removed(DOM::Node*) { }
|
virtual void form_associated_element_was_removed(DOM::Node*) { }
|
||||||
|
virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&) { }
|
||||||
|
|
||||||
void form_node_was_inserted();
|
void form_node_was_inserted();
|
||||||
void form_node_was_removed();
|
void form_node_was_removed();
|
||||||
|
void form_node_attribute_changed(FlyString const&, Optional<String> const&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WeakPtr<HTMLFormElement> m_form;
|
WeakPtr<HTMLFormElement> m_form;
|
||||||
|
|
|
@ -97,10 +97,8 @@ void HTMLImageElement::apply_presentational_hints(CSS::StyleProperties& style) c
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLImageElement::attribute_changed(FlyString const& name, Optional<String> const& value)
|
void HTMLImageElement::form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& value)
|
||||||
{
|
{
|
||||||
HTMLElement::attribute_changed(name, value);
|
|
||||||
|
|
||||||
if (name == HTML::AttributeNames::crossorigin) {
|
if (name == HTML::AttributeNames::crossorigin) {
|
||||||
m_cors_setting = cors_setting_attribute_from_keyword(value);
|
m_cors_setting = cors_setting_attribute_from_keyword(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class HTMLImageElement final
|
||||||
public:
|
public:
|
||||||
virtual ~HTMLImageElement() override;
|
virtual ~HTMLImageElement() override;
|
||||||
|
|
||||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& value) override;
|
virtual void form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& value) override;
|
||||||
|
|
||||||
String alt() const { return get_attribute_value(HTML::AttributeNames::alt); }
|
String alt() const { return get_attribute_value(HTML::AttributeNames::alt); }
|
||||||
String src() const { return get_attribute_value(HTML::AttributeNames::src); }
|
String src() const { return get_attribute_value(HTML::AttributeNames::src); }
|
||||||
|
|
|
@ -833,9 +833,8 @@ void HTMLInputElement::did_lose_focus()
|
||||||
commit_pending_changes();
|
commit_pending_changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLInputElement::attribute_changed(FlyString const& name, Optional<String> const& value)
|
void HTMLInputElement::form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& value)
|
||||||
{
|
{
|
||||||
HTMLElement::attribute_changed(name, value);
|
|
||||||
if (name == HTML::AttributeNames::checked) {
|
if (name == HTML::AttributeNames::checked) {
|
||||||
if (!value.has_value()) {
|
if (!value.has_value()) {
|
||||||
// When the checked content attribute is removed, if the control does not have dirty checkedness,
|
// When the checked content attribute is removed, if the control does not have dirty checkedness,
|
||||||
|
|
|
@ -126,9 +126,6 @@ public:
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute:the-input-element
|
// https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute:the-input-element
|
||||||
virtual bool is_focusable() const override { return m_type != TypeAttributeState::Hidden; }
|
virtual bool is_focusable() const override { return m_type != TypeAttributeState::Hidden; }
|
||||||
|
|
||||||
// ^HTMLElement
|
|
||||||
virtual void attribute_changed(FlyString const&, Optional<String> const&) override;
|
|
||||||
|
|
||||||
// ^FormAssociatedElement
|
// ^FormAssociatedElement
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
||||||
virtual bool is_listed() const override { return true; }
|
virtual bool is_listed() const override { return true; }
|
||||||
|
@ -152,6 +149,7 @@ public:
|
||||||
|
|
||||||
virtual void form_associated_element_was_inserted() override;
|
virtual void form_associated_element_was_inserted() override;
|
||||||
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
||||||
|
virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&) override;
|
||||||
|
|
||||||
// ^HTMLElement
|
// ^HTMLElement
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
||||||
|
|
|
@ -48,10 +48,8 @@ void HTMLObjectElement::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(m_image_request);
|
visitor.visit(m_image_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLObjectElement::attribute_changed(FlyString const& name, Optional<String> const& value)
|
void HTMLObjectElement::form_associated_element_attribute_changed(FlyString const& name, Optional<String> const&)
|
||||||
{
|
{
|
||||||
NavigableContainer::attribute_changed(name, value);
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element
|
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-object-element
|
||||||
// Whenever one of the following conditions occur:
|
// Whenever one of the following conditions occur:
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -35,7 +35,7 @@ class HTMLObjectElement final
|
||||||
public:
|
public:
|
||||||
virtual ~HTMLObjectElement() override;
|
virtual ~HTMLObjectElement() override;
|
||||||
|
|
||||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& value) override;
|
virtual void form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& value) override;
|
||||||
|
|
||||||
String data() const;
|
String data() const;
|
||||||
void set_data(String const& data) { MUST(set_attribute(HTML::AttributeNames::data, data)); }
|
void set_data(String const& data) { MUST(set_attribute(HTML::AttributeNames::data, data)); }
|
||||||
|
|
|
@ -240,9 +240,8 @@ void HTMLTextAreaElement::children_changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLTextAreaElement::attribute_changed(FlyString const& name, Optional<String> const& value)
|
void HTMLTextAreaElement::form_associated_element_attribute_changed(FlyString const& name, Optional<String> const& value)
|
||||||
{
|
{
|
||||||
HTMLElement::attribute_changed(name, value);
|
|
||||||
if (name == HTML::AttributeNames::placeholder) {
|
if (name == HTML::AttributeNames::placeholder) {
|
||||||
if (m_placeholder_text_node)
|
if (m_placeholder_text_node)
|
||||||
m_placeholder_text_node->set_data(value.value_or(String {}));
|
m_placeholder_text_node->set_data(value.value_or(String {}));
|
||||||
|
|
|
@ -55,9 +55,6 @@ public:
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#category-autocapitalize
|
// https://html.spec.whatwg.org/multipage/forms.html#category-autocapitalize
|
||||||
virtual bool is_auto_capitalize_inheriting() const override { return true; }
|
virtual bool is_auto_capitalize_inheriting() const override { return true; }
|
||||||
|
|
||||||
// ^HTMLElement
|
|
||||||
virtual void attribute_changed(FlyString const&, Optional<String> const&) override;
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
||||||
virtual bool is_labelable() const override { return true; }
|
virtual bool is_labelable() const override { return true; }
|
||||||
|
|
||||||
|
@ -65,6 +62,7 @@ public:
|
||||||
|
|
||||||
virtual void form_associated_element_was_inserted() override;
|
virtual void form_associated_element_was_inserted() override;
|
||||||
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
||||||
|
virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&) override;
|
||||||
|
|
||||||
virtual void children_changed() override;
|
virtual void children_changed() override;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue