script/dom/html/
htmloptgroupelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name};
7use js::context::JSContext;
8use js::rust::HandleObject;
9use script_bindings::str::DOMString;
10use stylo_dom::ElementState;
11
12use crate::dom::bindings::codegen::Bindings::HTMLOptGroupElementBinding::HTMLOptGroupElementMethods;
13use crate::dom::bindings::codegen::GenericBindings::NodeBinding::Node_Binding::NodeMethods;
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::document::Document;
17use crate::dom::element::attributes::storage::AttrRef;
18use crate::dom::element::{AttributeMutation, Element};
19use crate::dom::html::htmlelement::HTMLElement;
20use crate::dom::html::htmloptionelement::HTMLOptionElement;
21use crate::dom::html::htmlselectelement::HTMLSelectElement;
22use crate::dom::node::{BindContext, Node, UnbindContext};
23use crate::dom::validation::Validatable;
24use crate::dom::validitystate::ValidationFlags;
25use crate::dom::virtualmethods::VirtualMethods;
26
27#[dom_struct]
29pub(crate) struct HTMLOptGroupElement {
30 htmlelement: HTMLElement,
31}
32
33impl HTMLOptGroupElement {
34 fn new_inherited(
35 local_name: LocalName,
36 prefix: Option<Prefix>,
37 document: &Document,
38 ) -> HTMLOptGroupElement {
39 HTMLOptGroupElement {
40 htmlelement: HTMLElement::new_inherited_with_state(
41 ElementState::ENABLED,
42 local_name,
43 prefix,
44 document,
45 ),
46 }
47 }
48
49 pub(crate) fn new(
50 cx: &mut js::context::JSContext,
51 local_name: LocalName,
52 prefix: Option<Prefix>,
53 document: &Document,
54 proto: Option<HandleObject>,
55 ) -> DomRoot<HTMLOptGroupElement> {
56 Node::reflect_node_with_proto(
57 cx,
58 Box::new(HTMLOptGroupElement::new_inherited(
59 local_name, prefix, document,
60 )),
61 document,
62 proto,
63 )
64 }
65
66 fn update_select_validity(&self, cx: &mut JSContext) {
67 if let Some(select) = self.owner_select_element() {
68 select
69 .validity_state(cx)
70 .perform_validation_and_update(cx, ValidationFlags::all());
71 }
72 }
73
74 fn owner_select_element(&self) -> Option<DomRoot<HTMLSelectElement>> {
75 self.upcast::<Node>()
76 .GetParentNode()
77 .and_then(DomRoot::downcast)
78 }
79}
80
81impl HTMLOptGroupElementMethods<crate::DomTypeHolder> for HTMLOptGroupElement {
82 make_bool_getter!(Disabled, "disabled");
84
85 make_bool_setter!(SetDisabled, "disabled");
87
88 make_getter!(Label, "label");
90
91 make_setter!(SetLabel, "label");
93}
94
95impl VirtualMethods for HTMLOptGroupElement {
96 fn super_type(&self) -> Option<&dyn VirtualMethods> {
97 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
98 }
99
100 fn attribute_mutated(
101 &self,
102 cx: &mut js::context::JSContext,
103 attr: AttrRef<'_>,
104 mutation: AttributeMutation,
105 ) {
106 self.super_type()
107 .unwrap()
108 .attribute_mutated(cx, attr, mutation);
109 if attr.local_name() == &local_name!("disabled") {
110 let disabled_state = match mutation {
111 AttributeMutation::Set(None, _) => true,
112 AttributeMutation::Set(Some(_), _) => {
113 return;
115 },
116 AttributeMutation::Removed => false,
117 };
118 let el = self.upcast::<Element>();
119 el.set_disabled_state(disabled_state);
120 el.set_enabled_state(!disabled_state);
121 let options = el
122 .upcast::<Node>()
123 .children()
124 .filter(|child| child.is::<HTMLOptionElement>())
125 .map(|child| DomRoot::from_ref(child.downcast::<HTMLOptionElement>().unwrap()));
126 if disabled_state {
127 for option in options {
128 let el = option.upcast::<Element>();
129 el.set_disabled_state(true);
130 el.set_enabled_state(false);
131 }
132 } else {
133 for option in options {
134 let el = option.upcast::<Element>();
135 el.check_disabled_attribute();
136 }
137 }
138 }
139 }
140
141 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
142 if let Some(super_type) = self.super_type() {
143 super_type.bind_to_tree(cx, context);
144 }
145
146 self.update_select_validity(cx);
147 }
148
149 fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
150 self.super_type().unwrap().unbind_from_tree(cx, context);
151
152 if let Some(select) = context.parent.downcast::<HTMLSelectElement>() {
153 select
154 .validity_state(cx)
155 .perform_validation_and_update(cx, ValidationFlags::all());
156 }
157 }
158}