rooting_forms/
impl_option.rs

1use std::marker::PhantomData;
2use rooting::{
3    El,
4    el,
5};
6use wasm_bindgen::JsCast;
7use web_sys::HtmlInputElement;
8use crate::{
9    css::{
10        ATTR_LABEL,
11        CSS_CLASS_HIDDEN,
12        CSS_CLASS_OPTION_ENABLE,
13    },
14    FormElements,
15    FormState,
16    FormWith,
17};
18
19struct OptionFormState<C, T> {
20    checked_el: El,
21    subform: Box<dyn FormState<T>>,
22    _pd: PhantomData<C>,
23}
24
25impl<C, T: FormWith<C>> FormState<Option<T>> for OptionFormState<C, T> {
26    fn parse(&self) -> Result<Option<T>, ()> {
27        let checked = self.checked_el.raw().dyn_ref::<HtmlInputElement>().unwrap().checked();
28        if checked {
29            return Ok(Some(self.subform.parse()?));
30        } else {
31            return Ok(None);
32        }
33    }
34}
35
36impl<C: 'static, T: FormWith<C> + 'static> FormWith<C> for Option<T> {
37    fn new_form_with_(
38        context: &C,
39        field: &str,
40        from: Option<&Self>,
41        depth: usize,
42    ) -> (FormElements, Box<dyn FormState<Self>>) {
43        let (subform_elements, subform) = T::new_form_with_(context, field, from.and_then(|x| x.as_ref()), depth);
44        let mut additional = vec![];
45        additional.extend(subform_elements.error.iter().cloned());
46        additional.extend(subform_elements.elements);
47        let check = el("input")
48            //. .
49            .classes(&[CSS_CLASS_OPTION_ENABLE])
50            .attr(ATTR_LABEL, &format!("{} - Enabled", field))
51            .attr("type", "checkbox")
52            .on("click", {
53                let additional = additional.clone();
54                move |ev| {
55                    let checked = ev.target().unwrap().dyn_ref::<HtmlInputElement>().unwrap().checked();
56                    for e in &additional {
57                        e.ref_modify_classes(&[(CSS_CLASS_HIDDEN, checked)]);
58                    }
59                }
60            });
61        if from.map(|x| x.is_some()).unwrap_or(false) {
62            check.ref_attr("checked", "checked");
63        } else {
64            for e in &additional {
65                e.ref_modify_classes(&[(CSS_CLASS_HIDDEN, true)]);
66            }
67        }
68        let mut elements = vec![check.clone()];
69        elements.extend(additional);
70        return (FormElements {
71            error: None,
72            elements: elements,
73        }, Box::new(OptionFormState {
74            checked_el: check,
75            subform: subform,
76            _pd: Default::default(),
77        }));
78    }
79}