From 8d6db36cbb8279effe2b3d83a93798e6de5685fc Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Sat, 2 Oct 2021 20:33:45 +0100 Subject: [PATCH] LibWeb: Add support for NodeList This introduces 3 classes: NodeList, StaticNodeList and LiveNodeList. NodeList is the base of the static and live versions. Static is a snapshot whereas live acts on the underlying data and thus inhibits the same issues we have currently with HTMLCollection. They were split into separate classes to not have them weirdly mis-mashed together. The create functions for static and live both return a NNRP to the base class. This is to prevent having to do awkward casting at creation and/or return, as the bindings expect to see the base NodeList only. --- .../LibWeb/WrapperGenerator.cpp | 3 +- .../LibWeb/Bindings/WindowObjectHelper.h | 3 ++ Userland/Libraries/LibWeb/CMakeLists.txt | 3 ++ .../Libraries/LibWeb/DOM/LiveNodeList.cpp | 54 +++++++++++++++++++ Userland/Libraries/LibWeb/DOM/LiveNodeList.h | 38 +++++++++++++ Userland/Libraries/LibWeb/DOM/NodeList.h | 37 +++++++++++++ Userland/Libraries/LibWeb/DOM/NodeList.idl | 6 +++ .../Libraries/LibWeb/DOM/StaticNodeList.cpp | 39 ++++++++++++++ .../Libraries/LibWeb/DOM/StaticNodeList.h | 35 ++++++++++++ Userland/Libraries/LibWeb/Forward.h | 4 ++ 10 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 Userland/Libraries/LibWeb/DOM/LiveNodeList.cpp create mode 100644 Userland/Libraries/LibWeb/DOM/LiveNodeList.h create mode 100644 Userland/Libraries/LibWeb/DOM/NodeList.h create mode 100644 Userland/Libraries/LibWeb/DOM/NodeList.idl create mode 100644 Userland/Libraries/LibWeb/DOM/StaticNodeList.cpp create mode 100644 Userland/Libraries/LibWeb/DOM/StaticNodeList.h diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp index 1d8fadf8b53..0177f3db8a3 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp @@ -1226,7 +1226,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va )~~~"); } else if (type.name == "ArrayFromVector") { // FIXME: Remove this fake type hack once it's no longer needed. - // Basically once we have NodeList we can throw this out. + // Basically once we have sequence we can throw this out. scoped_generator.append(R"~~~( auto* new_array = JS::Array::create(global_object, 0); for (auto& element : @value@) @@ -2736,6 +2736,7 @@ void generate_prototype_implementation(IDL::Interface const& interface) #include #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h b/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h index 742db85dbaa..6f13e482300 100644 --- a/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h +++ b/Userland/Libraries/LibWeb/Bindings/WindowObjectHelper.h @@ -212,6 +212,8 @@ #include #include #include +#include +#include #include #include #include @@ -373,6 +375,7 @@ ADD_WINDOW_OBJECT_INTERFACE(MessageEvent) \ ADD_WINDOW_OBJECT_INTERFACE(MouseEvent) \ ADD_WINDOW_OBJECT_INTERFACE(Node) \ + ADD_WINDOW_OBJECT_INTERFACE(NodeList) \ ADD_WINDOW_OBJECT_INTERFACE(PageTransitionEvent) \ ADD_WINDOW_OBJECT_INTERFACE(Performance) \ ADD_WINDOW_OBJECT_INTERFACE(PerformanceTiming) \ diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index b2e36a510ad..d4de8dfde74 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -66,12 +66,14 @@ set(SOURCES DOM/EventListener.cpp DOM/EventTarget.cpp DOM/HTMLCollection.cpp + DOM/LiveNodeList.cpp DOM/Node.cpp DOM/ParentNode.cpp DOM/Position.cpp DOM/ProcessingInstruction.cpp DOM/Range.cpp DOM/ShadowRoot.cpp + DOM/StaticNodeList.cpp DOM/Text.cpp DOM/Text.idl DOM/Timer.cpp @@ -371,6 +373,7 @@ libweb_js_wrapper(DOM/HTMLCollection) libweb_js_wrapper(DOM/ProcessingInstruction) libweb_js_wrapper(DOM/ShadowRoot) libweb_js_wrapper(DOM/Node) +libweb_js_wrapper(DOM/NodeList) libweb_js_wrapper(DOM/Range) libweb_js_wrapper(DOM/Text) libweb_js_wrapper(Geometry/DOMRect) diff --git a/Userland/Libraries/LibWeb/DOM/LiveNodeList.cpp b/Userland/Libraries/LibWeb/DOM/LiveNodeList.cpp new file mode 100644 index 00000000000..c1b06046073 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/LiveNodeList.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::DOM { + +LiveNodeList::LiveNodeList(Node& root, Function filter) + : m_root(root) + , m_filter(move(filter)) +{ +} + +NonnullRefPtrVector LiveNodeList::collection() const +{ + NonnullRefPtrVector nodes; + m_root->for_each_in_inclusive_subtree_of_type([&](auto& node) { + if (m_filter(node)) + nodes.append(node); + + return IterationDecision::Continue; + }); + return nodes; +} + +// https://dom.spec.whatwg.org/#dom-nodelist-length +u32 LiveNodeList::length() const +{ + return collection().size(); +} + +// https://dom.spec.whatwg.org/#dom-nodelist-item +Node const* LiveNodeList::item(u32 index) const +{ + // The item(index) method must return the indexth node in the collection. If there is no indexth node in the collection, then the method must return null. + auto nodes = collection(); + if (index >= nodes.size()) + return nullptr; + return &nodes[index]; +} + +// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-indices +bool LiveNodeList::is_supported_property_index(u32 index) const +{ + // The object’s supported property indices are the numbers in the range zero to one less than the number of nodes represented by the collection. + // If there are no such elements, then there are no supported property indices. + return index < length(); +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/LiveNodeList.h b/Userland/Libraries/LibWeb/DOM/LiveNodeList.h new file mode 100644 index 00000000000..1fe1c70a31e --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/LiveNodeList.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::DOM { + +// FIXME: Just like HTMLCollection, LiveNodeList currently does no caching. + +class LiveNodeList : public NodeList { +public: + static NonnullRefPtr create(Node& root, Function filter) + { + return adopt_ref(*new LiveNodeList(root, move(filter))); + } + + virtual u32 length() const override; + virtual Node const* item(u32 index) const override; + + virtual bool is_supported_property_index(u32) const override; + +private: + LiveNodeList(Node& root, Function filter); + + NonnullRefPtrVector collection() const; + + NonnullRefPtr m_root; + Function m_filter; +}; + +} diff --git a/Userland/Libraries/LibWeb/DOM/NodeList.h b/Userland/Libraries/LibWeb/DOM/NodeList.h new file mode 100644 index 00000000000..839098865c6 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/NodeList.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::DOM { + +// https://dom.spec.whatwg.org/#nodelist +class NodeList + : public RefCounted + , public Bindings::Wrappable { + AK_MAKE_NONCOPYABLE(NodeList); + AK_MAKE_NONMOVABLE(NodeList); + +public: + using WrapperType = Bindings::NodeListWrapper; + + virtual ~NodeList() override = default; + + virtual u32 length() const = 0; + virtual Node const* item(u32 index) const = 0; + + virtual bool is_supported_property_index(u32) const = 0; + +protected: + NodeList() = default; +}; + +} diff --git a/Userland/Libraries/LibWeb/DOM/NodeList.idl b/Userland/Libraries/LibWeb/DOM/NodeList.idl new file mode 100644 index 00000000000..b6b26d347b5 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/NodeList.idl @@ -0,0 +1,6 @@ +[Exposed=Window] +interface NodeList { + getter Node? item(unsigned long index); + readonly attribute unsigned long length; + iterable; +}; diff --git a/Userland/Libraries/LibWeb/DOM/StaticNodeList.cpp b/Userland/Libraries/LibWeb/DOM/StaticNodeList.cpp new file mode 100644 index 00000000000..ec3707cdae2 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/StaticNodeList.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Web::DOM { + +StaticNodeList::StaticNodeList(NonnullRefPtrVector&& static_nodes) + : m_static_nodes(move(static_nodes)) +{ +} + +// https://dom.spec.whatwg.org/#dom-nodelist-length +u32 StaticNodeList::length() const +{ + return m_static_nodes.size(); +} + +// https://dom.spec.whatwg.org/#dom-nodelist-item +Node const* StaticNodeList::item(u32 index) const +{ + // The item(index) method must return the indexth node in the collection. If there is no indexth node in the collection, then the method must return null. + if (index >= m_static_nodes.size()) + return nullptr; + return &m_static_nodes[index]; +} + +// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-indices +bool StaticNodeList::is_supported_property_index(u32 index) const +{ + // The object’s supported property indices are the numbers in the range zero to one less than the number of nodes represented by the collection. + // If there are no such elements, then there are no supported property indices. + return index < m_static_nodes.size(); +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/StaticNodeList.h b/Userland/Libraries/LibWeb/DOM/StaticNodeList.h new file mode 100644 index 00000000000..240898b93f0 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/StaticNodeList.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021, Luke Wilde + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::DOM { + +class StaticNodeList : public NodeList { +public: + static NonnullRefPtr create(NonnullRefPtrVector&& static_nodes) + { + return adopt_ref(*new StaticNodeList(move(static_nodes))); + } + + virtual ~StaticNodeList() override = default; + + virtual u32 length() const override; + virtual Node const* item(u32 index) const override; + + virtual bool is_supported_property_index(u32) const override; + +private: + StaticNodeList(NonnullRefPtrVector&& static_nodes); + + NonnullRefPtrVector m_static_nodes; +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index da94990c070..17088b987cd 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -82,11 +82,14 @@ class EventHandler; class EventListener; class EventTarget; class HTMLCollection; +class LiveNodeList; class Node; +class NodeList; class ParentNode; class Position; class ProcessingInstruction; class ShadowRoot; +class StaticNodeList; class Text; class Timer; class Window; @@ -374,6 +377,7 @@ class MessageChannelWrapper; class MessageEventWrapper; class MessagePortWrapper; class MouseEventWrapper; +class NodeListWrapper; class NodeWrapper; class PageTransitionEventWrapper; class PerformanceTimingWrapper;