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:
1 parent
8b62b71e2d
commit
cab573eefd
54 files changed
+940
-729
No files matched your search
+63
-14
@@ -1,10 +1,6 @@
|
||||
use crate::{global_context::current_scope_id, properties::SuperFrom, Runtime, ScopeId};
|
||||
use generational_box::GenerationalBox;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{cell::RefCell, marker::PhantomData, rc::Rc};
|
||||
|
||||
/// A wrapper around some generic data that handles the event's state
|
||||
///
|
||||
@@ -26,19 +22,29 @@ use std::{
|
||||
pub struct Event<T: 'static + ?Sized> {
|
||||
/// The data associated with this event
|
||||
pub data: Rc<T>,
|
||||
pub(crate) propagates: Rc<Cell<bool>>,
|
||||
pub(crate) metadata: Rc<RefCell<EventMetadata>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct EventMetadata {
|
||||
pub(crate) propagates: bool,
|
||||
pub(crate) prevent_default: bool,
|
||||
}
|
||||
|
||||
impl<T: ?Sized + 'static> Event<T> {
|
||||
pub(crate) fn new(data: Rc<T>, bubbles: bool) -> Self {
|
||||
/// Create a new event from the inner data
|
||||
pub fn new(data: Rc<T>, propagates: bool) -> Self {
|
||||
Self {
|
||||
data,
|
||||
propagates: Rc::new(Cell::new(bubbles)),
|
||||
metadata: Rc::new(RefCell::new(EventMetadata {
|
||||
propagates,
|
||||
prevent_default: false,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Event<T> {
|
||||
impl<T: ?Sized> Event<T> {
|
||||
/// Map the event data to a new type
|
||||
///
|
||||
/// # Example
|
||||
@@ -57,7 +63,7 @@ impl<T> Event<T> {
|
||||
pub fn map<U: 'static, F: FnOnce(&T) -> U>(&self, f: F) -> Event<U> {
|
||||
Event {
|
||||
data: Rc::new(f(&self.data)),
|
||||
propagates: self.propagates.clone(),
|
||||
metadata: self.metadata.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +84,12 @@ impl<T> Event<T> {
|
||||
/// ```
|
||||
#[deprecated = "use stop_propagation instead"]
|
||||
pub fn cancel_bubble(&self) {
|
||||
self.propagates.set(false);
|
||||
self.metadata.borrow_mut().propagates = false;
|
||||
}
|
||||
|
||||
/// Check if the event propagates up the tree to parent elements
|
||||
pub fn propagates(&self) -> bool {
|
||||
self.metadata.borrow().propagates
|
||||
}
|
||||
|
||||
/// Prevent this event from continuing to bubble up the tree to parent elements.
|
||||
@@ -96,7 +107,7 @@ impl<T> Event<T> {
|
||||
/// };
|
||||
/// ```
|
||||
pub fn stop_propagation(&self) {
|
||||
self.propagates.set(false);
|
||||
self.metadata.borrow_mut().propagates = false;
|
||||
}
|
||||
|
||||
/// Get a reference to the inner data from this event
|
||||
@@ -117,12 +128,49 @@ impl<T> Event<T> {
|
||||
pub fn data(&self) -> Rc<T> {
|
||||
self.data.clone()
|
||||
}
|
||||
|
||||
/// Prevent the default action of the event.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// fn App() -> Element {
|
||||
/// rsx! {
|
||||
/// a {
|
||||
/// // You can prevent the default action of the event with `prevent_default`
|
||||
/// onclick: move |event| {
|
||||
/// event.prevent_default();
|
||||
/// },
|
||||
/// href: "https://dioxuslabs.com",
|
||||
/// "don't go to the link"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note: This must be called synchronously when handling the event. Calling it after the event has been handled will have no effect.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// This method is not available on the LiveView renderer because LiveView handles all events over a websocket which cannot block.
|
||||
///
|
||||
/// </div>
|
||||
#[track_caller]
|
||||
pub fn prevent_default(&self) {
|
||||
self.metadata.borrow_mut().prevent_default = true;
|
||||
}
|
||||
|
||||
/// Check if the default action of the event is enabled.
|
||||
pub fn default_action_enabled(&self) -> bool {
|
||||
!self.metadata.borrow().prevent_default
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Clone for Event<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
propagates: self.propagates.clone(),
|
||||
metadata: self.metadata.clone(),
|
||||
data: self.data.clone(),
|
||||
}
|
||||
}
|
||||
@@ -138,7 +186,8 @@ impl<T> std::ops::Deref for Event<T> {
|
||||
impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("UiEvent")
|
||||
.field("bubble_state", &self.propagates)
|
||||
.field("bubble_state", &self.propagates())
|
||||
.field("prevent_default", &!self.default_action_enabled())
|
||||
.field("data", &self.data)
|
||||
.finish()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user