stdweb/webapi/events/
drag.rs

1#[cfg(feature = "futures-support")]
2use futures_channel::oneshot;
3use webapi::event::{IEvent, IUiEvent, UiEvent, Event};
4use webapi::events::mouse::{IMouseEvent, MouseEvent};
5use webapi::file::File;
6use webcore::once::Once;
7use webcore::value::{Reference, Value};
8use webcore::try_from::TryInto;
9use webapi::file_list::FileList;
10use webapi::html_elements::ImageElement;
11use webapi::dom_exception::NotSupportedError;
12use webapi::dom_exception::InvalidStateError;
13
14/// The DragEvent interface is a DOM event that represents a drag and drop interaction.
15/// The user initiates a drag by placing a pointer device (such as a mouse) on the touch surface
16/// and then dragging the pointer to a new location (such as another DOM element).
17///
18/// This interface inherits properties from MouseEvent and Event.
19///
20/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent)
21// https://www.w3.org/TR/html51/editing.html#dragevent-dragevent
22pub trait IDragEvent: IMouseEvent {
23    /// The DataEvent.dataTransfer property holds the drag operation's data (as a DataTransfer object).
24    ///
25    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/dataTransfer)
26    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-dragevent-datatransfer-1
27    #[inline]
28    fn data_transfer(&self) -> Option<DataTransfer> {
29        js!(
30            return @{self.as_ref()}.dataTransfer;
31        ).try_into().unwrap()
32    }
33}
34
35/// A reference to a JavaScript object which implements the [IDragEvent](trait.IDragEvent.html)
36/// interface.
37///
38/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent)
39// https://www.w3.org/TR/html51/editing.html#the-dragevent-interface
40#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
41#[reference(instance_of = "DragEvent")]
42#[reference(subclass_of(Event, UiEvent, MouseEvent))]
43pub struct DragRelatedEvent(Reference);
44
45impl IEvent for DragRelatedEvent {}
46
47impl IUiEvent for DragRelatedEvent {}
48
49impl IMouseEvent for DragRelatedEvent {}
50
51impl IDragEvent for DragRelatedEvent {}
52
53/// The drag event is fired every few hundred milliseconds as an element or text selection is being
54/// dragged by the user.
55///
56/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/drag)
57// https://www.w3.org/TR/html51/editing.html#eventdef-global-drag
58#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
59#[reference(instance_of = "DragEvent")]
60#[reference(event = "drag")]
61#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
62pub struct DragEvent(Reference);
63
64impl IEvent for DragEvent {}
65
66impl IUiEvent for DragEvent {}
67
68impl IMouseEvent for DragEvent {}
69
70impl IDragEvent for DragEvent {}
71
72/// The dragstart event is fired when the user starts dragging an element or text selection.
73///
74/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/dragstart)
75// https://www.w3.org/TR/html51/editing.html#eventdef-global-dragstart
76#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
77#[reference(instance_of = "DragEvent")]
78#[reference(event = "dragstart")]
79#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
80pub struct DragStartEvent(Reference);
81
82impl IEvent for DragStartEvent {}
83
84impl IUiEvent for DragStartEvent {}
85
86impl IMouseEvent for DragStartEvent {}
87
88impl IDragEvent for DragStartEvent {}
89
90/// The dragenter event is fired when a dragged element or text selection enters a valid drop target.
91///
92/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/dragenter)
93// https://www.w3.org/TR/html51/editing.html#eventdef-global-dragenter
94#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
95#[reference(instance_of = "DragEvent")]
96#[reference(event = "dragenter")]
97#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
98pub struct DragEnterEvent(Reference);
99
100impl IEvent for DragEnterEvent {}
101
102impl IUiEvent for DragEnterEvent {}
103
104impl IMouseEvent for DragEnterEvent {}
105
106impl IDragEvent for DragEnterEvent {}
107
108/// The dragexit event is fired when an element is no longer the drag operation's immediate
109/// selection target.
110///
111/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/dragexit)
112// https://www.w3.org/TR/html51/editing.html#eventdef-global-dragexit
113#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
114#[reference(instance_of = "DragEvent")]
115#[reference(event = "dragexit")]
116#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
117pub struct DragExitEvent(Reference);
118
119impl IEvent for DragExitEvent {}
120
121impl IUiEvent for DragExitEvent {}
122
123impl IMouseEvent for DragExitEvent {}
124
125impl IDragEvent for DragExitEvent {}
126
127/// The dragleave event is fired when a dragged element or text selection leaves a valid drop target.
128///
129/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/dragleave)
130// https://www.w3.org/TR/html51/editing.html#eventdef-global-dragleave
131#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
132#[reference(instance_of = "DragEvent")]
133#[reference(event = "dragleave")]
134#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
135pub struct DragLeaveEvent(Reference);
136
137impl IEvent for DragLeaveEvent {}
138
139impl IUiEvent for DragLeaveEvent {}
140
141impl IMouseEvent for DragLeaveEvent {}
142
143impl IDragEvent for DragLeaveEvent {}
144
145/// The dragover event is fired when an element or text selection is being dragged over a valid drop
146/// target (every few hundred milliseconds).
147///
148/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/dragover)
149// https://www.w3.org/TR/html51/editing.html#eventdef-global-dragover
150#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
151#[reference(instance_of = "DragEvent")]
152#[reference(event = "dragover")]
153#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
154pub struct DragOverEvent(Reference);
155
156impl IEvent for DragOverEvent {}
157
158impl IUiEvent for DragOverEvent {}
159
160impl IMouseEvent for DragOverEvent {}
161
162impl IDragEvent for DragOverEvent {}
163
164/// The drop event is fired when an element or text selection is dropped on a valid drop target.
165///
166/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/drop)
167// https://www.w3.org/TR/html51/editing.html#eventdef-global-drop
168#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
169#[reference(instance_of = "DragEvent")]
170#[reference(event = "drop")]
171#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
172pub struct DragDropEvent(Reference);
173
174impl IEvent for DragDropEvent {}
175
176impl IUiEvent for DragDropEvent {}
177
178impl IMouseEvent for DragDropEvent {}
179
180impl IDragEvent for DragDropEvent {}
181
182/// The dragend event is fired when a drag operation is being ended (by releasing a mouse button or
183/// hitting the escape key).
184///
185/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/Events/dragend)
186// https://www.w3.org/TR/html51/editing.html#eventdef-global-dragend
187#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
188#[reference(instance_of = "DragEvent")]
189#[reference(event = "dragend")]
190#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
191pub struct DragEndEvent(Reference);
192
193impl IEvent for DragEndEvent {}
194
195impl IUiEvent for DragEndEvent {}
196
197impl IMouseEvent for DragEndEvent {}
198
199impl IDragEvent for DragEndEvent {}
200
201/// The DataTransfer object is used to hold the data that is being dragged during a drag and drop
202/// operation.
203///
204/// It may hold one or more data items, each of one or more data types.
205/// For more information about drag and drop, see HTML Drag and Drop API.
206///
207/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer)
208// https://www.w3.org/TR/html51/editing.html#datatransfer-datatransfer
209#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
210#[reference(instance_of = "DataTransfer")]
211pub struct DataTransfer( Reference );
212impl DataTransfer {
213    /// Gets the type of drag-and-drop operation currently selected type.
214    /// The value must be none, copy, link or move.
215    ///
216    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/dropEffect)
217    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-dropeffect-2
218    pub fn drop_effect( &self ) -> DropEffect {
219        let v: String = js!(
220            return @{self.as_ref()}.dropEffect;
221        ).try_into().unwrap();
222        match v.as_ref() {
223            "copy" => DropEffect::Copy,
224            "move" => DropEffect::Move,
225            "link" => DropEffect::Link,
226            "none" => DropEffect::None,
227            other => panic!("Expected valid dropEffect value, got {:?}", other),
228        }
229    }
230
231    /// Sets the type of drag-and-drop operation currently selected.
232    /// The value must be none, copy, link or move.
233    ///
234    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Element/dropEffect)
235    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-dropeffect-2
236    pub fn set_drop_effect( &self, value: DropEffect ) {
237        js! { @(no_return)
238            @{self.as_ref()}.dropEffect = @{match value {
239                DropEffect::Copy => "copy",
240                DropEffect::Move => "move",
241                DropEffect::Link => "link",
242                DropEffect::None => "none",
243            }};
244        }
245    }
246
247    /// Provides all of the types of operations that are possible.
248    /// Must be one of none, copy, copyLink, copyMove, link, linkMove, move, all or uninitialized.
249    ///
250    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/effectAllowed)
251    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-effectallowed-1
252    pub fn effect_allowed( &self ) -> EffectAllowed {
253        let v: String = js!(
254            return @{self.as_ref()}.effectAllowed;
255        ).try_into().unwrap();
256        match v.as_ref() {
257            "none" => EffectAllowed::None,
258            "copy" => EffectAllowed::Copy,
259            "copyLink" => EffectAllowed::CopyLink,
260            "copyMove" => EffectAllowed::CopyMove,
261            "link" => EffectAllowed::Link,
262            "linkMove" => EffectAllowed::LinkMove,
263            "move" => EffectAllowed::Move,
264            "all" => EffectAllowed::All,
265            "uninitialized" => EffectAllowed::Uninitialized,
266            other => panic!("Expected valid effectAllowed value, got {:?}", other),
267        }
268    }
269
270    /// Sets the effect that is allowed for a drag operation.
271    /// Must be one of none, copy, copyLink, copyMove, link, linkMove, move, all or uninitialized.
272    ///
273    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Element/effectAllowed)
274    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-effectallowed-1
275    pub fn set_effect_allowed( &self, value: EffectAllowed ) {
276        js! { @(no_return)
277            @{self.as_ref()}.effectAllowed = @{match value {
278            EffectAllowed::None => "none",
279            EffectAllowed::Copy => "copy",
280            EffectAllowed::CopyLink => "copyLink",
281            EffectAllowed::CopyMove => "copyMove",
282            EffectAllowed::Link => "link",
283            EffectAllowed::LinkMove => "linkMove",
284            EffectAllowed::Move => "move",
285            EffectAllowed::All => "all",
286            EffectAllowed::Uninitialized => "uninitialized",
287            }};
288        }
289    }
290
291    /// Gives a DataTransferItemList object which is a list of all of the drag data.
292    ///
293    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items)
294    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-items-1
295    pub fn items( &self ) -> DataTransferItemList {
296        js!(
297            return @{self.as_ref()}.items;
298        ).try_into().unwrap()
299    }
300
301    /// Contains a list of all the local files available on the data transfer.
302    /// If the drag operation doesn't involve dragging files, this property is an empty list.
303    ///
304    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/files)
305    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-files-1
306    pub fn files( &self ) -> FileList {
307        js!(
308            return @{self.as_ref()}.files;
309        ).try_into().unwrap()
310    }
311
312    /// An array of strings giving the formats that were set in the dragstart event.
313    ///
314    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types)
315    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-types-1
316    pub fn types( &self ) -> Vec<String> {
317        js!(
318            return @{self.as_ref()}.types;
319        ).try_into().unwrap()
320    }
321
322    /// Remove the data associated with a given type. The type argument is optional.
323    /// If the type is empty or not specified, the data associated with all types is removed.
324    /// If data for the specified type does not exist, or the data transfer contains no data,
325    /// this method will have no effect.
326    ///
327    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/clearData)
328    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-cleardata-1
329    pub fn clear_data( &self, format: Option<&str> ) {
330        match format {
331            None => js!(@(no_return) @{self.as_ref()}.clearData()),
332            Some(x) => js!(@(no_return) @{self.as_ref()}.clearData(@{x}))
333        };
334    }
335
336    /// Retrieves the data for a given type, or an empty string if data for that type does not exist
337    /// or the data transfer contains no data.
338    ///
339    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData)
340    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-getdata-1
341    pub fn get_data( &self, format: &str ) -> String {
342        js!(
343            return @{self.as_ref()}.getData(@{format});
344        ).try_into().unwrap()
345    }
346
347    /// Set the data for a given type.
348    /// If data for the type does not exist, it is added at the end, such that the last item in the
349    /// types list will be the new format.
350    /// If data for the type already exists, the existing data is replaced in the same position.
351    ///
352    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setData)
353    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-setdata-1
354    pub fn set_data( &self, format: &str, data: &str ) {
355        js!(@(no_return)
356            @{self.as_ref()}.setData(@{format}, @{data});
357        );
358    }
359
360    /// Set the image to be used for dragging if a custom one is desired.
361    ///
362    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setDragImage)
363    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransfer-setdragimage-1
364    pub fn set_drag_image( &self, img: &ImageElement, x_offset: i32, y_offset: i32 ) {
365        js!(@(no_return)
366            @{self.as_ref()}.setDragImage(@{img.as_ref()}, @{x_offset}, @{y_offset});
367        );
368    }
369}
370
371/// A DOMString representing the drag operation effect.
372// https://www.w3.org/TR/html51/editing.html#dom-datatransfer-dropeffect
373#[derive(Clone, Copy, Debug, PartialEq, Eq)]
374pub enum DropEffect {
375    /// A copy of the source item is made at the new location
376    Copy,
377    /// An item is moved to a new location.
378    Move,
379    /// A link is established to the source at the new location.
380    Link,
381    /// The item may not be dropped.
382    None,
383}
384
385/// A DOMString representing the drag operation that is allowed.
386// https://www.w3.org/TR/html51/editing.html#dom-datatransfer-effectallowed
387#[derive(Clone, Copy, Debug, PartialEq, Eq)]
388pub enum EffectAllowed {
389    /// The item may not be dropped.
390    None,
391    /// A copy of the source item may be made at the new location.
392    Copy,
393    /// A copy or link operation is permitted.
394    CopyLink,
395    /// A copy or move operation is permitted.
396    CopyMove,
397    /// A link may be established to the source at the new location.
398    Link,
399    /// A link or move operation is permitted.
400    LinkMove,
401    /// An item may be moved to a new location.
402    Move,
403    /// All operations are permitted.
404    All,
405    /// The default value when the effect has not been set, equivalent to all.
406    Uninitialized,
407}
408
409/// The DataTransferItemList object is a list of DataTransferItem objects representing items being
410/// dragged.
411/// During a drag operation, each DragEvent has a dataTransfer property and that property is a
412/// DataTransferItemList.
413///
414/// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList)
415// https://www.w3.org/TR/html51/editing.html#datatransferitemlist-datatransferitemlist
416#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
417#[reference(instance_of = "DataTransferItemList")]
418pub struct DataTransferItemList( Reference );
419impl DataTransferItemList {
420    /// An unsigned long that is the number of drag items in the list.
421    ///
422    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/length)
423    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitemlist-length-1
424    pub fn len( &self ) -> u32 {
425        js!(
426            return @{self.as_ref()}.length;
427        ).try_into().unwrap()
428    }
429
430    /// Adds an item of kind "string" to the drag item list and returns
431    /// a DataTransferItem object for the new item.
432    ///
433    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/add)
434    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitemlist-add-1
435    pub fn add_string( &self, data: &str, ty: &str ) -> Result<Option<DataTransferItem>, NotSupportedError> {
436        js_try!(
437            return @{self.as_ref()}.add(@{data}, @{ty});
438        ).unwrap()
439    }
440
441    /// Adds an item of kind "file" to the drag item list and returns
442    /// a DataTransferItem object for the new item.
443    ///
444    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/add)
445    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitemlist-add-2
446    pub fn add_file( &self, file: &File ) -> Option<DataTransferItem> {
447        js!(
448            return @{self.as_ref()}.add(@{file});
449        ).try_into().unwrap()
450    }
451
452    /// Removes the drag item from the list at the given index.
453    ///
454    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/remove)
455    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitemlist-remove-1
456    pub fn remove( &self, index: u32 ) -> Result<(), InvalidStateError> {
457        js_try!(@{self.as_ref()}.remove(@{index})).unwrap()
458    }
459
460    /// Removes all of the drag items from the list.
461    ///
462    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/clear)
463    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitemlist-clear-1
464    pub fn clear( &self ) {
465        js!(@(no_return) @{self.as_ref()}.clear());
466    }
467
468    /// Getter that returns a DataTransferItem at the given index.
469    ///
470    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList/DataTransferItem)
471    // https://www.w3.org/TR/html51/editing.html#ref-for-datatransferitem-datatransferitem-1
472    pub fn index( &self, index: u32 ) -> Option<DataTransferItem> {
473        let v: Value = js!(
474            return @{self.as_ref()}[@{index}];
475        );
476        match v {
477            Value::Reference(_) => Some(v.try_into().unwrap()),
478            _ => None,
479        }
480    }
481
482    /// Returns an iterator over the list
483    pub fn iter( &self ) -> DataTransferItemIter {
484        DataTransferItemIter {
485            list: self.clone(),
486            index: 0,
487        }
488    }
489}
490
491impl IntoIterator for DataTransferItemList {
492    type Item = DataTransferItem;
493    type IntoIter = DataTransferItemIter;
494
495    #[inline]
496    fn into_iter( self ) -> Self::IntoIter {
497        DataTransferItemIter {
498            list: self,
499            index: 0
500        }
501    }
502}
503
504impl< 'a > IntoIterator for &'a DataTransferItemList {
505    type Item = DataTransferItem;
506    type IntoIter = DataTransferItemIter;
507
508    #[inline]
509    fn into_iter( self ) -> Self::IntoIter {
510        DataTransferItemIter {
511            list: self.clone(),
512            index: 0
513        }
514    }
515}
516
517impl Iterator for DataTransferItemIter {
518    type Item = DataTransferItem;
519
520    fn next( &mut self ) -> Option< Self::Item > {
521        let v = self.list.index(self.index);
522        if v.is_some() {
523            self.index += 1;
524        }
525        v
526    }
527}
528
529#[derive(Debug)]
530pub struct DataTransferItemIter {
531    list: DataTransferItemList,
532    index: u32,
533}
534
535/// The DataTransferItem object represents one drag data item. During a drag operation, each drag
536/// event has a dataTransfer property which contains a list of drag data items. Each item in the
537/// list is a DataTransferItem object.
538///
539/// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem)
540// https://www.w3.org/TR/html51/editing.html#datatransferitem-datatransferitem
541#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
542#[reference(instance_of = "DataTransferItem")]
543pub struct DataTransferItem( Reference );
544
545impl DataTransferItem {
546    /// The kind of drag data item, string or file.
547    ///
548    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/kind)
549    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitem-kind-13
550    pub fn kind( &self ) -> DataTransferItemKind {
551        let kind: String = js!(
552            return @{self.as_ref()}.kind;
553        ).try_into().unwrap();
554        match kind.as_ref() {
555            "string" => DataTransferItemKind::String,
556            "file" => DataTransferItemKind::File,
557            other => DataTransferItemKind::__Other(OtherKind { name: String::from(other) }),
558        }
559    }
560
561    /// The drag data item's type, typically a MIME type.
562    ///
563    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/type)
564    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitem-type-2
565    pub fn ty( &self ) -> String {
566        js!(
567            return @{self.as_ref()}.type;
568        ).try_into().unwrap()
569    }
570
571    /// Returns the File object associated with the drag data item
572    /// (or null if the drag item is not a file)
573    ///
574    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/getAsFile)
575    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitem-getasfile-1
576    pub fn get_as_file( &self ) -> Option<File> {
577        js!(
578            return @{self.as_ref()}.getAsFile();
579        ).try_into().unwrap()
580    }
581
582    /// Invokes the specified callback with the drag data item string as its argument.
583    ///
584    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/getAsString)
585    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitem-getasstring-1
586    pub fn get_as_string<F>( &self, callback: F )
587        where F: FnOnce(String) + 'static {
588        js!(@(no_return)
589            @{self.as_ref()}.getAsString(@{Once(callback)});
590        );
591    }
592
593    /// Invokes the specified callback with the drag data item string as its argument.
594    ///
595    /// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/getAsString)
596    // https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitem-getasstring-1
597    #[cfg(feature = "futures-support")]
598    pub fn get_as_string_future( &self ) -> oneshot::Receiver<String> {
599        let (sender, receiver) = oneshot::channel();
600        let callback = |s: String| {
601            match sender.send(s) {
602                Ok(_) => {},
603                Err(_) => {},
604            };
605        };
606
607        js!(@(no_return)
608            @{self.as_ref()}.getAsString(@{Once(callback)});
609        );
610
611        receiver
612    }
613}
614
615/// The kind of drag data item, string or file.
616///
617/// [(Javascript docs)](https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/kind)
618// https://www.w3.org/TR/html51/editing.html#ref-for-dom-datatransferitem-kind-13
619// TODO use #[non_exhaustive] when available
620#[derive(Clone, Debug, PartialEq, Eq)]
621pub enum DataTransferItemKind {
622    /// If the drag data item is a file.
623    File,
624    /// If the kind of drag data item is a plain Unicode string.
625    String,
626    /// If the kind of drag data is something different (e.g. dragging an <img /> tag in Firefox)
627    #[doc(hidden)]
628    __Other(OtherKind),
629}
630
631impl DataTransferItemKind {
632    /// Returns the string representation of this DataTransferItemKind
633    /// Useful in case the browser returns a non-standard kind that you want to special case.
634    pub fn as_str( &self ) -> &str {
635        match *self {
636            DataTransferItemKind::File => "file",
637            DataTransferItemKind::String => "string",
638            DataTransferItemKind::__Other( ref other_kind ) => &other_kind.name
639        }
640    }
641}
642
643#[derive(Clone, Debug, PartialEq, Eq)]
644pub struct OtherKind {
645    name: String,
646}
647
648#[cfg(all(test, feature = "web_test"))]
649mod tests {
650    use super::*;
651    use webapi::event::ConcreteEvent;
652
653    #[test]
654    fn test_drag_event() {
655        let event: DragRelatedEvent = js!(
656            return new DragEvent(
657                @{DragStartEvent::EVENT_TYPE},
658                {
659                    dataTransfer: new DataTransfer()
660                }
661            );
662        ).try_into().unwrap();
663
664        // effects
665        assert_eq!(event.event_type(), DragStartEvent::EVENT_TYPE);
666        assert_eq!(event.data_transfer().unwrap().effect_allowed(), EffectAllowed::None);
667        assert_eq!(event.data_transfer().unwrap().drop_effect(), DropEffect::None);
668        event.data_transfer().unwrap().set_effect_allowed(EffectAllowed::CopyMove);
669        event.data_transfer().unwrap().set_drop_effect(DropEffect::Copy);
670        // TODO how to test? can only set these during ondragstart event triggered in browser
671        // assert_eq!(event.data_transfer().effect_allowed(), EffectAllowed::CopyMove);
672        // assert_eq!(event.data_transfer().drop_effect(), DropEffect::Copy);
673
674        // get, set, clear data
675        event.data_transfer().unwrap().set_data("myformat", "mydata");
676        event.data_transfer().unwrap().set_data("myformat2", "mydata2");
677        event.data_transfer().unwrap().clear_data(Some("myformat3"));
678        assert_eq!(event.data_transfer().unwrap().get_data("myformat"), String::from("mydata"));
679        event.data_transfer().unwrap().clear_data(Some("myformat"));
680        assert_eq!(event.data_transfer().unwrap().get_data("myformat"), String::from(""));
681        assert_eq!(event.data_transfer().unwrap().get_data("myformat2"), String::from("mydata2"));
682        event.data_transfer().unwrap().clear_data(None);
683        assert_eq!(event.data_transfer().unwrap().get_data("myformat2"), String::from(""));
684        let img = ImageElement::new();
685        event.data_transfer().unwrap().set_drag_image(&img, 10, 10);
686
687        // types
688        assert_eq!(event.data_transfer().unwrap().types().len(), 0);
689
690        // items
691        assert_eq!(event.data_transfer().unwrap().items().len(), 0);
692        let data = "mydata";
693        let ty = "text/plain";
694        let item = event.data_transfer().unwrap().items().add_string(data, ty).unwrap().unwrap();
695        assert_eq!(item.ty(), ty);
696        assert_eq!(item.kind(), DataTransferItemKind::String);
697        // TODO(https://github.com/koute/stdweb/issues/128) fix when async unit testing is available
698        // item.get_as_string().and_then(|s| {
699        //     assert_eq!(data, s);
700        //     assert_eq!(1, 1);
701        //     assert_eq!(2, 1);
702        // });
703        let filename = "myname";
704        let file = js!(return new File(["content"], @{filename})).try_into().unwrap();
705        event.data_transfer().unwrap().items().add_file(&file).unwrap();
706        assert_eq!(event.data_transfer().unwrap().items().len(), 2);
707        assert_eq!(event.data_transfer().unwrap().items().iter().count(), 2);
708        assert!(event.data_transfer().unwrap().items().index(2).is_none());
709        assert_eq!(event.data_transfer().unwrap().files().len(), 1);
710        let item = event.data_transfer().unwrap().items().index(1).unwrap();
711        assert_eq!(item.kind(), DataTransferItemKind::File);
712        assert_eq!(item.get_as_file().unwrap().name(), filename);
713        let result = event.data_transfer().unwrap().items().remove(0);
714        assert!(result.is_ok());
715        assert_eq!(event.data_transfer().unwrap().items().len(), 1);
716        event.data_transfer().unwrap().items().clear();
717        assert_eq!(event.data_transfer().unwrap().items().len(), 0);
718    }
719}