mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-01 05:39:11 +00:00
LibWeb/HTML: Implement inner text set according to spec
Replaced the ad-hoc implementation with a spec compliant one. This change fixes 36 WPT tests.
This commit is contained in:
parent
58c523ae46
commit
50f642613d
Notes:
github-actions[bot]
2024-10-20 20:15:59 +00:00
Author: https://github.com/samu698 🔰
Commit: 50f642613d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1873
Reviewed-by: https://github.com/AtkinsSJ
4 changed files with 61 additions and 1 deletions
3
Tests/LibWeb/Text/expected/HTML/set-innerText.txt
Normal file
3
Tests/LibWeb/Text/expected/HTML/set-innerText.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Empty string: ""
|
||||||
|
Simple text: "foo"
|
||||||
|
Text with newlines: "<br>foo<br>bar<br>baz<br><br>foobar<br>"
|
12
Tests/LibWeb/Text/input/HTML/set-innerText.html
Normal file
12
Tests/LibWeb/Text/input/HTML/set-innerText.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let element = document.createElement('div');
|
||||||
|
element.innerText = "";
|
||||||
|
println('Empty string: "' + element.innerHTML + '"');
|
||||||
|
element.innerText = "foo";
|
||||||
|
println('Simple text: "' + element.innerHTML + '"');
|
||||||
|
element.innerText = "\rfoo\nbar\r\nbaz\n\rfoobar\n";
|
||||||
|
println('Text with newlines: "' + element.innerHTML + '"');
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -9,6 +9,7 @@
|
||||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||||
#include <LibWeb/Bindings/HTMLElementPrototype.h>
|
#include <LibWeb/Bindings/HTMLElementPrototype.h>
|
||||||
#include <LibWeb/DOM/Document.h>
|
#include <LibWeb/DOM/Document.h>
|
||||||
|
#include <LibWeb/DOM/ElementFactory.h>
|
||||||
#include <LibWeb/DOM/IDLEventListener.h>
|
#include <LibWeb/DOM/IDLEventListener.h>
|
||||||
#include <LibWeb/DOM/LiveNodeList.h>
|
#include <LibWeb/DOM/LiveNodeList.h>
|
||||||
#include <LibWeb/DOM/ShadowRoot.h>
|
#include <LibWeb/DOM/ShadowRoot.h>
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
#include <LibWeb/Layout/Box.h>
|
#include <LibWeb/Layout/Box.h>
|
||||||
#include <LibWeb/Layout/BreakNode.h>
|
#include <LibWeb/Layout/BreakNode.h>
|
||||||
#include <LibWeb/Layout/TextNode.h>
|
#include <LibWeb/Layout/TextNode.h>
|
||||||
|
#include <LibWeb/Namespace.h>
|
||||||
#include <LibWeb/Painting/PaintableBox.h>
|
#include <LibWeb/Painting/PaintableBox.h>
|
||||||
#include <LibWeb/UIEvents/EventNames.h>
|
#include <LibWeb/UIEvents/EventNames.h>
|
||||||
#include <LibWeb/UIEvents/FocusEvent.h>
|
#include <LibWeb/UIEvents/FocusEvent.h>
|
||||||
|
@ -150,10 +152,13 @@ WebIDL::ExceptionOr<void> HTMLElement::set_content_editable(StringView content_e
|
||||||
return WebIDL::SyntaxError::create(realm(), "Invalid contentEditable value, must be 'true', 'false', or 'inherit'"_string);
|
return WebIDL::SyntaxError::create(realm(), "Invalid contentEditable value, must be 'true', 'false', or 'inherit'"_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/dom.html#set-the-inner-text-steps
|
||||||
void HTMLElement::set_inner_text(StringView text)
|
void HTMLElement::set_inner_text(StringView text)
|
||||||
{
|
{
|
||||||
|
// 1. Let fragment be the rendered text fragment for value given element's node document.
|
||||||
|
// 2. Replace all with fragment within element.
|
||||||
remove_all_children();
|
remove_all_children();
|
||||||
MUST(append_child(document().create_text_node(MUST(String::from_utf8(text)))));
|
append_rendered_text_fragment(text);
|
||||||
|
|
||||||
set_needs_style_update(true);
|
set_needs_style_update(true);
|
||||||
}
|
}
|
||||||
|
@ -165,6 +170,45 @@ WebIDL::ExceptionOr<void> HTMLElement::set_outer_text(String)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/dom.html#rendered-text-fragment
|
||||||
|
void HTMLElement::append_rendered_text_fragment(StringView input)
|
||||||
|
{
|
||||||
|
// FIXME: 1. Let fragment be a new DocumentFragment whose node document is document.
|
||||||
|
// Instead of creating a DocumentFragment the nodes are appended directly.
|
||||||
|
|
||||||
|
// 2. Let position be a position variable for input, initially pointing at the start of input.
|
||||||
|
// 3. Let text be the empty string.
|
||||||
|
// 4. While position is not past the end of input:
|
||||||
|
while (!input.is_empty()) {
|
||||||
|
// 1. Collect a sequence of code points that are not U+000A LF or U+000D CR from input given position, and set text to the result.
|
||||||
|
auto newline_index = input.find_any_of("\n\r"sv);
|
||||||
|
size_t const sequence_end_index = newline_index.value_or(input.length());
|
||||||
|
StringView const text = input.substring_view(0, sequence_end_index);
|
||||||
|
input = input.substring_view_starting_after_substring(text);
|
||||||
|
|
||||||
|
// 2. If text is not the empty string, then append a new Text node whose data is text and node document is document to fragment.
|
||||||
|
if (!text.is_empty()) {
|
||||||
|
MUST(append_child(document().create_text_node(MUST(String::from_utf8(text)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. While position is not past the end of input, and the code point at position is either U+000A LF or U+000D CR:
|
||||||
|
while (input.starts_with('\n') || input.starts_with('\r')) {
|
||||||
|
// 1. If the code point at position is U+000D CR and the next code point is U+000A LF, then advance position to the next code point in input.
|
||||||
|
if (input.starts_with("\r\n"sv)) {
|
||||||
|
// 2. Advance position to the next code point in input.
|
||||||
|
input = input.substring_view(2);
|
||||||
|
} else {
|
||||||
|
// 2. Advance position to the next code point in input.
|
||||||
|
input = input.substring_view(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Append the result of creating an element given document, br, and the HTML namespace to fragment.
|
||||||
|
auto br_element = DOM::create_element(document(), HTML::TagNames::br, Namespace::HTML).release_value();
|
||||||
|
MUST(append_child(br_element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/dom.html#get-the-text-steps
|
// https://html.spec.whatwg.org/multipage/dom.html#get-the-text-steps
|
||||||
String HTMLElement::get_the_text_steps()
|
String HTMLElement::get_the_text_steps()
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,6 +97,7 @@ private:
|
||||||
virtual void did_receive_focus() override;
|
virtual void did_receive_focus() override;
|
||||||
|
|
||||||
[[nodiscard]] String get_the_text_steps();
|
[[nodiscard]] String get_the_text_steps();
|
||||||
|
void append_rendered_text_fragment(StringView input);
|
||||||
|
|
||||||
JS::GCPtr<DOMStringMap> m_dataset;
|
JS::GCPtr<DOMStringMap> m_dataset;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue