/src/serenity/Userland/Libraries/LibWeb/HTML/FormAssociatedElement.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2024, Jelle Raaijmakers <jelle@gmta.nl> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <AK/String.h> |
11 | | #include <AK/WeakPtr.h> |
12 | | #include <LibWeb/Bindings/HTMLFormElementPrototype.h> |
13 | | #include <LibWeb/Forward.h> |
14 | | #include <LibWeb/WebIDL/Types.h> |
15 | | |
16 | | namespace Web::HTML { |
17 | | |
18 | | // Form-associated elements should invoke this macro to inject overridden FormAssociatedElement and HTMLElement |
19 | | // methods as needed. If your class wished to override an HTMLElement method that is overridden here, use the |
20 | | // following methods instead: |
21 | | // |
22 | | // HTMLElement::inserted() -> Use form_associated_element_was_inserted() |
23 | | // HTMLElement::removed_from() -> Use form_associated_element_was_removed() |
24 | | // |
25 | | #define FORM_ASSOCIATED_ELEMENT(ElementBaseClass, ElementClass) \ |
26 | | private: \ |
27 | | virtual HTMLElement& form_associated_element_to_html_element() override \ |
28 | 0 | { \ |
29 | 0 | static_assert(IsBaseOf<HTMLElement, ElementClass>); \ |
30 | 0 | return *this; \ |
31 | 0 | } \ Unexecuted instantiation: Web::HTML::HTMLImageElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLButtonElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLFieldSetElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLInputElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLSelectElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLTextAreaElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLObjectElement::form_associated_element_to_html_element() Unexecuted instantiation: Web::HTML::HTMLOutputElement::form_associated_element_to_html_element() |
32 | | \ |
33 | | virtual void inserted() override \ |
34 | 0 | { \ |
35 | 0 | ElementBaseClass::inserted(); \ |
36 | 0 | form_node_was_inserted(); \ |
37 | 0 | form_associated_element_was_inserted(); \ |
38 | 0 | } \ Unexecuted instantiation: Web::HTML::HTMLImageElement::inserted() Unexecuted instantiation: Web::HTML::HTMLButtonElement::inserted() Unexecuted instantiation: Web::HTML::HTMLFieldSetElement::inserted() Unexecuted instantiation: Web::HTML::HTMLInputElement::inserted() Unexecuted instantiation: Web::HTML::HTMLSelectElement::inserted() Unexecuted instantiation: Web::HTML::HTMLTextAreaElement::inserted() Unexecuted instantiation: Web::HTML::HTMLObjectElement::inserted() Unexecuted instantiation: Web::HTML::HTMLOutputElement::inserted() |
39 | | \ |
40 | | virtual void removed_from(DOM::Node* node) override \ |
41 | 0 | { \ |
42 | 0 | ElementBaseClass::removed_from(node); \ |
43 | 0 | form_node_was_removed(); \ |
44 | 0 | form_associated_element_was_removed(node); \ |
45 | 0 | } \ Unexecuted instantiation: Web::HTML::HTMLImageElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLButtonElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLFieldSetElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLInputElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLSelectElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLTextAreaElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLObjectElement::removed_from(Web::DOM::Node*) Unexecuted instantiation: Web::HTML::HTMLOutputElement::removed_from(Web::DOM::Node*) |
46 | | \ |
47 | | virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override \ |
48 | 0 | { \ |
49 | 0 | ElementBaseClass::attribute_changed(name, old_value, value); \ |
50 | 0 | form_node_attribute_changed(name, value); \ |
51 | 0 | form_associated_element_attribute_changed(name, value); \ |
52 | 0 | } Unexecuted instantiation: Web::HTML::HTMLImageElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLButtonElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLFieldSetElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLInputElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLSelectElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLTextAreaElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLObjectElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) Unexecuted instantiation: Web::HTML::HTMLOutputElement::attribute_changed(AK::FlyString const&, AK::Optional<AK::String> const&, AK::Optional<AK::String> const&) |
53 | | |
54 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#selection-direction |
55 | | enum class SelectionDirection { |
56 | | Forward, |
57 | | Backward, |
58 | | None, |
59 | | }; |
60 | | |
61 | | class FormAssociatedElement { |
62 | | public: |
63 | 0 | HTMLFormElement* form() { return m_form; } |
64 | 0 | HTMLFormElement const* form() const { return m_form; } |
65 | | |
66 | | void set_form(HTMLFormElement*); |
67 | | |
68 | | void element_id_changed(Badge<DOM::Document>); |
69 | | void element_with_id_was_added_or_removed(Badge<DOM::Document>); |
70 | | |
71 | | bool enabled() const; |
72 | | |
73 | | void set_parser_inserted(Badge<HTMLParser>); |
74 | | |
75 | | // https://html.spec.whatwg.org/multipage/forms.html#category-listed |
76 | 0 | virtual bool is_listed() const { return false; } |
77 | | |
78 | | // https://html.spec.whatwg.org/multipage/forms.html#category-submit |
79 | 0 | virtual bool is_submittable() const { return false; } |
80 | | |
81 | | // https://html.spec.whatwg.org/multipage/forms.html#category-reset |
82 | 0 | virtual bool is_resettable() const { return false; } |
83 | | |
84 | | // https://html.spec.whatwg.org/multipage/forms.html#category-autocapitalize |
85 | 0 | virtual bool is_auto_capitalize_inheriting() const { return false; } |
86 | | |
87 | | // https://html.spec.whatwg.org/multipage/forms.html#concept-button |
88 | 0 | virtual bool is_button() const { return false; } |
89 | | |
90 | | // https://html.spec.whatwg.org/multipage/forms.html#concept-submit-button |
91 | 0 | virtual bool is_submit_button() const { return false; } |
92 | | |
93 | 0 | virtual String value() const { return String {}; } |
94 | | |
95 | | virtual HTMLElement& form_associated_element_to_html_element() = 0; |
96 | 0 | HTMLElement const& form_associated_element_to_html_element() const { return const_cast<FormAssociatedElement&>(*this).form_associated_element_to_html_element(); } |
97 | | |
98 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-reset-control |
99 | 0 | virtual void reset_algorithm() {}; |
100 | | |
101 | | virtual void clear_algorithm(); |
102 | | |
103 | | String form_action() const; |
104 | | WebIDL::ExceptionOr<void> set_form_action(String const&); |
105 | | |
106 | | protected: |
107 | 0 | FormAssociatedElement() = default; |
108 | 0 | virtual ~FormAssociatedElement() = default; |
109 | | |
110 | 0 | virtual void form_associated_element_was_inserted() { } |
111 | 0 | virtual void form_associated_element_was_removed(DOM::Node*) { } |
112 | 0 | virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&) { } |
113 | | |
114 | | void form_node_was_inserted(); |
115 | | void form_node_was_removed(); |
116 | | void form_node_attribute_changed(FlyString const&, Optional<String> const&); |
117 | | |
118 | | private: |
119 | | void reset_form_owner(); |
120 | | |
121 | | WeakPtr<HTMLFormElement> m_form; |
122 | | |
123 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#parser-inserted-flag |
124 | | bool m_parser_inserted { false }; |
125 | | }; |
126 | | |
127 | | enum class SelectionSource { |
128 | | UI, |
129 | | DOM, |
130 | | }; |
131 | | |
132 | | class FormAssociatedTextControlElement : public FormAssociatedElement { |
133 | | public: |
134 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value |
135 | | virtual String relevant_value() = 0; |
136 | | virtual WebIDL::ExceptionOr<void> set_relevant_value(String const&) = 0; |
137 | | |
138 | | virtual void set_dirty_value_flag(bool flag) = 0; |
139 | | |
140 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-select |
141 | | WebIDL::ExceptionOr<void> select(); |
142 | | |
143 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionstart |
144 | | Optional<WebIDL::UnsignedLong> selection_start() const; |
145 | | WebIDL::ExceptionOr<void> set_selection_start(Optional<WebIDL::UnsignedLong> const&); |
146 | | |
147 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionend |
148 | | Optional<WebIDL::UnsignedLong> selection_end() const; |
149 | | WebIDL::ExceptionOr<void> set_selection_end(Optional<WebIDL::UnsignedLong> const&); |
150 | | |
151 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectiondirection |
152 | | Optional<String> selection_direction() const; |
153 | | void set_selection_direction(Optional<String> direction); |
154 | | WebIDL::ExceptionOr<void> set_selection_direction_binding(Optional<String> direction); |
155 | 0 | SelectionDirection selection_direction_state() const { return m_selection_direction; } |
156 | | |
157 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setrangetext |
158 | | WebIDL::ExceptionOr<void> set_range_text(String const& replacement); |
159 | | WebIDL::ExceptionOr<void> set_range_text(String const& replacement, WebIDL::UnsignedLong start, WebIDL::UnsignedLong end, Bindings::SelectionMode = Bindings::SelectionMode::Preserve); |
160 | | |
161 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setselectionrange |
162 | | void set_the_selection_range(Optional<WebIDL::UnsignedLong> start, Optional<WebIDL::UnsignedLong> end, SelectionDirection direction = SelectionDirection::None, SelectionSource source = SelectionSource::DOM); |
163 | | |
164 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-setselectionrange |
165 | | WebIDL::ExceptionOr<void> set_selection_range(Optional<WebIDL::UnsignedLong> start, Optional<WebIDL::UnsignedLong> end, Optional<String> direction); |
166 | | |
167 | | protected: |
168 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value |
169 | | void relevant_value_was_changed(JS::GCPtr<DOM::Text>); |
170 | | |
171 | 0 | virtual void selection_was_changed([[maybe_unused]] size_t selection_start, [[maybe_unused]] size_t selection_end) { } |
172 | | |
173 | | private: |
174 | | // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-selection |
175 | | WebIDL::UnsignedLong m_selection_start { 0 }; |
176 | | WebIDL::UnsignedLong m_selection_end { 0 }; |
177 | | SelectionDirection m_selection_direction { SelectionDirection::None }; |
178 | | }; |
179 | | |
180 | | } |