summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Wilde <lukew@serenityos.org>2021-09-22 18:06:19 +0100
committerAndreas Kling <kling@serenityos.org>2021-09-22 20:33:06 +0200
commitd47e431d54b4facd77703f8efd3b68e2eedc4835 (patch)
tree8503c4df277d67d6868b98f2258e84c186da3a17
parent5c7dca352679758ffc58103bea98921e19be4ad7 (diff)
downloadserenity-d47e431d54b4facd77703f8efd3b68e2eedc4835.zip
LibWeb: Add getElementsByTagNameNS and add support for * in non-NS
This also moves getElementsByTagName to ParentNode to remove the code duplication between Document and Element. This additionally fixes a bug where getElementsByTagName did not check if the element was a descendant, meaning it would also include the context element if the condition matched.
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.cpp11
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.h1
-rw-r--r--Userland/Libraries/LibWeb/DOM/Document.idl1
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.cpp11
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.h1
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.idl1
-rw-r--r--Userland/Libraries/LibWeb/DOM/ParentNode.cpp65
-rw-r--r--Userland/Libraries/LibWeb/DOM/ParentNode.h3
8 files changed, 70 insertions, 24 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp
index 217db327ca..d29c28cba1 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Document.cpp
@@ -511,17 +511,6 @@ NonnullRefPtr<HTMLCollection> Document::get_elements_by_name(String const& name)
});
}
-NonnullRefPtr<HTMLCollection> Document::get_elements_by_tag_name(FlyString const& tag_name)
-{
- // FIXME: Support "*" for tag_name
- // https://dom.spec.whatwg.org/#concept-getelementsbytagname
- return HTMLCollection::create(*this, [tag_name](Element const& element) {
- if (element.namespace_() == Namespace::HTML)
- return element.local_name().to_lowercase() == tag_name.to_lowercase();
- return element.local_name() == tag_name;
- });
-}
-
NonnullRefPtr<HTMLCollection> Document::get_elements_by_class_name(FlyString const& class_name)
{
return HTMLCollection::create(*this, [class_name, quirks_mode = document().in_quirks_mode()](Element const& element) {
diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h
index a356ac563f..28505b270c 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.h
+++ b/Userland/Libraries/LibWeb/DOM/Document.h
@@ -158,7 +158,6 @@ public:
void schedule_forced_layout();
NonnullRefPtr<HTMLCollection> get_elements_by_name(String const&);
- NonnullRefPtr<HTMLCollection> get_elements_by_tag_name(FlyString const&);
NonnullRefPtr<HTMLCollection> get_elements_by_class_name(FlyString const&);
NonnullRefPtr<HTMLCollection> applets();
diff --git a/Userland/Libraries/LibWeb/DOM/Document.idl b/Userland/Libraries/LibWeb/DOM/Document.idl
index 66c6bf8766..1345e41db0 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.idl
+++ b/Userland/Libraries/LibWeb/DOM/Document.idl
@@ -21,6 +21,7 @@ interface Document : Node {
Element? getElementById(DOMString id);
HTMLCollection getElementsByName(DOMString name);
HTMLCollection getElementsByTagName(DOMString tagName);
+ HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString className);
readonly attribute HTMLCollection applets;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index e706dac660..91c86d1978 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -272,17 +272,6 @@ bool Element::is_active() const
return document().active_element() == this;
}
-NonnullRefPtr<HTMLCollection> Element::get_elements_by_tag_name(FlyString const& tag_name)
-{
- // FIXME: Support "*" for tag_name
- // https://dom.spec.whatwg.org/#concept-getelementsbytagname
- return HTMLCollection::create(*this, [tag_name](Element const& element) {
- if (element.namespace_() == Namespace::HTML)
- return element.local_name().to_lowercase() == tag_name.to_lowercase();
- return element.local_name() == tag_name;
- });
-}
-
NonnullRefPtr<HTMLCollection> Element::get_elements_by_class_name(FlyString const& class_name)
{
return HTMLCollection::create(*this, [class_name, quirks_mode = document().in_quirks_mode()](Element const& element) {
diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h
index 6ce4597c32..10bb8b6f57 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.h
+++ b/Userland/Libraries/LibWeb/DOM/Element.h
@@ -89,7 +89,6 @@ public:
bool is_active() const;
- NonnullRefPtr<HTMLCollection> get_elements_by_tag_name(FlyString const&);
NonnullRefPtr<HTMLCollection> get_elements_by_class_name(FlyString const&);
ShadowRoot* shadow_root() { return m_shadow_root; }
diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl
index e791e9a88d..87c5ba58d7 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.idl
+++ b/Userland/Libraries/LibWeb/DOM/Element.idl
@@ -11,6 +11,7 @@ interface Element : Node {
boolean hasAttributes();
HTMLCollection getElementsByTagName(DOMString tagName);
+ HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString className);
// FIXME: This should come from a InnerHTML mixin.
diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp
index a13f29f647..b4550ebaae 100644
--- a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp
+++ b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp
@@ -9,6 +9,7 @@
#include <LibWeb/DOM/HTMLCollection.h>
#include <LibWeb/DOM/ParentNode.h>
#include <LibWeb/Dump.h>
+#include <LibWeb/Namespace.h>
namespace Web::DOM {
@@ -87,4 +88,68 @@ NonnullRefPtr<HTMLCollection> ParentNode::children()
});
}
+// https://dom.spec.whatwg.org/#concept-getelementsbytagname
+// NOTE: This method is only exposed on Document and Element, but is in ParentNode to prevent code duplication.
+NonnullRefPtr<HTMLCollection> ParentNode::get_elements_by_tag_name(FlyString const& qualified_name)
+{
+ // 1. If qualifiedName is "*" (U+002A), return a HTMLCollection rooted at root, whose filter matches only descendant elements.
+ if (qualified_name == "*") {
+ return HTMLCollection::create(*this, [this](Element const& element) {
+ return element.is_descendant_of(*this);
+ });
+ }
+
+ // FIXME: 2. Otherwise, if root’s node document is an HTML document, return a HTMLCollection rooted at root, whose filter matches the following descendant elements:
+ // (It is currently always a HTML document)
+ return HTMLCollection::create(*this, [this, qualified_name](Element const& element) {
+ if (!element.is_descendant_of(*this))
+ return false;
+
+ // - Whose namespace is the HTML namespace and whose qualified name is qualifiedName, in ASCII lowercase.
+ if (element.namespace_() == Namespace::HTML)
+ return element.qualified_name().to_lowercase() == qualified_name.to_lowercase();
+
+ // - Whose namespace is not the HTML namespace and whose qualified name is qualifiedName.
+ return element.qualified_name() == qualified_name;
+ });
+
+ // FIXME: 3. Otherwise, return a HTMLCollection rooted at root, whose filter matches descendant elements whose qualified name is qualifiedName.
+}
+
+// https://dom.spec.whatwg.org/#concept-getelementsbytagnamens
+// NOTE: This method is only exposed on Document and Element, but is in ParentNode to prevent code duplication.
+NonnullRefPtr<HTMLCollection> ParentNode::get_elements_by_tag_name_ns(FlyString const& nullable_namespace, FlyString const& local_name)
+{
+ // 1. If namespace is the empty string, set it to null.
+ String namespace_ = nullable_namespace;
+ if (namespace_.is_empty())
+ namespace_ = {};
+
+ // 2. If both namespace and localName are "*" (U+002A), return a HTMLCollection rooted at root, whose filter matches descendant elements.
+ if (namespace_ == "*" && local_name == "*") {
+ return HTMLCollection::create(*this, [this](Element const& element) {
+ return element.is_descendant_of(*this);
+ });
+ }
+
+ // 3. Otherwise, if namespace is "*" (U+002A), return a HTMLCollection rooted at root, whose filter matches descendant elements whose local name is localName.
+ if (namespace_ == "*") {
+ return HTMLCollection::create(*this, [this, local_name](Element const& element) {
+ return element.is_descendant_of(*this) && element.local_name() == local_name;
+ });
+ }
+
+ // 4. Otherwise, if localName is "*" (U+002A), return a HTMLCollection rooted at root, whose filter matches descendant elements whose namespace is namespace.
+ if (local_name == "*") {
+ return HTMLCollection::create(*this, [this, namespace_](Element const& element) {
+ return element.is_descendant_of(*this) && element.namespace_() == namespace_;
+ });
+ }
+
+ // 5. Otherwise, return a HTMLCollection rooted at root, whose filter matches descendant elements whose namespace is namespace and local name is localName.
+ return HTMLCollection::create(*this, [this, namespace_, local_name](Element const& element) {
+ return element.is_descendant_of(*this) && element.namespace_() == namespace_ && element.local_name() == local_name;
+ });
+}
+
}
diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.h b/Userland/Libraries/LibWeb/DOM/ParentNode.h
index fbbe4e0c3d..931813d63e 100644
--- a/Userland/Libraries/LibWeb/DOM/ParentNode.h
+++ b/Userland/Libraries/LibWeb/DOM/ParentNode.h
@@ -27,6 +27,9 @@ public:
NonnullRefPtr<HTMLCollection> children();
+ NonnullRefPtr<HTMLCollection> get_elements_by_tag_name(FlyString const&);
+ NonnullRefPtr<HTMLCollection> get_elements_by_tag_name_ns(FlyString const&, FlyString const&);
+
protected:
ParentNode(Document& document, NodeType type)
: Node(document, type)