diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp index 1d8fadf8b5..0177f3db8a 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 742db85dba..6f13e48230 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 b2e36a510a..d4de8dfde7 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 0000000000..c1b0604607 --- /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 0000000000..1fe1c70a31 --- /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 0000000000..839098865c --- /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 0000000000..b6b26d347b --- /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 0000000000..ec3707cdae --- /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 0000000000..240898b93f --- /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 da94990c07..17088b987c 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;