mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 09:04:59 +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
|
||||
elements.length: 12
|
||||
elements[0] === form.foo
|
||||
|
@ -32,3 +32,9 @@ Can we still use the same name?: true
|
|||
new hello is goodbye? false
|
||||
new hello is old hello? false
|
||||
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">
|
||||
</form>
|
||||
|
||||
<form id="changeForFormAttribute"></form>
|
||||
<input id="changeForFormAttributeInput" type="text" name="changeForFormAttribute" />
|
||||
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
|
@ -117,5 +120,23 @@
|
|||
println(`new hello is goodbye? ${changy.hello === goodbye}`);
|
||||
println(`new hello is old hello? ${changy.hello === hello}`);
|
||||
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>
|
||||
|
|
|
@ -72,13 +72,22 @@ void FormAssociatedElement::form_node_was_removed()
|
|||
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
|
||||
void FormAssociatedElement::reset_form_owner()
|
||||
{
|
||||
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:
|
||||
// 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 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::removed_from() -> Use form_associated_element_was_removed()
|
||||
//
|
||||
#define FORM_ASSOCIATED_ELEMENT(ElementBaseClass, ElementClass) \
|
||||
private: \
|
||||
virtual HTMLElement& form_associated_element_to_html_element() override \
|
||||
{ \
|
||||
static_assert(IsBaseOf<HTMLElement, ElementClass>); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
virtual void inserted() override \
|
||||
{ \
|
||||
ElementBaseClass::inserted(); \
|
||||
form_node_was_inserted(); \
|
||||
form_associated_element_was_inserted(); \
|
||||
} \
|
||||
\
|
||||
virtual void removed_from(DOM::Node* node) override \
|
||||
{ \
|
||||
ElementBaseClass::removed_from(node); \
|
||||
form_node_was_removed(); \
|
||||
form_associated_element_was_removed(node); \
|
||||
#define FORM_ASSOCIATED_ELEMENT(ElementBaseClass, ElementClass) \
|
||||
private: \
|
||||
virtual HTMLElement& form_associated_element_to_html_element() override \
|
||||
{ \
|
||||
static_assert(IsBaseOf<HTMLElement, ElementClass>); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
virtual void inserted() override \
|
||||
{ \
|
||||
ElementBaseClass::inserted(); \
|
||||
form_node_was_inserted(); \
|
||||
form_associated_element_was_inserted(); \
|
||||
} \
|
||||
\
|
||||
virtual void removed_from(DOM::Node* node) override \
|
||||
{ \
|
||||
ElementBaseClass::removed_from(node); \
|
||||
form_node_was_removed(); \
|
||||
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 {
|
||||
|
@ -83,9 +90,11 @@ protected:
|
|||
|
||||
virtual void form_associated_element_was_inserted() { }
|
||||
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_removed();
|
||||
void form_node_attribute_changed(FlyString const&, Optional<String> const&);
|
||||
|
||||
private:
|
||||
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) {
|
||||
m_cors_setting = cors_setting_attribute_from_keyword(value);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class HTMLImageElement final
|
|||
public:
|
||||
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 src() const { return get_attribute_value(HTML::AttributeNames::src); }
|
||||
|
|
|
@ -833,9 +833,8 @@ void HTMLInputElement::did_lose_focus()
|
|||
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 (!value.has_value()) {
|
||||
// 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
|
||||
virtual bool is_focusable() const override { return m_type != TypeAttributeState::Hidden; }
|
||||
|
||||
// ^HTMLElement
|
||||
virtual void attribute_changed(FlyString const&, Optional<String> const&) override;
|
||||
|
||||
// ^FormAssociatedElement
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
|
||||
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_removed(DOM::Node*) override;
|
||||
virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&) override;
|
||||
|
||||
// ^HTMLElement
|
||||
// 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);
|
||||
}
|
||||
|
||||
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
|
||||
// Whenever one of the following conditions occur:
|
||||
if (
|
||||
|
|
|
@ -35,7 +35,7 @@ class HTMLObjectElement final
|
|||
public:
|
||||
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;
|
||||
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 (m_placeholder_text_node)
|
||||
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
|
||||
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
|
||||
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_removed(DOM::Node*) override;
|
||||
virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&) override;
|
||||
|
||||
virtual void children_changed() override;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue