Преглед на файлове

LibWeb: Handle input element value setting & getting closer to the spec

We should not set the 'value' attribute when an input element's value is
changed (by the user or programmatically). Instead, we should track the
value internally and mark it with a dirty flag when it is changed.
Timothy Flynn преди 3 години
родител
ревизия
859a75fd4c
променени са 2 файла, в които са добавени 36 реда и са изтрити 10 реда
  1. 32 10
      Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
  2. 4 0
      Userland/Libraries/LibWeb/HTML/HTMLInputElement.h

+ 32 - 10
Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp

@@ -22,6 +22,7 @@ namespace Web::HTML {
 
 
 HTMLInputElement::HTMLInputElement(DOM::Document& document, DOM::QualifiedName qualified_name)
 HTMLInputElement::HTMLInputElement(DOM::Document& document, DOM::QualifiedName qualified_name)
     : FormAssociatedElement(document, move(qualified_name))
     : FormAssociatedElement(document, move(qualified_name))
+    , m_value(String::empty())
 {
 {
     activation_behavior = [this](auto&) {
     activation_behavior = [this](auto&) {
         // The activation behavior for input elements are these steps:
         // The activation behavior for input elements are these steps:
@@ -117,6 +118,10 @@ void HTMLInputElement::run_input_activation_behavior()
 
 
 void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
 void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
 {
 {
+    // An input element's dirty value flag must be set to true whenever the user interacts with the control in a way that changes the value.
+    m_value = value_sanitization_algorithm(m_text_node->data());
+    m_dirty_value = true;
+
     // NOTE: This is a bit ad-hoc, but basically implements part of "4.10.5.5 Common event behaviors"
     // NOTE: This is a bit ad-hoc, but basically implements part of "4.10.5.5 Common event behaviors"
     //       https://html.spec.whatwg.org/multipage/input.html#common-input-element-events
     //       https://html.spec.whatwg.org/multipage/input.html#common-input-element-events
     queue_an_element_task(HTML::Task::Source::UserInteraction, [this] {
     queue_an_element_task(HTML::Task::Source::UserInteraction, [this] {
@@ -132,22 +137,33 @@ void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
     });
     });
 }
 }
 
 
+// https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
 String HTMLInputElement::value() const
 String HTMLInputElement::value() const
 {
 {
-    if (m_text_node)
-        return m_text_node->data();
-    return default_value();
+    // Return the current value of the element.
+    return m_value;
 }
 }
 
 
+// https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
 void HTMLInputElement::set_value(String value)
 void HTMLInputElement::set_value(String value)
 {
 {
-    auto sanitised_value = value_sanitization_algorithm(move(value));
+    // 1. Let oldValue be the element's value.
+    auto old_value = move(m_value);
 
 
-    if (m_text_node) {
-        m_text_node->set_data(sanitised_value);
-        return;
-    }
-    set_attribute(HTML::AttributeNames::value, sanitised_value);
+    // 2. Set the element's value to the new value.
+    // NOTE: This is done as part of step 4 below.
+
+    // 3. Set the element's dirty value flag to true.
+    m_dirty_value = true;
+
+    // 4. Invoke the value sanitization algorithm, if the element's type attribute's current state defines one.
+    m_value = value_sanitization_algorithm(move(value));
+
+    // 5. If the element's value (after applying the value sanitization algorithm) is different from oldValue,
+    //    and the element has a text entry cursor position, move the text entry cursor position to the end of the
+    //    text control, unselecting any selected text and resetting the selection direction to "none".
+    if (m_text_node && (m_value != old_value))
+        m_text_node->set_data(m_value);
 }
 }
 
 
 void HTMLInputElement::create_shadow_tree_if_needed()
 void HTMLInputElement::create_shadow_tree_if_needed()
@@ -169,7 +185,7 @@ void HTMLInputElement::create_shadow_tree_if_needed()
     }
     }
 
 
     auto shadow_root = adopt_ref(*new DOM::ShadowRoot(document(), *this));
     auto shadow_root = adopt_ref(*new DOM::ShadowRoot(document(), *this));
-    auto initial_value = attribute(HTML::AttributeNames::value);
+    auto initial_value = m_value;
     if (initial_value.is_null())
     if (initial_value.is_null())
         initial_value = String::empty();
         initial_value = String::empty();
     auto element = document().create_element(HTML::TagNames::div).release_value();
     auto element = document().create_element(HTML::TagNames::div).release_value();
@@ -207,6 +223,9 @@ void HTMLInputElement::parse_attribute(FlyString const& name, String const& valu
             set_checked(true, ChangeSource::Programmatic);
             set_checked(true, ChangeSource::Programmatic);
     } else if (name == HTML::AttributeNames::type) {
     } else if (name == HTML::AttributeNames::type) {
         m_type = parse_type_attribute(value);
         m_type = parse_type_attribute(value);
+    } else if (name == HTML::AttributeNames::value) {
+        if (!m_dirty_value)
+            m_value = value_sanitization_algorithm(value);
     }
     }
 }
 }
 
 
@@ -232,6 +251,9 @@ void HTMLInputElement::did_remove_attribute(FlyString const& name)
         // the user agent must set the checkedness of the element to false.
         // the user agent must set the checkedness of the element to false.
         if (!m_dirty_checkedness)
         if (!m_dirty_checkedness)
             set_checked(false, ChangeSource::Programmatic);
             set_checked(false, ChangeSource::Programmatic);
+    } else if (name == HTML::AttributeNames::value) {
+        if (!m_dirty_value)
+            m_value = String::empty();
     }
     }
 }
 }
 
 

+ 4 - 0
Userland/Libraries/LibWeb/HTML/HTMLInputElement.h

@@ -119,11 +119,15 @@ private:
     // https://html.spec.whatwg.org/multipage/input.html#concept-input-checked-dirty-flag
     // https://html.spec.whatwg.org/multipage/input.html#concept-input-checked-dirty-flag
     bool m_dirty_checkedness { false };
     bool m_dirty_checkedness { false };
 
 
+    // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-dirty
+    bool m_dirty_value { false };
+
     // https://html.spec.whatwg.org/multipage/input.html#the-input-element:legacy-pre-activation-behavior
     // https://html.spec.whatwg.org/multipage/input.html#the-input-element:legacy-pre-activation-behavior
     bool m_before_legacy_pre_activation_behavior_checked { false };
     bool m_before_legacy_pre_activation_behavior_checked { false };
     RefPtr<HTMLInputElement> m_legacy_pre_activation_behavior_checked_element_in_group;
     RefPtr<HTMLInputElement> m_legacy_pre_activation_behavior_checked_element_in_group;
 
 
     TypeAttributeState m_type { TypeAttributeState::Text };
     TypeAttributeState m_type { TypeAttributeState::Text };
+    String m_value;
 };
 };
 
 
 }
 }