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    use EventData::*;
57
58    // a little macro-esque thing to make the code below more readable
59    #[inline]
60    fn de<'de, F>(f: &'de serde_json::Value) -> Result<F, serde_json::Error>
61    where
62        F: Deserialize<'de>,
63    {
64        F::deserialize(f)
65    }
66
67    let data = match name {
68        // Cancel
69        "cancel" => Cancel(de(data)?),
70
71        // Mouse
72        "click" | "contextmenu" | "dblclick" | "doubleclick" | "mousedown" | "mouseenter"
73        | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => Mouse(de(data)?),
74
75        // Clipboard
76        "copy" | "cut" | "paste" => Clipboard(de(data)?),
77
78        // Composition
79        "compositionend" | "compositionstart" | "compositionupdate" => Composition(de(data)?),
80
81        // Keyboard
82        "keydown" | "keypress" | "keyup" => Keyboard(de(data)?),
83
84        // Focus
85        "blur" | "focus" | "focusin" | "focusout" => Focus(de(data)?),
86
87        // Form
88        "change" | "input" | "invalid" | "reset" | "submit" => Form(de(data)?),
89
90        // Drag
91        "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart"
92        | "drop" => Drag(de(data)?),
93
94        // Pointer
95        "pointerlockchange" | "pointerlockerror" | "pointerdown" | "pointermove" | "pointerup"
96        | "pointerover" | "pointerout" | "pointerenter" | "pointerleave" | "gotpointercapture"
97        | "lostpointercapture" => Pointer(de(data)?),
98
99        // Selection
100        "selectstart" | "selectionchange" | "select" => Selection(de(data)?),
101
102        // Touch
103        "touchcancel" | "touchend" | "touchmove" | "touchstart" => Touch(de(data)?),
104
105        // Resize
106        "resize" => Resize(de(data)?),
107
108        // Scroll
109        "scroll" => Scroll(de(data)?),
110
111        // Visible
112        "visible" => Visible(de(data)?),
113
114        // Wheel
115        "wheel" => Wheel(de(data)?),
116
117        // Media
118        "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
119        | "ended" | "interruptbegin" | "interruptend" | "loadeddata" | "loadedmetadata"
120        | "loadstart" | "pause" | "play" | "playing" | "progress" | "ratechange" | "seeked"
121        | "seeking" | "stalled" | "suspend" | "timeupdate" | "volumechange" | "waiting"
122        | "loadend" | "timeout" => Media(de(data)?),
123
124        // Animation
125        "animationstart" | "animationend" | "animationiteration" => Animation(de(data)?),
126
127        // Transition
128        "transitionend" => Transition(de(data)?),
129
130        // Toggle
131        "toggle" => Toggle(de(data)?),
132
133        "load" | "error" => Image(de(data)?),
134
135        // Mounted
136        "mounted" => Mounted,
137
138        // OtherData => "abort" | "afterprint" | "beforeprint" | "beforeunload" | "hashchange" | "languagechange" | "message" | "offline" | "online" | "pagehide" | "pageshow" | "popstate" | "rejectionhandled" | "storage" | "unhandledrejection" | "unload" | "userproximity" | "vrdisplayactivate" | "vrdisplayblur" | "vrdisplayconnect" | "vrdisplaydeactivate" | "vrdisplaydisconnect" | "vrdisplayfocus" | "vrdisplaypointerrestricted" | "vrdisplaypointerunrestricted" | "vrdisplaypresentchange";
139        other => {
140            return Err(serde::de::Error::custom(format!(
141                "Unknown event type: {other}"
142            )))
143        }
144    };
145
146    Ok(data)
147}
148
149#[cfg(feature = "serialize")]
150impl HtmlEvent {
151    pub fn bubbles(&self) -> bool {
152        self.bubbles
153    }
154}
155
156#[derive(Deserialize, Serialize, Debug, PartialEq)]
157#[serde(untagged)]
158#[non_exhaustive]
159pub enum EventData {
160    Cancel(SerializedCancelData),
161    Mouse(SerializedMouseData),
162    Clipboard(SerializedClipboardData),
163    Composition(SerializedCompositionData),
164    Keyboard(SerializedKeyboardData),
165    Focus(SerializedFocusData),
166    Form(SerializedFormData),
167    Drag(SerializedDragData),
168    Pointer(SerializedPointerData),
169    Selection(SerializedSelectionData),
170    Touch(SerializedTouchData),
171    Resize(SerializedResizeData),
172    Scroll(SerializedScrollData),
173    Visible(SerializedVisibleData),
174    Wheel(SerializedWheelData),
175    Media(SerializedMediaData),
176    Animation(SerializedAnimationData),
177    Transition(SerializedTransitionData),
178    Toggle(SerializedToggleData),
179    Image(SerializedImageData),
180    Mounted,
181}
182
183impl EventData {
184    pub fn into_any(self) -> Rc<dyn Any> {
185        match self {
186            EventData::Cancel(data) => {
187                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
188            }
189            EventData::Mouse(data) => {
190                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
191            }
192            EventData::Clipboard(data) => {
193                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
194            }
195            EventData::Composition(data) => {
196                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
197            }
198            EventData::Keyboard(data) => {
199                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
200            }
201            EventData::Focus(data) => {
202                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
203            }
204            EventData::Form(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
205            EventData::Drag(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
206            EventData::Pointer(data) => {
207                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
208            }
209            EventData::Selection(data) => {
210                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
211            }
212            EventData::Touch(data) => {
213                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
214            }
215            EventData::Resize(data) => {
216                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
217            }
218            EventData::Scroll(data) => {
219                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
220            }
221            EventData::Visible(data) => {
222                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
223            }
224            EventData::Wheel(data) => {
225                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
226            }
227            EventData::Media(data) => {
228                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
229            }
230            EventData::Animation(data) => {
231                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
232            }
233            EventData::Transition(data) => {
234                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
235            }
236            EventData::Toggle(data) => {
237                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
238            }
239            EventData::Image(data) => {
240                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
241            }
242            EventData::Mounted => {
243                Rc::new(PlatformEventData::new(Box::new(MountedData::new(())))) as Rc<dyn Any>
244            }
245        }
246    }
247}
248
249#[test]
250fn test_back_and_forth() {
251    let data = HtmlEvent {
252        element: ElementId(0),
253        data: EventData::Mouse(SerializedMouseData::default()),
254        name: "click".to_string(),
255        bubbles: true,
256    };
257
258    println!("{}", serde_json::to_string_pretty(&data).unwrap());
259
260    let o = r#"
261{
262  "element": 0,
263  "name": "click",
264  "bubbles": true,
265  "data": {
266    "alt_key": false,
267    "button": 0,
268    "buttons": 0,
269    "client_x": 0,
270    "client_y": 0,
271    "ctrl_key": false,
272    "meta_key": false,
273    "offset_x": 0,
274    "offset_y": 0,
275    "page_x": 0,
276    "page_y": 0,
277    "screen_x": 0,
278    "screen_y": 0,
279    "shift_key": false
280  }
281}
282    "#;
283
284    let p: HtmlEvent = serde_json::from_str(o).unwrap();
285
286    assert_eq!(data, p);
287}
288
289/// A trait for converting from a serialized event to a concrete event type.
290pub struct SerializedHtmlEventConverter;
291
292impl HtmlEventConverter for SerializedHtmlEventConverter {
293    fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData {
294        event
295            .downcast::<SerializedAnimationData>()
296            .cloned()
297            .unwrap()
298            .into()
299    }
300
301    fn convert_cancel_data(&self, event: &PlatformEventData) -> CancelData {
302        event
303            .downcast::<SerializedCancelData>()
304            .cloned()
305            .unwrap()
306            .into()
307    }
308
309    fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData {
310        event
311            .downcast::<SerializedClipboardData>()
312            .cloned()
313            .unwrap()
314            .into()
315    }
316
317    fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData {
318        event
319            .downcast::<SerializedCompositionData>()
320            .cloned()
321            .unwrap()
322            .into()
323    }
324
325    fn convert_drag_data(&self, event: &PlatformEventData) -> DragData {
326        event
327            .downcast::<SerializedDragData>()
328            .cloned()
329            .unwrap()
330            .into()
331    }
332
333    fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData {
334        event
335            .downcast::<SerializedFocusData>()
336            .cloned()
337            .unwrap()
338            .into()
339    }
340
341    fn convert_form_data(&self, event: &PlatformEventData) -> FormData {
342        event
343            .downcast::<SerializedFormData>()
344            .cloned()
345            .unwrap()
346            .into()
347    }
348
349    fn convert_image_data(&self, event: &PlatformEventData) -> ImageData {
350        event
351            .downcast::<SerializedImageData>()
352            .cloned()
353            .unwrap()
354            .into()
355    }
356
357    fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData {
358        event
359            .downcast::<SerializedKeyboardData>()
360            .cloned()
361            .unwrap()
362            .into()
363    }
364
365    fn convert_media_data(&self, event: &PlatformEventData) -> MediaData {
366        event
367            .downcast::<SerializedMediaData>()
368            .cloned()
369            .unwrap()
370            .into()
371    }
372
373    fn convert_mounted_data(&self, _: &PlatformEventData) -> MountedData {
374        MountedData::from(())
375    }
376
377    fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData {
378        event
379            .downcast::<SerializedMouseData>()
380            .cloned()
381            .unwrap()
382            .into()
383    }
384
385    fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData {
386        event
387            .downcast::<SerializedPointerData>()
388            .cloned()
389            .unwrap()
390            .into()
391    }
392    fn convert_resize_data(&self, event: &PlatformEventData) -> ResizeData {
393        event
394            .downcast::<SerializedResizeData>()
395            .cloned()
396            .unwrap()
397            .into()
398    }
399
400    fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData {
401        event
402            .downcast::<SerializedScrollData>()
403            .cloned()
404            .unwrap()
405            .into()
406    }
407
408    fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData {
409        event
410            .downcast::<SerializedSelectionData>()
411            .cloned()
412            .unwrap()
413            .into()
414    }
415
416    fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData {
417        event
418            .downcast::<SerializedToggleData>()
419            .cloned()
420            .unwrap()
421            .into()
422    }
423
424    fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData {
425        event
426            .downcast::<SerializedTouchData>()
427            .cloned()
428            .unwrap()
429            .into()
430    }
431
432    fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData {
433        event
434            .downcast::<SerializedTransitionData>()
435            .cloned()
436            .unwrap()
437            .into()
438    }
439
440    fn convert_visible_data(&self, event: &PlatformEventData) -> VisibleData {
441        event
442            .downcast::<SerializedVisibleData>()
443            .cloned()
444            .unwrap()
445            .into()
446    }
447
448    fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData {
449        event
450            .downcast::<SerializedWheelData>()
451            .cloned()
452            .unwrap()
453            .into()
454    }
455}