Skip to main content

script/dom/clipboard/
clipboardevent.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::rust::HandleObject;
8use script_bindings::match_domstring_ascii;
9use script_bindings::reflector::reflect_dom_object_with_proto;
10use script_bindings::str::DOMString;
11use style::Atom;
12
13use crate::dom::bindings::codegen::Bindings::ClipboardEventBinding::{
14    ClipboardEventInit, ClipboardEventMethods,
15};
16use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::root::{DomRoot, MutNullableDom};
19use crate::dom::datatransfer::DataTransfer;
20use crate::dom::event::{Event, EventBubbles, EventCancelable};
21use crate::dom::window::Window;
22use crate::drag::drag_data_store::Kind;
23
24/// The types of clipboard events in the Clipboard APIs specification:
25/// <https://www.w3.org/TR/clipboard-apis/#clipboard-actions>.
26#[derive(Clone, Debug, MallocSizeOf)]
27pub(crate) enum ClipboardEventType {
28    Change,
29    Copy,
30    Cut,
31    Paste,
32    Other(Atom),
33}
34
35impl ClipboardEventType {
36    /// Convert this [`ClipboardEventType`] to an `Atom` for use in creating DOM events.
37    pub(crate) fn as_atom(&self) -> Atom {
38        match self {
39            ClipboardEventType::Change => "clipboardchange".into(),
40            ClipboardEventType::Copy => "copy".into(),
41            ClipboardEventType::Cut => "cut".into(),
42            ClipboardEventType::Paste => "paste".into(),
43            ClipboardEventType::Other(atom) => atom.clone(),
44        }
45    }
46}
47
48impl From<DOMString> for ClipboardEventType {
49    fn from(value: DOMString) -> Self {
50        match_domstring_ascii!(value,
51            "clipboardchange" => return ClipboardEventType::Change,
52            "copy" => return ClipboardEventType::Copy,
53            "cut" => return ClipboardEventType::Cut,
54            "paste" => return ClipboardEventType::Paste,
55            _ => {},
56        );
57        ClipboardEventType::Other(value.into())
58    }
59}
60
61#[dom_struct]
62pub(crate) struct ClipboardEvent {
63    event: Event,
64    #[no_trace]
65    clipboard_event_type: ClipboardEventType,
66    clipboard_data: MutNullableDom<DataTransfer>,
67}
68
69impl ClipboardEvent {
70    fn new_inherited(
71        clipboard_event_type: ClipboardEventType,
72        clipboard_data: Option<&DataTransfer>,
73    ) -> ClipboardEvent {
74        ClipboardEvent {
75            event: Event::new_inherited(),
76            clipboard_event_type,
77            clipboard_data: MutNullableDom::new(clipboard_data),
78        }
79    }
80
81    pub(crate) fn new(
82        cx: &mut JSContext,
83        window: &Window,
84        proto: Option<HandleObject>,
85        clipboard_event_type: ClipboardEventType,
86        can_bubble: EventBubbles,
87        cancelable: EventCancelable,
88        clipboard_data: Option<&DataTransfer>,
89    ) -> DomRoot<ClipboardEvent> {
90        let event_type = clipboard_event_type.as_atom();
91        let event = reflect_dom_object_with_proto(
92            cx,
93            Box::new(ClipboardEvent::new_inherited(
94                clipboard_event_type,
95                clipboard_data,
96            )),
97            window,
98            proto,
99        );
100        event.upcast::<Event>().init_event(
101            event_type,
102            bool::from(can_bubble),
103            bool::from(cancelable),
104        );
105        event
106    }
107
108    pub(crate) fn clipboard_event_type(&self) -> &ClipboardEventType {
109        &self.clipboard_event_type
110    }
111
112    pub(crate) fn set_clipboard_data(&self, clipboard_data: Option<&DataTransfer>) {
113        self.clipboard_data.set(clipboard_data);
114    }
115
116    pub(crate) fn clipboard_data(&self) -> Option<DomRoot<DataTransfer>> {
117        self.clipboard_data.get()
118    }
119
120    /// Returns the text content of this [`ClipboardEvent`]'s [`DataTransfer`] object if
121    /// any exists.
122    pub(crate) fn text_content(&self) -> Option<String> {
123        self.clipboard_data()?
124            .data_store()?
125            .iter_item_list()
126            .find_map(|item| match item {
127                Kind::Text { data, .. } if !data.is_empty() => Some(data.to_string()),
128                _ => None,
129            })
130    }
131}
132
133impl ClipboardEventMethods<crate::DomTypeHolder> for ClipboardEvent {
134    /// <https://www.w3.org/TR/clipboard-apis/#dom-clipboardevent-clipboardevent>
135    fn Constructor(
136        cx: &mut JSContext,
137        window: &Window,
138        proto: Option<HandleObject>,
139        event_type: DOMString,
140        init: &ClipboardEventInit,
141    ) -> DomRoot<ClipboardEvent> {
142        let bubbles = EventBubbles::from(init.parent.bubbles);
143        let cancelable = EventCancelable::from(init.parent.cancelable);
144        let event = ClipboardEvent::new(
145            cx,
146            window,
147            proto,
148            event_type.into(),
149            bubbles,
150            cancelable,
151            init.clipboardData.as_deref(),
152        );
153        event.upcast::<Event>().set_composed(init.parent.composed);
154        event
155    }
156
157    /// <https://www.w3.org/TR/clipboard-apis/#dom-clipboardevent-clipboarddata>
158    fn GetClipboardData(&self) -> Option<DomRoot<DataTransfer>> {
159        self.clipboard_data.get()
160    }
161
162    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
163    fn IsTrusted(&self) -> bool {
164        self.event.IsTrusted()
165    }
166}