Skip to main content

dioxus_html/
transit.rs

1use std::{any::Any, rc::Rc};
2
3use crate::events::*;
4use dioxus_core::ElementId;
5use serde::{Deserialize, Serialize};
6
7#[cfg(feature = "serialize")]
8#[derive(Serialize, Debug, PartialEq)]
9pub struct HtmlEvent {
10    pub element: ElementId,
11    pub name: String,
12    pub bubbles: bool,
13    pub data: EventData,
14}
15
16#[cfg(feature = "serialize")]
17impl<'de> Deserialize<'de> for HtmlEvent {
18    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
19    where
20        D: serde::Deserializer<'de>,
21    {
22        #[derive(Deserialize, Debug, Clone)]
23        struct Inner {
24            element: ElementId,
25            name: String,
26            bubbles: bool,
27            data: serde_json::Value,
28        }
29
30        let Inner {
31            element,
32            name,
33            bubbles,
34            data,
35        } = Inner::deserialize(deserializer)?;
36
37        // in debug mode let's try and be helpful as to why the deserialization failed
38        let data = deserialize_raw(&name, &data).map_err(|e| {
39            serde::de::Error::custom(format!(
40                "Failed to deserialize event data for event {}:  {}\n'{:#?}'",
41                name, e, data,
42            ))
43        })?;
44
45        Ok(HtmlEvent {
46            data,
47            element,
48            bubbles,
49            name,
50        })
51    }
52}
53
54#[cfg(feature = "serialize")]
55fn deserialize_raw(name: &str, data: &serde_json::Value) -> Result<EventData, serde_json::Error> {
56    match deserialize_raw_event(name, data)? {
57        Some(result) => Ok(result),
58        None => Err(serde::de::Error::custom(format!(
59            "Unknown event type: {name}"
60        ))),
61    }
62}
63
64#[cfg(feature = "serialize")]
65impl HtmlEvent {
66    pub fn bubbles(&self) -> bool {
67        self.bubbles
68    }
69}
70
71#[derive(Deserialize, Serialize, Debug, PartialEq)]
72#[serde(untagged)]
73#[non_exhaustive]
74pub enum EventData {
75    Cancel(SerializedCancelData),
76    Mouse(SerializedMouseData),
77    Clipboard(SerializedClipboardData),
78    Composition(SerializedCompositionData),
79    Keyboard(SerializedKeyboardData),
80    Focus(SerializedFocusData),
81    Form(SerializedFormData),
82    Drag(SerializedDragData),
83    Pointer(SerializedPointerData),
84    Selection(SerializedSelectionData),
85    Touch(SerializedTouchData),
86    Resize(SerializedResizeData),
87    Scroll(SerializedScrollData),
88    Visible(SerializedVisibleData),
89    Wheel(SerializedWheelData),
90    Media(SerializedMediaData),
91    Animation(SerializedAnimationData),
92    Transition(SerializedTransitionData),
93    Toggle(SerializedToggleData),
94    Image(SerializedImageData),
95    Mounted,
96}
97
98impl EventData {
99    pub fn into_any(self) -> Rc<dyn Any> {
100        match self {
101            EventData::Cancel(data) => {
102                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
103            }
104            EventData::Mouse(data) => {
105                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
106            }
107            EventData::Clipboard(data) => {
108                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
109            }
110            EventData::Composition(data) => {
111                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
112            }
113            EventData::Keyboard(data) => {
114                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
115            }
116            EventData::Focus(data) => {
117                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
118            }
119            EventData::Form(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
120            EventData::Drag(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
121            EventData::Pointer(data) => {
122                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
123            }
124            EventData::Selection(data) => {
125                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
126            }
127            EventData::Touch(data) => {
128                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
129            }
130            EventData::Resize(data) => {
131                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
132            }
133            EventData::Scroll(data) => {
134                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
135            }
136            EventData::Visible(data) => {
137                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
138            }
139            EventData::Wheel(data) => {
140                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
141            }
142            EventData::Media(data) => {
143                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
144            }
145            EventData::Animation(data) => {
146                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
147            }
148            EventData::Transition(data) => {
149                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
150            }
151            EventData::Toggle(data) => {
152                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
153            }
154            EventData::Image(data) => {
155                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
156            }
157            EventData::Mounted => {
158                Rc::new(PlatformEventData::new(Box::new(MountedData::new(())))) as Rc<dyn Any>
159            }
160        }
161    }
162}
163
164#[test]
165fn test_back_and_forth() {
166    let data = HtmlEvent {
167        element: ElementId(0),
168        data: EventData::Mouse(SerializedMouseData::default()),
169        name: "click".to_string(),
170        bubbles: true,
171    };
172
173    println!("{}", serde_json::to_string_pretty(&data).unwrap());
174
175    let o = r#"
176{
177  "element": 0,
178  "name": "click",
179  "bubbles": true,
180  "data": {
181    "alt_key": false,
182    "button": 0,
183    "buttons": 0,
184    "client_x": 0,
185    "client_y": 0,
186    "ctrl_key": false,
187    "meta_key": false,
188    "offset_x": 0,
189    "offset_y": 0,
190    "page_x": 0,
191    "page_y": 0,
192    "screen_x": 0,
193    "screen_y": 0,
194    "shift_key": false
195  }
196}
197    "#;
198
199    let p: HtmlEvent = serde_json::from_str(o).unwrap();
200
201    assert_eq!(data, p);
202}
203
204/// A trait for converting from a serialized event to a concrete event type.
205pub struct SerializedHtmlEventConverter;
206
207impl HtmlEventConverter for SerializedHtmlEventConverter {
208    fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData {
209        event
210            .downcast::<SerializedAnimationData>()
211            .cloned()
212            .unwrap()
213            .into()
214    }
215
216    fn convert_cancel_data(&self, event: &PlatformEventData) -> CancelData {
217        event
218            .downcast::<SerializedCancelData>()
219            .cloned()
220            .unwrap()
221            .into()
222    }
223
224    fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData {
225        event
226            .downcast::<SerializedClipboardData>()
227            .cloned()
228            .unwrap()
229            .into()
230    }
231
232    fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData {
233        event
234            .downcast::<SerializedCompositionData>()
235            .cloned()
236            .unwrap()
237            .into()
238    }
239
240    fn convert_drag_data(&self, event: &PlatformEventData) -> DragData {
241        event
242            .downcast::<SerializedDragData>()
243            .cloned()
244            .unwrap()
245            .into()
246    }
247
248    fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData {
249        event
250            .downcast::<SerializedFocusData>()
251            .cloned()
252            .unwrap()
253            .into()
254    }
255
256    fn convert_form_data(&self, event: &PlatformEventData) -> FormData {
257        event
258            .downcast::<SerializedFormData>()
259            .cloned()
260            .unwrap()
261            .into()
262    }
263
264    fn convert_image_data(&self, event: &PlatformEventData) -> ImageData {
265        event
266            .downcast::<SerializedImageData>()
267            .cloned()
268            .unwrap()
269            .into()
270    }
271
272    fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData {
273        event
274            .downcast::<SerializedKeyboardData>()
275            .cloned()
276            .unwrap()
277            .into()
278    }
279
280    fn convert_media_data(&self, event: &PlatformEventData) -> MediaData {
281        event
282            .downcast::<SerializedMediaData>()
283            .cloned()
284            .unwrap()
285            .into()
286    }
287
288    fn convert_mounted_data(&self, _: &PlatformEventData) -> MountedData {
289        MountedData::from(())
290    }
291
292    fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData {
293        event
294            .downcast::<SerializedMouseData>()
295            .cloned()
296            .unwrap()
297            .into()
298    }
299
300    fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData {
301        event
302            .downcast::<SerializedPointerData>()
303            .cloned()
304            .unwrap()
305            .into()
306    }
307    fn convert_resize_data(&self, event: &PlatformEventData) -> ResizeData {
308        event
309            .downcast::<SerializedResizeData>()
310            .cloned()
311            .unwrap()
312            .into()
313    }
314
315    fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData {
316        event
317            .downcast::<SerializedScrollData>()
318            .cloned()
319            .unwrap()
320            .into()
321    }
322
323    fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData {
324        event
325            .downcast::<SerializedSelectionData>()
326            .cloned()
327            .unwrap()
328            .into()
329    }
330
331    fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData {
332        event
333            .downcast::<SerializedToggleData>()
334            .cloned()
335            .unwrap()
336            .into()
337    }
338
339    fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData {
340        event
341            .downcast::<SerializedTouchData>()
342            .cloned()
343            .unwrap()
344            .into()
345    }
346
347    fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData {
348        event
349            .downcast::<SerializedTransitionData>()
350            .cloned()
351            .unwrap()
352            .into()
353    }
354
355    fn convert_visible_data(&self, event: &PlatformEventData) -> VisibleData {
356        event
357            .downcast::<SerializedVisibleData>()
358            .cloned()
359            .unwrap()
360            .into()
361    }
362
363    fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData {
364        event
365            .downcast::<SerializedWheelData>()
366            .cloned()
367            .unwrap()
368            .into()
369    }
370}