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 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 #[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" => Cancel(de(data)?),
70
71 "click" | "contextmenu" | "dblclick" | "doubleclick" | "mousedown" | "mouseenter"
73 | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => Mouse(de(data)?),
74
75 "copy" | "cut" | "paste" => Clipboard(de(data)?),
77
78 "compositionend" | "compositionstart" | "compositionupdate" => Composition(de(data)?),
80
81 "keydown" | "keypress" | "keyup" => Keyboard(de(data)?),
83
84 "blur" | "focus" | "focusin" | "focusout" => Focus(de(data)?),
86
87 "change" | "input" | "invalid" | "reset" | "submit" => Form(de(data)?),
89
90 "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart"
92 | "drop" => Drag(de(data)?),
93
94 "pointerlockchange" | "pointerlockerror" | "pointerdown" | "pointermove" | "pointerup"
96 | "pointerover" | "pointerout" | "pointerenter" | "pointerleave" | "gotpointercapture"
97 | "lostpointercapture" => Pointer(de(data)?),
98
99 "selectstart" | "selectionchange" | "select" => Selection(de(data)?),
101
102 "touchcancel" | "touchend" | "touchmove" | "touchstart" => Touch(de(data)?),
104
105 "resize" => Resize(de(data)?),
107
108 "scroll" => Scroll(de(data)?),
110
111 "visible" => Visible(de(data)?),
113
114 "wheel" => Wheel(de(data)?),
116
117 "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 "animationstart" | "animationend" | "animationiteration" => Animation(de(data)?),
126
127 "transitionend" => Transition(de(data)?),
129
130 "toggle" => Toggle(de(data)?),
132
133 "load" | "error" => Image(de(data)?),
134
135 "mounted" => Mounted,
137
138 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
289pub 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}