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