script/dom/
radionodelist.rs1use dom_struct::dom_struct;
6use js::context::JSContext;
7use script_bindings::reflector::reflect_dom_object_with_cx;
8use script_bindings::root::DomRoot;
9use stylo_atoms::Atom;
10
11use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
12use crate::dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
13use crate::dom::bindings::codegen::Bindings::RadioNodeListBinding::RadioNodeListMethods;
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::str::DOMString;
16use crate::dom::html::htmlformelement::HTMLFormElement;
17use crate::dom::html::input_element::HTMLInputElement;
18use crate::dom::input_element::input_type::InputType;
19use crate::dom::node::Node;
20use crate::dom::nodelist::{NodeList, NodeListType, RadioList, RadioListMode};
21use crate::dom::window::Window;
22
23#[dom_struct]
24pub(crate) struct RadioNodeList {
25 node_list: NodeList,
26}
27
28impl RadioNodeList {
29 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
30 fn new_inherited(list_type: NodeListType) -> RadioNodeList {
31 RadioNodeList {
32 node_list: NodeList::new_inherited(list_type),
33 }
34 }
35
36 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
37 pub(crate) fn new(
38 cx: &mut JSContext,
39 window: &Window,
40 list_type: NodeListType,
41 ) -> DomRoot<RadioNodeList> {
42 reflect_dom_object_with_cx(
43 Box::new(RadioNodeList::new_inherited(list_type)),
44 window,
45 cx,
46 )
47 }
48
49 pub(crate) fn new_controls_except_image_inputs(
50 cx: &mut JSContext,
51 window: &Window,
52 form: &HTMLFormElement,
53 name: &Atom,
54 ) -> DomRoot<RadioNodeList> {
55 RadioNodeList::new(
56 cx,
57 window,
58 NodeListType::Radio(RadioList::new(
59 form,
60 RadioListMode::ControlsExceptImageInputs,
61 name.clone(),
62 )),
63 )
64 }
65
66 pub(crate) fn new_images(
67 cx: &mut JSContext,
68 window: &Window,
69 form: &HTMLFormElement,
70 name: &Atom,
71 ) -> DomRoot<RadioNodeList> {
72 RadioNodeList::new(
73 cx,
74 window,
75 NodeListType::Radio(RadioList::new(form, RadioListMode::Images, name.clone())),
76 )
77 }
78}
79
80impl RadioNodeListMethods<crate::DomTypeHolder> for RadioNodeList {
81 fn Length(&self) -> u32 {
84 self.node_list.Length()
85 }
86
87 fn Value(&self) -> DOMString {
89 self.upcast::<NodeList>()
90 .iter()
91 .find_map(|node| {
92 node.downcast::<HTMLInputElement>().and_then(|input| {
94 if matches!(*input.input_type(), InputType::Radio(_)) && input.Checked() {
95 let value = input.Value();
97 Some(if value.is_empty() {
98 DOMString::from("on")
99 } else {
100 value
101 })
102 } else {
103 None
104 }
105 })
106 })
107 .unwrap_or(DOMString::from(""))
109 }
110
111 fn SetValue(&self, cx: &mut JSContext, value: DOMString) {
113 for node in self.upcast::<NodeList>().iter() {
114 if let Some(input) = node.downcast::<HTMLInputElement>() {
116 match *input.input_type() {
117 InputType::Radio(_) if value == *"on" => {
118 let val = input.Value();
120 if val.is_empty() || val == value {
121 input.SetChecked(cx, true);
122 return;
123 }
124 },
125 InputType::Radio(_) if input.Value() == value => {
126 input.SetChecked(cx, true);
128 return;
129 },
130 _ => {},
131 }
132 }
133 }
134 }
135
136 fn IndexedGetter(&self, index: u32) -> Option<DomRoot<Node>> {
142 self.node_list.IndexedGetter(index)
143 }
144}