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