dioxus_html/events/
clipboard.rs1use dioxus_core::Event;
2
3use crate::data_transfer::{DataTransfer, HasDataTransferData};
4use crate::file_data::{FileData, HasFileData};
5
6pub type ClipboardEvent = Event<ClipboardData>;
7
8pub struct ClipboardData {
18 inner: Box<dyn HasClipboardData>,
19}
20
21impl<E: HasClipboardData> From<E> for ClipboardData {
22 fn from(e: E) -> Self {
23 Self { inner: Box::new(e) }
24 }
25}
26
27impl std::fmt::Debug for ClipboardData {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 let dt = self.data_transfer();
30 f.debug_struct("ClipboardData")
31 .field("text", &dt.get_as_text())
32 .field("files", &dt.files().len())
33 .finish()
34 }
35}
36
37impl PartialEq for ClipboardData {
38 fn eq(&self, other: &Self) -> bool {
39 let (this, that) = (self.data_transfer(), other.data_transfer());
42 this.get_as_text() == that.get_as_text()
43 }
44}
45
46impl ClipboardData {
47 pub fn new(inner: impl HasClipboardData) -> Self {
49 Self {
50 inner: Box::new(inner),
51 }
52 }
53
54 pub fn data_transfer(&self) -> DataTransfer {
59 self.inner.data_transfer()
60 }
61
62 #[inline(always)]
64 pub fn downcast<T: 'static>(&self) -> Option<&T> {
65 self.inner.as_ref().as_any().downcast_ref::<T>()
66 }
67}
68
69impl HasFileData for ClipboardData {
70 fn files(&self) -> Vec<FileData> {
71 self.inner.files()
72 }
73}
74
75pub trait HasClipboardData: HasDataTransferData + HasFileData {
76 fn as_any(&self) -> &dyn std::any::Any;
78}
79
80#[cfg(feature = "serialize")]
81pub use ser::*;
82
83#[cfg(feature = "serialize")]
84mod ser {
85 use super::*;
86 use crate::data_transfer::SerializedDataTransfer;
87
88 #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
91 pub struct SerializedClipboardData {
92 pub data_transfer: SerializedDataTransfer,
93 }
94
95 impl SerializedClipboardData {
96 fn new(clipboard: &ClipboardData) -> Self {
97 let data_transfer = clipboard.data_transfer();
98 Self {
99 data_transfer: SerializedDataTransfer::from_data_transfer(&data_transfer),
100 }
101 }
102 }
103
104 impl HasDataTransferData for SerializedClipboardData {
105 fn data_transfer(&self) -> DataTransfer {
106 DataTransfer::new(self.data_transfer.clone())
107 }
108 }
109
110 impl HasFileData for SerializedClipboardData {
111 fn files(&self) -> Vec<FileData> {
112 self.data_transfer().files()
113 }
114 }
115
116 impl HasClipboardData for SerializedClipboardData {
117 fn as_any(&self) -> &dyn std::any::Any {
118 self
119 }
120 }
121
122 impl serde::Serialize for ClipboardData {
123 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
124 SerializedClipboardData::new(self).serialize(serializer)
125 }
126 }
127
128 impl<'de> serde::Deserialize<'de> for ClipboardData {
129 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
130 let data = SerializedClipboardData::deserialize(deserializer)?;
131 Ok(Self {
132 inner: Box::new(data),
133 })
134 }
135 }
136}
137
138#[cfg(all(test, feature = "serialize"))]
139mod tests {
140 use super::*;
141
142 #[test]
147 fn deserializes_paste_payload_from_js_interpreter() {
148 let payload = r#"{
149 "data_transfer": {
150 "items": [
151 { "kind": "string", "type_": "text/plain", "data": "hello pasted" }
152 ],
153 "files": [],
154 "effect_allowed": "uninitialized",
155 "drop_effect": "none"
156 }
157 }"#;
158
159 let data: ClipboardData = serde_json::from_str(payload).unwrap();
160 assert_eq!(
161 data.data_transfer().get_as_text().as_deref(),
162 Some("hello pasted")
163 );
164 assert_eq!(
165 data.data_transfer().get_data("text/plain").as_deref(),
166 Some("hello pasted")
167 );
168 assert!(data.files().is_empty());
169 }
170
171 #[test]
172 fn paste_text_round_trips_through_serde() {
173 let payload = r#"{
174 "data_transfer": {
175 "items": [
176 { "kind": "string", "type_": "text/plain", "data": "round trip" }
177 ],
178 "files": [],
179 "effect_allowed": "",
180 "drop_effect": ""
181 }
182 }"#;
183
184 let data: ClipboardData = serde_json::from_str(payload).unwrap();
185 let json = serde_json::to_string(&data).unwrap();
186 let back: ClipboardData = serde_json::from_str(&json).unwrap();
187 assert_eq!(
188 back.data_transfer().get_as_text().as_deref(),
189 Some("round trip")
190 );
191 }
192}