LiveNodeList.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  3. * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibJS/Heap/Heap.h>
  8. #include <LibJS/Runtime/Error.h>
  9. #include <LibWeb/DOM/LiveNodeList.h>
  10. #include <LibWeb/DOM/Node.h>
  11. namespace Web::DOM {
  12. JS_DEFINE_ALLOCATOR(LiveNodeList);
  13. JS::NonnullGCPtr<NodeList> LiveNodeList::create(JS::Realm& realm, Node const& root, Scope scope, Function<bool(Node const&)> filter)
  14. {
  15. return realm.heap().allocate<LiveNodeList>(realm, realm, root, scope, move(filter));
  16. }
  17. LiveNodeList::LiveNodeList(JS::Realm& realm, Node const& root, Scope scope, Function<bool(Node const&)> filter)
  18. : NodeList(realm)
  19. , m_root(root)
  20. , m_filter(move(filter))
  21. , m_scope(scope)
  22. {
  23. }
  24. LiveNodeList::~LiveNodeList() = default;
  25. void LiveNodeList::visit_edges(Cell::Visitor& visitor)
  26. {
  27. Base::visit_edges(visitor);
  28. visitor.visit(m_root);
  29. }
  30. JS::MarkedVector<Node*> LiveNodeList::collection() const
  31. {
  32. JS::MarkedVector<Node*> nodes(heap());
  33. if (m_scope == Scope::Descendants) {
  34. m_root->for_each_in_subtree([&](auto& node) {
  35. if (m_filter(node))
  36. nodes.append(const_cast<Node*>(&node));
  37. return IterationDecision::Continue;
  38. });
  39. } else {
  40. m_root->for_each_child([&](auto& node) {
  41. if (m_filter(node))
  42. nodes.append(const_cast<Node*>(&node));
  43. return IterationDecision::Continue;
  44. });
  45. }
  46. return nodes;
  47. }
  48. Node* LiveNodeList::first_matching(Function<bool(Node const&)> const& filter) const
  49. {
  50. Node* matched_node = nullptr;
  51. if (m_scope == Scope::Descendants) {
  52. m_root->for_each_in_subtree([&](auto& node) {
  53. if (m_filter(node) && filter(node)) {
  54. matched_node = const_cast<Node*>(&node);
  55. return IterationDecision::Break;
  56. }
  57. return IterationDecision::Continue;
  58. });
  59. } else {
  60. m_root->for_each_child([&](auto& node) {
  61. if (m_filter(node) && filter(node)) {
  62. matched_node = const_cast<Node*>(&node);
  63. return IterationDecision::Break;
  64. }
  65. return IterationDecision::Continue;
  66. });
  67. }
  68. return matched_node;
  69. }
  70. // https://dom.spec.whatwg.org/#dom-nodelist-length
  71. u32 LiveNodeList::length() const
  72. {
  73. return collection().size();
  74. }
  75. // https://dom.spec.whatwg.org/#dom-nodelist-item
  76. Node const* LiveNodeList::item(u32 index) const
  77. {
  78. // 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.
  79. auto nodes = collection();
  80. if (index >= nodes.size())
  81. return nullptr;
  82. return nodes[index];
  83. }
  84. // https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-indices
  85. bool LiveNodeList::is_supported_property_index(u32 index) const
  86. {
  87. // 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.
  88. // If there are no such elements, then there are no supported property indices.
  89. return index < length();
  90. }
  91. }