mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-25 10:48:53 +00:00
LibWeb: Implement the labels
attribute for all labelable elements
This returns a `NodeList` of all the labels associated with the given element.
This commit is contained in:
parent
3dc86747f0
commit
2447a25753
Notes:
sideshowbarker
2024-07-16 20:39:14 +09:00
Author: https://github.com/tcl3
Commit: 2447a25753
Pull-request: https://github.com/SerenityOS/serenity/pull/24359
11 changed files with 89 additions and 7 deletions
21
Tests/LibWeb/Text/expected/HTML/HTMLElement-labels.txt
Normal file
21
Tests/LibWeb/Text/expected/HTML/HTMLElement-labels.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
input.labels.length: 1
|
||||||
|
input.labels[0] === label: true
|
||||||
|
input.labels always returns the same object: true
|
||||||
|
meter.labels.length: 1
|
||||||
|
meter.labels[0] === label: true
|
||||||
|
meter.labels always returns the same object: true
|
||||||
|
output.labels.length: 1
|
||||||
|
output.labels[0] === label: true
|
||||||
|
output.labels always returns the same object: true
|
||||||
|
progress.labels.length: 1
|
||||||
|
progress.labels[0] === label: true
|
||||||
|
progress.labels always returns the same object: true
|
||||||
|
select.labels.length: 1
|
||||||
|
select.labels[0] === label: true
|
||||||
|
select.labels always returns the same object: true
|
||||||
|
textarea.labels.length: 1
|
||||||
|
textarea.labels[0] === label: true
|
||||||
|
textarea.labels always returns the same object: true
|
||||||
|
input.labels returns null if input type is hidden: true
|
||||||
|
input.labels.length after input type is changed from hidden: 1
|
||||||
|
input.labels[0] === label after input type is changed from hidden: true
|
36
Tests/LibWeb/Text/input/HTML/HTMLElement-labels.html
Normal file
36
Tests/LibWeb/Text/input/HTML/HTMLElement-labels.html
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const labelableElements = ["input", "meter", "output", "progress", "select", "textarea"];
|
||||||
|
for (const tagName of labelableElements) {
|
||||||
|
const element = document.createElement(tagName);
|
||||||
|
element.id = `${tagName}Id`;
|
||||||
|
const label = document.createElement("label")
|
||||||
|
label.htmlFor = `${tagName}Id`;
|
||||||
|
document.body.appendChild(label);
|
||||||
|
document.body.appendChild(element);
|
||||||
|
const labels = element.labels;
|
||||||
|
println(`${tagName}.labels.length: ${labels.length}`);
|
||||||
|
println(`${tagName}.labels[0] === label: ${labels[0] === label}`);
|
||||||
|
println(`${tagName}.labels always returns the same object: ${labels === element.labels}`);
|
||||||
|
document.body.removeChild(label);
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputElement = document.createElement("input");
|
||||||
|
inputElement.type = "hidden";
|
||||||
|
inputElement.id = "inputId"
|
||||||
|
const label = document.createElement("label")
|
||||||
|
label.htmlFor = 'inputId';
|
||||||
|
document.body.appendChild(label);
|
||||||
|
document.body.appendChild(inputElement);
|
||||||
|
println(`input.labels returns null if input type is hidden: ${inputElement.labels === null}`);
|
||||||
|
inputElement.type = "text";
|
||||||
|
const labels = inputElement.labels;
|
||||||
|
println(`input.labels.length after input type is changed from hidden: ${labels.length}`);
|
||||||
|
println(`input.labels[0] === label after input type is changed from hidden: ${labels[0] === label}`);
|
||||||
|
document.body.removeChild(label);
|
||||||
|
document.body.removeChild(inputElement);
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -31,6 +31,6 @@ interface HTMLButtonElement : HTMLElement {
|
||||||
// FIXME: boolean reportValidity();
|
// FIXME: boolean reportValidity();
|
||||||
// FIXME: undefined setCustomValidity(DOMString error);
|
// FIXME: undefined setCustomValidity(DOMString error);
|
||||||
|
|
||||||
// FIXME: readonly attribute NodeList labels;
|
readonly attribute NodeList labels;
|
||||||
};
|
};
|
||||||
// FIXME: HTMLButtonElement includes PopoverInvokerElement;
|
// FIXME: HTMLButtonElement includes PopoverInvokerElement;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <LibWeb/Bindings/HTMLElementPrototype.h>
|
#include <LibWeb/Bindings/HTMLElementPrototype.h>
|
||||||
#include <LibWeb/DOM/Document.h>
|
#include <LibWeb/DOM/Document.h>
|
||||||
#include <LibWeb/DOM/IDLEventListener.h>
|
#include <LibWeb/DOM/IDLEventListener.h>
|
||||||
|
#include <LibWeb/DOM/LiveNodeList.h>
|
||||||
#include <LibWeb/DOM/ShadowRoot.h>
|
#include <LibWeb/DOM/ShadowRoot.h>
|
||||||
#include <LibWeb/HTML/BrowsingContext.h>
|
#include <LibWeb/HTML/BrowsingContext.h>
|
||||||
#include <LibWeb/HTML/DOMStringMap.h>
|
#include <LibWeb/HTML/DOMStringMap.h>
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
#include <LibWeb/HTML/HTMLBaseElement.h>
|
#include <LibWeb/HTML/HTMLBaseElement.h>
|
||||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||||
#include <LibWeb/HTML/HTMLElement.h>
|
#include <LibWeb/HTML/HTMLElement.h>
|
||||||
|
#include <LibWeb/HTML/HTMLLabelElement.h>
|
||||||
#include <LibWeb/HTML/NavigableContainer.h>
|
#include <LibWeb/HTML/NavigableContainer.h>
|
||||||
#include <LibWeb/HTML/VisibilityState.h>
|
#include <LibWeb/HTML/VisibilityState.h>
|
||||||
#include <LibWeb/HTML/Window.h>
|
#include <LibWeb/HTML/Window.h>
|
||||||
|
@ -436,6 +438,25 @@ bool HTMLElement::fire_a_synthetic_pointer_event(FlyString const& type, DOM::Ele
|
||||||
return target.dispatch_event(event);
|
return target.dispatch_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/forms.html#dom-lfe-labels-dev
|
||||||
|
JS::GCPtr<DOM::NodeList> HTMLElement::labels()
|
||||||
|
{
|
||||||
|
// Labelable elements and all input elements have a live NodeList object associated with them that represents the list of label elements, in tree order,
|
||||||
|
// whose labeled control is the element in question. The labels IDL attribute of labelable elements that are not form-associated custom elements,
|
||||||
|
// and the labels IDL attribute of input elements, on getting, must return that NodeList object, and that same value must always be returned,
|
||||||
|
// unless this element is an input element whose type attribute is in the Hidden state, in which case it must instead return null.
|
||||||
|
if (!is_labelable())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!m_labels) {
|
||||||
|
m_labels = DOM::LiveNodeList::create(realm(), root(), DOM::LiveNodeList::Scope::Descendants, [&](auto& node) {
|
||||||
|
return is<HTMLLabelElement>(node) && verify_cast<HTMLLabelElement>(node).control() == this;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_labels;
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-click
|
// https://html.spec.whatwg.org/multipage/interaction.html#dom-click
|
||||||
void HTMLElement::click()
|
void HTMLElement::click()
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,6 +68,8 @@ public:
|
||||||
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
||||||
virtual bool is_labelable() const { return false; }
|
virtual bool is_labelable() const { return false; }
|
||||||
|
|
||||||
|
JS::GCPtr<DOM::NodeList> labels();
|
||||||
|
|
||||||
virtual Optional<ARIA::Role> default_role() const override;
|
virtual Optional<ARIA::Role> default_role() const override;
|
||||||
|
|
||||||
String get_an_elements_target() const;
|
String get_an_elements_target() const;
|
||||||
|
@ -93,6 +95,8 @@ private:
|
||||||
|
|
||||||
JS::GCPtr<DOMStringMap> m_dataset;
|
JS::GCPtr<DOMStringMap> m_dataset;
|
||||||
|
|
||||||
|
JS::GCPtr<DOM::NodeList> m_labels;
|
||||||
|
|
||||||
enum class ContentEditableState {
|
enum class ContentEditableState {
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
|
|
|
@ -54,7 +54,7 @@ interface HTMLInputElement : HTMLElement {
|
||||||
boolean reportValidity();
|
boolean reportValidity();
|
||||||
undefined setCustomValidity(DOMString error);
|
undefined setCustomValidity(DOMString error);
|
||||||
|
|
||||||
// FIXME: readonly attribute NodeList? labels;
|
readonly attribute NodeList? labels;
|
||||||
|
|
||||||
undefined select();
|
undefined select();
|
||||||
// FIXME: attribute unsigned long? selectionStart;
|
// FIXME: attribute unsigned long? selectionStart;
|
||||||
|
|
|
@ -11,5 +11,5 @@ interface HTMLMeterElement : HTMLElement {
|
||||||
[CEReactions] attribute double low;
|
[CEReactions] attribute double low;
|
||||||
[CEReactions] attribute double high;
|
[CEReactions] attribute double high;
|
||||||
[CEReactions] attribute double optimum;
|
[CEReactions] attribute double optimum;
|
||||||
// FIXME: readonly attribute NodeList labels;
|
readonly attribute NodeList labels;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,5 +21,5 @@ interface HTMLOutputElement : HTMLElement {
|
||||||
// FIXME: boolean reportValidity();
|
// FIXME: boolean reportValidity();
|
||||||
// FIXME: undefined setCustomValidity(DOMString error);
|
// FIXME: undefined setCustomValidity(DOMString error);
|
||||||
|
|
||||||
// FIXME: readonly attribute NodeList labels;
|
readonly attribute NodeList labels;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,5 +8,5 @@ interface HTMLProgressElement : HTMLElement {
|
||||||
[CEReactions] attribute double value;
|
[CEReactions] attribute double value;
|
||||||
[CEReactions] attribute double max;
|
[CEReactions] attribute double max;
|
||||||
readonly attribute double position;
|
readonly attribute double position;
|
||||||
// FIXME: readonly attribute NodeList labels;
|
readonly attribute NodeList labels;
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,5 +37,5 @@ interface HTMLSelectElement : HTMLElement {
|
||||||
// FIXME: boolean reportValidity();
|
// FIXME: boolean reportValidity();
|
||||||
// FIXME: undefined setCustomValidity(DOMString error);
|
// FIXME: undefined setCustomValidity(DOMString error);
|
||||||
|
|
||||||
// FIXME: readonly attribute NodeList labels;
|
readonly attribute NodeList labels;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,7 @@ interface HTMLTextAreaElement : HTMLElement {
|
||||||
boolean reportValidity();
|
boolean reportValidity();
|
||||||
undefined setCustomValidity(DOMString error);
|
undefined setCustomValidity(DOMString error);
|
||||||
|
|
||||||
// FIXME: readonly attribute NodeList labels;
|
readonly attribute NodeList labels;
|
||||||
|
|
||||||
// FIXME: undefined select();
|
// FIXME: undefined select();
|
||||||
attribute unsigned long selectionStart;
|
attribute unsigned long selectionStart;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue