diff options
author | Luke Wilde <lukew@serenityos.org> | 2021-09-22 18:06:19 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-09-22 20:33:06 +0200 |
commit | d47e431d54b4facd77703f8efd3b68e2eedc4835 (patch) | |
tree | 8503c4df277d67d6868b98f2258e84c186da3a17 | |
parent | 5c7dca352679758ffc58103bea98921e19be4ad7 (diff) | |
download | serenity-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.cpp | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Document.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Document.idl | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Element.cpp | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Element.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Element.idl | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ParentNode.cpp | 65 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ParentNode.h | 3 |
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) |