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