diff --git a/Libraries/LibWeb/HTML/HTMLOptGroupElement.cpp b/Libraries/LibWeb/HTML/HTMLOptGroupElement.cpp
index fd45a79dc3fa..a60283c2c396 100644
--- a/Libraries/LibWeb/HTML/HTMLOptGroupElement.cpp
+++ b/Libraries/LibWeb/HTML/HTMLOptGroupElement.cpp
@@ -36,14 +36,4 @@ void HTMLOptGroupElement::inserted()
static_cast(*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(*old_parent) && first_child_of_type())
- static_cast(*old_parent).update_selectedness();
-}
-
}
diff --git a/Libraries/LibWeb/HTML/HTMLOptGroupElement.h b/Libraries/LibWeb/HTML/HTMLOptGroupElement.h
index a13f207cac39..f0aad855c5b8 100644
--- a/Libraries/LibWeb/HTML/HTMLOptGroupElement.h
+++ b/Libraries/LibWeb/HTML/HTMLOptGroupElement.h
@@ -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;
};
diff --git a/Libraries/LibWeb/HTML/HTMLOptionElement.cpp b/Libraries/LibWeb/HTML/HTMLOptionElement.cpp
index 87995bb31df6..e8af709ce7f7 100644
--- a/Libraries/LibWeb/HTML/HTMLOptionElement.cpp
+++ b/Libraries/LibWeb/HTML/HTMLOptionElement.cpp
@@ -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(*parent()))
- static_cast(*parent()).update_selectedness();
- else if (is(parent()) && parent()->parent() && is(*parent()->parent()))
- static_cast(*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(*ancestor)) {
+ static_cast(*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(*old_parent))
- static_cast(*old_parent).update_selectedness();
- else if (is(*old_parent) && old_parent->parent_element() && is(old_parent->parent_element()))
- static_cast(*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(*ancestor)) {
+ static_cast(*ancestor).update_selectedness();
+ return;
+ }
}
}
diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp
index a51dd08ca736..13a942e0bcb2 100644
--- a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp
+++ b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp
@@ -199,24 +199,20 @@ GC::Ref HTMLSelectElement::selected_options()
// https://html.spec.whatwg.org/multipage/form-elements.html#concept-select-option-list
Vector> 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> list;
-
- for_each_child_of_type([&](HTMLOptionElement& option_element) {
- list.append(GC::make_root(option_element));
- return IterationDecision::Continue;
+ // 1. Let options be « ».
+ Vector> 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(node))
+ return TraversalDecision::Break;
+
+ // 1. If node is an option element, then append node to options.
+ if (is(node))
+ options.append(GC::make_root(const_cast(static_cast(node))));
+ return TraversalDecision::Continue;
});
-
- for_each_child_of_type([&](HTMLOptGroupElement const& optgroup_element) {
- optgroup_element.for_each_child_of_type([&](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
diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp
index 8e64a273904a..1639cb34640f 100644
--- a/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp
+++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp
@@ -434,12 +434,6 @@ void HTMLParser::process_using_the_rules_for(InsertionMode mode, HTMLToken& toke
case InsertionMode::InTableText:
handle_in_table_text(token);
break;
- case InsertionMode::InSelectInTable:
- handle_in_select_in_table(token);
- break;
- case InsertionMode::InSelect:
- handle_in_select(token);
- break;
case InsertionMode::InCaption:
handle_in_caption(token);
break;
@@ -2164,7 +2158,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
}
// -> An end tag whose tag name is one of: "address", "article", "aside", "blockquote", "button", "center", "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre", "search", "section", "summary", "ul"
- if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::address, HTML::TagNames::article, HTML::TagNames::aside, HTML::TagNames::blockquote, HTML::TagNames::button, HTML::TagNames::center, HTML::TagNames::details, HTML::TagNames::dialog, HTML::TagNames::dir, HTML::TagNames::div, HTML::TagNames::dl, HTML::TagNames::fieldset, HTML::TagNames::figcaption, HTML::TagNames::figure, HTML::TagNames::footer, HTML::TagNames::header, HTML::TagNames::hgroup, HTML::TagNames::listing, HTML::TagNames::main, HTML::TagNames::menu, HTML::TagNames::nav, HTML::TagNames::ol, HTML::TagNames::pre, HTML::TagNames::search, HTML::TagNames::section, HTML::TagNames::summary, HTML::TagNames::ul)) {
+ if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::address, HTML::TagNames::article, HTML::TagNames::aside, HTML::TagNames::blockquote, HTML::TagNames::button, HTML::TagNames::center, HTML::TagNames::details, HTML::TagNames::dialog, HTML::TagNames::dir, HTML::TagNames::div, HTML::TagNames::dl, HTML::TagNames::fieldset, HTML::TagNames::figcaption, HTML::TagNames::figure, HTML::TagNames::footer, HTML::TagNames::header, HTML::TagNames::hgroup, HTML::TagNames::listing, HTML::TagNames::main, HTML::TagNames::menu, HTML::TagNames::nav, HTML::TagNames::ol, HTML::TagNames::pre, HTML::TagNames::search, HTML::TagNames::section, HTML::TagNames::summary, HTML::TagNames::ul, HTML::TagNames::select)) {
// If the stack of open elements does not have an element in scope that is an HTML element with the same tag name as that of the token, then this is a parse error; ignore the token.
if (!m_stack_of_open_elements.has_in_scope(token.tag_name())) {
log_parse_error();
@@ -2514,6 +2508,16 @@ void HTMLParser::handle_in_body(HTMLToken& token)
if (m_stack_of_open_elements.has_in_button_scope(HTML::TagNames::p))
close_a_p_element();
+ // If the stack of open elements has a select element in scope, then:
+ if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::select)) {
+ // 1. Generate implied end tags.
+ generate_implied_end_tags();
+
+ // 2. If the stack of open elements has an option element in scope or has an optgroup element in scope, then this is a parse error.
+ if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::option) || m_stack_of_open_elements.has_in_scope(HTML::TagNames::optgroup))
+ log_parse_error();
+ }
+
// Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
(void)insert_html_element(token);
(void)m_stack_of_open_elements.pop();
@@ -2606,35 +2610,65 @@ void HTMLParser::handle_in_body(HTMLToken& token)
// -> A start tag whose tag name is "select"
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::select) {
+ // If the stack of open elements has a select element in scope then:
+ if (m_stack_of_open_elements.has_in_scope(token.tag_name())) {
+ // 1. Parse error.
+ log_parse_error();
+
+ // 2. Pop elements from the stack of open elements until a select element has been popped from the stack.
+ m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(token.tag_name());
+ }
+ // Otherwise
+ else {
+ // Reconstruct the active formatting elements, if any.
+ reconstruct_the_active_formatting_elements();
+
+ // Insert an HTML element for the token.
+ (void)insert_html_element(token);
+
+ // Set the frameset-ok flag to "not ok".
+ m_frameset_ok = false;
+ }
+ return;
+ }
+
+ // -> A start tag whose tag name is "option"
+ if (token.is_start_tag() && token.tag_name() == HTML::TagNames::option) {
+ // If the stack of open elements has a select element in scope, then:
+ if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::select)) {
+ // 1. Generate implied end tags except for optgroup elements.
+ generate_implied_end_tags(HTML::TagNames::optgroup);
+ // 2. If the stack of open elements has an option element in scope, then this is a parse error.
+ if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::option))
+ log_parse_error();
+ }
+ // Otherwise:
+ else {
+ // 1. If the current node is an option element, then pop the current node off the stack of open elements.
+ if (current_node()->local_name() == HTML::TagNames::option)
+ (void)m_stack_of_open_elements.pop();
+ }
+
// Reconstruct the active formatting elements, if any.
reconstruct_the_active_formatting_elements();
// Insert an HTML element for the token.
(void)insert_html_element(token);
-
- // Set the frameset-ok flag to "not ok".
- m_frameset_ok = false;
-
- // If the insertion mode is one of "in table", "in caption", "in table body", "in row", or "in cell", then switch the insertion mode to "in select in table". Otherwise, switch the insertion mode to "in select".
- switch (m_insertion_mode) {
- case InsertionMode::InTable:
- case InsertionMode::InCaption:
- case InsertionMode::InTableBody:
- case InsertionMode::InRow:
- case InsertionMode::InCell:
- m_insertion_mode = InsertionMode::InSelectInTable;
- break;
- default:
- m_insertion_mode = InsertionMode::InSelect;
- break;
- }
return;
}
- // -> A start tag whose tag name is one of: "optgroup", "option"
- if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::optgroup, HTML::TagNames::option)) {
- // If the current node is an option element, then pop the current node off the stack of open elements.
- if (current_node()->local_name() == HTML::TagNames::option)
+ // -> A start tag whose tag name is "optgroup"
+ if (token.is_start_tag() && token.tag_name() == HTML::TagNames::optgroup) {
+ // If the stack of open elements has a select element in scope, then:
+ if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::select)) {
+ // 1. Generate implied end tags.
+ generate_implied_end_tags();
+ // 2. If the stack of open elements has an option element in scope or has an optgroup element in scope, then this is a parse error.
+ if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::option) || m_stack_of_open_elements.has_in_scope(HTML::TagNames::optgroup))
+ log_parse_error();
+ }
+ // Otherwise, if the current node is an option element, then pop the current node from the stack of open elements.
+ else if (current_node()->local_name() == HTML::TagNames::option)
(void)m_stack_of_open_elements.pop();
// Reconstruct the active formatting elements, if any.
@@ -3582,173 +3616,6 @@ void HTMLParser::handle_in_table(HTMLToken& token)
m_foster_parenting = false;
}
-void HTMLParser::handle_in_select_in_table(HTMLToken& token)
-{
- if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr, HTML::TagNames::td, HTML::TagNames::th)) {
- log_parse_error();
- m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
- reset_the_insertion_mode_appropriately();
- process_using_the_rules_for(m_insertion_mode, token);
- return;
- }
-
- if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr, HTML::TagNames::td, HTML::TagNames::th)) {
- log_parse_error();
-
- if (!m_stack_of_open_elements.has_in_table_scope(token.tag_name()))
- return;
-
- m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
- reset_the_insertion_mode_appropriately();
- process_using_the_rules_for(m_insertion_mode, token);
- return;
- }
-
- process_using_the_rules_for(InsertionMode::InSelect, token);
-}
-
-void HTMLParser::handle_in_select(HTMLToken& token)
-{
- if (token.is_character()) {
- if (token.code_point() == 0) {
- log_parse_error();
- return;
- }
- insert_character(token.code_point());
- return;
- }
-
- if (token.is_comment()) {
- insert_comment(token);
- return;
- }
-
- if (token.is_doctype()) {
- log_parse_error();
- return;
- }
-
- if (token.is_start_tag() && token.tag_name() == HTML::TagNames::html) {
- process_using_the_rules_for(InsertionMode::InBody, token);
- return;
- }
-
- if (token.is_start_tag() && token.tag_name() == HTML::TagNames::option) {
- if (current_node()->local_name() == HTML::TagNames::option) {
- (void)m_stack_of_open_elements.pop();
- }
- (void)insert_html_element(token);
- return;
- }
-
- if (token.is_start_tag() && token.tag_name() == HTML::TagNames::optgroup) {
- if (current_node()->local_name() == HTML::TagNames::option) {
- (void)m_stack_of_open_elements.pop();
- }
- if (current_node()->local_name() == HTML::TagNames::optgroup) {
- (void)m_stack_of_open_elements.pop();
- }
- (void)insert_html_element(token);
- return;
- }
-
- // -> A start tag whose tag name is "hr"
- if (token.is_start_tag() && token.tag_name() == HTML::TagNames::hr) {
- // If the current node is an option element, pop that node from the stack of open elements.
- if (current_node()->local_name() == HTML::TagNames::option) {
- (void)m_stack_of_open_elements.pop();
- }
- // If the current node is an optgroup element, pop that node from the stack of open elements.
- if (current_node()->local_name() == HTML::TagNames::optgroup) {
- (void)m_stack_of_open_elements.pop();
- }
- // Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
- (void)insert_html_element(token);
- (void)m_stack_of_open_elements.pop();
- // Acknowledge the token's self-closing flag, if it is set.
- token.acknowledge_self_closing_flag_if_set();
- return;
- }
-
- if (token.is_end_tag() && token.tag_name() == HTML::TagNames::optgroup) {
- if (current_node()->local_name() == HTML::TagNames::option && node_before_current_node()->local_name() == HTML::TagNames::optgroup)
- (void)m_stack_of_open_elements.pop();
-
- if (current_node()->local_name() == HTML::TagNames::optgroup) {
- (void)m_stack_of_open_elements.pop();
- } else {
- log_parse_error();
- return;
- }
- return;
- }
-
- if (token.is_end_tag() && token.tag_name() == HTML::TagNames::option) {
- if (current_node()->local_name() == HTML::TagNames::option) {
- (void)m_stack_of_open_elements.pop();
- } else {
- log_parse_error();
- return;
- }
- return;
- }
-
- if (token.is_end_tag() && token.tag_name() == HTML::TagNames::select) {
- if (!m_stack_of_open_elements.has_in_select_scope(HTML::TagNames::select)) {
- VERIFY(m_parsing_fragment);
- log_parse_error();
- return;
- }
- m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
- reset_the_insertion_mode_appropriately();
- return;
- }
-
- if (token.is_start_tag() && token.tag_name() == HTML::TagNames::select) {
- log_parse_error();
-
- if (!m_stack_of_open_elements.has_in_select_scope(HTML::TagNames::select)) {
- VERIFY(m_parsing_fragment);
- return;
- }
-
- m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
- reset_the_insertion_mode_appropriately();
- return;
- }
-
- if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::input, HTML::TagNames::keygen, HTML::TagNames::textarea)) {
- log_parse_error();
-
- if (!m_stack_of_open_elements.has_in_select_scope(HTML::TagNames::select)) {
- VERIFY(m_parsing_fragment);
- return;
- }
-
- m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::select);
- reset_the_insertion_mode_appropriately();
- process_using_the_rules_for(m_insertion_mode, token);
- return;
- }
-
- if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::script, HTML::TagNames::template_)) {
- process_using_the_rules_for(InsertionMode::InHead, token);
- return;
- }
-
- if (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_) {
- process_using_the_rules_for(InsertionMode::InHead, token);
- return;
- }
-
- if (token.is_end_of_file()) {
- process_using_the_rules_for(InsertionMode::InBody, token);
- return;
- }
-
- log_parse_error();
-}
-
void HTMLParser::handle_in_caption(HTMLToken& token)
{
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::caption) {
@@ -4348,25 +4215,6 @@ void HTMLParser::reset_the_insertion_mode_appropriately()
if (node->namespace_uri() != Namespace::HTML)
continue;
- if (node->local_name() == HTML::TagNames::select) {
- if (!last) {
- for (ssize_t j = i; j > 0; --j) {
- auto& ancestor = m_stack_of_open_elements.elements().at(j - 1);
-
- if (is(*ancestor))
- break;
-
- if (is(*ancestor)) {
- m_insertion_mode = InsertionMode::InSelectInTable;
- return;
- }
- }
- }
-
- m_insertion_mode = InsertionMode::InSelect;
- return;
- }
-
if (!last && node->local_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th)) {
m_insertion_mode = InsertionMode::InCell;
return;
diff --git a/Libraries/LibWeb/HTML/Parser/HTMLParser.h b/Libraries/LibWeb/HTML/Parser/HTMLParser.h
index 387f800af4c9..80a913481afb 100644
--- a/Libraries/LibWeb/HTML/Parser/HTMLParser.h
+++ b/Libraries/LibWeb/HTML/Parser/HTMLParser.h
@@ -16,29 +16,27 @@
namespace Web::HTML {
-#define ENUMERATE_INSERTION_MODES \
- __ENUMERATE_INSERTION_MODE(Initial) \
- __ENUMERATE_INSERTION_MODE(BeforeHTML) \
- __ENUMERATE_INSERTION_MODE(BeforeHead) \
- __ENUMERATE_INSERTION_MODE(InHead) \
- __ENUMERATE_INSERTION_MODE(InHeadNoscript) \
- __ENUMERATE_INSERTION_MODE(AfterHead) \
- __ENUMERATE_INSERTION_MODE(InBody) \
- __ENUMERATE_INSERTION_MODE(Text) \
- __ENUMERATE_INSERTION_MODE(InTable) \
- __ENUMERATE_INSERTION_MODE(InTableText) \
- __ENUMERATE_INSERTION_MODE(InCaption) \
- __ENUMERATE_INSERTION_MODE(InColumnGroup) \
- __ENUMERATE_INSERTION_MODE(InTableBody) \
- __ENUMERATE_INSERTION_MODE(InRow) \
- __ENUMERATE_INSERTION_MODE(InCell) \
- __ENUMERATE_INSERTION_MODE(InSelect) \
- __ENUMERATE_INSERTION_MODE(InSelectInTable) \
- __ENUMERATE_INSERTION_MODE(InTemplate) \
- __ENUMERATE_INSERTION_MODE(AfterBody) \
- __ENUMERATE_INSERTION_MODE(InFrameset) \
- __ENUMERATE_INSERTION_MODE(AfterFrameset) \
- __ENUMERATE_INSERTION_MODE(AfterAfterBody) \
+#define ENUMERATE_INSERTION_MODES \
+ __ENUMERATE_INSERTION_MODE(Initial) \
+ __ENUMERATE_INSERTION_MODE(BeforeHTML) \
+ __ENUMERATE_INSERTION_MODE(BeforeHead) \
+ __ENUMERATE_INSERTION_MODE(InHead) \
+ __ENUMERATE_INSERTION_MODE(InHeadNoscript) \
+ __ENUMERATE_INSERTION_MODE(AfterHead) \
+ __ENUMERATE_INSERTION_MODE(InBody) \
+ __ENUMERATE_INSERTION_MODE(Text) \
+ __ENUMERATE_INSERTION_MODE(InTable) \
+ __ENUMERATE_INSERTION_MODE(InTableText) \
+ __ENUMERATE_INSERTION_MODE(InCaption) \
+ __ENUMERATE_INSERTION_MODE(InColumnGroup) \
+ __ENUMERATE_INSERTION_MODE(InTableBody) \
+ __ENUMERATE_INSERTION_MODE(InRow) \
+ __ENUMERATE_INSERTION_MODE(InCell) \
+ __ENUMERATE_INSERTION_MODE(InTemplate) \
+ __ENUMERATE_INSERTION_MODE(AfterBody) \
+ __ENUMERATE_INSERTION_MODE(InFrameset) \
+ __ENUMERATE_INSERTION_MODE(AfterFrameset) \
+ __ENUMERATE_INSERTION_MODE(AfterAfterBody) \
__ENUMERATE_INSERTION_MODE(AfterAfterFrameset)
class HTMLParser final : public JS::Cell {
@@ -116,8 +114,6 @@ class HTMLParser final : public JS::Cell {
void handle_in_row(HTMLToken&);
void handle_in_cell(HTMLToken&);
void handle_in_table_text(HTMLToken&);
- void handle_in_select_in_table(HTMLToken&);
- void handle_in_select(HTMLToken&);
void handle_in_caption(HTMLToken&);
void handle_in_column_group(HTMLToken&);
void handle_in_template(HTMLToken&);
diff --git a/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp b/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp
index c01022081a3d..1d091a6d4d44 100644
--- a/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp
+++ b/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.cpp
@@ -11,7 +11,7 @@
namespace Web::HTML {
-static Vector s_base_list { "applet"_fly_string, "caption"_fly_string, "html"_fly_string, "table"_fly_string, "td"_fly_string, "th"_fly_string, "marquee"_fly_string, "object"_fly_string, "template"_fly_string };
+static Vector s_base_list { "applet"_fly_string, "caption"_fly_string, "html"_fly_string, "table"_fly_string, "td"_fly_string, "th"_fly_string, "marquee"_fly_string, "object"_fly_string, "template"_fly_string, "select"_fly_string };
StackOfOpenElements::~StackOfOpenElements() = default;
@@ -72,31 +72,6 @@ bool StackOfOpenElements::has_in_list_item_scope(FlyString const& tag_name) cons
return has_in_scope_impl(tag_name, list);
}
-// https://html.spec.whatwg.org/multipage/parsing.html#has-an-element-in-select-scope
-// The stack of open elements is said to have a particular element in select scope
-// when it has that element in the specific scope consisting of all element types except the following:
-// - optgroup in the HTML namespace
-// - option in the HTML namespace
-// NOTE: In this case it's "all element types _except_"
-bool StackOfOpenElements::has_in_select_scope(FlyString const& tag_name) const
-{
- // https://html.spec.whatwg.org/multipage/parsing.html#has-an-element-in-the-specific-scope
- // 1. Initialize node to be the current node (the bottommost node of the stack).
- for (auto& node : m_elements.in_reverse()) {
- // 2. If node is the target node, terminate in a match state.
- if (node->local_name() == tag_name)
- return true;
- // 3. Otherwise, if node is one of the element types in list, terminate in a failure state.
- // NOTE: Here "list" refers to all elements except option and optgroup
- if (node->local_name() != HTML::TagNames::option && node->local_name() != HTML::TagNames::optgroup)
- return false;
- // 4. Otherwise, set node to the previous entry in the stack of open elements and return to step 2.
- }
- // [4.] (This will never fail, since the loop will always terminate in the previous step if the top of the stack
- // — an html element — is reached.)
- VERIFY_NOT_REACHED();
-}
-
bool StackOfOpenElements::contains(const DOM::Element& element) const
{
for (auto& element_on_stack : m_elements) {
diff --git a/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.h b/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.h
index 540a6224e634..292797599f77 100644
--- a/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.h
+++ b/Libraries/LibWeb/HTML/Parser/StackOfOpenElements.h
@@ -39,7 +39,6 @@ class StackOfOpenElements {
bool has_in_button_scope(FlyString const& tag_name) const;
bool has_in_table_scope(FlyString const& tag_name) const;
bool has_in_list_item_scope(FlyString const& tag_name) const;
- bool has_in_select_scope(FlyString const& tag_name) const;
bool has_in_scope(const DOM::Element&) const;
diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.txt
new file mode 100644
index 000000000000..c70d5febf08d
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/html/semantics/forms/the-select-element/customizable-select/select-parsing.tentative.txt
@@ -0,0 +1,16 @@
+Harness status: OK
+
+Found 11 tests
+
+11 Pass
+Pass