ChildNode.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (c) 2021-2022, Luke Wilde <lukew@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <LibWeb/DOM/ExceptionOr.h>
  8. #include <LibWeb/DOM/NodeOperations.h>
  9. namespace Web::DOM {
  10. // https://dom.spec.whatwg.org/#childnode
  11. template<typename NodeType>
  12. class ChildNode {
  13. public:
  14. // https://dom.spec.whatwg.org/#dom-childnode-before
  15. ExceptionOr<void> before(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes)
  16. {
  17. auto* node = static_cast<NodeType*>(this);
  18. // 1. Let parent be this’s parent.
  19. auto* parent = node->parent();
  20. // 2. If parent is null, then return.
  21. if (!parent)
  22. return {};
  23. // 3. Let viablePreviousSibling be this’s first preceding sibling not in nodes; otherwise null.
  24. auto viable_previous_sibling = viable_previous_sibling_for_insertion(nodes);
  25. // 4. Let node be the result of converting nodes into a node, given nodes and this’s node document.
  26. auto node_or_exception = convert_nodes_to_single_node(nodes, node->document());
  27. if (node_or_exception.is_exception())
  28. return node_or_exception.exception();
  29. auto node_to_insert = node_or_exception.release_value();
  30. // 5. If viablePreviousSibling is null, then set it to parent’s first child; otherwise to viablePreviousSibling’s next sibling.
  31. if (!viable_previous_sibling)
  32. viable_previous_sibling = parent->first_child();
  33. else
  34. viable_previous_sibling = viable_previous_sibling->next_sibling();
  35. // 6. Pre-insert node into parent before viablePreviousSibling.
  36. auto result = parent->pre_insert(node_to_insert, viable_previous_sibling);
  37. if (result.is_exception())
  38. return result.exception();
  39. return {};
  40. }
  41. // https://dom.spec.whatwg.org/#dom-childnode-after
  42. ExceptionOr<void> after(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes)
  43. {
  44. auto* node = static_cast<NodeType*>(this);
  45. // 1. Let parent be this’s parent.
  46. auto* parent = node->parent();
  47. // 2. If parent is null, then return.
  48. if (!parent)
  49. return {};
  50. // 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null.
  51. auto viable_next_sibling = viable_nest_sibling_for_insertion(nodes);
  52. // 4. Let node be the result of converting nodes into a node, given nodes and this’s node document.
  53. auto node_or_exception = convert_nodes_to_single_node(nodes, node->document());
  54. if (node_or_exception.is_exception())
  55. return node_or_exception.exception();
  56. auto node_to_insert = node_or_exception.release_value();
  57. // 5. Pre-insert node into parent before viableNextSibling.
  58. auto result = parent->pre_insert(node_to_insert, viable_next_sibling);
  59. if (result.is_exception())
  60. return result.exception();
  61. return {};
  62. }
  63. // https://dom.spec.whatwg.org/#dom-childnode-replacewith
  64. ExceptionOr<void> replace_with(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes)
  65. {
  66. auto* node = static_cast<NodeType*>(this);
  67. // 1. Let parent be this’s parent.
  68. auto* parent = node->parent();
  69. // 2. If parent is null, then return.
  70. if (!parent)
  71. return {};
  72. // 3. Let viableNextSibling be this’s first following sibling not in nodes; otherwise null.
  73. auto viable_next_sibling = viable_nest_sibling_for_insertion(nodes);
  74. // 4. Let node be the result of converting nodes into a node, given nodes and this’s node document.
  75. auto node_or_exception = convert_nodes_to_single_node(nodes, node->document());
  76. if (node_or_exception.is_exception())
  77. return node_or_exception.exception();
  78. auto node_to_insert = node_or_exception.release_value();
  79. // 5. If this’s parent is parent, replace this with node within parent.
  80. // Note: This could have been inserted into node.
  81. if (node->parent() == parent) {
  82. auto result = parent->replace_child(node_to_insert, *node);
  83. if (result.is_exception())
  84. return result.exception();
  85. return {};
  86. }
  87. // 6. Otherwise, pre-insert node into parent before viableNextSibling.
  88. auto result = parent->pre_insert(node_to_insert, viable_next_sibling);
  89. if (result.is_exception())
  90. return result.exception();
  91. return {};
  92. }
  93. // https://dom.spec.whatwg.org/#dom-childnode-remove
  94. void remove_binding()
  95. {
  96. auto* node = static_cast<NodeType*>(this);
  97. // 1. If this’s parent is null, then return.
  98. if (!node->parent())
  99. return;
  100. // 2. Remove this.
  101. node->remove();
  102. }
  103. protected:
  104. ChildNode() = default;
  105. private:
  106. RefPtr<Node> viable_previous_sibling_for_insertion(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes) const
  107. {
  108. auto* node = static_cast<NodeType const*>(this);
  109. while (auto* previous_sibling = node->previous_sibling()) {
  110. bool contained_in_nodes = false;
  111. for (auto const& node_or_string : nodes) {
  112. if (!node_or_string.template has<NonnullRefPtr<Node>>())
  113. continue;
  114. auto node_in_vector = node_or_string.template get<NonnullRefPtr<Node>>();
  115. if (node_in_vector.ptr() == previous_sibling) {
  116. contained_in_nodes = true;
  117. break;
  118. }
  119. }
  120. if (!contained_in_nodes)
  121. return previous_sibling;
  122. }
  123. return nullptr;
  124. }
  125. RefPtr<Node> viable_nest_sibling_for_insertion(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes) const
  126. {
  127. auto* node = static_cast<NodeType const*>(this);
  128. while (auto* next_sibling = node->next_sibling()) {
  129. bool contained_in_nodes = false;
  130. for (auto const& node_or_string : nodes) {
  131. if (!node_or_string.template has<NonnullRefPtr<Node>>())
  132. continue;
  133. auto node_in_vector = node_or_string.template get<NonnullRefPtr<Node>>();
  134. if (node_in_vector.ptr() == next_sibling) {
  135. contained_in_nodes = true;
  136. break;
  137. }
  138. }
  139. if (!contained_in_nodes)
  140. return next_sibling;
  141. }
  142. return nullptr;
  143. }
  144. };
  145. }