Skip to content

Commit

Permalink
LibWeb: Implement relaxed parser for <select>
Browse files Browse the repository at this point in the history
- Allow general content within select element
- Update processing of options for select

See whatwg/html#10557
  • Loading branch information
lukewarlow committed Dec 4, 2024
1 parent d4d335e commit 7f9a109
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 310 deletions.
10 changes: 0 additions & 10 deletions Libraries/LibWeb/HTML/HTMLOptGroupElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,4 @@ void HTMLOptGroupElement::inserted()
static_cast<HTMLSelectElement&>(*parent()).update_selectedness();
}

void HTMLOptGroupElement::removed_from(Node* old_parent)
{
Base::removed_from(old_parent);

// The optgroup HTML element removing steps, given removedNode and oldParent, are:
// 1. If oldParent is a select element and removedNode has an option child, then run oldParent's selectedness setting algorithm.
if (old_parent && is<HTMLSelectElement>(*old_parent) && first_child_of_type<HTMLOptionElement>())
static_cast<HTMLSelectElement&>(*old_parent).update_selectedness();
}

}
1 change: 0 additions & 1 deletion Libraries/LibWeb/HTML/HTMLOptGroupElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class HTMLOptGroupElement final : public HTMLElement {
HTMLOptGroupElement(DOM::Document&, DOM::QualifiedName);

virtual void initialize(JS::Realm&) override;
virtual void removed_from(Node*) override;
virtual void inserted() override;
};

Expand Down
33 changes: 17 additions & 16 deletions Libraries/LibWeb/HTML/HTMLOptionElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,28 +205,29 @@ void HTMLOptionElement::inserted()

set_selected_internal(selected());

// 1. The option HTML element insertion steps, given insertedNode, are:
// If insertedNode's parent is a select element,
// or insertedNode's parent is an optgroup element whose parent is a select element,
// then run that select element's selectedness setting algorithm.
if (is<HTMLSelectElement>(*parent()))
static_cast<HTMLSelectElement&>(*parent()).update_selectedness();
else if (is<HTMLOptGroupElement>(parent()) && parent()->parent() && is<HTMLSelectElement>(*parent()->parent()))
static_cast<HTMLSelectElement&>(*parent()->parent()).update_selectedness();
// The option HTML element insertion steps, given insertedOption, are:
// 1. For each ancestor of insertedOption's ancestors in reverse tree order:
for (auto* ancestor = parent_node(); ancestor; ancestor = ancestor->parent_node()) {
// 1. If ancestor is a select element, then run the selectedness setting algorithm given ancestor and return.
if (is<HTMLSelectElement>(*ancestor)) {
static_cast<HTMLSelectElement&>(*ancestor).update_selectedness();
return;
}
}
}

void HTMLOptionElement::removed_from(Node* old_parent)
{
Base::removed_from(old_parent);

// The option HTML element removing steps, given removedNode and oldParent, are:
// 1. If oldParent is a select element, or oldParent is an optgroup element whose parent is a select element,
// then run that select element's selectedness setting algorithm.
if (old_parent) {
if (is<HTMLSelectElement>(*old_parent))
static_cast<HTMLSelectElement&>(*old_parent).update_selectedness();
else if (is<HTMLOptGroupElement>(*old_parent) && old_parent->parent_element() && is<HTMLSelectElement>(old_parent->parent_element()))
static_cast<HTMLSelectElement&>(*old_parent->parent_element()).update_selectedness();
// The option HTML element removing steps, given removedOption and oldParent, are:
// 1. For each ancestor of oldParent's inclusive ancestors in reverse tree order:
for (auto* ancestor = old_parent; ancestor; ancestor = ancestor->parent_node()) {
// 1. If ancestor is a select element, then run the selectedness setting algorithm given ancestor and return.
if (is<HTMLSelectElement>(*ancestor)) {
static_cast<HTMLSelectElement&>(*ancestor).update_selectedness();
return;
}
}
}

Expand Down
30 changes: 13 additions & 17 deletions Libraries/LibWeb/HTML/HTMLSelectElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,24 +199,20 @@ GC::Ref<DOM::HTMLCollection> HTMLSelectElement::selected_options()
// https://html.spec.whatwg.org/multipage/form-elements.html#concept-select-option-list
Vector<GC::Root<HTMLOptionElement>> HTMLSelectElement::list_of_options() const
{
// The list of options for a select element consists of all the option element children of the select element,
// and all the option element children of all the optgroup element children of the select element, in tree order.
Vector<GC::Root<HTMLOptionElement>> list;

for_each_child_of_type<HTMLOptionElement>([&](HTMLOptionElement& option_element) {
list.append(GC::make_root(option_element));
return IterationDecision::Continue;
// 1. Let options be « ».
Vector<GC::Root<HTMLOptionElement>> options;
// 2. For each node of select's descendants in tree order except the descendants which are select elements and their subtrees:
for_each_in_subtree([&](auto& node) {
if (is<HTMLSelectElement>(node))
return TraversalDecision::Break;

// 1. If node is an option element, then append node to options.
if (is<HTMLOptionElement>(node))
options.append(GC::make_root(const_cast<HTMLOptionElement&>(static_cast<HTMLOptionElement const&>(node))));
return TraversalDecision::Continue;
});

for_each_child_of_type<HTMLOptGroupElement>([&](HTMLOptGroupElement const& optgroup_element) {
optgroup_element.for_each_child_of_type<HTMLOptionElement>([&](HTMLOptionElement& option_element) {
list.append(GC::make_root(option_element));
return IterationDecision::Continue;
});
return IterationDecision::Continue;
});

return list;
// 3. Return options.
return options;
}

// https://html.spec.whatwg.org/multipage/form-elements.html#the-select-element:concept-form-reset-control
Expand Down
Loading

0 comments on commit 7f9a109

Please sign in to comment.