#[cfg(feature = "futures-support")]
use futures_channel::oneshot;
use webapi::event::{IEvent, IUiEvent, UiEvent, Event};
use webapi::events::mouse::{IMouseEvent, MouseEvent};
use webapi::file::File;
use webcore::once::Once;
use webcore::value::{Reference, Value};
use webcore::try_from::TryInto;
use webapi::file_list::FileList;
use webapi::html_elements::ImageElement;
use webapi::dom_exception::NotSupportedError;
use webapi::dom_exception::InvalidStateError;
pub trait IDragEvent: IMouseEvent {
#[inline]
fn data_transfer(&self) -> Option<DataTransfer> {
js!(
return @{self.as_ref()}.dataTransfer;
).try_into().unwrap()
}
}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(subclass_of(Event, UiEvent, MouseEvent))]
pub struct DragRelatedEvent(Reference);
impl IEvent for DragRelatedEvent {}
impl IUiEvent for DragRelatedEvent {}
impl IMouseEvent for DragRelatedEvent {}
impl IDragEvent for DragRelatedEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "drag")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragEvent(Reference);
impl IEvent for DragEvent {}
impl IUiEvent for DragEvent {}
impl IMouseEvent for DragEvent {}
impl IDragEvent for DragEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "dragstart")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragStartEvent(Reference);
impl IEvent for DragStartEvent {}
impl IUiEvent for DragStartEvent {}
impl IMouseEvent for DragStartEvent {}
impl IDragEvent for DragStartEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "dragenter")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragEnterEvent(Reference);
impl IEvent for DragEnterEvent {}
impl IUiEvent for DragEnterEvent {}
impl IMouseEvent for DragEnterEvent {}
impl IDragEvent for DragEnterEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "dragexit")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragExitEvent(Reference);
impl IEvent for DragExitEvent {}
impl IUiEvent for DragExitEvent {}
impl IMouseEvent for DragExitEvent {}
impl IDragEvent for DragExitEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "dragleave")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragLeaveEvent(Reference);
impl IEvent for DragLeaveEvent {}
impl IUiEvent for DragLeaveEvent {}
impl IMouseEvent for DragLeaveEvent {}
impl IDragEvent for DragLeaveEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "dragover")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragOverEvent(Reference);
impl IEvent for DragOverEvent {}
impl IUiEvent for DragOverEvent {}
impl IMouseEvent for DragOverEvent {}
impl IDragEvent for DragOverEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "drop")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragDropEvent(Reference);
impl IEvent for DragDropEvent {}
impl IUiEvent for DragDropEvent {}
impl IMouseEvent for DragDropEvent {}
impl IDragEvent for DragDropEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DragEvent")]
#[reference(event = "dragend")]
#[reference(subclass_of(Event, UiEvent, MouseEvent, DragRelatedEvent))]
pub struct DragEndEvent(Reference);
impl IEvent for DragEndEvent {}
impl IUiEvent for DragEndEvent {}
impl IMouseEvent for DragEndEvent {}
impl IDragEvent for DragEndEvent {}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DataTransfer")]
pub struct DataTransfer( Reference );
impl DataTransfer {
pub fn drop_effect( &self ) -> DropEffect {
let v: String = js!(
return @{self.as_ref()}.dropEffect;
).try_into().unwrap();
match v.as_ref() {
"copy" => DropEffect::Copy,
"move" => DropEffect::Move,
"link" => DropEffect::Link,
"none" => DropEffect::None,
other => panic!("Expected valid dropEffect value, got {:?}", other),
}
}
pub fn set_drop_effect( &self, value: DropEffect ) {
js! { @(no_return)
@{self.as_ref()}.dropEffect = @{match value {
DropEffect::Copy => "copy",
DropEffect::Move => "move",
DropEffect::Link => "link",
DropEffect::None => "none",
}};
}
}
pub fn effect_allowed( &self ) -> EffectAllowed {
let v: String = js!(
return @{self.as_ref()}.effectAllowed;
).try_into().unwrap();
match v.as_ref() {
"none" => EffectAllowed::None,
"copy" => EffectAllowed::Copy,
"copyLink" => EffectAllowed::CopyLink,
"copyMove" => EffectAllowed::CopyMove,
"link" => EffectAllowed::Link,
"linkMove" => EffectAllowed::LinkMove,
"move" => EffectAllowed::Move,
"all" => EffectAllowed::All,
"uninitialized" => EffectAllowed::Uninitialized,
other => panic!("Expected valid effectAllowed value, got {:?}", other),
}
}
pub fn set_effect_allowed( &self, value: EffectAllowed ) {
js! { @(no_return)
@{self.as_ref()}.effectAllowed = @{match value {
EffectAllowed::None => "none",
EffectAllowed::Copy => "copy",
EffectAllowed::CopyLink => "copyLink",
EffectAllowed::CopyMove => "copyMove",
EffectAllowed::Link => "link",
EffectAllowed::LinkMove => "linkMove",
EffectAllowed::Move => "move",
EffectAllowed::All => "all",
EffectAllowed::Uninitialized => "uninitialized",
}};
}
}
pub fn items( &self ) -> DataTransferItemList {
js!(
return @{self.as_ref()}.items;
).try_into().unwrap()
}
pub fn files( &self ) -> FileList {
js!(
return @{self.as_ref()}.files;
).try_into().unwrap()
}
pub fn types( &self ) -> Vec<String> {
js!(
return @{self.as_ref()}.types;
).try_into().unwrap()
}
pub fn clear_data( &self, format: Option<&str> ) {
match format {
None => js!(@(no_return) @{self.as_ref()}.clearData()),
Some(x) => js!(@(no_return) @{self.as_ref()}.clearData(@{x}))
};
}
pub fn get_data( &self, format: &str ) -> String {
js!(
return @{self.as_ref()}.getData(@{format});
).try_into().unwrap()
}
pub fn set_data( &self, format: &str, data: &str ) {
js!(@(no_return)
@{self.as_ref()}.setData(@{format}, @{data});
);
}
pub fn set_drag_image( &self, img: &ImageElement, x_offset: i32, y_offset: i32 ) {
js!(@(no_return)
@{self.as_ref()}.setDragImage(@{img.as_ref()}, @{x_offset}, @{y_offset});
);
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DropEffect {
Copy,
Move,
Link,
None,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EffectAllowed {
None,
Copy,
CopyLink,
CopyMove,
Link,
LinkMove,
Move,
All,
Uninitialized,
}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DataTransferItemList")]
pub struct DataTransferItemList( Reference );
impl DataTransferItemList {
pub fn len( &self ) -> u32 {
js!(
return @{self.as_ref()}.length;
).try_into().unwrap()
}
pub fn add_string( &self, data: &str, ty: &str ) -> Result<Option<DataTransferItem>, NotSupportedError> {
js_try!(
return @{self.as_ref()}.add(@{data}, @{ty});
).unwrap()
}
pub fn add_file( &self, file: &File ) -> Option<DataTransferItem> {
js!(
return @{self.as_ref()}.add(@{file});
).try_into().unwrap()
}
pub fn remove( &self, index: u32 ) -> Result<(), InvalidStateError> {
js_try!(@{self.as_ref()}.remove(@{index})).unwrap()
}
pub fn clear( &self ) {
js!(@(no_return) @{self.as_ref()}.clear());
}
pub fn index( &self, index: u32 ) -> Option<DataTransferItem> {
let v: Value = js!(
return @{self.as_ref()}[@{index}];
);
match v {
Value::Reference(_) => Some(v.try_into().unwrap()),
_ => None,
}
}
pub fn iter( &self ) -> DataTransferItemIter {
DataTransferItemIter {
list: self.clone(),
index: 0,
}
}
}
impl IntoIterator for DataTransferItemList {
type Item = DataTransferItem;
type IntoIter = DataTransferItemIter;
#[inline]
fn into_iter( self ) -> Self::IntoIter {
DataTransferItemIter {
list: self,
index: 0
}
}
}
impl< 'a > IntoIterator for &'a DataTransferItemList {
type Item = DataTransferItem;
type IntoIter = DataTransferItemIter;
#[inline]
fn into_iter( self ) -> Self::IntoIter {
DataTransferItemIter {
list: self.clone(),
index: 0
}
}
}
impl Iterator for DataTransferItemIter {
type Item = DataTransferItem;
fn next( &mut self ) -> Option< Self::Item > {
let v = self.list.index(self.index);
if v.is_some() {
self.index += 1;
}
v
}
}
#[derive(Debug)]
pub struct DataTransferItemIter {
list: DataTransferItemList,
index: u32,
}
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "DataTransferItem")]
pub struct DataTransferItem( Reference );
impl DataTransferItem {
pub fn kind( &self ) -> DataTransferItemKind {
let kind: String = js!(
return @{self.as_ref()}.kind;
).try_into().unwrap();
match kind.as_ref() {
"string" => DataTransferItemKind::String,
"file" => DataTransferItemKind::File,
other => DataTransferItemKind::__Other(OtherKind { name: String::from(other) }),
}
}
pub fn ty( &self ) -> String {
js!(
return @{self.as_ref()}.type;
).try_into().unwrap()
}
pub fn get_as_file( &self ) -> Option<File> {
js!(
return @{self.as_ref()}.getAsFile();
).try_into().unwrap()
}
pub fn get_as_string<F>( &self, callback: F )
where F: FnOnce(String) + 'static {
js!(@(no_return)
@{self.as_ref()}.getAsString(@{Once(callback)});
);
}
#[cfg(feature = "futures-support")]
pub fn get_as_string_future( &self ) -> oneshot::Receiver<String> {
let (sender, receiver) = oneshot::channel();
let callback = |s: String| {
match sender.send(s) {
Ok(_) => {},
Err(_) => {},
};
};
js!(@(no_return)
@{self.as_ref()}.getAsString(@{Once(callback)});
);
receiver
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DataTransferItemKind {
File,
String,
#[doc(hidden)]
__Other(OtherKind),
}
impl DataTransferItemKind {
pub fn as_str( &self ) -> &str {
match *self {
DataTransferItemKind::File => "file",
DataTransferItemKind::String => "string",
DataTransferItemKind::__Other( ref other_kind ) => &other_kind.name
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OtherKind {
name: String,
}
#[cfg(all(test, feature = "web_test"))]
mod tests {
use super::*;
use webapi::event::ConcreteEvent;
#[test]
fn test_drag_event() {
let event: DragRelatedEvent = js!(
return new DragEvent(
@{DragStartEvent::EVENT_TYPE},
{
dataTransfer: new DataTransfer()
}
);
).try_into().unwrap();
assert_eq!(event.event_type(), DragStartEvent::EVENT_TYPE);
assert_eq!(event.data_transfer().unwrap().effect_allowed(), EffectAllowed::None);
assert_eq!(event.data_transfer().unwrap().drop_effect(), DropEffect::None);
event.data_transfer().unwrap().set_effect_allowed(EffectAllowed::CopyMove);
event.data_transfer().unwrap().set_drop_effect(DropEffect::Copy);
event.data_transfer().unwrap().set_data("myformat", "mydata");
event.data_transfer().unwrap().set_data("myformat2", "mydata2");
event.data_transfer().unwrap().clear_data(Some("myformat3"));
assert_eq!(event.data_transfer().unwrap().get_data("myformat"), String::from("mydata"));
event.data_transfer().unwrap().clear_data(Some("myformat"));
assert_eq!(event.data_transfer().unwrap().get_data("myformat"), String::from(""));
assert_eq!(event.data_transfer().unwrap().get_data("myformat2"), String::from("mydata2"));
event.data_transfer().unwrap().clear_data(None);
assert_eq!(event.data_transfer().unwrap().get_data("myformat2"), String::from(""));
let img = ImageElement::new();
event.data_transfer().unwrap().set_drag_image(&img, 10, 10);
assert_eq!(event.data_transfer().unwrap().types().len(), 0);
assert_eq!(event.data_transfer().unwrap().items().len(), 0);
let data = "mydata";
let ty = "text/plain";
let item = event.data_transfer().unwrap().items().add_string(data, ty).unwrap().unwrap();
assert_eq!(item.ty(), ty);
assert_eq!(item.kind(), DataTransferItemKind::String);
let filename = "myname";
let file = js!(return new File(["content"], @{filename})).try_into().unwrap();
event.data_transfer().unwrap().items().add_file(&file).unwrap();
assert_eq!(event.data_transfer().unwrap().items().len(), 2);
assert_eq!(event.data_transfer().unwrap().items().iter().count(), 2);
assert!(event.data_transfer().unwrap().items().index(2).is_none());
assert_eq!(event.data_transfer().unwrap().files().len(), 1);
let item = event.data_transfer().unwrap().items().index(1).unwrap();
assert_eq!(item.kind(), DataTransferItemKind::File);
assert_eq!(item.get_as_file().unwrap().name(), filename);
let result = event.data_transfer().unwrap().items().remove(0);
assert!(result.is_ok());
assert_eq!(event.data_transfer().unwrap().items().len(), 1);
event.data_transfer().unwrap().items().clear();
assert_eq!(event.data_transfer().unwrap().items().len(), 0);
}
}