Serenity Operating System
at master 124 lines 6.2 kB view raw
1/* 2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibWeb/HTML/FormAssociatedElement.h> 8#include <LibWeb/HTML/HTMLButtonElement.h> 9#include <LibWeb/HTML/HTMLFieldSetElement.h> 10#include <LibWeb/HTML/HTMLFormElement.h> 11#include <LibWeb/HTML/HTMLInputElement.h> 12#include <LibWeb/HTML/HTMLLegendElement.h> 13#include <LibWeb/HTML/HTMLSelectElement.h> 14#include <LibWeb/HTML/HTMLTextAreaElement.h> 15#include <LibWeb/HTML/Parser/HTMLParser.h> 16 17namespace Web::HTML { 18 19void FormAssociatedElement::set_form(HTMLFormElement* form) 20{ 21 if (m_form) 22 m_form->remove_associated_element({}, form_associated_element_to_html_element()); 23 m_form = form; 24 if (m_form) 25 m_form->add_associated_element({}, form_associated_element_to_html_element()); 26} 27 28bool FormAssociatedElement::enabled() const 29{ 30 // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled 31 auto const& html_element = const_cast<FormAssociatedElement&>(*this).form_associated_element_to_html_element(); 32 33 // A form control is disabled if any of the following conditions are met: 34 // 1. The element is a button, input, select, textarea, or form-associated custom element, and the disabled attribute is specified on this element (regardless of its value). 35 // FIXME: This doesn't check for form-associated custom elements. 36 if ((is<HTMLButtonElement>(html_element) || is<HTMLInputElement>(html_element) || is<HTMLSelectElement>(html_element) || is<HTMLTextAreaElement>(html_element)) && html_element.has_attribute(HTML::AttributeNames::disabled)) 37 return false; 38 39 // 2. The element is a descendant of a fieldset element whose disabled attribute is specified, and is not a descendant of that fieldset element's first legend element child, if any. 40 for (auto* fieldset_ancestor = html_element.first_ancestor_of_type<HTMLFieldSetElement>(); fieldset_ancestor; fieldset_ancestor = fieldset_ancestor->first_ancestor_of_type<HTMLFieldSetElement>()) { 41 if (fieldset_ancestor->has_attribute(HTML::AttributeNames::disabled)) { 42 auto* first_legend_element_child = fieldset_ancestor->first_child_of_type<HTMLLegendElement>(); 43 if (!first_legend_element_child || !html_element.is_descendant_of(*first_legend_element_child)) 44 return false; 45 } 46 } 47 48 return true; 49} 50 51void FormAssociatedElement::set_parser_inserted(Badge<HTMLParser>) 52{ 53 m_parser_inserted = true; 54} 55 56// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#association-of-controls-and-forms:nodes-are-inserted 57void FormAssociatedElement::form_node_was_inserted() 58{ 59 // 1. If the form-associated element's parser inserted flag is set, then return. 60 if (m_parser_inserted) 61 return; 62 63 // 2. Reset the form owner of the form-associated element. 64 reset_form_owner(); 65} 66 67// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#association-of-controls-and-forms:nodes-are-removed 68void FormAssociatedElement::form_node_was_removed() 69{ 70 // 1. If the form-associated element has a form owner and the form-associated element and its form owner are no longer in the same tree, then reset the form owner of the form-associated element. 71 if (m_form && &form_associated_element_to_html_element().root() != &m_form->root()) 72 reset_form_owner(); 73} 74 75// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#reset-the-form-owner 76void FormAssociatedElement::reset_form_owner() 77{ 78 auto& html_element = form_associated_element_to_html_element(); 79 80 // Although these aren't in the "reset form owner" algorithm, these here as they are triggers for this algorithm: 81 // 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. 82 // 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. 83 // 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. 84 85 // 1. Unset element's parser inserted flag. 86 m_parser_inserted = false; 87 88 // 2. If all of the following conditions are true 89 // - element's form owner is not null 90 // - element is not listed or its form content attribute is not present 91 // - element's form owner is its nearest form element ancestor after the change to the ancestor chain 92 // then do nothing, and return. 93 if (m_form 94 && (!is_listed() || !html_element.has_attribute(HTML::AttributeNames::form)) 95 && html_element.first_ancestor_of_type<HTMLFormElement>() == m_form.ptr()) { 96 return; 97 } 98 99 // 3. Set element's form owner to null. 100 set_form(nullptr); 101 102 // 4. If element is listed, has a form content attribute, and is connected, then: 103 if (is_listed() && html_element.has_attribute(HTML::AttributeNames::form) && html_element.is_connected()) { 104 // 1. If the first element in element's tree, in tree order, to have an ID that is identical to element's form content attribute's value, is a form element, then associate the element with that form element. 105 auto form_value = html_element.attribute(HTML::AttributeNames::form); 106 html_element.root().for_each_in_inclusive_subtree_of_type<HTMLFormElement>([this, &form_value](HTMLFormElement& form_element) { 107 if (form_element.attribute(HTML::AttributeNames::id) == form_value) { 108 set_form(&form_element); 109 return IterationDecision::Break; 110 } 111 112 return IterationDecision::Continue; 113 }); 114 } 115 116 // 5. Otherwise, if element has an ancestor form element, then associate element with the nearest such ancestor form element. 117 else { 118 auto* form_ancestor = html_element.first_ancestor_of_type<HTMLFormElement>(); 119 if (form_ancestor) 120 set_form(form_ancestor); 121 } 122} 123 124}