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

@@ -51,7 +51,7 @@ pub struct HistoryButtonProps {
/// # vdom.rebuild_in_place();
/// # assert_eq!(
/// # dioxus_ssr::render(&vdom),
/// # r#"<button disabled="true" dioxus-prevent-default="onclick">go back</button>"#
/// # r#"<button disabled="true">go back</button>"#
/// # );
/// ```
pub fn GoBackButton(props: HistoryButtonProps) -> Element {
@@ -75,8 +75,10 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
rsx! {
button {
disabled: "{disabled}",
prevent_default: "onclick",
onclick: move |_| router.go_back(),
onclick: move |evt| {
evt.prevent_default();
router.go_back()
},
{children}
}
}
@@ -122,7 +124,7 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
/// # vdom.rebuild_in_place();
/// # assert_eq!(
/// # dioxus_ssr::render(&vdom),
/// # r#"<button disabled="true" dioxus-prevent-default="onclick">go forward</button>"#
/// # r#"<button disabled="true">go forward</button>"#
/// # );
/// ```
pub fn GoForwardButton(props: HistoryButtonProps) -> Element {
@@ -146,8 +148,10 @@ pub fn GoForwardButton(props: HistoryButtonProps) -> Element {
rsx! {
button {
disabled: "{disabled}",
prevent_default: "onclick",
onclick: move |_| router.go_forward(),
onclick: move |evt| {
evt.prevent_default();
router.go_forward()
},
{children}
}
}
+24 -4
View File
@@ -195,7 +195,7 @@ impl Debug for LinkProps {
/// # vdom.rebuild_in_place();
/// # assert_eq!(
/// # dioxus_ssr::render(&vdom),
/// # r#"<a href="/" dioxus-prevent-default="" class="link_class active" rel="link_rel" target="_blank" aria-current="page" id="link_id">A fully configured link</a>"#
/// # r#"<a href="/" class="link_class active" rel="link_rel" target="_blank" aria-current="page" id="link_id">A fully configured link</a>"#
/// # );
/// ```
#[doc(alias = "<a>")]
@@ -259,12 +259,21 @@ pub fn Link(props: LinkProps) -> Element {
let is_external = matches!(parsed_route, NavigationTarget::External(_));
let is_router_nav = !is_external && !new_tab;
let prevent_default = is_router_nav.then_some("onclick").unwrap_or_default();
let rel = rel.or_else(|| is_external.then_some("noopener noreferrer".to_string()));
let do_default = onclick.is_none() || !onclick_only;
let action = move |event| {
let action = move |event: MouseEvent| {
// Only handle events without modifiers
if !event.modifiers().is_empty() {
return;
}
// only handle left clicks
if event.trigger_button() != Some(dioxus_elements::input_data::MouseButton::Primary) {
return;
}
event.prevent_default();
if do_default && is_router_nav {
router.push_any(router.resolve_into_routable(to.clone()));
}
@@ -280,12 +289,23 @@ pub fn Link(props: LinkProps) -> Element {
}
};
// In liveview, we need to prevent the default action if the user clicks on the link with modifiers
// in javascript. The prevent_default method is not available in the liveview renderer because
// event handlers are handled over a websocket.
let liveview_prevent_default = {
// If the event is a click with the left mouse button and no modifiers, prevent the default action
// and navigate to the href with client side routing
router.is_liveview().then_some(
"if (event.button === 0 && !event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey) { event.preventDefault() }"
)
};
rsx! {
a {
onclick: action,
"onclick": liveview_prevent_default,
href,
onmounted: onmounted,
prevent_default,
class,
rel,
target: tag_target,
+13
View File
@@ -165,6 +165,19 @@ impl RouterContext {
}
}
/// Check if the router is running in a liveview context
/// We do some slightly weird things for liveview because of the network boundary
pub fn is_liveview(&self) -> bool {
#[cfg(feature = "liveview")]
{
self.inner.read().history.is_liveview()
}
#[cfg(not(feature = "liveview"))]
{
false
}
}
pub(crate) fn route_from_str(&self, route: &str) -> Result<Rc<dyn Any>, String> {
self.inner.read().history.parse_route(route)
}
+11 -1
View File
@@ -317,6 +317,9 @@ pub(crate) trait AnyHistoryProvider {
#[allow(unused_variables)]
fn updater(&mut self, callback: Arc<dyn Fn() + Send + Sync>) {}
#[cfg(feature = "liveview")]
fn is_liveview(&self) -> bool;
}
pub(crate) struct AnyHistoryProviderImplWrapper<R, H> {
@@ -339,7 +342,7 @@ impl<R, H: Default> Default for AnyHistoryProviderImplWrapper<R, H> {
}
}
impl<R, H> AnyHistoryProvider for AnyHistoryProviderImplWrapper<R, H>
impl<R, H: 'static> AnyHistoryProvider for AnyHistoryProviderImplWrapper<R, H>
where
R: Routable,
<R as std::str::FromStr>::Err: std::fmt::Display,
@@ -389,4 +392,11 @@ where
fn updater(&mut self, callback: Arc<dyn Fn() + Send + Sync>) {
self.inner.updater(callback)
}
#[cfg(feature = "liveview")]
fn is_liveview(&self) -> bool {
use std::any::TypeId;
TypeId::of::<H>() == TypeId::of::<LiveviewHistory<R>>()
}
}