diff --git a/Tests/LibWeb/Text/expected/textarea-value.txt b/Tests/LibWeb/Text/expected/textarea-value.txt index aa11dd98079..41ac855eac7 100644 --- a/Tests/LibWeb/Text/expected/textarea-value.txt +++ b/Tests/LibWeb/Text/expected/textarea-value.txt @@ -3,3 +3,4 @@ 3. "PASS" 4. 4 5. "PASS" +6. "[0x0a]text[0x0a]with[0x0a]carriage[0x0a][0x0a]return[0x0a][0x0a]" diff --git a/Tests/LibWeb/Text/input/textarea-value.html b/Tests/LibWeb/Text/input/textarea-value.html index 2189534bac0..3efe7f1988c 100644 --- a/Tests/LibWeb/Text/input/textarea-value.html +++ b/Tests/LibWeb/Text/input/textarea-value.html @@ -49,5 +49,12 @@ document.body.removeChild(textarea); return value; }); + + // 6. Textarea set value with carriage return + testPart(() => { + const textarea = document.createElement('textarea'); + textarea.value = '\ntext\rwith\r\ncarriage\n\rreturn\r\r'; + return textarea.value.replaceAll('\n', '[0x0a]'); + }); }); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index 6954307f718..be38efdb3b1 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace Web::HTML { @@ -93,7 +94,7 @@ void HTMLTextAreaElement::reset_algorithm() // The reset algorithm for textarea elements is to set the dirty value flag back to false, m_dirty_value = false; // and set the raw value of element to its child text content. - m_raw_value = child_text_content(); + set_raw_value(child_text_content()); update_placeholder_visibility(); } @@ -126,7 +127,7 @@ void HTMLTextAreaElement::set_default_value(String const& default_value) String HTMLTextAreaElement::value() const { // The value IDL attribute must, on getting, return the element's API value. - return m_raw_value; + return api_value(); } // https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-value @@ -135,7 +136,7 @@ void HTMLTextAreaElement::set_value(String const& value) // FIXME: 1. Let oldAPIValue be this element's API value. // 2. Set this element's raw value to the new value. - m_raw_value = value; + set_raw_value(value); // 3. Set this element's dirty value flag to true. m_dirty_value = true; @@ -144,12 +145,27 @@ void HTMLTextAreaElement::set_value(String const& value) update_placeholder_visibility(); } +void HTMLTextAreaElement::set_raw_value(String value) +{ + m_raw_value = move(value); + m_api_value.clear(); +} + +// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:concept-fe-api-value-3 +String HTMLTextAreaElement::api_value() const +{ + // The algorithm for obtaining the element's API value is to return the element's raw value, with newlines normalized. + if (!m_api_value.has_value()) + m_api_value = Infra::normalize_newlines(m_raw_value); + return *m_api_value; +} + // https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-textlength u32 HTMLTextAreaElement::text_length() const { // The textLength IDL attribute must return the length of the element's API value. // FIXME: This is inefficient! - auto utf16_data = MUST(AK::utf8_to_utf16(m_raw_value)); + auto utf16_data = MUST(AK::utf8_to_utf16(api_value())); return Utf16View { utf16_data }.length_in_code_units(); } @@ -317,7 +333,7 @@ void HTMLTextAreaElement::children_changed() // The children changed steps for textarea elements must, if the element's dirty value flag is false, // set the element's raw value to its child text content. if (!m_dirty_value) { - m_raw_value = child_text_content(); + set_raw_value(child_text_content()); if (m_text_node) m_text_node->set_text_content(m_raw_value); update_placeholder_visibility(); @@ -339,7 +355,7 @@ void HTMLTextAreaElement::form_associated_element_attribute_changed(FlyString co void HTMLTextAreaElement::did_edit_text_node(Badge) { VERIFY(m_text_node); - m_raw_value = m_text_node->data(); + set_raw_value(m_text_node->data()); // Any time the user causes the element's raw value to change, the user agent must queue an element task on the user // interaction task source given the textarea element to fire an event named input at the textarea element, with the diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h index 6fe152e2d2c..7f254cec57d 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h @@ -102,6 +102,9 @@ private: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; + void set_raw_value(String); + String api_value() const; + // ^DOM::Element virtual i32 default_tab_index_value() const override; @@ -129,6 +132,9 @@ private: // https://html.spec.whatwg.org/multipage/form-elements.html#concept-textarea-raw-value String m_raw_value; + + // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-api-value + mutable Optional m_api_value; }; }