Переглянути джерело

LibWeb: Update the stored textarea value upon change

And fire the "input" event upon change. This is needed to submit a
comment on GitHub; otherwise, GitHub thinks the textarea value is empty.
Timothy Flynn 1 рік тому
батько
коміт
ed13793110

+ 1 - 0
Tests/LibWeb/Text/expected/textarea-value.txt

@@ -2,3 +2,4 @@
 2. "PASS"
 3. "PASS"
 4. 4
+5. "PASS"

+ 14 - 0
Tests/LibWeb/Text/input/textarea-value.html

@@ -35,5 +35,19 @@
             textarea.innerHTML = 'PASS';
             return textarea.textLength;
         });
+
+        // 5. Textarea input via keyboard events.
+        testPart(() => {
+            const textarea = document.createElement('textarea');
+
+            // The element currently has to be part of a document to be able to receive keyboard events.
+            document.body.appendChild(textarea);
+
+            internals.sendText(textarea, 'PASS');
+            const value = textarea.value;
+
+            document.body.removeChild(textarea);
+            return value;
+        });
     });
 </script>

+ 19 - 0
Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp

@@ -24,6 +24,7 @@ JS_DEFINE_ALLOCATOR(HTMLTextAreaElement);
 
 HTMLTextAreaElement::HTMLTextAreaElement(DOM::Document& document, DOM::QualifiedName qualified_name)
     : HTMLElement(document, move(qualified_name))
+    , m_input_event_timer(Web::Platform::Timer::create_single_shot(0, [this]() { queue_firing_input_event(); }))
 {
 }
 
@@ -333,10 +334,28 @@ void HTMLTextAreaElement::form_associated_element_attribute_changed(FlyString co
 
 void HTMLTextAreaElement::did_edit_text_node(Badge<Web::HTML::BrowsingContext>)
 {
+    VERIFY(m_text_node);
+    m_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
+    // bubbles and composed attributes initialized to true. User agents may wait for a suitable break in the user's
+    // interaction before queuing the task; for example, a user agent could wait for the user to have not hit a key for
+    // 100ms, so as to only fire the event when the user pauses, instead of continuously for each keystroke.
+    m_input_event_timer->restart(100);
+
     // A textarea element's dirty value flag must be set to true whenever the user interacts with the control in a way that changes the raw value.
     m_dirty_value = true;
 
     update_placeholder_visibility();
 }
 
+void HTMLTextAreaElement::queue_firing_input_event()
+{
+    queue_an_element_task(HTML::Task::Source::UserInteraction, [this]() {
+        auto change_event = DOM::Event::create(realm(), HTML::EventNames::input, { .bubbles = true, .composed = true });
+        dispatch_event(change_event);
+    });
+}
+
 }

+ 5 - 0
Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h

@@ -12,6 +12,7 @@
 #include <LibWeb/DOM/Text.h>
 #include <LibWeb/HTML/FormAssociatedElement.h>
 #include <LibWeb/HTML/HTMLElement.h>
+#include <LibWeb/Platform/Timer.h>
 #include <LibWeb/WebIDL/Types.h>
 
 namespace Web::HTML {
@@ -109,6 +110,8 @@ private:
     void handle_readonly_attribute(Optional<String> const& value);
     void handle_maxlength_attribute();
 
+    void queue_firing_input_event();
+
     void update_placeholder_visibility();
     JS::GCPtr<DOM::Element> m_placeholder_element;
     JS::GCPtr<DOM::Text> m_placeholder_text_node;
@@ -116,6 +119,8 @@ private:
     JS::GCPtr<DOM::Element> m_inner_text_element;
     JS::GCPtr<DOM::Text> m_text_node;
 
+    RefPtr<Web::Platform::Timer> m_input_event_timer;
+
     // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-dirty
     bool m_dirty_value { false };