Browse Source

LibWeb: Support RadioNodeList named items in HTMLFormControlsCollection

We would previously not return a RadioNodeList in the curious case where
a named item resolves to two different elements within the form.

This was not a problem when calling namedItem directly in the IDL as
named_item_or_radio_node_list shadows named_item but is exposed when
calling the property through array bracket notation (as an example).

Fix this, and add a bunch more tests to cover
HTMLFormControlsCollection.
Shannon Booth 1 year ago
parent
commit
ec2b4c271f

+ 79 - 0
Tests/LibWeb/Text/expected/html-form-controls-collection.txt

@@ -1,8 +1,87 @@
       HTMLFormControlsCollection
+2
+-------------------
+form.namedItem("formcontrol")
+-------------------
 RadioNodeList
 2
 button
 text
+-------------------
+form.namedItem("one")
+-------------------
+HTMLInputElement
+formcontrol
+button
+-------------------
+form.namedItem("two")
+-------------------
+HTMLInputElement
+formcontrol
+text
+-------------------
+form.namedItem("nomatch")
+-------------------
 null
+-------------------
+form["formcontrol"]
+-------------------
+RadioNodeList
+2
+button
+text
+-------------------
+form["one"]
+-------------------
+HTMLInputElement
+formcontrol
+button
+-------------------
+form["two"]
+-------------------
+HTMLInputElement
+formcontrol
+text
+-------------------
+form["nomatch"]
+-------------------
+undefined
+-------------------
+form.formcontrol
+-------------------
+RadioNodeList
+2
+button
+text
+-------------------
+form.one
+-------------------
+HTMLInputElement
+formcontrol
+button
+-------------------
+form.two
+-------------------
+HTMLInputElement
+formcontrol
+text
+-------------------
+form.nomatch
+-------------------
+undefined
+-------------------
+form[0]
+-------------------
+HTMLInputElement
+formcontrol
+button
+-------------------
+form[1]
+-------------------
 HTMLInputElement
+formcontrol
 text
+-------------------
+form[2]
+-------------------
+undefined

+ 44 - 11
Tests/LibWeb/Text/input/html-form-controls-collection.html

@@ -1,24 +1,57 @@
 <form>
-  <input name="one" id="my-form-control" type="button" />
-  <input name="two" id="my-form-control" type="text" />
+  <input name="one" id="formcontrol" type="button" />
+  <input name="two" id="formcontrol" type="text" />
 </form>
 <script src="include.js"></script>
 <script>
-    test(() => {
-        const formElements = document.forms[0].elements;
-        const radioNodeList = formElements.namedItem("my-form-control");
+    function printDescription(name) {
+        println("-------------------");
+        println(name);
+        println("-------------------");
+    }
+
+    function dumpInput(name, item) {
+        printDescription(name);
+        println(item.constructor.name);
+        println(item.id);
+        println(item.type);
+    }
 
-        println(formElements.constructor.name);
+    function dumpRadioNodeList(name, radioNodeList) {
+        printDescription(name);
         println(radioNodeList.constructor.name);
         println(radioNodeList.length);
         println(radioNodeList[0].type);
         println(radioNodeList[1].type);
+    }
+
+    function dumpNoMatch(name, item) {
+        printDescription(name);
+        println(item);
+    }
+
+    test(() => {
+        const form = document.forms[0].elements;
+        println(form.constructor.name);
+        println(form.length);
+
+        dumpRadioNodeList('form.namedItem("formcontrol")', form.namedItem("formcontrol"))
+        dumpInput('form.namedItem("one")', form.namedItem("one"));
+        dumpInput('form.namedItem("two")', form.namedItem("two"));
+        dumpNoMatch('form.namedItem("nomatch")', form.namedItem("nomatch"));
+
+        dumpRadioNodeList('form["formcontrol"]', form["formcontrol"])
+        dumpInput('form["one"]', form["one"]);
+        dumpInput('form["two"]', form["two"]);
+        dumpNoMatch('form["nomatch"]', form["nomatch"]);
 
-        const nonMatching = formElements.namedItem("no match");
-        println(nonMatching);
+        dumpRadioNodeList('form.formcontrol', form.formcontrol)
+        dumpInput('form.one', form.one);
+        dumpInput('form.two', form.two);
+        dumpNoMatch('form.nomatch', form.nomatch);
 
-        const singleElement = formElements.namedItem("two");
-        println(singleElement.constructor.name);
-        println(singleElement.type);
+        dumpInput('form[0]', form[0]);
+        dumpInput('form[1]', form[1]);
+        dumpNoMatch('form[2]', form[2]);
     })
 </script>

+ 7 - 0
Userland/Libraries/LibWeb/DOM/HTMLFormControlsCollection.cpp

@@ -77,4 +77,11 @@ Variant<Empty, Element*, JS::Handle<RadioNodeList>> HTMLFormControlsCollection::
     }));
 }
 
+WebIDL::ExceptionOr<JS::Value> HTMLFormControlsCollection::named_item_value(FlyString const& name) const
+{
+    return named_item_or_radio_node_list(name).visit(
+        [](Empty) -> JS::Value { return JS::js_undefined(); },
+        [](auto const& value) -> JS::Value { return value; });
+}
+
 }

+ 2 - 0
Userland/Libraries/LibWeb/DOM/HTMLFormControlsCollection.h

@@ -25,6 +25,8 @@ public:
 protected:
     virtual void initialize(JS::Realm&) override;
 
+    virtual WebIDL::ExceptionOr<JS::Value> named_item_value(FlyString const& name) const final;
+
 private:
     HTMLFormControlsCollection(ParentNode& root, Scope, Function<bool(Element const&)> filter);
 };