Просмотр исходного кода

LibWeb: Implement selectedness algorithm

Implement selectedness setting algorithm in HTMLSelectElement
Timur Sultanov 1 год назад
Родитель
Сommit
f4102b1dc9

+ 6 - 1
Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp

@@ -57,11 +57,16 @@ void HTMLOptionElement::attribute_changed(FlyString const& name, Optional<String
 void HTMLOptionElement::set_selected(bool selected)
 {
     // On setting, it must set the element's selectedness to the new value, set its dirtiness to true, and then cause the element to ask for a reset.
-    m_selected = selected;
+    set_selected_internal(selected);
     m_dirty = true;
     ask_for_a_reset();
 }
 
+void HTMLOptionElement::set_selected_internal(bool selected)
+{
+    m_selected = selected;
+}
+
 // https://html.spec.whatwg.org/multipage/form-elements.html#dom-option-value
 String HTMLOptionElement::value() const
 {

+ 1 - 0
Userland/Libraries/LibWeb/HTML/HTMLOptionElement.h

@@ -20,6 +20,7 @@ public:
 
     bool selected() const { return m_selected; }
     void set_selected(bool);
+    void set_selected_internal(bool);
 
     String value() const;
     WebIDL::ExceptionOr<void> set_value(String const&);

+ 56 - 14
Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp

@@ -135,12 +135,7 @@ WebIDL::ExceptionOr<void> HTMLSelectElement::add(HTMLOptionOrOptGroupElement ele
     // Similarly, the add(element, before) method must act like its namesake method on that same options collection.
     TRY(const_cast<HTMLOptionsCollection&>(*options()).add(move(element), move(before)));
 
-    // If the inserted element is the first and only element, mark it as selected
-    auto options = list_of_options();
-    if (options.size() == 1) {
-        options.at(0)->set_selected(true);
-        update_inner_text_element();
-    }
+    update_selectedness(); // Not in spec
 
     return {};
 }
@@ -481,14 +476,7 @@ void HTMLSelectElement::form_associated_element_was_inserted()
 
     // Wait until children are ready
     queue_an_element_task(HTML::Task::Source::Microtask, [this] {
-        // Select first option when no other option is selected
-        if (selected_index() == -1) {
-            auto options = list_of_options();
-            if (options.size() > 0) {
-                options.at(0)->set_selected(true);
-            }
-        }
-        update_inner_text_element();
+        update_selectedness();
     });
 }
 
@@ -558,4 +546,58 @@ void HTMLSelectElement::update_inner_text_element()
         }
     }
 }
+
+// https://html.spec.whatwg.org/multipage/form-elements.html#selectedness-setting-algorithm
+void HTMLSelectElement::update_selectedness()
+{
+    if (has_attribute(AttributeNames::multiple))
+        return;
+
+    // If element's multiple attribute is absent, and element's display size is 1,
+    if (size() == 1) {
+        bool has_selected_elements = false;
+        for (auto const& option_element : list_of_options()) {
+            if (option_element->selected()) {
+                has_selected_elements = true;
+                break;
+            }
+        }
+
+        // and no option elements in the element's list of options have their selectedness set to true,
+        if (!has_selected_elements) {
+            // then set the selectedness of the first option element in the list of options in tree order
+            // that is not disabled, if any, to true, and return.
+            for (auto const& option_element : list_of_options()) {
+                if (!option_element->disabled()) {
+                    option_element->set_selected_internal(true);
+                    update_inner_text_element();
+                    return;
+                }
+            }
+        }
+    }
+
+    // If element's multiple attribute is absent,
+    // and two or more option elements in element's list of options have their selectedness set to true,
+    // then set the selectedness of all but the last option element with its selectedness set to true
+    // in the list of options in tree order to false.
+    int number_of_selected = 0;
+    for (auto const& option_element : list_of_options()) {
+        if (option_element->selected())
+            ++number_of_selected;
+    }
+    // and two or more option elements in element's list of options have their selectedness set to true,
+    if (number_of_selected >= 2) {
+        // then set the selectedness of all but the last option element with its selectedness set to true
+        // in the list of options in tree order to false.
+        for (auto const& option_element : list_of_options()) {
+            if (number_of_selected == 1) {
+                break;
+            }
+            option_element->set_selected_internal(false);
+            --number_of_selected;
+        }
+    }
+    update_inner_text_element();
+}
 }

+ 2 - 0
Userland/Libraries/LibWeb/HTML/HTMLSelectElement.h

@@ -92,6 +92,8 @@ public:
 
     void did_select_item(Optional<u32> const& id);
 
+    void update_selectedness();
+
 private:
     HTMLSelectElement(DOM::Document&, DOM::QualifiedName);