Synchronous prevent default (#2792)

* add prevent default methods to the event

* sync prevent default almost working

* sync prevent default working

* Move event handling into the runtime

* update core tests

* restore desktop file dialog

* implement prevent default on web

* add a hint about the new prevent default method

* fix web prevent default

* Fix CTRL+click on links

* fix values memorize in place test

* Fix a few more tests

* Add a playwright test for sync prevent default

* Fix core doc tests

* create a deprecated VirtualDom::handle_event

* fix macos imports in desktop

* Fix onmounted event

* Fix liveview support

* switch to RefCell for metadata

* Remove println

* remove prevent default attribute

* remove web specific link behavior

* Fix liveview links

* more liveview fixes for link

* Fix merge conflicts

* Fix clippy

* use the new prevent default in the file upload example
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-08-13 11:57:54 -07:00
1 parent 8b62b71e2d
commit cab573eefd
54 files changed
+940 -729

No files matched your search

+39 -35
View File
@@ -1,64 +1,68 @@
use std::cell::Cell;
use std::{cell::RefCell, collections::VecDeque, rc::Rc, task::Waker};
use dioxus_interpreter_js::MutationState;
/// This handles communication between the requests that the webview makes and the interpreter. The interpreter constantly makes long running requests to the webview to get any edits that should be made to the DOM almost like server side events.
/// It will hold onto the requests until the interpreter is ready to handle them and hold onto any pending edits until a new request is made.
#[derive(Default, Clone)]
pub(crate) struct EditQueue {
queue: Rc<RefCell<VecDeque<Vec<u8>>>>,
responder: Rc<RefCell<Option<wry::RequestAsyncResponder>>>,
// Stores any futures waiting for edits to be applied to the webview
// NOTE: We don't use a Notify here because we need polling the notify to be cancel safe
waiting_for_edits_flushed: Rc<RefCell<Vec<Waker>>>,
// If this webview is currently waiting for an edit to be flushed. We don't run the virtual dom while this is true to avoid running effects before the dom has been updated
edits_in_progress: Rc<Cell<bool>>,
pub(crate) struct WryQueue {
inner: Rc<RefCell<WryQueueInner>>,
}
impl EditQueue {
#[derive(Default)]
pub(crate) struct WryQueueInner {
edit_queue: VecDeque<Vec<u8>>,
edit_responder: Option<wry::RequestAsyncResponder>,
// Stores any futures waiting for edits to be applied to the webview
// NOTE: We don't use a Notify here because we need polling the notify to be cancel safe
waiting_for_edits_flushed: Vec<Waker>,
// If this webview is currently waiting for an edit to be flushed. We don't run the virtual dom while this is true to avoid running effects before the dom has been updated
edits_in_progress: bool,
mutation_state: MutationState,
}
impl WryQueue {
pub fn handle_request(&self, responder: wry::RequestAsyncResponder) {
let mut queue = self.queue.borrow_mut();
if let Some(bytes) = queue.pop_back() {
let mut myself = self.inner.borrow_mut();
if let Some(bytes) = myself.edit_queue.pop_back() {
responder.respond(wry::http::Response::new(bytes));
} else {
// There are now no edits that need to be applied to the webview
self.edits_finished();
*self.responder.borrow_mut() = Some(responder);
for waker in myself.waiting_for_edits_flushed.drain(..) {
waker.wake();
}
myself.edits_in_progress = false;
myself.edit_responder = Some(responder);
}
}
pub fn add_edits(&self, edits: Vec<u8>) {
let mut responder = self.responder.borrow_mut();
pub fn mutation_state_mut(&self) -> std::cell::RefMut<'_, MutationState> {
std::cell::RefMut::map(self.inner.borrow_mut(), |myself| &mut myself.mutation_state)
}
/// Send a list of mutations to the webview
pub(crate) fn send_edits(&self) {
let mut myself = self.inner.borrow_mut();
let serialized_edits = myself.mutation_state.export_memory();
// There are pending edits that need to be applied to the webview before we run futures
self.start_edits();
if let Some(responder) = responder.take() {
responder.respond(wry::http::Response::new(edits));
myself.edits_in_progress = true;
if let Some(responder) = myself.edit_responder.take() {
responder.respond(wry::http::Response::new(serialized_edits));
} else {
self.queue.borrow_mut().push_front(edits);
myself.edit_queue.push_front(serialized_edits);
}
}
fn start_edits(&self) {
self.edits_in_progress.set(true);
}
fn edits_finished(&self) {
for waker in self.waiting_for_edits_flushed.borrow_mut().drain(..) {
waker.wake();
}
self.edits_in_progress.set(false);
}
fn edits_in_progress(&self) -> bool {
self.edits_in_progress.get()
self.inner.borrow().edits_in_progress
}
/// Wait until all pending edits have been rendered in the webview
pub fn poll_edits_flushed(&self, cx: &mut std::task::Context<'_>) -> std::task::Poll<()> {
if self.edits_in_progress() {
let mut myself = self.inner.borrow_mut();
let waker = cx.waker();
self.waiting_for_edits_flushed
.borrow_mut()
.push(waker.clone());
myself.waiting_for_edits_flushed.push(waker.clone());
std::task::Poll::Pending
} else {
std::task::Poll::Ready(())