Serenity Operating System
at master 115 lines 4.6 kB view raw
1/* 2 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibWeb/Bindings/Intrinsics.h> 8#include <LibWeb/DOM/Range.h> 9#include <LibWeb/DOM/Text.h> 10#include <LibWeb/HTML/HTMLInputElement.h> 11#include <LibWeb/HTML/Scripting/Environments.h> 12#include <LibWeb/HTML/Window.h> 13#include <LibWeb/Layout/TextNode.h> 14 15namespace Web::DOM { 16 17Text::Text(Document& document, DeprecatedString const& data) 18 : CharacterData(document, NodeType::TEXT_NODE, data) 19{ 20} 21 22Text::Text(Document& document, NodeType type, DeprecatedString const& data) 23 : CharacterData(document, type, data) 24{ 25} 26 27JS::ThrowCompletionOr<void> Text::initialize(JS::Realm& realm) 28{ 29 MUST_OR_THROW_OOM(Base::initialize(realm)); 30 set_prototype(&Bindings::ensure_web_prototype<Bindings::TextPrototype>(realm, "Text")); 31 32 return {}; 33} 34 35void Text::visit_edges(Cell::Visitor& visitor) 36{ 37 Base::visit_edges(visitor); 38 visitor.visit(m_owner_input_element.ptr()); 39} 40 41// https://dom.spec.whatwg.org/#dom-text-text 42WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> Text::construct_impl(JS::Realm& realm, DeprecatedString const& data) 43{ 44 // The new Text(data) constructor steps are to set this’s data to data and this’s node document to current global object’s associated Document. 45 auto& window = verify_cast<HTML::Window>(HTML::current_global_object()); 46 return MUST_OR_THROW_OOM(realm.heap().allocate<Text>(realm, window.associated_document(), data)); 47} 48 49void Text::set_owner_input_element(Badge<HTML::HTMLInputElement>, HTML::HTMLInputElement& input_element) 50{ 51 m_owner_input_element = &input_element; 52} 53 54// https://dom.spec.whatwg.org/#dom-text-splittext 55// https://dom.spec.whatwg.org/#concept-text-split 56WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> Text::split_text(size_t offset) 57{ 58 // 1. Let length be node’s length. 59 auto length = this->length(); 60 61 // 2. If offset is greater than length, then throw an "IndexSizeError" DOMException. 62 if (offset > length) 63 return WebIDL::IndexSizeError::create(realm(), "Split offset is greater than length"); 64 65 // 3. Let count be length minus offset. 66 auto count = length - offset; 67 68 // 4. Let new data be the result of substringing data with node node, offset offset, and count count. 69 auto new_data = TRY(substring_data(offset, count)); 70 71 // 5. Let new node be a new Text node, with the same node document as node. Set new node’s data to new data. 72 auto new_node = MUST_OR_THROW_OOM(heap().allocate<Text>(realm(), document(), new_data)); 73 74 // 6. Let parent be node’s parent. 75 JS::GCPtr<Node> parent = this->parent(); 76 77 // 7. If parent is not null, then: 78 if (parent) { 79 // 1. Insert new node into parent before node’s next sibling. 80 parent->insert_before(*new_node, next_sibling()); 81 82 // 2. For each live range whose start node is node and start offset is greater than offset, set its start node to new node and decrease its start offset by offset. 83 for (auto& range : Range::live_ranges()) { 84 if (range->start_container() == this && range->start_offset() > offset) 85 TRY(range->set_start(*new_node, range->start_offset() - offset)); 86 } 87 88 // 3. For each live range whose end node is node and end offset is greater than offset, set its end node to new node and decrease its end offset by offset. 89 for (auto& range : Range::live_ranges()) { 90 if (range->end_container() == this && range->end_offset() > offset) 91 TRY(range->set_end(*new_node, range->end_offset() - offset)); 92 } 93 94 // 4. For each live range whose start node is parent and start offset is equal to the index of node plus 1, increase its start offset by 1. 95 for (auto& range : Range::live_ranges()) { 96 if (range->start_container() == this && range->start_offset() == index() + 1) 97 TRY(range->set_start(*range->start_container(), range->start_offset() + 1)); 98 } 99 100 // 5. For each live range whose end node is parent and end offset is equal to the index of node plus 1, increase its end offset by 1. 101 for (auto& range : Range::live_ranges()) { 102 if (range->end_container() == parent.ptr() && range->end_offset() == index() + 1) { 103 TRY(range->set_end(*range->end_container(), range->end_offset() + 1)); 104 } 105 } 106 } 107 108 // 8. Replace data with node node, offset offset, count count, and data the empty string. 109 TRY(replace_data(offset, count, "")); 110 111 // 9. Return new node. 112 return new_node; 113} 114 115}