mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:18:11 +00:00
LibWeb: Support parsing "select" elements (outside of tables)
This commit is contained in:
parent
60352c7b9b
commit
ca6fbefbc9
4 changed files with 173 additions and 2 deletions
|
@ -141,6 +141,12 @@ void HTMLDocumentParser::process_using_the_rules_for(InsertionMode mode, HTMLTok
|
||||||
case InsertionMode::InTableText:
|
case InsertionMode::InTableText:
|
||||||
handle_in_table_text(token);
|
handle_in_table_text(token);
|
||||||
break;
|
break;
|
||||||
|
case InsertionMode::InSelectInTable:
|
||||||
|
handle_in_select_in_table(token);
|
||||||
|
break;
|
||||||
|
case InsertionMode::InSelect:
|
||||||
|
handle_in_select(token);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -220,6 +226,11 @@ Element& HTMLDocumentParser::current_node()
|
||||||
return m_stack_of_open_elements.current_node();
|
return m_stack_of_open_elements.current_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Element& HTMLDocumentParser::node_before_current_node()
|
||||||
|
{
|
||||||
|
return m_stack_of_open_elements.elements().at(m_stack_of_open_elements.elements().size() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<Node> HTMLDocumentParser::find_appropriate_place_for_inserting_node()
|
RefPtr<Node> HTMLDocumentParser::find_appropriate_place_for_inserting_node()
|
||||||
{
|
{
|
||||||
auto& target = current_node();
|
auto& target = current_node();
|
||||||
|
@ -1201,7 +1212,22 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.is_start_tag() && token.tag_name() == "select") {
|
if (token.is_start_tag() && token.tag_name() == "select") {
|
||||||
TODO();
|
reconstruct_the_active_formatting_elements();
|
||||||
|
insert_html_element(token);
|
||||||
|
m_frameset_ok = false;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.is_start_tag() && token.tag_name().is_one_of("optgroup", "option")) {
|
if (token.is_start_tag() && token.tag_name().is_one_of("optgroup", "option")) {
|
||||||
|
@ -1539,7 +1565,14 @@ void HTMLDocumentParser::handle_in_table_body(HTMLToken& token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.is_end_tag() && token.tag_name().is_one_of("tbody", "tfoot", "thead")) {
|
if (token.is_end_tag() && token.tag_name().is_one_of("tbody", "tfoot", "thead")) {
|
||||||
TODO();
|
if (!m_stack_of_open_elements.has_in_table_scope(token.tag_name())) {
|
||||||
|
PARSE_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clear_the_stack_back_to_a_table_body_context();
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
m_insertion_mode = InsertionMode::InTable;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((token.is_start_tag() && token.tag_name().is_one_of("caption", "col", "colgroup", "tbody", "tfoot", "thead"))
|
if ((token.is_start_tag() && token.tag_name().is_one_of("caption", "col", "colgroup", "tbody", "tfoot", "thead"))
|
||||||
|
@ -1621,6 +1654,132 @@ void HTMLDocumentParser::handle_in_table(HTMLToken& token)
|
||||||
TODO();
|
TODO();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTMLDocumentParser::handle_in_select_in_table(HTMLToken& token)
|
||||||
|
{
|
||||||
|
(void)token;
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTMLDocumentParser::handle_in_select(HTMLToken& token)
|
||||||
|
{
|
||||||
|
if (token.is_character()) {
|
||||||
|
if (token.codepoint() == 0) {
|
||||||
|
PARSE_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insert_character(token.codepoint());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_comment()) {
|
||||||
|
insert_comment(token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_doctype()) {
|
||||||
|
PARSE_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_start_tag() && token.tag_name() == "html") {
|
||||||
|
process_using_the_rules_for(InsertionMode::InBody, token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_start_tag() && token.tag_name() == "option") {
|
||||||
|
if (current_node().tag_name() == "option") {
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
}
|
||||||
|
insert_html_element(token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_start_tag() && token.tag_name() == "optgroup") {
|
||||||
|
if (current_node().tag_name() == "option") {
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
}
|
||||||
|
if (current_node().tag_name() == "optgroup") {
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
}
|
||||||
|
insert_html_element(token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_end_tag() && token.tag_name() == "optgroup") {
|
||||||
|
if (current_node().tag_name() == "option" && node_before_current_node().tag_name() == "optgroup")
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
|
||||||
|
if (current_node().tag_name() == "optgroup") {
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
} else {
|
||||||
|
PARSE_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_end_tag() && token.tag_name() == "option") {
|
||||||
|
if (current_node().tag_name() == "option") {
|
||||||
|
m_stack_of_open_elements.pop();
|
||||||
|
} else {
|
||||||
|
PARSE_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_end_tag() && token.tag_name() == "select") {
|
||||||
|
if (m_stack_of_open_elements.has_in_select_scope("select")) {
|
||||||
|
PARSE_ERROR();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped("select");
|
||||||
|
reset_the_insertion_mode_appropriately();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_start_tag() && token.tag_name() == "select") {
|
||||||
|
PARSE_ERROR();
|
||||||
|
|
||||||
|
if (!m_stack_of_open_elements.has_in_select_scope("select"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped("select");
|
||||||
|
reset_the_insertion_mode_appropriately();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_start_tag() && token.tag_name().is_one_of("input", "keygen", "textarea")) {
|
||||||
|
PARSE_ERROR();
|
||||||
|
|
||||||
|
if (!m_stack_of_open_elements.has_in_select_scope("select")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped("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("script", "template")) {
|
||||||
|
process_using_the_rules_for(InsertionMode::InHead, token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.is_end_tag() && token.tag_name() == "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;
|
||||||
|
}
|
||||||
|
|
||||||
|
PARSE_ERROR();
|
||||||
|
}
|
||||||
|
|
||||||
void HTMLDocumentParser::reset_the_insertion_mode_appropriately()
|
void HTMLDocumentParser::reset_the_insertion_mode_appropriately()
|
||||||
{
|
{
|
||||||
for (ssize_t i = m_stack_of_open_elements.elements().size() - 1; i >= 0; --i) {
|
for (ssize_t i = m_stack_of_open_elements.elements().size() - 1; i >= 0; --i) {
|
||||||
|
|
|
@ -96,6 +96,8 @@ private:
|
||||||
void handle_in_row(HTMLToken&);
|
void handle_in_row(HTMLToken&);
|
||||||
void handle_in_cell(HTMLToken&);
|
void handle_in_cell(HTMLToken&);
|
||||||
void handle_in_table_text(HTMLToken&);
|
void handle_in_table_text(HTMLToken&);
|
||||||
|
void handle_in_select_in_table(HTMLToken&);
|
||||||
|
void handle_in_select(HTMLToken&);
|
||||||
|
|
||||||
void stop_parsing() { m_stop_parsing = true; }
|
void stop_parsing() { m_stop_parsing = true; }
|
||||||
|
|
||||||
|
@ -105,6 +107,7 @@ private:
|
||||||
RefPtr<Node> find_appropriate_place_for_inserting_node();
|
RefPtr<Node> find_appropriate_place_for_inserting_node();
|
||||||
RefPtr<Element> insert_html_element(HTMLToken&);
|
RefPtr<Element> insert_html_element(HTMLToken&);
|
||||||
Element& current_node();
|
Element& current_node();
|
||||||
|
Element& node_before_current_node();
|
||||||
void insert_character(u32 data);
|
void insert_character(u32 data);
|
||||||
void insert_comment(HTMLToken&);
|
void insert_comment(HTMLToken&);
|
||||||
void reconstruct_the_active_formatting_elements();
|
void reconstruct_the_active_formatting_elements();
|
||||||
|
|
|
@ -94,6 +94,14 @@ bool StackOfOpenElements::has_in_list_item_scope(const FlyString& tag_name) cons
|
||||||
return has_in_scope_impl(tag_name, list);
|
return has_in_scope_impl(tag_name, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StackOfOpenElements::has_in_select_scope(const FlyString& tag_name) const
|
||||||
|
{
|
||||||
|
auto list = s_base_list;
|
||||||
|
list.append("option");
|
||||||
|
list.append("optgroup");
|
||||||
|
return has_in_scope_impl(tag_name, list);
|
||||||
|
}
|
||||||
|
|
||||||
bool StackOfOpenElements::contains(const Element& element) const
|
bool StackOfOpenElements::contains(const Element& element) const
|
||||||
{
|
{
|
||||||
for (auto& element_on_stack : m_elements) {
|
for (auto& element_on_stack : m_elements) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
bool has_in_button_scope(const FlyString& tag_name) const;
|
bool has_in_button_scope(const FlyString& tag_name) const;
|
||||||
bool has_in_table_scope(const FlyString& tag_name) const;
|
bool has_in_table_scope(const FlyString& tag_name) const;
|
||||||
bool has_in_list_item_scope(const FlyString& tag_name) const;
|
bool has_in_list_item_scope(const FlyString& tag_name) const;
|
||||||
|
bool has_in_select_scope(const FlyString& tag_name) const;
|
||||||
|
|
||||||
bool has_in_scope(const Element&) const;
|
bool has_in_scope(const Element&) const;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue