diff options
-rw-r--r-- | Base/res/html/misc/innertext_textcontent.html | 15 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/Element.cpp | 34 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/Element.h | 3 | ||||
-rw-r--r-- | Libraries/LibWeb/DOM/Element.idl | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Tests/DOM/Element.js | 24 | ||||
-rw-r--r-- | Libraries/LibWeb/Tests/DOM/Node.js | 10 |
6 files changed, 86 insertions, 1 deletions
diff --git a/Base/res/html/misc/innertext_textcontent.html b/Base/res/html/misc/innertext_textcontent.html new file mode 100644 index 0000000000..f8e2a3d94d --- /dev/null +++ b/Base/res/html/misc/innertext_textcontent.html @@ -0,0 +1,15 @@ +<html> + <head><title>Small test page</title></head> + <body bgcolor="#408080" text="#ffffff"> + <h1 title="This is a heading" >Hello friends!</h1> + <p>This is a <b>very small</b> test page :^)</p> + <p>Visit the <a title="This is a link" href="http://www.serenityos.org/">SerenityOS home page</a> today!</p> + + <p id="source"> + <style>#source { color: red; } #text { text-transform: uppercase; }</style> + <span id=text>Take a look at<br>how this text<br>is interpreted + below.</span> + <span style="display:none">HIDDEN TEXT</span> + </p> + </body> +</html> diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 19cc1733ad..b5445ab593 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -41,6 +41,7 @@ #include <LibWeb/Layout/LayoutTableCell.h> #include <LibWeb/Layout/LayoutTableRow.h> #include <LibWeb/Layout/LayoutTableRowGroup.h> +#include <LibWeb/Layout/LayoutText.h> #include <LibWeb/Layout/LayoutTreeBuilder.h> namespace Web::DOM { @@ -295,6 +296,39 @@ String Element::inner_html() const return builder.to_string(); } +void Element::set_inner_text(StringView text) +{ + remove_all_children(); + append_child(document().create_text_node(text)); + + set_needs_style_update(true); + document().schedule_style_update(); + document().invalidate_layout(); +} + +String Element::inner_text() +{ + StringBuilder builder; + + // innerText for element being rendered takes visibility into account, so force a layout and then walk the layout tree. + document().layout(); + if (!layout_node()) + return text_content(); + + Function<void(const LayoutNode&)> recurse = [&](auto& node) { + for (auto* child = node.first_child(); child; child = child->next_sibling()) { + if (child->is_text()) + builder.append(downcast<LayoutText>(*child).text_for_rendering()); + if (child->is_break()) + builder.append('\n'); + recurse(*child); + } + }; + recurse(*layout_node()); + + return builder.to_string(); +} + bool Element::is_focused() const { return document().focused_element() == this; diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index b08ff34e42..253f532aff 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -87,6 +87,9 @@ public: String inner_html() const; void set_inner_html(StringView); + String inner_text(); + void set_inner_text(StringView); + bool is_focused() const; virtual bool is_focusable() const { return false; } diff --git a/Libraries/LibWeb/DOM/Element.idl b/Libraries/LibWeb/DOM/Element.idl index 082d0a951a..34baef070e 100644 --- a/Libraries/LibWeb/DOM/Element.idl +++ b/Libraries/LibWeb/DOM/Element.idl @@ -9,6 +9,7 @@ interface Element : Node { ArrayFromVector querySelectorAll(DOMString selectors); attribute DOMString innerHTML; + attribute DOMString innerText; [Reflect] attribute DOMString id; [Reflect=class] attribute DOMString className; diff --git a/Libraries/LibWeb/Tests/DOM/Element.js b/Libraries/LibWeb/Tests/DOM/Element.js new file mode 100644 index 0000000000..0fd40594cc --- /dev/null +++ b/Libraries/LibWeb/Tests/DOM/Element.js @@ -0,0 +1,24 @@ +loadPage("file:///res/html/misc/innertext_textcontent.html"); + +afterInitialPageLoad(() => { + test("Element.innerText", () => { + var p = document.getElementsByTagName("p")[0]; + expect(p.innerText).toBe("This is a very small test page :^)"); + + // FIXME: Call this on p once that's supported. + var b = document.getElementsByTagName("b")[0]; + b.innerText = "foo"; + expect(b.innerText).toBe("foo"); + expect(p.innerText).toBe("This is a foo test page :^)"); + + p.innerText = "bar"; + expect(p.innerText).toBe("bar"); + + var p = document.getElementById("source"); + // FIXME: The leading and trailing two spaces each are wrong. + // FIXME: The text should be affected by the text-transform:uppercase. + expect(p.innerText).toBe(` Take a look at +how this text +is interpreted below. `); + }); +}); diff --git a/Libraries/LibWeb/Tests/DOM/Node.js b/Libraries/LibWeb/Tests/DOM/Node.js index 2af91d1cbb..5427d143bd 100644 --- a/Libraries/LibWeb/Tests/DOM/Node.js +++ b/Libraries/LibWeb/Tests/DOM/Node.js @@ -1,4 +1,4 @@ -loadPage("file:///res/html/misc/small.html"); +loadPage("file:///res/html/misc/innertext_textcontent.html"); afterInitialPageLoad(() => { test("Node.textContent", () => { @@ -16,5 +16,13 @@ afterInitialPageLoad(() => { expect(p.textContent).toBe("bar"); expect(p.firstChild.textContent).toBe("bar"); expect(p.firstChild.firstChild).toBe(null); + + var p = document.getElementById("source"); + expect(p.textContent).toBe(` + #source { color: red; } #text { text-transform: uppercase; } + Take a look athow this textis interpreted + below. + HIDDEN TEXT + `); }); }); |