/src/serenity/Userland/Libraries/LibWeb/DOM/HTMLCollection.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021-2022, Andreas Kling <kling@serenityos.org> |
3 | | * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #pragma once |
9 | | |
10 | | #include <AK/Function.h> |
11 | | #include <LibJS/Heap/GCPtr.h> |
12 | | #include <LibWeb/Bindings/PlatformObject.h> |
13 | | #include <LibWeb/Forward.h> |
14 | | |
15 | | namespace Web::DOM { |
16 | | |
17 | | // NOTE: HTMLCollection is in the DOM namespace because it's part of the DOM specification. |
18 | | |
19 | | // This class implements a live, filtered view of a DOM subtree. |
20 | | // When constructing an HTMLCollection, you provide a root node + a filter. |
21 | | // The filter is a simple Function object that answers the question |
22 | | // "is this Element part of the collection?" |
23 | | |
24 | | class HTMLCollection : public Bindings::PlatformObject { |
25 | | WEB_PLATFORM_OBJECT(HTMLCollection, Bindings::PlatformObject); |
26 | | JS_DECLARE_ALLOCATOR(HTMLCollection); |
27 | | |
28 | | public: |
29 | | enum class Scope { |
30 | | Children, |
31 | | Descendants, |
32 | | }; |
33 | | [[nodiscard]] static JS::NonnullGCPtr<HTMLCollection> create(ParentNode& root, Scope, ESCAPING Function<bool(Element const&)> filter); |
34 | | |
35 | | virtual ~HTMLCollection() override; |
36 | | |
37 | | size_t length() const; |
38 | | Element* item(size_t index) const; |
39 | | Element* named_item(FlyString const& key) const; |
40 | | |
41 | | JS::MarkedVector<JS::NonnullGCPtr<Element>> collect_matching_elements() const; |
42 | | |
43 | | virtual Optional<JS::Value> item_value(size_t index) const override; |
44 | | virtual JS::Value named_item_value(FlyString const& name) const override; |
45 | | virtual Vector<FlyString> supported_property_names() const override; |
46 | | virtual bool is_supported_property_name(FlyString const&) const override; |
47 | | |
48 | | protected: |
49 | | HTMLCollection(ParentNode& root, Scope, ESCAPING Function<bool(Element const&)> filter); |
50 | | |
51 | | virtual void initialize(JS::Realm&) override; |
52 | | |
53 | 0 | JS::NonnullGCPtr<ParentNode> root() { return *m_root; } |
54 | 0 | JS::NonnullGCPtr<ParentNode const> root() const { return *m_root; } |
55 | | |
56 | | private: |
57 | | virtual void visit_edges(Cell::Visitor&) override; |
58 | | |
59 | | void update_cache_if_needed() const; |
60 | | void update_name_to_element_mappings_if_needed() const; |
61 | | |
62 | | mutable u64 m_cached_dom_tree_version { 0 }; |
63 | | mutable Vector<JS::NonnullGCPtr<Element>> m_cached_elements; |
64 | | mutable OwnPtr<OrderedHashMap<FlyString, JS::NonnullGCPtr<Element>>> m_cached_name_to_element_mappings; |
65 | | |
66 | | JS::NonnullGCPtr<ParentNode> m_root; |
67 | | Function<bool(Element const&)> m_filter; |
68 | | |
69 | | Scope m_scope { Scope::Descendants }; |
70 | | }; |
71 | | |
72 | | } |