wip: native file handles when dropping 🎉
This commit is contained in:
11 files changed
+134
-76
No files matched your search
@@ -9,7 +9,7 @@ use dioxus::prelude::*;
|
|||||||
use dioxus::{html::HasFileData, prelude::dioxus_elements::FileEngine};
|
use dioxus::{html::HasFileData, prelude::dioxus_elements::FileEngine};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
launch(app);
|
LaunchBuilder::desktop().launch(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app() -> Element {
|
fn app() -> Element {
|
||||||
@@ -51,7 +51,7 @@ fn app() -> Element {
|
|||||||
|
|
||||||
input {
|
input {
|
||||||
r#type: "file",
|
r#type: "file",
|
||||||
accept: ".txt,.rs",
|
accept: ".txt,.rs,.js",
|
||||||
multiple: true,
|
multiple: true,
|
||||||
name: "textreader",
|
name: "textreader",
|
||||||
directory: enable_directory_upload,
|
directory: enable_directory_upload,
|
||||||
@@ -64,10 +64,9 @@ fn app() -> Element {
|
|||||||
// cheating with a little bit of JS...
|
// cheating with a little bit of JS...
|
||||||
"ondragover": "this.style.backgroundColor='#88FF88';",
|
"ondragover": "this.style.backgroundColor='#88FF88';",
|
||||||
"ondragleave": "this.style.backgroundColor='#FFFFFF';",
|
"ondragleave": "this.style.backgroundColor='#FFFFFF';",
|
||||||
|
"ondrop": "this.style.backgroundColor='#FFFFFF';",
|
||||||
id: "drop-zone",
|
id: "drop-zone",
|
||||||
// prevent_default: "ondrop dragover dragenter",
|
|
||||||
ondrop: handle_file_drop,
|
ondrop: handle_file_drop,
|
||||||
ondragover: move |event| event.stop_propagation(),
|
|
||||||
"Drop files here"
|
"Drop files here"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -262,6 +262,8 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_file_drag(&mut self, msg: IpcMessage, window: WindowId) {}
|
||||||
|
|
||||||
pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
|
pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
|
||||||
let Ok(file_dialog) = serde_json::from_value::<FileDialogRequest>(msg.params()) else {
|
let Ok(file_dialog) = serde_json::from_value::<FileDialogRequest>(msg.params()) else {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -118,15 +118,6 @@ impl Config {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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(WindowId, FileDropEvent) -> bool + 'static,
|
|
||||||
) -> Self {
|
|
||||||
self.file_drop_handler = Some(Box::new(handler));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a custom protocol
|
/// Set a custom protocol
|
||||||
pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
|
pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
app::SharedContext,
|
app::SharedContext,
|
||||||
assets::AssetHandlerRegistry,
|
assets::AssetHandlerRegistry,
|
||||||
edits::EditQueue,
|
edits::EditQueue,
|
||||||
|
file_upload::NativeFileHover,
|
||||||
ipc::{EventData, UserWindowEvent},
|
ipc::{EventData, UserWindowEvent},
|
||||||
query::QueryEngine,
|
query::QueryEngine,
|
||||||
shortcut::{HotKey, ShortcutHandle, ShortcutRegistryError},
|
shortcut::{HotKey, ShortcutHandle, ShortcutRegistryError},
|
||||||
@@ -13,13 +14,17 @@ use dioxus_core::{
|
|||||||
VirtualDom,
|
VirtualDom,
|
||||||
};
|
};
|
||||||
use dioxus_interpreter_js::MutationState;
|
use dioxus_interpreter_js::MutationState;
|
||||||
use std::{cell::RefCell, rc::Rc, rc::Weak};
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
rc::{Rc, Weak},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
use tao::{
|
use tao::{
|
||||||
event::Event,
|
event::Event,
|
||||||
event_loop::EventLoopWindowTarget,
|
event_loop::EventLoopWindowTarget,
|
||||||
window::{Fullscreen as WryFullscreen, Window, WindowId},
|
window::{Fullscreen as WryFullscreen, Window, WindowId},
|
||||||
};
|
};
|
||||||
use wry::{RequestAsyncResponder, WebView};
|
use wry::{FileDropEvent, RequestAsyncResponder, WebView};
|
||||||
|
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
use tao::platform::ios::WindowExtIOS;
|
use tao::platform::ios::WindowExtIOS;
|
||||||
@@ -62,6 +67,7 @@ pub struct DesktopService {
|
|||||||
pub(crate) edit_queue: EditQueue,
|
pub(crate) edit_queue: EditQueue,
|
||||||
pub(crate) mutation_state: RefCell<MutationState>,
|
pub(crate) mutation_state: RefCell<MutationState>,
|
||||||
pub(crate) asset_handlers: AssetHandlerRegistry,
|
pub(crate) asset_handlers: AssetHandlerRegistry,
|
||||||
|
pub(crate) file_hover: NativeFileHover,
|
||||||
|
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
pub(crate) views: Rc<RefCell<Vec<*mut objc::runtime::Object>>>,
|
pub(crate) views: Rc<RefCell<Vec<*mut objc::runtime::Object>>>,
|
||||||
@@ -83,14 +89,16 @@ impl DesktopService {
|
|||||||
shared: Rc<SharedContext>,
|
shared: Rc<SharedContext>,
|
||||||
edit_queue: EditQueue,
|
edit_queue: EditQueue,
|
||||||
asset_handlers: AssetHandlerRegistry,
|
asset_handlers: AssetHandlerRegistry,
|
||||||
|
file_hover: NativeFileHover,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
window,
|
window,
|
||||||
webview,
|
webview,
|
||||||
shared,
|
shared,
|
||||||
edit_queue,
|
edit_queue,
|
||||||
mutation_state: Default::default(),
|
|
||||||
asset_handlers,
|
asset_handlers,
|
||||||
|
file_hover,
|
||||||
|
mutation_state: Default::default(),
|
||||||
query: Default::default(),
|
query: Default::default(),
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
views: Default::default(),
|
views: Default::default(),
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
use dioxus_html::{native_bind::NativeFileEngine, FileEngine, HasFileData, HasFormData};
|
use dioxus_html::{native_bind::NativeFileEngine, FileEngine, HasFileData, HasFormData};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{path::PathBuf, str::FromStr, sync::Arc};
|
use std::{cell::Cell, path::PathBuf, rc::Rc, str::FromStr, sync::Arc};
|
||||||
|
use wry::FileDropEvent;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub(crate) struct FileDialogRequest {
|
pub(crate) struct FileDialogRequest {
|
||||||
@@ -142,3 +143,13 @@ impl HasFormData for DesktopFileUploadForm {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct NativeFileHover {
|
||||||
|
event: Rc<Cell<Option<FileDropEvent>>>,
|
||||||
|
}
|
||||||
|
impl NativeFileHover {
|
||||||
|
pub fn set(&self, event: FileDropEvent) {
|
||||||
|
self.event.set(Some(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,7 @@ pub enum IpcMethod<'a> {
|
|||||||
Query,
|
Query,
|
||||||
BrowserOpen,
|
BrowserOpen,
|
||||||
Initialize,
|
Initialize,
|
||||||
|
FileDrag,
|
||||||
Other(&'a str),
|
Other(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ impl IpcMessage {
|
|||||||
match self.method.as_str() {
|
match self.method.as_str() {
|
||||||
// todo: this is a misspelling, needs to be fixed
|
// todo: this is a misspelling, needs to be fixed
|
||||||
"file_dialog" => IpcMethod::FileDialog,
|
"file_dialog" => IpcMethod::FileDialog,
|
||||||
|
"file_drag" => IpcMethod::FileDrag,
|
||||||
"user_event" => IpcMethod::UserEvent,
|
"user_event" => IpcMethod::UserEvent,
|
||||||
"query" => IpcMethod::Query,
|
"query" => IpcMethod::Query,
|
||||||
"browser_open" => IpcMethod::BrowserOpen,
|
"browser_open" => IpcMethod::BrowserOpen,
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Conf
|
|||||||
EventData::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
|
EventData::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
|
||||||
EventData::Ipc(msg) => match msg.method() {
|
EventData::Ipc(msg) => match msg.method() {
|
||||||
IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id),
|
IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id),
|
||||||
|
IpcMethod::FileDrag => app.handle_file_drag(msg, id),
|
||||||
IpcMethod::UserEvent => app.handle_user_event_msg(msg, id),
|
IpcMethod::UserEvent => app.handle_user_event_msg(msg, id),
|
||||||
IpcMethod::Query => app.handle_query_msg(msg, id),
|
IpcMethod::Query => app.handle_query_msg(msg, id),
|
||||||
IpcMethod::BrowserOpen => app.handle_browser_open(msg),
|
IpcMethod::BrowserOpen => app.handle_browser_open(msg),
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ use crate::{
|
|||||||
assets::AssetHandlerRegistry,
|
assets::AssetHandlerRegistry,
|
||||||
edits::EditQueue,
|
edits::EditQueue,
|
||||||
eval::DesktopEvalProvider,
|
eval::DesktopEvalProvider,
|
||||||
|
file_upload::NativeFileHover,
|
||||||
ipc::{EventData, UserWindowEvent},
|
ipc::{EventData, UserWindowEvent},
|
||||||
protocol::{self},
|
protocol,
|
||||||
waker::tao_waker,
|
waker::tao_waker,
|
||||||
Config, DesktopContext, DesktopService,
|
Config, DesktopContext, DesktopService,
|
||||||
};
|
};
|
||||||
@@ -65,7 +66,6 @@ impl WebviewInstance {
|
|||||||
|
|
||||||
// Rust :(
|
// Rust :(
|
||||||
let window_id = window.id();
|
let window_id = window.id();
|
||||||
let file_handler = cfg.file_drop_handler.take();
|
|
||||||
let custom_head = cfg.custom_head.clone();
|
let custom_head = cfg.custom_head.clone();
|
||||||
let index_file = cfg.custom_index.clone();
|
let index_file = cfg.custom_index.clone();
|
||||||
let root_name = cfg.root_name.clone();
|
let root_name = cfg.root_name.clone();
|
||||||
@@ -102,6 +102,8 @@ impl WebviewInstance {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let file_hover = NativeFileHover::default();
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
target_os = "windows",
|
target_os = "windows",
|
||||||
target_os = "macos",
|
target_os = "macos",
|
||||||
@@ -128,12 +130,18 @@ impl WebviewInstance {
|
|||||||
.with_url("dioxus://index.html/")
|
.with_url("dioxus://index.html/")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_ipc_handler(ipc_handler)
|
.with_ipc_handler(ipc_handler)
|
||||||
|
.with_navigation_handler(|var| var.contains("dioxus")) // prevent all navigations
|
||||||
.with_asynchronous_custom_protocol(String::from("dioxus"), request_handler)
|
.with_asynchronous_custom_protocol(String::from("dioxus"), request_handler)
|
||||||
.with_web_context(&mut web_context);
|
.with_web_context(&mut web_context)
|
||||||
|
.with_file_drop_handler({
|
||||||
if let Some(handler) = file_handler {
|
let file_hover = file_hover.clone();
|
||||||
webview = webview.with_file_drop_handler(move |evt| handler(window_id, evt))
|
move |evt| {
|
||||||
}
|
println!("file drop: {:?}", evt);
|
||||||
|
// Update the most recent file hover status
|
||||||
|
file_hover.set(evt);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(color) = cfg.background_color {
|
if let Some(color) = cfg.background_color {
|
||||||
webview = webview.with_background_color(color);
|
webview = webview.with_background_color(color);
|
||||||
@@ -178,6 +186,7 @@ impl WebviewInstance {
|
|||||||
shared.clone(),
|
shared.clone(),
|
||||||
edit_queue,
|
edit_queue,
|
||||||
asset_handlers,
|
asset_handlers,
|
||||||
|
file_hover,
|
||||||
));
|
));
|
||||||
|
|
||||||
let provider: Rc<dyn EvalProvider> =
|
let provider: Rc<dyn EvalProvider> =
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
12023679989252671232
|
2617078454438840343
|
||||||
@@ -248,6 +248,8 @@ class NativeInterpreter extends JSChannel_ {
|
|||||||
initialize(root) {
|
initialize(root) {
|
||||||
this.intercept_link_redirects = true;
|
this.intercept_link_redirects = true;
|
||||||
this.liveview = false;
|
this.liveview = false;
|
||||||
|
const dragEventHandler = (e) => {
|
||||||
|
};
|
||||||
window.addEventListener("dragover", function(e) {
|
window.addEventListener("dragover", function(e) {
|
||||||
if (e.target instanceof Element && e.target.tagName != "INPUT") {
|
if (e.target instanceof Element && e.target.tagName != "INPUT") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -349,25 +351,8 @@ class NativeInterpreter extends JSChannel_ {
|
|||||||
} else {
|
} else {
|
||||||
const message = this.serializeIpcMessage("user_event", body);
|
const message = this.serializeIpcMessage("user_event", body);
|
||||||
this.ipc.postMessage(message);
|
this.ipc.postMessage(message);
|
||||||
console.log("sent message to host: ", message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async readFiles(target, contents, bubbles, realId, name) {
|
|
||||||
let files = target.files;
|
|
||||||
let 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()));
|
|
||||||
}
|
|
||||||
contents.files = { files: file_contents };
|
|
||||||
const message = this.serializeIpcMessage("user_event", {
|
|
||||||
name,
|
|
||||||
element: realId,
|
|
||||||
data: contents,
|
|
||||||
bubbles
|
|
||||||
});
|
|
||||||
this.ipc.postMessage(message);
|
|
||||||
}
|
|
||||||
preventDefaults(event, target) {
|
preventDefaults(event, target) {
|
||||||
let preventDefaultRequests = null;
|
let preventDefaultRequests = null;
|
||||||
if (target instanceof Element) {
|
if (target instanceof Element) {
|
||||||
@@ -415,6 +400,22 @@ class NativeInterpreter extends JSChannel_ {
|
|||||||
this.waitForRequest(headless);
|
this.waitForRequest(headless);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async readFiles(target, contents, bubbles, realId, name) {
|
||||||
|
let files = target.files;
|
||||||
|
let 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()));
|
||||||
|
}
|
||||||
|
contents.files = { files: file_contents };
|
||||||
|
const message = this.serializeIpcMessage("user_event", {
|
||||||
|
name,
|
||||||
|
element: realId,
|
||||||
|
data: contents,
|
||||||
|
bubbles
|
||||||
|
});
|
||||||
|
this.ipc.postMessage(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export {
|
export {
|
||||||
NativeInterpreter
|
NativeInterpreter
|
||||||
|
|||||||
@@ -29,10 +29,50 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initialize(root: HTMLElement): void {
|
initialize(root: HTMLElement): void {
|
||||||
|
|
||||||
this.intercept_link_redirects = true;
|
this.intercept_link_redirects = true;
|
||||||
this.liveview = false;
|
this.liveview = false;
|
||||||
|
|
||||||
|
|
||||||
|
const dragEventHandler = (e: DragEvent) => {
|
||||||
|
// e.preventDefault();
|
||||||
|
// e.dataTransfer.effectAllowed = 'none';
|
||||||
|
// e.dataTransfer.dropEffect = 'none';
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// we need to signal to the host to provide a native file path,
|
||||||
|
// not the one coming from here
|
||||||
|
|
||||||
|
// We can't get native
|
||||||
|
// if (e.type === "drop") {
|
||||||
|
// let target = e.target;
|
||||||
|
|
||||||
|
// if (target instanceof Element) {
|
||||||
|
// let target_id = getTargetId(target);
|
||||||
|
// if (target_id !== null) {
|
||||||
|
// const message = this.serializeIpcMessage("file_drop", {
|
||||||
|
// event: "drop",
|
||||||
|
// target: target_id,
|
||||||
|
// data: Array.from(e.dataTransfer.files).map(file => {
|
||||||
|
// return {
|
||||||
|
// name: file.name,
|
||||||
|
// type: file.type,
|
||||||
|
// size: file.size,
|
||||||
|
// };
|
||||||
|
// }),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// this.ipc.postMessage(message);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ["dragenter", "dragover", "drop"].forEach((event) => {
|
||||||
|
// window.addEventListener(event, dragEventHandler, false)
|
||||||
|
// });
|
||||||
|
|
||||||
// attach an event listener on the body that prevents file drops from navigating
|
// attach an event listener on the body that prevents file drops from navigating
|
||||||
// this is because the browser will try to navigate to the file if it's dropped on the window
|
// this is because the browser will try to navigate to the file if it's dropped on the window
|
||||||
window.addEventListener("dragover", function (e) {
|
window.addEventListener("dragover", function (e) {
|
||||||
@@ -51,9 +91,6 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
|
|
||||||
// Dropping a file on the window will navigate to the file, which we don't want
|
// Dropping a file on the window will navigate to the file, which we don't want
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// if the element has a drop listener on it, we should send a message to the host with the contents of the drop instead
|
|
||||||
|
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
// attach a listener to the route that listens for clicks and prevents the default file dialog
|
// attach a listener to the route that listens for clicks and prevents the default file dialog
|
||||||
@@ -123,7 +160,7 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore the fact the base interpreter uses ptr + len but we use array
|
// ignore the fact the base interpreter uses ptr + len but we use array...
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
loadChild(array: number[]) {
|
loadChild(array: number[]) {
|
||||||
// iterate through each number and get that child
|
// iterate through each number and get that child
|
||||||
@@ -168,9 +205,6 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
// Liveview will still need to use this
|
// Liveview will still need to use this
|
||||||
this.preventDefaults(event, target);
|
this.preventDefaults(event, target);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// liveview does not have syncronous event handling, so we need to send the event to the host
|
// liveview does not have syncronous event handling, so we need to send the event to the host
|
||||||
if (this.liveview) {
|
if (this.liveview) {
|
||||||
// Okay, so the user might've requested some files to be read
|
// Okay, so the user might've requested some files to be read
|
||||||
@@ -184,8 +218,6 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
const message = this.serializeIpcMessage("user_event", body);
|
const message = this.serializeIpcMessage("user_event", body);
|
||||||
this.ipc.postMessage(message);
|
this.ipc.postMessage(message);
|
||||||
|
|
||||||
console.log("sent message to host: ", message);
|
|
||||||
|
|
||||||
// // Run the event handler on the virtualdom
|
// // Run the event handler on the virtualdom
|
||||||
// // capture/prevent default of the event if the virtualdom wants to
|
// // capture/prevent default of the event if the virtualdom wants to
|
||||||
// const res = handleVirtualdomEventSync(JSON.stringify(body));
|
// const res = handleVirtualdomEventSync(JSON.stringify(body));
|
||||||
@@ -200,30 +232,6 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A liveview only function
|
|
||||||
// Desktop will intercept the event before it hits this
|
|
||||||
async readFiles(target: HTMLInputElement, contents: SerializedEvent, bubbles: boolean, realId: NodeId, name: string) {
|
|
||||||
let files = target.files!;
|
|
||||||
let file_contents: { [name: string]: number[] } = {};
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
const file = files[i];
|
|
||||||
file_contents[file.name] = Array.from(
|
|
||||||
new Uint8Array(await file.arrayBuffer())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
contents.files = { files: file_contents };
|
|
||||||
|
|
||||||
const message = this.serializeIpcMessage("user_event", {
|
|
||||||
name: name,
|
|
||||||
element: realId,
|
|
||||||
data: contents,
|
|
||||||
bubbles,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ipc.postMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This should:
|
// This should:
|
||||||
@@ -308,6 +316,32 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
this.waitForRequest(headless);
|
this.waitForRequest(headless);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A liveview only function
|
||||||
|
// Desktop will intercept the event before it hits this
|
||||||
|
async readFiles(target: HTMLInputElement, contents: SerializedEvent, bubbles: boolean, realId: NodeId, name: string) {
|
||||||
|
let files = target.files!;
|
||||||
|
let file_contents: { [name: string]: number[] } = {};
|
||||||
|
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
const file = files[i];
|
||||||
|
file_contents[file.name] = Array.from(
|
||||||
|
new Uint8Array(await file.arrayBuffer())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
contents.files = { files: file_contents };
|
||||||
|
|
||||||
|
const message = this.serializeIpcMessage("user_event", {
|
||||||
|
name: name,
|
||||||
|
element: realId,
|
||||||
|
data: contents,
|
||||||
|
bubbles,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ipc.postMessage(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventSyncResult = {
|
type EventSyncResult = {
|
||||||
|
|||||||
Reference in new issue
Block a user