script/dom/html/form_controls/
htmllabelelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name};
7use js::context::NoGC;
8use js::rust::HandleObject;
9use style::attr::AttrValue;
10
11use crate::dom::activation::Activatable;
12use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
13use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
14use crate::dom::bindings::codegen::Bindings::HTMLLabelElementBinding::HTMLLabelElementMethods;
15use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
16use crate::dom::bindings::inheritance::Castable;
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::bindings::str::DOMString;
19use crate::dom::document::Document;
20use crate::dom::element::attributes::storage::AttrRef;
21use crate::dom::element::{AttributeMutation, Element};
22use crate::dom::event::Event;
23use crate::dom::eventtarget::EventTarget;
24use crate::dom::html::htmlelement::HTMLElement;
25use crate::dom::html::htmlformelement::{FormControlElementHelpers, HTMLFormElement};
26use crate::dom::iterators::ShadowIncluding;
27use crate::dom::node::Node;
28use crate::dom::node::virtualmethods::VirtualMethods;
29
30#[dom_struct]
31pub(crate) struct HTMLLabelElement {
32 htmlelement: HTMLElement,
33}
34
35impl HTMLLabelElement {
36 fn new_inherited(
37 local_name: LocalName,
38 prefix: Option<Prefix>,
39 document: &Document,
40 ) -> HTMLLabelElement {
41 HTMLLabelElement {
42 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
43 }
44 }
45
46 pub(crate) fn new(
47 cx: &mut js::context::JSContext,
48 local_name: LocalName,
49 prefix: Option<Prefix>,
50 document: &Document,
51 proto: Option<HandleObject>,
52 ) -> DomRoot<HTMLLabelElement> {
53 Node::reflect_node_with_proto(
54 cx,
55 Box::new(HTMLLabelElement::new_inherited(
56 local_name, prefix, document,
57 )),
58 document,
59 proto,
60 )
61 }
62}
63
64impl Activatable for HTMLLabelElement {
65 fn as_element(&self) -> &Element {
66 self.upcast::<Element>()
67 }
68
69 fn is_instance_activatable(&self) -> bool {
70 true
71 }
72
73 fn activation_behavior(
79 &self,
80 cx: &mut js::context::JSContext,
81 _event: &Event,
82 _target: &EventTarget,
83 ) {
84 if let Some(e) = self.GetControl(cx.no_gc()) {
85 e.Click(cx);
86 }
87 }
88}
89
90impl HTMLLabelElementMethods<crate::DomTypeHolder> for HTMLLabelElement {
91 fn GetForm(&self, no_gc: &NoGC) -> Option<DomRoot<HTMLFormElement>> {
93 self.GetControl(no_gc)
100 .map(DomRoot::upcast::<Element>)
101 .and_then(|element| {
102 element
103 .as_maybe_form_control()
104 .and_then(|control| control.form_owner())
105 })
106 }
107
108 make_getter!(HtmlFor, "for");
110
111 make_atomic_setter!(SetHtmlFor, "for");
113
114 fn GetControl(&self, no_gc: &NoGC) -> Option<DomRoot<HTMLElement>> {
116 let Some(for_value) = self
117 .upcast::<Element>()
118 .get_attribute_string_value(&local_name!("for"))
119 else {
120 return self.first_labelable_descendant();
121 };
122
123 let maybe_found = self
133 .upcast::<Node>()
134 .GetRootNode(&GetRootNodeOptions::empty())
135 .traverse_preorder_unrooted(no_gc, ShadowIncluding::No)
136 .find_map(|e| {
137 if let Some(htmle) = e.downcast::<HTMLElement>() {
138 if htmle.upcast::<Element>().Id() == for_value {
139 Some(DomRoot::from_ref(htmle))
140 } else {
141 None
142 }
143 } else {
144 None
145 }
146 });
147 if let Some(ref maybe_labelable) = maybe_found &&
150 maybe_labelable.is_labelable_element()
151 {
152 return maybe_found;
153 }
154 None
155 }
156}
157
158impl VirtualMethods for HTMLLabelElement {
159 fn super_type(&self) -> Option<&dyn VirtualMethods> {
160 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
161 }
162
163 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
164 match name {
165 &local_name!("for") => AttrValue::from_atomic(value.into()),
166 _ => self
167 .super_type()
168 .unwrap()
169 .parse_plain_attribute(name, value),
170 }
171 }
172
173 fn attribute_mutated(
174 &self,
175 cx: &mut js::context::JSContext,
176 attr: AttrRef<'_>,
177 mutation: AttributeMutation,
178 ) {
179 self.super_type()
180 .unwrap()
181 .attribute_mutated(cx, attr, mutation);
182 }
183}
184
185impl HTMLLabelElement {
186 pub(crate) fn first_labelable_descendant(&self) -> Option<DomRoot<HTMLElement>> {
187 self.upcast::<Node>()
188 .traverse_preorder(ShadowIncluding::No)
189 .filter_map(DomRoot::downcast::<HTMLElement>)
190 .find(|elem| elem.is_labelable_element())
191 }
192}