Pārlūkot izejas kodu

LibWeb: Implement Text.wholeText

This getter returns the concatenation of the data of the contiguous
Text nodes of `this` (being this plus its siblings) in tree order.
Ángel Carias 1 gadu atpakaļ
vecāks
revīzija
69da6a0ce4

+ 6 - 0
Tests/LibWeb/Text/expected/DOM/Text-wholeText.txt

@@ -0,0 +1,6 @@
+Text node A with no siblings: A
+Text node B with previous sibling A: AB
+Text node B with previous sibling A and next sibling C: ABC
+CDATA section D with no siblings: D
+CDATA section E with previous sibling D: DE
+CDATA section E with previous sibling D and next sibling F: DEF

+ 36 - 0
Tests/LibWeb/Text/input/DOM/Text-wholeText.html

@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        // HTML Text Nodes
+        const fragment = document.createDocumentFragment();
+
+        const firstNode = document.createTextNode("A");
+        fragment.appendChild(firstNode);
+        println(`Text node ${firstNode.data} with no siblings: ${firstNode.wholeText}`);
+
+        const secondNode = document.createTextNode("B");
+        fragment.appendChild(secondNode);
+        println(`Text node ${secondNode.data} with previous sibling ${secondNode.previousSibling.data}: ${secondNode.wholeText}`);
+
+        const thirdNode = document.createTextNode("C");
+        fragment.appendChild(thirdNode);
+        println(`Text node ${secondNode.data} with previous sibling ${secondNode.previousSibling.data} and next sibling ${secondNode.nextSibling.data}: ${secondNode.wholeText}`);
+
+        // XML CDATA Sections
+        const xmlDoc = new DOMParser().parseFromString("<root></root>", "application/xml");
+        const xmlFrag = xmlDoc.querySelector("root");
+
+        const firstSection = xmlDoc.createCDATASection("D");
+        xmlFrag.appendChild(firstSection);
+        println(`CDATA section ${firstSection.data} with no siblings: ${firstSection.wholeText}`);
+
+        const secondSection = xmlDoc.createCDATASection("E");
+        xmlFrag.appendChild(secondSection);
+        println(`CDATA section ${secondSection.data} with previous sibling ${secondSection.previousSibling.data}: ${secondSection.wholeText}`);
+
+        const thirdSection = xmlDoc.createCDATASection("F");
+        xmlFrag.appendChild(thirdSection);
+        println(`CDATA section ${secondSection.data} with previous sibling ${secondSection.previousSibling.data} and next sibling ${secondSection.nextSibling.data}: ${secondSection.wholeText}`);
+    });
+</script>

+ 32 - 0
Userland/Libraries/LibWeb/DOM/Text.cpp

@@ -117,4 +117,36 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> Text::split_text(size_t offset)
     return new_node;
 }
 
+// https://dom.spec.whatwg.org/#dom-text-wholetext
+String Text::whole_text()
+{
+    // https://dom.spec.whatwg.org/#contiguous-text-nodes
+    // The contiguous Text nodes of a node node are node, node’s previous sibling Text node, if any, and its contiguous
+    // Text nodes, and node’s next sibling Text node, if any, and its contiguous Text nodes, avoiding any duplicates.
+    Vector<Text*> nodes;
+
+    nodes.append(this);
+
+    auto* current_node = previous_sibling();
+    while (current_node && (current_node->is_text() || current_node->is_cdata_section())) {
+        nodes.append(static_cast<Text*>(current_node));
+        current_node = current_node->previous_sibling();
+    }
+
+    // Reverse nodes so they are in tree order
+    nodes.reverse();
+
+    current_node = next_sibling();
+    while (current_node && (current_node->is_text() || current_node->is_cdata_section())) {
+        nodes.append(static_cast<Text*>(current_node));
+        current_node = current_node->next_sibling();
+    }
+
+    StringBuilder builder;
+    for (auto const& text_node : nodes)
+        builder.append(text_node->data());
+
+    return MUST(builder.to_string());
+}
+
 }

+ 1 - 0
Userland/Libraries/LibWeb/DOM/Text.h

@@ -43,6 +43,7 @@ public:
     EditableTextNodeOwner* editable_text_node_owner();
 
     WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> split_text(size_t offset);
+    String whole_text();
 
     bool is_password_input() const { return m_is_password_input; }
     void set_is_password_input(Badge<HTML::HTMLInputElement>, bool b) { m_is_password_input = b; }

+ 1 - 1
Userland/Libraries/LibWeb/DOM/Text.idl

@@ -8,7 +8,7 @@ interface Text : CharacterData {
     constructor(optional DOMString data = "");
 
     [NewObject] Text splitText(unsigned long offset);
-    [FIXME] readonly attribute DOMString wholeText;
+    readonly attribute DOMString wholeText;
 };
 
 Text includes Slottable;