diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 89033e44daa..9cc494e2596 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -536,6 +536,7 @@ void Document::visit_edges(Cell::Visitor& visitor) visitor.visit(m_fonts); visitor.visit(m_selection); visitor.visit(m_first_base_element_with_href_in_tree_order); + visitor.visit(m_first_base_element_with_target_in_tree_order); visitor.visit(m_parser); visitor.visit(m_lazy_load_intersection_observer); visitor.visit(m_visual_viewport); @@ -1075,18 +1076,26 @@ Vector const* Document::background_layers() const void Document::update_base_element(Badge) { - GC::Ptr base_element; + GC::Ptr base_element_with_href = nullptr; + GC::Ptr base_element_with_target = nullptr; - for_each_in_subtree_of_type([&base_element](HTML::HTMLBaseElement const& base_element_in_tree) { - if (base_element_in_tree.has_attribute(HTML::AttributeNames::href)) { - base_element = &base_element_in_tree; - return TraversalDecision::Break; + for_each_in_subtree_of_type([&base_element_with_href, &base_element_with_target](HTML::HTMLBaseElement const& base_element_in_tree) { + if (!base_element_with_href && base_element_in_tree.has_attribute(HTML::AttributeNames::href)) { + base_element_with_href = &base_element_in_tree; + if (base_element_with_target) + return TraversalDecision::Break; + } + if (!base_element_with_target && base_element_in_tree.has_attribute(HTML::AttributeNames::target)) { + base_element_with_target = &base_element_in_tree; + if (base_element_with_href) + return TraversalDecision::Break; } return TraversalDecision::Continue; }); - m_first_base_element_with_href_in_tree_order = base_element; + m_first_base_element_with_href_in_tree_order = base_element_with_href; + m_first_base_element_with_target_in_tree_order = base_element_with_target; } GC::Ptr Document::first_base_element_with_href_in_tree_order() const @@ -1094,6 +1103,11 @@ GC::Ptr Document::first_base_element_with_href_in_t return m_first_base_element_with_href_in_tree_order; } +GC::Ptr Document::first_base_element_with_target_in_tree_order() const +{ + return m_first_base_element_with_target_in_tree_order; +} + // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#fallback-base-url URL::URL Document::fallback_base_url() const { diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 582f288d23e..5416b277df2 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -152,6 +152,7 @@ public: void update_base_element(Badge); GC::Ptr first_base_element_with_href_in_tree_order() const; + GC::Ptr first_base_element_with_target_in_tree_order() const; String url_string() const { return m_url.to_string(); } String document_uri() const { return url_string(); } @@ -1022,8 +1023,9 @@ private: // https://w3c.github.io/selection-api/#dfn-selection GC::Ptr m_selection; - // NOTE: This is a cache to make finding the first element O(1). + // NOTE: This is a cache to make finding the first or element O(1). GC::Ptr m_first_base_element_with_href_in_tree_order; + GC::Ptr m_first_base_element_with_target_in_tree_order; // https://html.spec.whatwg.org/multipage/images.html#list-of-available-images GC::Ptr m_list_of_available_images; diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp index 0059947fabd..0dbfc95f2ea 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -948,8 +948,10 @@ String HTMLElement::get_an_elements_target(Optional target) const if (auto maybe_target = attribute(AttributeNames::target); maybe_target.has_value()) { target = maybe_target.release_value(); } - // FIXME: 2. Otherwise, if element's node document contains a base element with a target attribute, + // 2. Otherwise, if element's node document contains a base element with a target attribute, // set target to the value of the target attribute of the first such base element. + if (auto base_element = document().first_base_element_with_target_in_tree_order()) + target = base_element->attribute(AttributeNames::target); } // 2. If target is not null, and contains an ASCII tab or newline and a U+003C (<), then set target to "_blank". diff --git a/Tests/LibWeb/Text/data/base/a-element-target-sub-alt.html b/Tests/LibWeb/Text/data/base/a-element-target-sub-alt.html new file mode 100644 index 00000000000..04acb3f2ccc --- /dev/null +++ b/Tests/LibWeb/Text/data/base/a-element-target-sub-alt.html @@ -0,0 +1,2 @@ + +SUCCESS! diff --git a/Tests/LibWeb/Text/data/base/a-element-target-sub-sub.html b/Tests/LibWeb/Text/data/base/a-element-target-sub-sub.html new file mode 100644 index 00000000000..b454f61a562 --- /dev/null +++ b/Tests/LibWeb/Text/data/base/a-element-target-sub-sub.html @@ -0,0 +1,3 @@ + + +Click me! diff --git a/Tests/LibWeb/Text/data/base/a-element-target-sub.html b/Tests/LibWeb/Text/data/base/a-element-target-sub.html new file mode 100644 index 00000000000..0dbd838ffab --- /dev/null +++ b/Tests/LibWeb/Text/data/base/a-element-target-sub.html @@ -0,0 +1,2 @@ + + diff --git a/Tests/LibWeb/Text/expected/base/a-element-target.txt b/Tests/LibWeb/Text/expected/base/a-element-target.txt new file mode 100644 index 00000000000..4b96f03b635 --- /dev/null +++ b/Tests/LibWeb/Text/expected/base/a-element-target.txt @@ -0,0 +1 @@ +Parent frame navigated successfully! diff --git a/Tests/LibWeb/Text/input/base/a-element-target.html b/Tests/LibWeb/Text/input/base/a-element-target.html new file mode 100644 index 00000000000..a6352a6fa56 --- /dev/null +++ b/Tests/LibWeb/Text/input/base/a-element-target.html @@ -0,0 +1,16 @@ + + + +