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
@@ -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}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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>>()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user