EditingHostManager.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/DOM/Document.h>
  7. #include <LibWeb/DOM/EditingHostManager.h>
  8. #include <LibWeb/DOM/Range.h>
  9. #include <LibWeb/DOM/Text.h>
  10. #include <LibWeb/Selection/Selection.h>
  11. namespace Web::DOM {
  12. GC_DEFINE_ALLOCATOR(EditingHostManager);
  13. GC::Ref<EditingHostManager> EditingHostManager::create(JS::Realm& realm, GC::Ref<Document> document)
  14. {
  15. return realm.create<EditingHostManager>(document);
  16. }
  17. EditingHostManager::EditingHostManager(GC::Ref<Document> document)
  18. : m_document(document)
  19. {
  20. }
  21. void EditingHostManager::visit_edges(Cell::Visitor& visitor)
  22. {
  23. Base::visit_edges(visitor);
  24. visitor.visit(m_document);
  25. visitor.visit(m_active_contenteditable_element);
  26. }
  27. void EditingHostManager::handle_insert(String const& data)
  28. {
  29. auto selection = m_document->get_selection();
  30. auto selection_range = selection->range();
  31. if (!selection_range)
  32. return;
  33. auto node = selection->anchor_node();
  34. if (!node || !node->is_editable_or_editing_host())
  35. return;
  36. if (!is<DOM::Text>(*node)) {
  37. auto& realm = node->realm();
  38. auto text = realm.create<DOM::Text>(node->document(), data);
  39. MUST(node->append_child(*text));
  40. MUST(selection->collapse(*text, 1));
  41. return;
  42. }
  43. auto& text_node = static_cast<DOM::Text&>(*node);
  44. MUST(selection_range->delete_contents());
  45. MUST(text_node.insert_data(selection->anchor_offset(), data));
  46. VERIFY(selection->is_collapsed());
  47. auto utf16_data = MUST(AK::utf8_to_utf16(data));
  48. Utf16View const utf16_view { utf16_data };
  49. auto length = utf16_view.length_in_code_units();
  50. MUST(selection->collapse(*node, selection->anchor_offset() + length));
  51. text_node.invalidate_style(DOM::StyleInvalidationReason::EditingInsertion);
  52. }
  53. void EditingHostManager::select_all()
  54. {
  55. if (!m_active_contenteditable_element) {
  56. return;
  57. }
  58. auto selection = m_document->get_selection();
  59. if (!selection->anchor_node() || !selection->focus_node()) {
  60. return;
  61. }
  62. MUST(selection->set_base_and_extent(*selection->anchor_node(), 0, *selection->focus_node(), selection->focus_node()->length()));
  63. }
  64. void EditingHostManager::set_selection_anchor(GC::Ref<DOM::Node> anchor_node, size_t anchor_offset)
  65. {
  66. auto selection = m_document->get_selection();
  67. MUST(selection->collapse(*anchor_node, anchor_offset));
  68. m_document->reset_cursor_blink_cycle();
  69. }
  70. void EditingHostManager::set_selection_focus(GC::Ref<DOM::Node> focus_node, size_t focus_offset)
  71. {
  72. if (!m_active_contenteditable_element || !m_active_contenteditable_element->is_ancestor_of(*focus_node))
  73. return;
  74. auto selection = m_document->get_selection();
  75. if (!selection->anchor_node())
  76. return;
  77. MUST(selection->set_base_and_extent(*selection->anchor_node(), selection->anchor_offset(), *focus_node, focus_offset));
  78. m_document->reset_cursor_blink_cycle();
  79. }
  80. void EditingHostManager::move_cursor_to_start(CollapseSelection collapse)
  81. {
  82. auto selection = m_document->get_selection();
  83. auto node = selection->anchor_node();
  84. if (!node || !is<DOM::Text>(*node))
  85. return;
  86. if (collapse == CollapseSelection::Yes) {
  87. MUST(selection->collapse(node, 0));
  88. m_document->reset_cursor_blink_cycle();
  89. return;
  90. }
  91. MUST(selection->set_base_and_extent(*node, selection->anchor_offset(), *node, 0));
  92. }
  93. void EditingHostManager::move_cursor_to_end(CollapseSelection collapse)
  94. {
  95. auto selection = m_document->get_selection();
  96. auto node = selection->anchor_node();
  97. if (!node || !is<DOM::Text>(*node))
  98. return;
  99. if (collapse == CollapseSelection::Yes) {
  100. m_document->reset_cursor_blink_cycle();
  101. MUST(selection->collapse(node, node->length()));
  102. return;
  103. }
  104. MUST(selection->set_base_and_extent(*node, selection->anchor_offset(), *node, node->length()));
  105. }
  106. void EditingHostManager::increment_cursor_position_offset(CollapseSelection collapse)
  107. {
  108. auto selection = m_document->get_selection();
  109. if (!selection)
  110. return;
  111. selection->move_offset_to_next_character(collapse == CollapseSelection::Yes);
  112. }
  113. void EditingHostManager::decrement_cursor_position_offset(CollapseSelection collapse)
  114. {
  115. auto selection = m_document->get_selection();
  116. if (!selection)
  117. return;
  118. selection->move_offset_to_previous_character(collapse == CollapseSelection::Yes);
  119. }
  120. void EditingHostManager::increment_cursor_position_to_next_word(CollapseSelection collapse)
  121. {
  122. auto selection = m_document->get_selection();
  123. if (!selection)
  124. return;
  125. selection->move_offset_to_next_character(collapse == CollapseSelection::Yes);
  126. }
  127. void EditingHostManager::decrement_cursor_position_to_previous_word(CollapseSelection collapse)
  128. {
  129. auto selection = m_document->get_selection();
  130. if (!selection)
  131. return;
  132. selection->move_offset_to_previous_word(collapse == CollapseSelection::Yes);
  133. }
  134. void EditingHostManager::handle_delete(DeleteDirection direction)
  135. {
  136. auto selection = m_document->get_selection();
  137. auto selection_range = selection->range();
  138. if (!selection_range) {
  139. return;
  140. }
  141. if (selection->is_collapsed()) {
  142. auto node = selection->anchor_node();
  143. if (!node || !is<DOM::Text>(*node)) {
  144. return;
  145. }
  146. auto& text_node = static_cast<DOM::Text&>(*node);
  147. if (direction == DeleteDirection::Backward) {
  148. if (selection->anchor_offset() > 0) {
  149. MUST(text_node.delete_data(selection->anchor_offset() - 1, 1));
  150. text_node.invalidate_style(DOM::StyleInvalidationReason::EditingInsertion);
  151. }
  152. } else {
  153. if (selection->anchor_offset() < text_node.data().bytes_as_string_view().length()) {
  154. MUST(text_node.delete_data(selection->anchor_offset(), 1));
  155. text_node.invalidate_style(DOM::StyleInvalidationReason::EditingInsertion);
  156. }
  157. }
  158. m_document->reset_cursor_blink_cycle();
  159. return;
  160. }
  161. MUST(selection_range->delete_contents());
  162. }
  163. void EditingHostManager::handle_return_key()
  164. {
  165. dbgln("FIXME: Implement EditingHostManager::handle_return_key()");
  166. }
  167. }