ftd_rt/
event.rs

1#[derive(serde::Deserialize, Clone)]
2#[cfg_attr(
3    not(feature = "wasm"),
4    derive(serde::Serialize, PartialEq, Debug, Default)
5)]
6pub struct Event {
7    // $event-click$: toggle foo
8    // will be parsed into this Event struct
9    pub name: String, // click
10    pub action: Action,
11}
12
13pub(crate) fn group_by_js_event(evts: &[Event]) -> std::collections::HashMap<String, String> {
14    // key: onclick
15    // value: after group by for onclick find all actions, and call to_js_event()
16    let mut events: std::collections::HashMap<String, Vec<Action>> = Default::default();
17    for event in evts {
18        if let Some(actions) = events.get_mut(&event.name) {
19            actions.push(event.action.to_owned());
20        } else {
21            events.insert(event.name.to_string(), vec![event.action.to_owned()]);
22        }
23    }
24    let mut string_events: std::collections::HashMap<String, String> = Default::default();
25    for (k, v) in events {
26        string_events.insert(k, serde_json::to_string(&v).expect(""));
27    }
28    string_events
29}
30
31#[derive(serde::Deserialize, Clone, Debug, serde::Serialize)]
32#[cfg_attr(not(feature = "wasm"), derive(PartialEq, Default))]
33pub struct Action {
34    pub action: String, // toggle
35    pub target: String, // foo
36    pub parameters: std::collections::BTreeMap<String, Vec<String>>,
37}
38
39#[cfg(feature = "wasm")]
40impl Action {
41    fn to_action(a: &str, doc_id: &str) -> crate::Result<Self> {
42        match a {
43            _ if a.starts_with("toggle") => {
44                let target = a.replace("toggle ", "");
45                Ok(Self {
46                    action: "toggle".to_string(),
47                    target,
48                    parameters: Default::default(),
49                })
50            }
51            t => return crate::e(format!("{} is not a valid action", t), doc_id),
52        }
53    }
54
55    fn from_action(&self) -> String {
56        // input: { action: toggle, target: x }
57        // output: "toggle x;"
58        format!("{} {};", self.action, self.target)
59    }
60
61    pub(crate) fn parse_js_event(s: &str, doc_id: &str) -> Vec<Action> {
62        // input: "toggle x; set-true y"
63        // output: { action: toggle, target: x }, { action: set-true, target: y }
64        let actions_string: Vec<_> = s.split(";").collect();
65        let mut actions = vec![];
66        for action in actions_string {
67            let a = action.trim();
68            if !a.is_empty() {
69                actions.push(Action::to_action(action, doc_id).expect("Can't convert to action"));
70            }
71        }
72        actions
73    }
74
75    pub(crate) fn handle_action(&self, doc: &mut ftd_rt::Document) {
76        match self.action.as_str() {
77            "toggle" => {
78                let data = doc
79                    .data
80                    .get(&self.target)
81                    .expect(format!("{} should be present", self.target).as_str());
82                let value = !data
83                    .value
84                    .parse::<bool>()
85                    .expect(format!("Can't parse value for {} into bool", self.target).as_str());
86                let dependencies = data.dependencies.to_owned();
87
88                doc.data.insert(
89                    self.target.to_string(),
90                    ftd_rt::Data {
91                        value: value.to_string(),
92                        dependencies,
93                    },
94                );
95            }
96            _ => unimplemented!(),
97        }
98    }
99}