Browse Source

LibWeb: Implement the `HTMLLabelElement.form` attribute

This returns the form element associated with the given label element's
control or null if the label has no control.
Tim Ledbetter 1 year ago
parent
commit
6bf22075ed

+ 12 - 0
Tests/LibWeb/Text/expected/HTML/HTMLLabelElement-form.txt

@@ -0,0 +1,12 @@
+              Form for #label-no-for is null
+Control for #label-no-for is null: true
+Form for #parent-of-input2: #form2
+label.form is the same as label.control.form for #parent-of-input2: true
+Form for #label-for-input2: #form2
+label.form is the same as label.control.form for #label-for-input2: true
+Form for #label-for-input1: #form1
+label.form is the same as label.control.form for #label-for-input1: true
+Form for #label-for-non-labelable-element is null
+Control for #label-for-non-labelable-element is null: true
+Form for #label-for-nonexistent-element is null
+Control for #label-for-nonexistent-element is null: true

+ 28 - 0
Tests/LibWeb/Text/input/HTML/HTMLLabelElement-form.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<label id="label-no-for"></label>
+<span id="non-labelable"></span>
+<form id="form1">
+    <input id="input1">
+</form>
+<form id="form2">
+    <label id="parent-of-input2"><input id="input2" ></label>    
+    <label id="label-for-input2" for="input2"></label>
+    <label id="label-for-input1" for="input1"></label>
+    <label id="label-for-non-labelable-element" for="non-labelable"></label>
+    <label id="label-for-nonexistent-element" for="invalid"></label>
+</form>
+</form>
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        for (const labelElement of document.querySelectorAll("label")) {
+            if (labelElement.form) {
+                println(`Form for #${labelElement.id}: #${labelElement.form.id}`);
+                println(`label.form is the same as label.control.form for #${labelElement.id}: ${labelElement.form === labelElement.control.form}`);
+            } else {
+                println(`Form for #${labelElement.id} is null`);
+                println(`Control for #${labelElement.id} is null: ${labelElement.control === null}`);
+            }
+        }
+    });
+</script>

+ 18 - 0
Userland/Libraries/LibWeb/HTML/HTMLLabelElement.cpp

@@ -6,6 +6,7 @@
 
 #include <LibWeb/Bindings/HTMLLabelElementPrototype.h>
 #include <LibWeb/DOM/Document.h>
+#include <LibWeb/HTML/FormAssociatedElement.h>
 #include <LibWeb/HTML/HTMLLabelElement.h>
 #include <LibWeb/Layout/Label.h>
 
@@ -66,4 +67,21 @@ JS::GCPtr<HTMLElement> HTMLLabelElement::control() const
     return control;
 }
 
+// https://html.spec.whatwg.org/multipage/forms.html#dom-label-form
+JS::GCPtr<HTMLFormElement> HTMLLabelElement::form() const
+{
+    auto labeled_control = control();
+
+    // 1. If the label element has no labeled control, then return null.
+    if (!labeled_control)
+        return {};
+
+    // 2. If the label element's labeled control is not a form-associated element, then return null.
+    if (!is<FormAssociatedElement>(*labeled_control))
+        return {};
+
+    // 3. Return the label element's labeled control's form owner (which can still be null).
+    return dynamic_cast<FormAssociatedElement*>(labeled_control.ptr())->form();
+}
+
 }

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

@@ -22,6 +22,7 @@ public:
     Optional<String> for_() const { return attribute(HTML::AttributeNames::for_); }
 
     JS::GCPtr<HTMLElement> control() const;
+    JS::GCPtr<HTMLFormElement> form() const;
 
 private:
     HTMLLabelElement(DOM::Document&, DOM::QualifiedName);

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLLabelElement.idl

@@ -6,7 +6,7 @@ interface HTMLLabelElement : HTMLElement {
 
     [HTMLConstructor] constructor();
 
-    // FIXME: readonly attribute HTMLFormElement? form;
+    readonly attribute HTMLFormElement? form;
     [CEReactions, Reflect=for] attribute DOMString htmlFor;
     readonly attribute HTMLElement? control;