feat: events bubble now
This commit is contained in:
1 parent
b6262edd53
commit
f2234068ba
6 files changed
+63
-57
No files matched your search
@@ -12,6 +12,7 @@ use std::{
|
||||
any::Any,
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Arguments, Debug, Formatter},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||
@@ -366,7 +367,8 @@ pub struct Listener<'bump> {
|
||||
pub event: &'static str,
|
||||
|
||||
/// The actual callback that the user specified
|
||||
pub(crate) callback: RefCell<Option<BumpBox<'bump, dyn FnMut(Box<dyn Any + Send>) + 'bump>>>,
|
||||
pub(crate) callback:
|
||||
RefCell<Option<BumpBox<'bump, dyn FnMut(std::sync::Arc<dyn Any + Send + Sync>) + 'bump>>>,
|
||||
}
|
||||
|
||||
/// Virtual Components for custom user-defined components
|
||||
@@ -643,7 +645,7 @@ impl<'a> NodeFactory<'a> {
|
||||
pub fn listener(
|
||||
self,
|
||||
event: &'static str,
|
||||
callback: BumpBox<'a, dyn FnMut(Box<dyn Any + Send>) + 'a>,
|
||||
callback: BumpBox<'a, dyn FnMut(Arc<dyn Any + Send + Sync>) + 'a>,
|
||||
) -> Listener<'a> {
|
||||
Listener {
|
||||
mounted_node: Cell::new(None),
|
||||
|
||||
@@ -449,30 +449,6 @@ impl Scope {
|
||||
self.generation.set(self.generation.get() + 1);
|
||||
}
|
||||
|
||||
/// A safe wrapper around calling listeners
|
||||
pub(crate) fn call_listener(&self, event: UserEvent, element: ElementId) {
|
||||
let listners = &mut self.items.borrow_mut().listeners;
|
||||
|
||||
let listener = listners.iter().find(|lis| {
|
||||
let search = lis;
|
||||
if search.event == event.name {
|
||||
let search_id = search.mounted_node.get();
|
||||
search_id.map(|f| f == element).unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(listener) = listener {
|
||||
let mut cb = listener.callback.borrow_mut();
|
||||
if let Some(cb) = cb.as_mut() {
|
||||
(cb)(event.event);
|
||||
}
|
||||
} else {
|
||||
log::warn!("An event was triggered but there was no listener to handle it");
|
||||
}
|
||||
}
|
||||
|
||||
// General strategy here is to load up the appropriate suspended task and then run it.
|
||||
// Suspended nodes cannot be called repeatedly.
|
||||
pub(crate) fn call_suspended_node<'a>(&'a mut self, task_id: u64) {
|
||||
|
||||
@@ -2,7 +2,10 @@ use bumpalo::Bump;
|
||||
use futures_channel::mpsc::UnboundedSender;
|
||||
use fxhash::FxHashMap;
|
||||
use slab::Slab;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
cell::{Cell, RefCell},
|
||||
};
|
||||
|
||||
use crate::innerlude::*;
|
||||
|
||||
@@ -361,6 +364,28 @@ impl ScopeArena {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_listener_with_bubbling(&self, event: UserEvent, element: ElementId) {
|
||||
let nodes = self.nodes.borrow();
|
||||
let mut cur_el = Some(element);
|
||||
|
||||
while let Some(id) = cur_el.take() {
|
||||
if let Some(el) = nodes.get(id.0) {
|
||||
let real_el = unsafe { &**el };
|
||||
if let VNode::Element(real_el) = real_el {
|
||||
for listener in real_el.listeners.borrow().iter() {
|
||||
if listener.event == event.name {
|
||||
let mut cb = listener.callback.borrow_mut();
|
||||
if let Some(cb) = cb.as_mut() {
|
||||
(cb)(event.event.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
cur_el = real_el.parent_id.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The head of the bumpframe is the first linked NodeLink
|
||||
pub fn wip_head(&self, id: &ScopeId) -> &VNode {
|
||||
let scope = self.get_scope(id).unwrap();
|
||||
|
||||
@@ -8,6 +8,8 @@ use futures_util::{Future, StreamExt};
|
||||
use fxhash::FxHashSet;
|
||||
use indexmap::IndexSet;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
use std::{any::Any, collections::VecDeque};
|
||||
|
||||
@@ -402,9 +404,7 @@ impl VirtualDom {
|
||||
log::info!("Calling listener {:?}, {:?}", event.scope_id, element);
|
||||
|
||||
if let Some(scope) = self.scopes.get_scope(&event.scope_id) {
|
||||
// TODO: bubble properly here
|
||||
scope.call_listener(event, element);
|
||||
|
||||
self.scopes.call_listener_with_bubbling(event, element);
|
||||
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
|
||||
self.pending_messages.push_front(dirty_scope);
|
||||
}
|
||||
@@ -644,7 +644,7 @@ pub struct UserEvent {
|
||||
pub name: &'static str,
|
||||
|
||||
/// Event Data
|
||||
pub event: Box<dyn Any + Send>,
|
||||
pub event: Arc<dyn Any + Send + Sync>,
|
||||
}
|
||||
|
||||
/// Priority of Event Triggers.
|
||||
|
||||
Reference in new issue
Block a user