script/dom/datatransfer/
datatransferitemlist.rs1use std::cell::RefCell;
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use js::context::JSContext;
10use js::rust::MutableHandleValue;
11use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
12
13use crate::dom::bindings::codegen::Bindings::DataTransferItemListBinding::DataTransferItemListMethods;
14use crate::dom::bindings::error::{Error, Fallible};
15use crate::dom::bindings::frozenarray::CachedFrozenArray;
16use crate::dom::bindings::reflector::DomGlobal;
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::bindings::str::DOMString;
19use crate::dom::datatransferitem::DataTransferItem;
20use crate::dom::file::File;
21use crate::dom::window::Window;
22use crate::drag_data_store::{DragDataStore, Kind, Mode};
23
24#[dom_struct]
25pub(crate) struct DataTransferItemList {
26 reflector_: Reflector,
27 #[conditional_malloc_size_of]
28 #[no_trace]
29 data_store: Rc<RefCell<Option<DragDataStore>>>,
30 #[ignore_malloc_size_of = "mozjs"]
31 frozen_types: CachedFrozenArray,
32}
33
34impl DataTransferItemList {
35 fn new_inherited(data_store: Rc<RefCell<Option<DragDataStore>>>) -> DataTransferItemList {
36 DataTransferItemList {
37 reflector_: Reflector::new(),
38 frozen_types: CachedFrozenArray::new(),
39 data_store,
40 }
41 }
42
43 pub(crate) fn new(
44 cx: &mut JSContext,
45 window: &Window,
46 data_store: Rc<RefCell<Option<DragDataStore>>>,
47 ) -> DomRoot<DataTransferItemList> {
48 reflect_dom_object_with_cx(
49 Box::new(DataTransferItemList::new_inherited(data_store)),
50 window,
51 cx,
52 )
53 }
54
55 pub(crate) fn frozen_types(&self, cx: &mut js::context::JSContext, retval: MutableHandleValue) {
56 self.frozen_types.get_or_init(
57 cx,
58 || {
59 self.data_store
60 .borrow()
61 .as_ref()
62 .map_or(Vec::new(), |data_store| data_store.types())
63 },
64 retval,
65 );
66 }
67
68 pub(crate) fn invalidate_frozen_types(&self) {
69 self.frozen_types.clear();
70 }
71}
72
73impl DataTransferItemListMethods<crate::DomTypeHolder> for DataTransferItemList {
74 fn Length(&self) -> u32 {
76 self.data_store
79 .borrow()
80 .as_ref()
81 .map_or(0, |data_store| data_store.list_len() as u32)
82 }
83
84 fn IndexedGetter(
86 &self,
87 cx: &mut js::context::JSContext,
88 index: u32,
89 ) -> Option<DomRoot<DataTransferItem>> {
90 let option = self.data_store.borrow();
92 let data_store = match option.as_ref() {
93 Some(value) => value,
94 _ => return None,
95 };
96
97 data_store.get_by_index(index as usize).map(|(id, _)| {
99 DataTransferItem::new(cx, &self.global(), Rc::clone(&self.data_store), *id)
100 })
101 }
102
103 fn Add(
105 &self,
106 cx: &mut js::context::JSContext,
107 data: DOMString,
108 mut type_: DOMString,
109 ) -> Fallible<Option<DomRoot<DataTransferItem>>> {
110 let mut option = self.data_store.borrow_mut();
112 let data_store = match option.as_mut() {
113 Some(value) if value.mode() == Mode::ReadWrite => value,
114 _ => return Ok(None),
115 };
116
117 type_.make_ascii_lowercase();
121 data_store.add(Kind::Text { data, type_ }).map(|id| {
122 self.frozen_types.clear();
123
124 Some(DataTransferItem::new(
127 cx,
128 &self.global(),
129 Rc::clone(&self.data_store),
130 id,
131 ))
132 })
133 }
134
135 fn Add_(
137 &self,
138 cx: &mut js::context::JSContext,
139 data: &File,
140 ) -> Fallible<Option<DomRoot<DataTransferItem>>> {
141 let mut option = self.data_store.borrow_mut();
143 let data_store = match option.as_mut() {
144 Some(value) if value.mode() == Mode::ReadWrite => value,
145 _ => return Ok(None),
146 };
147
148 let mut type_ = data.file_type();
152 type_.make_ascii_lowercase();
153 let bytes = data.file_bytes().unwrap_or_default();
154 let name = data.name().clone();
155
156 data_store.add(Kind::File { bytes, name, type_ }).map(|id| {
157 self.frozen_types.clear();
158
159 Some(DataTransferItem::new(
162 cx,
163 &self.global(),
164 Rc::clone(&self.data_store),
165 id,
166 ))
167 })
168 }
169
170 fn Remove(&self, index: u32) -> Fallible<()> {
172 let mut option = self.data_store.borrow_mut();
175 let data_store = match option.as_mut() {
176 Some(value) if value.mode() == Mode::ReadWrite => value,
177 _ => return Err(Error::InvalidState(None)),
178 };
179
180 let index = index as usize;
181
182 if index < data_store.list_len() {
184 data_store.remove(index);
186 self.frozen_types.clear();
187 }
188
189 Ok(())
190 }
191
192 fn Clear(&self) {
194 let mut option = self.data_store.borrow_mut();
197 let data_store = match option.as_mut() {
198 Some(value) if value.mode() == Mode::ReadWrite => value,
199 _ => return,
200 };
201
202 if data_store.list_len() > 0 {
204 data_store.clear_list();
205 self.frozen_types.clear();
206 }
207 }
208}