ladybird/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h
Timothy Flynn a17074422e LibWeb: Reset form association when any element with an ID changes
When an element with an ID is added to or removed from the DOM, or if
an ID is added, removed, or changed, then we must reset the form owner
of all form-associated elements who have a form attribute.

We do this in 2 steps, using the DOM document as the messenger to handle
these changes:

1. All form-associated elements with a form attribute are stored on the
   document. If the form attribute is removed, the element is removed
   from that list as well.

2. When a DOM element with an ID undergoes any of the aforementioned
   changes, it notifies the document of the change. The document then
   forwards that change to the stored form-associated elements.
2024-02-03 15:30:16 -07:00

112 lines
5.4 KiB
C++

/*
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/String.h>
#include <AK/WeakPtr.h>
#include <LibWeb/Forward.h>
namespace Web::HTML {
// Form-associated elements should invoke this macro to inject overridden FormAssociatedElement and HTMLElement
// methods as needed. If your class wished to override an HTMLElement method that is overridden here, use the
// following methods instead:
//
// 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); \
} \
\
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 {
public:
HTMLFormElement* form() { return m_form; }
HTMLFormElement const* form() const { return m_form; }
void set_form(HTMLFormElement*);
void element_id_changed(Badge<DOM::Document>);
void element_with_id_was_added_or_removed(Badge<DOM::Document>);
bool enabled() const;
void set_parser_inserted(Badge<HTMLParser>);
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
virtual bool is_listed() const { return false; }
// https://html.spec.whatwg.org/multipage/forms.html#category-submit
virtual bool is_submittable() const { return false; }
// https://html.spec.whatwg.org/multipage/forms.html#category-reset
virtual bool is_resettable() const { return false; }
// https://html.spec.whatwg.org/multipage/forms.html#category-autocapitalize
virtual bool is_auto_capitalize_inheriting() const { return false; }
// https://html.spec.whatwg.org/multipage/forms.html#concept-button
virtual bool is_button() const { return false; }
// https://html.spec.whatwg.org/multipage/forms.html#concept-submit-button
virtual bool is_submit_button() const { return false; }
virtual String value() const { return String {}; }
virtual HTMLElement& form_associated_element_to_html_element() = 0;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-reset-control
virtual void reset_algorithm() {};
protected:
FormAssociatedElement() = default;
virtual ~FormAssociatedElement() = default;
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;
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#parser-inserted-flag
bool m_parser_inserted { false };
void reset_form_owner();
};
}