script/dom/html/
htmllabelelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name, ns};
7use js::rust::HandleObject;
8use style::attr::AttrValue;
9
10use crate::dom::activation::Activatable;
11use crate::dom::attr::Attr;
12use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
13use crate::dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
14use crate::dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods;
15use crate::dom::bindings::codegen::Bindings::HTMLLabelElementBinding::HTMLLabelElementMethods;
16use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::root::DomRoot;
19use crate::dom::bindings::str::DOMString;
20use crate::dom::document::Document;
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::{FormControl, FormControlElementHelpers, HTMLFormElement};
26use crate::dom::node::{Node, ShadowIncluding};
27use crate::dom::virtualmethods::VirtualMethods;
28use crate::script_runtime::CanGc;
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 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
47 pub(crate) fn new(
48 local_name: LocalName,
49 prefix: Option<Prefix>,
50 document: &Document,
51 proto: Option<HandleObject>,
52 can_gc: CanGc,
53 ) -> DomRoot<HTMLLabelElement> {
54 Node::reflect_node_with_proto(
55 Box::new(HTMLLabelElement::new_inherited(
56 local_name, prefix, document,
57 )),
58 document,
59 proto,
60 can_gc,
61 )
62 }
63}
64
65impl Activatable for HTMLLabelElement {
66 fn as_element(&self) -> &Element {
67 self.upcast::<Element>()
68 }
69
70 fn is_instance_activatable(&self) -> bool {
71 true
72 }
73
74 fn activation_behavior(&self, _event: &Event, _target: &EventTarget, can_gc: CanGc) {
80 if let Some(e) = self.GetControl() {
81 e.Click(can_gc);
82 }
83 }
84}
85
86impl HTMLLabelElementMethods<crate::DomTypeHolder> for HTMLLabelElement {
87 fn GetForm(&self) -> Option<DomRoot<HTMLFormElement>> {
89 self.form_owner()
90 }
91
92 make_getter!(HtmlFor, "for");
94
95 make_atomic_setter!(SetHtmlFor, "for");
97
98 fn GetControl(&self) -> Option<DomRoot<HTMLElement>> {
100 let for_attr = match self
101 .upcast::<Element>()
102 .get_attribute(&ns!(), &local_name!("for"))
103 {
104 Some(for_attr) => for_attr,
105 None => return self.first_labelable_descendant(),
106 };
107
108 let for_value = for_attr.Value();
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 if maybe_labelable.is_labelable_element() {
138 return maybe_found;
139 }
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(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
161 self.super_type()
162 .unwrap()
163 .attribute_mutated(attr, mutation, can_gc);
164 if *attr.local_name() == local_name!("form") {
165 self.form_attribute_mutated(mutation, can_gc);
166 }
167 }
168}
169
170impl HTMLLabelElement {
171 pub(crate) fn first_labelable_descendant(&self) -> Option<DomRoot<HTMLElement>> {
172 self.upcast::<Node>()
173 .traverse_preorder(ShadowIncluding::No)
174 .filter_map(DomRoot::downcast::<HTMLElement>)
175 .find(|elem| elem.is_labelable_element())
176 }
177}
178
179impl FormControl for HTMLLabelElement {
180 fn form_owner(&self) -> Option<DomRoot<HTMLFormElement>> {
181 self.GetControl()
182 .map(DomRoot::upcast::<Element>)
183 .and_then(|elem| {
184 elem.as_maybe_form_control()
185 .and_then(|control| control.form_owner())
186 })
187 }
188
189 fn set_form_owner(&self, _: Option<&HTMLFormElement>) {
190 }
193
194 fn to_element(&self) -> &Element {
195 self.upcast::<Element>()
196 }
197}