mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
148 lines
5.3 KiB
Rust
148 lines
5.3 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
use std::cell::{Cell, Ref, RefCell};
|
|
use std::rc::Rc;
|
|
|
|
use dom_struct::dom_struct;
|
|
|
|
use crate::dom::bindings::callback::ExceptionHandling;
|
|
use crate::dom::bindings::cell::DomRefCell;
|
|
use crate::dom::bindings::codegen::Bindings::DataTransferItemBinding::{
|
|
DataTransferItemMethods, FunctionStringCallback,
|
|
};
|
|
use crate::dom::bindings::refcounted::Trusted;
|
|
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
|
use crate::dom::bindings::root::DomRoot;
|
|
use crate::dom::bindings::str::DOMString;
|
|
use crate::dom::file::File;
|
|
use crate::dom::globalscope::GlobalScope;
|
|
use crate::drag_data_store::{DragDataStore, Kind, Mode};
|
|
use crate::script_runtime::CanGc;
|
|
|
|
#[dom_struct]
|
|
pub(crate) struct DataTransferItem {
|
|
reflector_: Reflector,
|
|
#[ignore_malloc_size_of = "Rc"]
|
|
#[no_trace]
|
|
data_store: Rc<RefCell<Option<DragDataStore>>>,
|
|
id: u16,
|
|
pending_callbacks: DomRefCell<Vec<PendingStringCallback>>,
|
|
next_callback: Cell<usize>,
|
|
}
|
|
|
|
#[derive(JSTraceable, MallocSizeOf)]
|
|
struct PendingStringCallback {
|
|
id: usize,
|
|
#[ignore_malloc_size_of = "Rc"]
|
|
callback: Rc<FunctionStringCallback>,
|
|
}
|
|
|
|
impl DataTransferItem {
|
|
fn new_inherited(data_store: Rc<RefCell<Option<DragDataStore>>>, id: u16) -> DataTransferItem {
|
|
DataTransferItem {
|
|
reflector_: Reflector::new(),
|
|
data_store,
|
|
id,
|
|
pending_callbacks: Default::default(),
|
|
next_callback: Cell::new(0),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn new(
|
|
global: &GlobalScope,
|
|
data_store: Rc<RefCell<Option<DragDataStore>>>,
|
|
id: u16,
|
|
can_gc: CanGc,
|
|
) -> DomRoot<DataTransferItem> {
|
|
reflect_dom_object(
|
|
Box::new(DataTransferItem::new_inherited(data_store, id)),
|
|
global,
|
|
can_gc,
|
|
)
|
|
}
|
|
|
|
fn item_kind(&self) -> Option<Ref<Kind>> {
|
|
Ref::filter_map(self.data_store.borrow(), |data_store| {
|
|
data_store
|
|
.as_ref()
|
|
.and_then(|data_store| data_store.get_by_id(&self.id))
|
|
})
|
|
.ok()
|
|
}
|
|
|
|
fn can_read(&self) -> bool {
|
|
self.data_store
|
|
.borrow()
|
|
.as_ref()
|
|
.is_some_and(|data_store| data_store.mode() != Mode::Protected)
|
|
}
|
|
}
|
|
|
|
impl DataTransferItemMethods<crate::DomTypeHolder> for DataTransferItem {
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-datatransferitem-kind>
|
|
fn Kind(&self) -> DOMString {
|
|
self.item_kind()
|
|
.map_or(DOMString::new(), |item| match *item {
|
|
Kind::Text { .. } => DOMString::from("string"),
|
|
Kind::File { .. } => DOMString::from("file"),
|
|
})
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-datatransferitem-type>
|
|
fn Type(&self) -> DOMString {
|
|
self.item_kind()
|
|
.map_or(DOMString::new(), |item| item.type_())
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-datatransferitem-getasstring>
|
|
fn GetAsString(&self, callback: Option<Rc<FunctionStringCallback>>) {
|
|
// Step 1 If the callback is null, return.
|
|
let Some(callback) = callback else {
|
|
return;
|
|
};
|
|
|
|
// Step 2 If the DataTransferItem object is not in the read/write mode or the read-only mode, return.
|
|
if !self.can_read() {
|
|
return;
|
|
}
|
|
|
|
// Step 3 If the drag data item kind is not text, then return.
|
|
if let Some(string) = self.item_kind().and_then(|item| item.as_string()) {
|
|
let id = self.next_callback.get();
|
|
let pending_callback = PendingStringCallback { id, callback };
|
|
self.pending_callbacks.borrow_mut().push(pending_callback);
|
|
|
|
self.next_callback.set(id + 1);
|
|
let this = Trusted::new(self);
|
|
|
|
// Step 4 Otherwise, queue a task to invoke callback,
|
|
// passing the actual data of the item represented by the DataTransferItem object as the argument.
|
|
self.global()
|
|
.task_manager()
|
|
.dom_manipulation_task_source()
|
|
.queue(task!(invoke_callback: move || {
|
|
let maybe_index = this.root().pending_callbacks.borrow().iter().position(|val| val.id == id);
|
|
if let Some(index) = maybe_index {
|
|
let callback = this.root().pending_callbacks.borrow_mut().swap_remove(index).callback;
|
|
let _ = callback.Call__(DOMString::from(string), ExceptionHandling::Report, CanGc::note());
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
|
|
/// <https://html.spec.whatwg.org/multipage/#dom-datatransferitem-getasfile>
|
|
fn GetAsFile(&self, can_gc: CanGc) -> Option<DomRoot<File>> {
|
|
// Step 1 If the DataTransferItem object is not in the read/write mode or the read-only mode, then return null.
|
|
if !self.can_read() {
|
|
return None;
|
|
}
|
|
|
|
// Step 2 If the drag data item kind is not File, then return null.
|
|
// Step 3 Return a new File object representing the actual data
|
|
// of the item represented by the DataTransferItem object.
|
|
self.item_kind()
|
|
.and_then(|item| item.as_file(&self.global(), can_gc))
|
|
}
|
|
}
|