mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
add file property to drag data
This commit is contained in:
parent
c904411190
commit
ada246c12e
11 changed files with 133 additions and 77 deletions
|
@ -2,10 +2,10 @@
|
|||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus_desktop::launch(App);
|
||||
dioxus_desktop::launch(app);
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
fn app(cx: Scope) -> Element {
|
||||
let files_uploaded: &UseRef<Vec<String>> = use_ref(cx, Vec::new);
|
||||
|
||||
cx.render(rsx! {
|
||||
|
@ -27,6 +27,29 @@ fn App(cx: Scope) -> Element {
|
|||
}
|
||||
},
|
||||
}
|
||||
div {
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
border: "1px solid black",
|
||||
prevent_default: "ondrop dragover dragenter",
|
||||
ondrop: move |evt| {
|
||||
to_owned![files_uploaded];
|
||||
async move {
|
||||
if let Some(file_engine) = &evt.files {
|
||||
let files = file_engine.files();
|
||||
for file_name in &files {
|
||||
if let Some(file) = file_engine.read_file_to_string(file_name).await{
|
||||
files_uploaded.write().push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ondragover: move |event: DragEvent| {
|
||||
event.stop_propagation();
|
||||
},
|
||||
"Drop files here"
|
||||
}
|
||||
|
||||
ul {
|
||||
for file in files_uploaded.read().iter() {
|
||||
|
|
|
@ -87,7 +87,7 @@ impl Config {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set a file drop handler
|
||||
/// Set a file drop handler. If this is enabled, html drag events will be disabled.
|
||||
pub fn with_file_drop_handler(
|
||||
mut self,
|
||||
handler: impl Fn(&Window, FileDropEvent) -> bool + 'static,
|
||||
|
|
|
@ -49,14 +49,12 @@ pub fn build(
|
|||
.with_custom_protocol(String::from("dioxus"), move |r| {
|
||||
protocol::desktop_handler(r, custom_head.clone(), index_file.clone(), &root_name)
|
||||
})
|
||||
.with_file_drop_handler(move |window, evet| {
|
||||
file_handler
|
||||
.as_ref()
|
||||
.map(|handler| handler(window, evet))
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.with_web_context(&mut web_context);
|
||||
|
||||
if let Some(handler) = file_handler {
|
||||
webview = webview.with_file_drop_handler(handler)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// Windows has a platform specific settings to disable the browser shortcut keys
|
||||
|
|
|
@ -41,6 +41,7 @@ features = [
|
|||
"FocusEvent",
|
||||
"CompositionEvent",
|
||||
"ClipboardEvent",
|
||||
"DragEvent"
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use dioxus_core::Event;
|
||||
|
||||
use crate::FileEngine;
|
||||
use crate::MouseData;
|
||||
|
||||
use dioxus_core::Event;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub type DragEvent = Event<DragData>;
|
||||
|
||||
/// The DragEvent interface is a DOM event that represents a drag and drop interaction. The user initiates a drag by
|
||||
|
@ -9,12 +11,38 @@ pub type DragEvent = Event<DragData>;
|
|||
/// (such as another DOM element). Applications are free to interpret a drag and drop interaction in an
|
||||
/// application-specific way.
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Clone)]
|
||||
pub struct DragData {
|
||||
/// Inherit mouse data
|
||||
pub mouse: MouseData,
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
serde(
|
||||
default,
|
||||
skip_serializing,
|
||||
deserialize_with = "crate::events::deserialize_file_engine"
|
||||
)
|
||||
)]
|
||||
pub files: Option<std::sync::Arc<dyn FileEngine>>,
|
||||
}
|
||||
|
||||
impl Debug for DragData {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DragData")
|
||||
.field("mouse", &self.mouse)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for DragData {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.mouse == other.mouse
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for DragData {}
|
||||
|
||||
impl_event! {
|
||||
DragData;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ impl FileEngine for SerializedFileEngine {
|
|||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
fn deserialize_file_engine<'de, D>(
|
||||
pub(crate) fn deserialize_file_engine<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<std::sync::Arc<dyn FileEngine>>, D::Error>
|
||||
where
|
||||
|
|
|
@ -123,6 +123,7 @@ impl From<&MouseEvent> for DragData {
|
|||
fn from(value: &MouseEvent) -> Self {
|
||||
Self {
|
||||
mouse: MouseData::from(value),
|
||||
files: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,7 +351,11 @@ class Interpreter {
|
|||
let handler = (event) => {
|
||||
let target = event.target;
|
||||
if (target != null) {
|
||||
let realId = target.getAttribute(`data-dioxus-id`);
|
||||
const realId = find_real_id(target);
|
||||
if (realId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let shouldPreventDefault = target.getAttribute(
|
||||
`dioxus-prevent-default`
|
||||
);
|
||||
|
@ -379,22 +383,6 @@ class Interpreter {
|
|||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
// walk the tree to find the real element
|
||||
while (realId == null) {
|
||||
// we've reached the root we don't want to send an event
|
||||
if (target.parentElement === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
target = target.parentElement;
|
||||
realId = target.getAttribute(`data-dioxus-id`);
|
||||
}
|
||||
|
||||
shouldPreventDefault = target.getAttribute(
|
||||
`dioxus-prevent-default`
|
||||
);
|
||||
|
||||
let contents = serialize_event(event);
|
||||
|
||||
if (shouldPreventDefault === `on${event.type}`) {
|
||||
event.preventDefault();
|
||||
|
@ -404,41 +392,42 @@ class Interpreter {
|
|||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (
|
||||
target.tagName === "FORM" &&
|
||||
(event.type === "submit" || event.type === "input")
|
||||
) {
|
||||
for (let x = 0; x < target.elements.length; x++) {
|
||||
let element = target.elements[x];
|
||||
let name = element.getAttribute("name");
|
||||
if (name != null) {
|
||||
if (element.getAttribute("type") === "checkbox") {
|
||||
// @ts-ignore
|
||||
contents.values[name] = element.checked ? "true" : "false";
|
||||
} else if (element.getAttribute("type") === "radio") {
|
||||
if (element.checked) {
|
||||
contents.values[name] = element.value;
|
||||
serialize_event(event).then((contents) => {
|
||||
if (
|
||||
target.tagName === "FORM" &&
|
||||
(event.type === "submit" || event.type === "input")
|
||||
) {
|
||||
for (let x = 0; x < target.elements.length; x++) {
|
||||
let element = target.elements[x];
|
||||
let name = element.getAttribute("name");
|
||||
if (name != null) {
|
||||
if (element.getAttribute("type") === "checkbox") {
|
||||
// @ts-ignore
|
||||
contents.values[name] = element.checked
|
||||
? "true"
|
||||
: "false";
|
||||
} else if (element.getAttribute("type") === "radio") {
|
||||
if (element.checked) {
|
||||
contents.values[name] = element.value;
|
||||
}
|
||||
} else {
|
||||
// @ts-ignore
|
||||
contents.values[name] =
|
||||
element.value ?? element.textContent;
|
||||
}
|
||||
} else {
|
||||
// @ts-ignore
|
||||
contents.values[name] =
|
||||
element.value ?? element.textContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (realId === null) {
|
||||
return;
|
||||
}
|
||||
window.ipc.postMessage(
|
||||
serializeIpcMessage("user_event", {
|
||||
name: edit.name,
|
||||
element: parseInt(realId),
|
||||
data: contents,
|
||||
bubbles,
|
||||
})
|
||||
);
|
||||
window.ipc.postMessage(
|
||||
serializeIpcMessage("user_event", {
|
||||
name: edit.name,
|
||||
element: parseInt(realId),
|
||||
data: contents,
|
||||
bubbles,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
this.NewEventListener(edit.name, edit.id, bubbles, handler);
|
||||
|
@ -575,7 +564,7 @@ function get_mouse_data(event) {
|
|||
};
|
||||
}
|
||||
|
||||
function serialize_event(event) {
|
||||
async function serialize_event(event) {
|
||||
switch (event.type) {
|
||||
case "copy":
|
||||
case "cut":
|
||||
|
@ -661,7 +650,11 @@ function serialize_event(event) {
|
|||
case "dragover":
|
||||
case "dragstart":
|
||||
case "drop": {
|
||||
return { mouse: get_mouse_data(event) };
|
||||
let files = null;
|
||||
if (event.dataTransfer && event.dataTransfer.files) {
|
||||
files = await serializeFileList(event.dataTransfer.files);
|
||||
}
|
||||
return { mouse: get_mouse_data(event), files };
|
||||
}
|
||||
case "click":
|
||||
case "contextmenu":
|
||||
|
@ -816,6 +809,20 @@ function serialize_event(event) {
|
|||
}
|
||||
}
|
||||
}
|
||||
async function serializeFileList(fileList) {
|
||||
const file_contents = {};
|
||||
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
const file = fileList[i];
|
||||
|
||||
file_contents[file.name] = Array.from(
|
||||
new Uint8Array(await file.arrayBuffer())
|
||||
);
|
||||
}
|
||||
return {
|
||||
files: file_contents,
|
||||
};
|
||||
}
|
||||
function serializeIpcMessage(method, params = {}) {
|
||||
return JSON.stringify({ method, params });
|
||||
}
|
||||
|
|
|
@ -45,19 +45,7 @@ static INTERPRETER_JS: Lazy<String> = Lazy::new(|| {
|
|||
const type = target.getAttribute("type");
|
||||
if (type === "file") {
|
||||
async function read_files() {
|
||||
const files = target.files;
|
||||
const file_contents = {};
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
|
||||
file_contents[file.name] = Array.from(
|
||||
new Uint8Array(await file.arrayBuffer())
|
||||
);
|
||||
}
|
||||
let file_engine = {
|
||||
files: file_contents,
|
||||
};
|
||||
const file_engine=await serializeFileList( target.files);
|
||||
contents.files = file_engine;
|
||||
|
||||
if (realId === null) {
|
||||
|
|
|
@ -79,7 +79,8 @@ features = [
|
|||
"console",
|
||||
"FileList",
|
||||
"File",
|
||||
"FileReader"
|
||||
"FileReader",
|
||||
"DataTransfer"
|
||||
]
|
||||
|
||||
[features]
|
||||
|
|
|
@ -244,8 +244,17 @@ pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -
|
|||
}
|
||||
"drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart"
|
||||
| "drop" => {
|
||||
let mut files = None;
|
||||
if let Some(event) = event.dyn_ref::<web_sys::DragEvent>() {
|
||||
if let Some(data) = event.data_transfer() {
|
||||
if let Some(file_list) = data.files() {
|
||||
files = WebFileEngine::new(file_list)
|
||||
.map(|f| Arc::new(f) as Arc<dyn FileEngine>);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mouse = MouseData::from(event);
|
||||
Rc::new(DragData { mouse })
|
||||
Rc::new(DragData { mouse, files })
|
||||
}
|
||||
|
||||
"pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
|
||||
|
|
Loading…
Reference in a new issue