arwa/html/
html_form_element.rs1use std::convert::TryFrom;
2
3use delegate::delegate;
4use wasm_bindgen::JsCast;
5
6use crate::console::{Write, Writer};
7use crate::html::{AutoComplete, GenericHtmlElement, HtmlElement};
8use crate::{Element, GenericElement, GenericNode, GlobalEventHandlers, InvalidCast, Node};
9
10#[derive(Clone, Copy, PartialEq, Eq, Debug)]
11pub enum FormMethod {
12 Get,
13 Post,
14 Dialog,
15}
16
17impl Default for FormMethod {
18 fn default() -> Self {
19 FormMethod::Get
20 }
21}
22
23#[derive(Clone)]
24pub struct HtmlFormElement {
25 inner: web_sys::HtmlFormElement,
26}
27
28impl HtmlFormElement {
29 delegate! {
33 target self.inner {
34 pub fn accept_charset(&self) -> String;
35
36 pub fn set_accept_charset(&self, accept_charset: &str);
37
38 pub fn action(&self) -> String;
39
40 pub fn set_action(&self, action: &str);
41
42 pub fn encoding(&self) -> String;
43
44 pub fn set_encoding(&self, encoding: &str);
45
46 pub fn no_validate(&self) -> bool;
47
48 pub fn set_no_validate(&self, no_validate: bool);
49
50 pub fn target(&self) -> String;
51
52 pub fn set_target(&self, target: &str);
53
54 pub fn check_validity(&self) -> bool;
55
56 pub fn report_validity(&self) -> bool;
57
58 pub fn reset(&self);
59 }
60 }
61
62 pub fn autocomplete(&self) -> AutoComplete {
63 match &*self.inner.autocomplete() {
64 "off" => AutoComplete::Off,
65 _ => AutoComplete::On,
66 }
67 }
68
69 pub fn set_autocomplete(&self, autocomplete: AutoComplete) {
70 let autocomplete = match autocomplete {
71 AutoComplete::On => "on",
72 AutoComplete::Off => "off",
73 };
74
75 self.inner.set_autocomplete(autocomplete);
76 }
77
78 pub fn method(&self) -> FormMethod {
79 match &*self.inner.method() {
80 "post" => FormMethod::Post,
81 "dialog" => FormMethod::Dialog,
82 _ => FormMethod::Get,
83 }
84 }
85
86 pub fn set_method(&self, method: FormMethod) {
87 let method = match method {
88 FormMethod::Get => "get",
89 FormMethod::Post => "post",
90 FormMethod::Dialog => "dialog",
91 };
92
93 self.inner.set_method(method);
94 }
95
96 pub fn elements(&self) -> FormControlElements {
97 FormControlElements {
98 inner: self.inner.elements().unchecked_into(),
99 }
100 }
101
102 pub fn submit(&self) {
103 self.inner.submit().unwrap();
106 }
107}
108
109impl_html_common_traits!(HtmlFormElement);
110
111pub struct FormControlElements {
112 inner: web_sys::HtmlFormControlsCollection,
113}
114
115impl FormControlElements {
116 pub fn get(&self, id_or_name: &str) -> Option<FormControl> {
118 self.inner
119 .named_item(id_or_name)
120 .map(|inner| FormControl { inner })
121 }
122
123 pub fn len(&self) -> usize {
124 self.inner.length() as usize
125 }
126}
127
128impl Write for FormControlElements {
129 fn write(&self, writer: &mut Writer) {
130 writer.write_1(self.inner.as_ref());
131 }
132}
133
134pub struct FormControl {
135 inner: js_sys::Object,
136}
137
138impl TryFrom<FormControl> for RadioNodes {
139 type Error = InvalidCast<FormControl>;
140
141 fn try_from(value: FormControl) -> Result<Self, Self::Error> {
142 value
143 .inner
144 .dyn_into::<web_sys::RadioNodeList>()
145 .map(|inner| RadioNodes { inner })
146 .map_err(|inner| InvalidCast(FormControl { inner }))
147 }
148}
149
150impl TryFrom<FormControl> for GenericHtmlElement {
151 type Error = InvalidCast<FormControl>;
152
153 fn try_from(value: FormControl) -> Result<Self, Self::Error> {
154 value
155 .inner
156 .dyn_into::<web_sys::HtmlElement>()
157 .map(|e| e.into())
158 .map_err(|inner| InvalidCast(FormControl { inner }))
159 }
160}
161
162impl Write for FormControl {
163 fn write(&self, writer: &mut Writer) {
164 writer.write_1(self.inner.as_ref());
165 }
166}
167
168pub struct RadioNodes {
172 inner: web_sys::RadioNodeList,
173}
174
175impl RadioNodes {
176 delegate! {
177 target self.inner {
178 pub fn value(&self) -> String;
179
180 pub fn set_value(&self, value: &str);
181 }
182 }
183
184 pub fn get(&self, index: usize) -> Option<GenericNode> {
185 u32::try_from(index)
186 .ok()
187 .and_then(|index| self.inner.get(index))
188 .map(|e| e.into())
189 }
190
191 pub fn len(&self) -> usize {
192 self.inner.length() as usize
193 }
194
195 pub fn is_empty(&self) -> bool {
196 self.len() == 0
197 }
198
199 pub fn is_not_empty(&self) -> bool {
200 !self.is_empty()
201 }
202
203 pub fn first(&self) -> Option<GenericNode> {
204 self.get(0)
205 }
206
207 pub fn last(&self) -> Option<GenericNode> {
208 let len = self.len();
209
210 if len > 0 {
211 self.get(len - 1)
212 } else {
213 None
214 }
215 }
216
217 pub fn iter(&self) -> RadioNodesIter {
218 RadioNodesIter {
219 radio_nodes: self,
220 current: 0,
221 }
222 }
223}
224
225impl Write for RadioNodes {
226 fn write(&self, writer: &mut Writer) {
227 writer.write_1(self.inner.as_ref());
228 }
229}
230
231impl IntoIterator for RadioNodes {
232 type Item = GenericNode;
233 type IntoIter = RadioNodesIntoIter;
234
235 fn into_iter(self) -> Self::IntoIter {
236 RadioNodesIntoIter {
237 radio_nodes: self,
238 current: 0,
239 }
240 }
241}
242
243pub struct RadioNodesIter<'a> {
244 radio_nodes: &'a RadioNodes,
245 current: usize,
246}
247
248impl<'a> Iterator for RadioNodesIter<'a> {
249 type Item = GenericNode;
250
251 fn next(&mut self) -> Option<Self::Item> {
252 let current = self.current;
253
254 self.current += 1;
255
256 self.radio_nodes.get(current)
257 }
258}
259
260pub struct RadioNodesIntoIter {
261 radio_nodes: RadioNodes,
262 current: usize,
263}
264
265impl Iterator for RadioNodesIntoIter {
266 type Item = GenericNode;
267
268 fn next(&mut self) -> Option<Self::Item> {
269 let current = self.current;
270
271 self.current += 1;
272
273 self.radio_nodes.get(current)
274 }
275}