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    BeforeInput(SerializedBeforeInputData),
76    Cancel(SerializedCancelData),
77    Mouse(SerializedMouseData),
78    Clipboard(SerializedClipboardData),
79    Composition(SerializedCompositionData),
80    Keyboard(SerializedKeyboardData),
81    Focus(SerializedFocusData),
82    Form(SerializedFormData),
83    Drag(SerializedDragData),
84    Pointer(SerializedPointerData),
85    Selection(SerializedSelectionData),
86    Touch(SerializedTouchData),
87    Resize(SerializedResizeData),
88    Scroll(SerializedScrollData),
89    Visible(SerializedVisibleData),
90    Wheel(SerializedWheelData),
91    Media(SerializedMediaData),
92    Animation(SerializedAnimationData),
93    Transition(SerializedTransitionData),
94    Toggle(SerializedToggleData),
95    Image(SerializedImageData),
96    Mounted,
97}
98
99impl EventData {
100    pub fn into_any(self) -> Rc<dyn Any> {
101        match self {
102            EventData::BeforeInput(data) => {
103                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
104            }
105            EventData::Cancel(data) => {
106                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
107            }
108            EventData::Mouse(data) => {
109                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
110            }
111            EventData::Clipboard(data) => {
112                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
113            }
114            EventData::Composition(data) => {
115                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
116            }
117            EventData::Keyboard(data) => {
118                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
119            }
120            EventData::Focus(data) => {
121                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
122            }
123            EventData::Form(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
124            EventData::Drag(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
125            EventData::Pointer(data) => {
126                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
127            }
128            EventData::Selection(data) => {
129                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
130            }
131            EventData::Touch(data) => {
132                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
133            }
134            EventData::Resize(data) => {
135                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
136            }
137            EventData::Scroll(data) => {
138                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
139            }
140            EventData::Visible(data) => {
141                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
142            }
143            EventData::Wheel(data) => {
144                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
145            }
146            EventData::Media(data) => {
147                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
148            }
149            EventData::Animation(data) => {
150                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
151            }
152            EventData::Transition(data) => {
153                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
154            }
155            EventData::Toggle(data) => {
156                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
157            }
158            EventData::Image(data) => {
159                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
160            }
161            EventData::Mounted => {
162                Rc::new(PlatformEventData::new(Box::new(MountedData::new(())))) as Rc<dyn Any>
163            }
164        }
165    }
166}
167
168#[test]
169fn beforeinput_event_deserializes_from_interpreter_payload() {
170    let raw = r#"
171{
172    "element": 0,
173    "name": "beforeinput",
174    "bubbles": true,
175    "data": {
176        "input_type": "insertText",
177        "data": "x",
178        "is_composing": false,
179        "value": "hello"
180    }
181}
182    "#;
183
184    let event: HtmlEvent = serde_json::from_str(raw).unwrap();
185    assert_eq!(event.name, "beforeinput");
186    assert!(event.bubbles);
187    match event.data {
188        EventData::BeforeInput(data) => {
189            assert_eq!(data.input_type, "insertText");
190            assert_eq!(data.data.as_deref(), Some("x"));
191            assert!(!data.is_composing);
192            assert_eq!(data.value, "hello");
193        }
194        other => panic!("expected EventData::BeforeInput, got {other:?}"),
195    }
196}
197
198#[test]
199fn test_back_and_forth() {
200    let data = HtmlEvent {
201        element: ElementId(0),
202        data: EventData::Mouse(SerializedMouseData::default()),
203        name: "click".to_string(),
204        bubbles: true,
205    };
206
207    println!("{}", serde_json::to_string_pretty(&data).unwrap());
208
209    let o = r#"
210{
211  "element": 0,
212  "name": "click",
213  "bubbles": true,
214  "data": {
215    "alt_key": false,
216    "button": 0,
217    "buttons": 0,
218    "client_x": 0,
219    "client_y": 0,
220    "ctrl_key": false,
221    "meta_key": false,
222    "offset_x": 0,
223    "offset_y": 0,
224    "page_x": 0,
225    "page_y": 0,
226    "screen_x": 0,
227    "screen_y": 0,
228    "shift_key": false
229  }
230}
231    "#;
232
233    let p: HtmlEvent = serde_json::from_str(o).unwrap();
234
235    assert_eq!(data, p);
236}
237
238/// A trait for converting from a serialized event to a concrete event type.
239pub struct SerializedHtmlEventConverter;
240
241impl HtmlEventConverter for SerializedHtmlEventConverter {
242    fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData {
243        event
244            .downcast::<SerializedAnimationData>()
245            .cloned()
246            .unwrap()
247            .into()
248    }
249
250    fn convert_before_input_data(&self, event: &PlatformEventData) -> BeforeInputData {
251        event
252            .downcast::<SerializedBeforeInputData>()
253            .cloned()
254            .unwrap()
255            .into()
256    }
257
258    fn convert_cancel_data(&self, event: &PlatformEventData) -> CancelData {
259        event
260            .downcast::<SerializedCancelData>()
261            .cloned()
262            .unwrap()
263            .into()
264    }
265
266    fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData {
267        event
268            .downcast::<SerializedClipboardData>()
269            .cloned()
270            .unwrap()
271            .into()
272    }
273
274    fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData {
275        event
276            .downcast::<SerializedCompositionData>()
277            .cloned()
278            .unwrap()
279            .into()
280    }
281
282    fn convert_drag_data(&self, event: &PlatformEventData) -> DragData {
283        event
284            .downcast::<SerializedDragData>()
285            .cloned()
286            .unwrap()
287            .into()
288    }
289
290    fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData {
291        event
292            .downcast::<SerializedFocusData>()
293            .cloned()
294            .unwrap()
295            .into()
296    }
297
298    fn convert_form_data(&self, event: &PlatformEventData) -> FormData {
299        event
300            .downcast::<SerializedFormData>()
301            .cloned()
302            .unwrap()
303            .into()
304    }
305
306    fn convert_image_data(&self, event: &PlatformEventData) -> ImageData {
307        event
308            .downcast::<SerializedImageData>()
309            .cloned()
310            .unwrap()
311            .into()
312    }
313
314    fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData {
315        event
316            .downcast::<SerializedKeyboardData>()
317            .cloned()
318            .unwrap()
319            .into()
320    }
321
322    fn convert_media_data(&self, event: &PlatformEventData) -> MediaData {
323        event
324            .downcast::<SerializedMediaData>()
325            .cloned()
326            .unwrap()
327            .into()
328    }
329
330    fn convert_mounted_data(&self, _: &PlatformEventData) -> MountedData {
331        MountedData::from(())
332    }
333
334    fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData {
335        event
336            .downcast::<SerializedMouseData>()
337            .cloned()
338            .unwrap()
339            .into()
340    }
341
342    fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData {
343        event
344            .downcast::<SerializedPointerData>()
345            .cloned()
346            .unwrap()
347            .into()
348    }
349    fn convert_resize_data(&self, event: &PlatformEventData) -> ResizeData {
350        event
351            .downcast::<SerializedResizeData>()
352            .cloned()
353            .unwrap()
354            .into()
355    }
356
357    fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData {
358        event
359            .downcast::<SerializedScrollData>()
360            .cloned()
361            .unwrap()
362            .into()
363    }
364
365    fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData {
366        event
367            .downcast::<SerializedSelectionData>()
368            .cloned()
369            .unwrap()
370            .into()
371    }
372
373    fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData {
374        event
375            .downcast::<SerializedToggleData>()
376            .cloned()
377            .unwrap()
378            .into()
379    }
380
381    fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData {
382        event
383            .downcast::<SerializedTouchData>()
384            .cloned()
385            .unwrap()
386            .into()
387    }
388
389    fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData {
390        event
391            .downcast::<SerializedTransitionData>()
392            .cloned()
393            .unwrap()
394            .into()
395    }
396
397    fn convert_visible_data(&self, event: &PlatformEventData) -> VisibleData {
398        event
399            .downcast::<SerializedVisibleData>()
400            .cloned()
401            .unwrap()
402            .into()
403    }
404
405    fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData {
406        event
407            .downcast::<SerializedWheelData>()
408            .cloned()
409            .unwrap()
410            .into()
411    }
412}