feat: events work again!
This commit is contained in:
1 parent
73047fe956
commit
9d7ee79826
18 files changed
+621
-222
No files matched your search
@@ -16,7 +16,7 @@ impl DebugRenderer {
|
||||
///
|
||||
/// This means that the root component must either consumes its own context, or statics are used to generate the page.
|
||||
/// The root component can access things like routing in its context.
|
||||
pub fn new(root: impl for<'a> Fn(Context<'a, ()>) -> VNode + 'static) -> Self {
|
||||
pub fn new(root: FC<()>) -> Self {
|
||||
Self::new_with_props(root, ())
|
||||
}
|
||||
|
||||
@@ -24,10 +24,7 @@ impl DebugRenderer {
|
||||
/// Automatically progresses the creation of the VNode tree to completion.
|
||||
///
|
||||
/// A VDom is automatically created. If you want more granular control of the VDom, use `from_vdom`
|
||||
pub fn new_with_props<T: Properties + 'static>(
|
||||
root: impl for<'a> Fn(Context<'a, T>) -> VNode + 'static,
|
||||
root_props: T,
|
||||
) -> Self {
|
||||
pub fn new_with_props<T: Properties + 'static>(root: FC<T>, root_props: T) -> Self {
|
||||
Self::from_vdom(VirtualDom::new_with_props(root, root_props))
|
||||
}
|
||||
|
||||
|
||||
+69
-43
@@ -60,7 +60,13 @@ pub trait RealDom {
|
||||
fn create_element_ns(&mut self, tag: &str, namespace: &str) -> RealDomNode;
|
||||
|
||||
// events
|
||||
fn new_event_listener(&mut self, event: &str, scope: ScopeIdx, id: usize);
|
||||
fn new_event_listener(
|
||||
&mut self,
|
||||
event: &str,
|
||||
scope: ScopeIdx,
|
||||
element_id: usize,
|
||||
realnode: RealDomNode,
|
||||
);
|
||||
// fn new_event_listener(&mut self, event: &str);
|
||||
fn remove_event_listener(&mut self, event: &str);
|
||||
|
||||
@@ -138,6 +144,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
self.dom.replace_with();
|
||||
return;
|
||||
}
|
||||
new.dom_id.set(old.dom_id.get());
|
||||
|
||||
self.diff_listeners(old.listeners, new.listeners);
|
||||
self.diff_attr(old.attributes, new.attributes, new.namespace.is_some());
|
||||
@@ -145,6 +152,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
}
|
||||
// New node is a text element, need to replace the element with a simple text node
|
||||
VNode::Text(_) => {
|
||||
log::debug!("Replacing el with text");
|
||||
self.create(new_node);
|
||||
self.dom.replace_with();
|
||||
}
|
||||
@@ -169,8 +177,10 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
VNode::Text(old) => match new_node {
|
||||
VNode::Text(new) => {
|
||||
if old.text != new.text {
|
||||
log::debug!("Text has changed {}, {}", old.text, new.text);
|
||||
self.dom.set_text(new.text);
|
||||
}
|
||||
new.dom_id.set(old.dom_id.get());
|
||||
}
|
||||
VNode::Element(_) | VNode::Component(_) => {
|
||||
self.create(new_node);
|
||||
@@ -316,10 +326,10 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
};
|
||||
el.dom_id.set(real_id);
|
||||
|
||||
listeners.iter().enumerate().for_each(|(_id, listener)| {
|
||||
todo!()
|
||||
// dom
|
||||
// .new_event_listener(listener.event, listener.scope, listener.id)
|
||||
listeners.iter().enumerate().for_each(|(idx, listener)| {
|
||||
self.dom
|
||||
.new_event_listener(listener.event, listener.scope, idx, real_id);
|
||||
listener.mounted_node.set(real_id);
|
||||
});
|
||||
|
||||
for attr in *attributes {
|
||||
@@ -333,12 +343,12 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
// to emit three instructions to (1) create a text node, (2) set its
|
||||
// text content, and finally (3) append the text node to this
|
||||
// parent.
|
||||
if children.len() == 1 {
|
||||
if let VNode::Text(text) = &children[0] {
|
||||
self.dom.set_text(text.text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if children.len() == 1 {
|
||||
// if let VNode::Text(text) = &children[0] {
|
||||
// self.dom.set_text(text.text);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
for child in *children {
|
||||
self.create(child);
|
||||
@@ -405,8 +415,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
new_component.run_scope().unwrap();
|
||||
|
||||
// And then run the diff algorithm
|
||||
todo!();
|
||||
// self.diff_node(new_component.old_frame(), new_component.next_frame());
|
||||
// todo!();
|
||||
self.diff_node(new_component.old_frame(), new_component.next_frame());
|
||||
|
||||
// Finally, insert this node as a seen node.
|
||||
self.seen_nodes.insert(idx);
|
||||
@@ -473,6 +483,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
if !old.is_empty() || !new.is_empty() {
|
||||
// self.dom.commit_traversal();
|
||||
}
|
||||
// TODO
|
||||
// what does "diffing listeners" even mean?
|
||||
|
||||
'outer1: for (_l_idx, new_l) in new.iter().enumerate() {
|
||||
// go through each new listener
|
||||
@@ -480,34 +492,34 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
// if any characteristics changed, remove and then re-add
|
||||
|
||||
// if nothing changed, then just move on
|
||||
|
||||
let event_type = new_l.event;
|
||||
|
||||
for old_l in old {
|
||||
if new_l.event == old_l.event {
|
||||
if new_l.id != old_l.id {
|
||||
self.dom.remove_event_listener(event_type);
|
||||
// TODO! we need to mess with events and assign them by RealDomNode
|
||||
// self.dom
|
||||
// .update_event_listener(event_type, new_l.scope, new_l.id)
|
||||
}
|
||||
new_l.mounted_node.set(old_l.mounted_node.get());
|
||||
// if new_l.id != old_l.id {
|
||||
// self.dom.remove_event_listener(event_type);
|
||||
// // TODO! we need to mess with events and assign them by RealDomNode
|
||||
// // self.dom
|
||||
// // .update_event_listener(event_type, new_l.scope, new_l.id)
|
||||
// }
|
||||
|
||||
continue 'outer1;
|
||||
}
|
||||
}
|
||||
|
||||
self.dom
|
||||
.new_event_listener(event_type, new_l.scope, new_l.id);
|
||||
// self.dom
|
||||
// .new_event_listener(event_type, new_l.scope, new_l.id);
|
||||
}
|
||||
|
||||
'outer2: for old_l in old {
|
||||
for new_l in new {
|
||||
if new_l.event == old_l.event {
|
||||
continue 'outer2;
|
||||
}
|
||||
}
|
||||
self.dom.remove_event_listener(old_l.event);
|
||||
}
|
||||
// 'outer2: for old_l in old {
|
||||
// for new_l in new {
|
||||
// if new_l.event == old_l.event {
|
||||
// continue 'outer2;
|
||||
// }
|
||||
// }
|
||||
// self.dom.remove_event_listener(old_l.event);
|
||||
// }
|
||||
}
|
||||
|
||||
// Diff a node's attributes.
|
||||
@@ -590,11 +602,12 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
// Don't take this fast path...
|
||||
}
|
||||
|
||||
(_, VNode::Text(text)) => {
|
||||
// self.dom.commit_traversal();
|
||||
self.dom.set_text(text.text);
|
||||
return;
|
||||
}
|
||||
// (_, VNode::Text(text)) => {
|
||||
// // self.dom.commit_traversal();
|
||||
// log::debug!("using optimized text set");
|
||||
// self.dom.set_text(text.text);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// todo: any more optimizations
|
||||
(_, _) => {}
|
||||
@@ -1047,7 +1060,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
// [... parent]
|
||||
//
|
||||
// the change list stack is in the same state when this function returns.
|
||||
fn diff_non_keyed_children(&self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
|
||||
fn diff_non_keyed_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
|
||||
// Handled these cases in `diff_children` before calling this function.
|
||||
debug_assert!(!new.is_empty());
|
||||
debug_assert!(!old.is_empty());
|
||||
@@ -1057,13 +1070,26 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> {
|
||||
// self.dom.push_root()
|
||||
// [... parent child]
|
||||
|
||||
todo!()
|
||||
// for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
|
||||
// // [... parent prev_child]
|
||||
// self.dom.go_to_sibling(i);
|
||||
// // [... parent this_child]
|
||||
// self.diff_node(old_child, new_child);
|
||||
// }
|
||||
// todo!()
|
||||
for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
|
||||
// [... parent prev_child]
|
||||
// self.dom.go_to_sibling(i);
|
||||
// [... parent this_child]
|
||||
self.dom.push_root(old_child.get_mounted_id().unwrap());
|
||||
self.diff_node(old_child, new_child);
|
||||
|
||||
let old_id = old_child.get_mounted_id().unwrap();
|
||||
let new_id = new_child.get_mounted_id().unwrap();
|
||||
|
||||
log::debug!(
|
||||
"pushed root. {:?}, {:?}",
|
||||
old_child.get_mounted_id().unwrap(),
|
||||
new_child.get_mounted_id().unwrap()
|
||||
);
|
||||
if old_id != new_id {
|
||||
log::debug!("Mismatch: {:?}", new_child);
|
||||
}
|
||||
}
|
||||
|
||||
// match old.len().cmp(&new.len()) {
|
||||
// // old.len > new.len -> removing some nodes
|
||||
|
||||
+18
-20
@@ -6,20 +6,20 @@
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::innerlude::ScopeIdx;
|
||||
use crate::{innerlude::ScopeIdx, virtual_dom::RealDomNode};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventTrigger {
|
||||
pub component_id: ScopeIdx,
|
||||
pub listener_id: usize,
|
||||
pub real_node_id: RealDomNode,
|
||||
pub event: VirtualEvent,
|
||||
}
|
||||
|
||||
impl EventTrigger {
|
||||
pub fn new(event: VirtualEvent, scope: ScopeIdx, id: usize) -> Self {
|
||||
pub fn new(event: VirtualEvent, scope: ScopeIdx, mounted_dom_id: RealDomNode) -> Self {
|
||||
Self {
|
||||
component_id: scope,
|
||||
listener_id: id,
|
||||
real_node_id: mounted_dom_id,
|
||||
event,
|
||||
}
|
||||
}
|
||||
@@ -55,17 +55,15 @@ pub mod on {
|
||||
use crate::{
|
||||
builder::ElementBuilder,
|
||||
builder::NodeCtx,
|
||||
innerlude::{Attribute, Listener, VNode},
|
||||
innerlude::{Attribute, Listener, RealDomNode, VNode},
|
||||
};
|
||||
use std::cell::Cell;
|
||||
|
||||
use super::VirtualEvent;
|
||||
|
||||
macro_rules! event_directory {
|
||||
( $( $eventdata:ident: [ $( $name:ident )* ]; )* ) => {
|
||||
$(
|
||||
|
||||
|
||||
|
||||
$(
|
||||
pub fn $name<'a>(
|
||||
c: &'_ NodeCtx<'a>,
|
||||
@@ -74,7 +72,7 @@ pub mod on {
|
||||
let bump = &c.bump();
|
||||
Listener {
|
||||
event: stringify!($name),
|
||||
id: *c.listener_id.borrow(),
|
||||
mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
|
||||
scope: c.scope_ref.arena_idx,
|
||||
callback: bump.alloc(move |evt: VirtualEvent| match evt {
|
||||
VirtualEvent::$eventdata(event) => callback(event),
|
||||
@@ -121,31 +119,31 @@ pub mod on {
|
||||
/// Returns whether or not a specific event is a bubbling event
|
||||
fn bubbles(&self) -> bool;
|
||||
/// Sets or returns whether the event should propagate up the hierarchy or not
|
||||
fn cancelBubble(&self) -> ();
|
||||
fn cancel_bubble(&self);
|
||||
/// Returns whether or not an event can have its default action prevented
|
||||
fn cancelable(&self) -> bool;
|
||||
/// Returns whether the event is composed or not
|
||||
fn composed(&self) -> bool;
|
||||
/// Returns the event's path
|
||||
fn composedPath(&self) -> ();
|
||||
fn composed_path(&self) -> String;
|
||||
/// Returns the element whose event listeners triggered the event
|
||||
fn currentTarget(&self) -> ();
|
||||
fn current_target(&self);
|
||||
/// Returns whether or not the preventDefault method was called for the event
|
||||
fn defaultPrevented(&self) -> ();
|
||||
fn default_prevented(&self) -> bool;
|
||||
/// Returns which phase of the event flow is currently being evaluated
|
||||
fn eventPhase(&self) -> ();
|
||||
fn event_phase(&self) -> usize;
|
||||
/// Returns whether or not an event is trusted
|
||||
fn isTrusted(&self) -> ();
|
||||
fn is_trusted(&self) -> bool;
|
||||
/// Cancels the event if it is cancelable, meaning that the default action that belongs to the event will
|
||||
fn preventDefault(&self) -> ();
|
||||
fn prevent_default(&self);
|
||||
/// Prevents other listeners of the same event from being called
|
||||
fn stopImmediatePropagation(&self) -> ();
|
||||
fn stop_immediate_propagation(&self);
|
||||
/// Prevents further propagation of an event during event flow
|
||||
fn stopPropagation(&self) -> ();
|
||||
fn stop_propagation(&self);
|
||||
/// Returns the element that triggered the event
|
||||
fn target(&self) -> ();
|
||||
fn target(&self);
|
||||
/// Returns the time (in milliseconds relative to the epoch) at which the event was created
|
||||
fn timeStamp(&self) -> usize;
|
||||
fn time_stamp(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait ClipboardEvent: Debug {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
//! Helpers for building virtual DOM VNodes.
|
||||
|
||||
use std::{
|
||||
any::Any, borrow::BorrowMut, cell::RefCell, fmt::Arguments, intrinsics::transmute, u128,
|
||||
any::Any,
|
||||
borrow::BorrowMut,
|
||||
cell::{Cell, RefCell},
|
||||
fmt::Arguments,
|
||||
intrinsics::transmute,
|
||||
u128,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -9,7 +14,7 @@ use crate::{
|
||||
innerlude::{Properties, VComponent, FC},
|
||||
nodes::{Attribute, Listener, NodeKey, VNode},
|
||||
prelude::{VElement, VFragment},
|
||||
virtual_dom::Scope,
|
||||
virtual_dom::{RealDomNode, Scope},
|
||||
};
|
||||
|
||||
/// A virtual DOM element builder.
|
||||
@@ -353,12 +358,11 @@ where
|
||||
/// ```
|
||||
pub fn on(self, event: &'static str, callback: impl Fn(VirtualEvent) + 'a) -> Self {
|
||||
let bump = &self.ctx.bump();
|
||||
|
||||
let listener = Listener {
|
||||
event,
|
||||
callback: bump.alloc(callback),
|
||||
id: *self.ctx.listener_id.borrow(),
|
||||
scope: self.ctx.scope_ref.arena_idx,
|
||||
mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
|
||||
};
|
||||
self.add_listener(listener)
|
||||
}
|
||||
@@ -367,7 +371,8 @@ where
|
||||
self.listeners.push(listener);
|
||||
|
||||
// bump the context id forward
|
||||
*self.ctx.listener_id.borrow_mut() += 1;
|
||||
let id = self.ctx.listener_id.get();
|
||||
self.ctx.listener_id.set(id + 1);
|
||||
|
||||
// Add this listener to the context list
|
||||
// This casts the listener to a self-referential pointer
|
||||
@@ -378,7 +383,7 @@ where
|
||||
.scope_ref
|
||||
.listeners
|
||||
.borrow_mut()
|
||||
.push(r.callback as *const _);
|
||||
.push((r.mounted_node as *const _, r.callback as *const _));
|
||||
});
|
||||
|
||||
self
|
||||
@@ -499,15 +504,19 @@ where
|
||||
let child = item.into_vnode(&self.ctx);
|
||||
self.children.push(child);
|
||||
}
|
||||
let len_after = self.children.len();
|
||||
if len_after > len_before {
|
||||
let last_child = self.children.last().unwrap();
|
||||
if last_child.key().is_none() {
|
||||
// TODO: Somehow get the name of the component when NodeCtx is being made
|
||||
const ERR_MSG: &str = r#"Warning: Each child in an array or iterator should have a unique "key" prop.
|
||||
Check the render method of XXXX.
|
||||
See fb.me/react-warning-keys for more information. "#;
|
||||
log::error!("{}", ERR_MSG);
|
||||
if self.children.len() > len_before + 1 {
|
||||
if self.children.last().unwrap().key().is_none() {
|
||||
if cfg!(debug_assertions) {
|
||||
log::error!(
|
||||
r#"
|
||||
Warning: Each child in an array or iterator should have a unique "key" prop.
|
||||
Not providing a key will lead to poor performance with lists.
|
||||
See docs.rs/dioxus for more information.
|
||||
---
|
||||
To help you identify where this error is coming from, we've generated a backtrace.
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
@@ -549,17 +558,6 @@ impl<'a, F> VNodeBuilder<'a, LazyNodes<'a, F>> for LazyNodes<'a, F> where
|
||||
{
|
||||
}
|
||||
|
||||
// Cover the cases where nodes are pre-rendered.
|
||||
// Likely used by enums.
|
||||
// ----
|
||||
// let nodes = ctx.render(rsx!{ ... };
|
||||
// rsx! { {nodes } }
|
||||
// impl<'a> IntoVNode<'a> for VNode {
|
||||
// fn into_vnode(self, _ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
// self.root
|
||||
// }
|
||||
// }
|
||||
|
||||
// Wrap the the node-builder closure in a concrete type.
|
||||
// ---
|
||||
// This is a bit of a hack to implement the IntoVNode trait for closure types.
|
||||
@@ -611,12 +609,14 @@ where
|
||||
|
||||
impl<'a> IntoVNode<'a> for () {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
todo!();
|
||||
VNode::Suspended
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for Option<()> {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
todo!();
|
||||
VNode::Suspended
|
||||
}
|
||||
}
|
||||
@@ -735,7 +735,8 @@ impl<'a, 'b> ChildrenList<'a, 'b> {
|
||||
#[derive(Clone)]
|
||||
pub struct NodeCtx<'a> {
|
||||
pub scope_ref: &'a Scope,
|
||||
pub listener_id: RefCell<usize>,
|
||||
pub listener_id: Cell<usize>,
|
||||
// pub listener_id: RefCell<usize>,
|
||||
}
|
||||
|
||||
impl<'a> NodeCtx<'a> {
|
||||
@@ -744,11 +745,13 @@ impl<'a> NodeCtx<'a> {
|
||||
&self.scope_ref.cur_frame().bump
|
||||
}
|
||||
|
||||
fn text(&self, args: Arguments) -> VNode<'a> {
|
||||
/// Create some text that's allocated along with the other vnodes
|
||||
pub fn text(&self, args: Arguments) -> VNode<'a> {
|
||||
text3(self.bump(), args)
|
||||
}
|
||||
|
||||
fn element<'b, Listeners, Attributes, Children>(
|
||||
/// Create an element builder
|
||||
pub fn element<'b, Listeners, Attributes, Children>(
|
||||
&'b self,
|
||||
tag_name: &'static str,
|
||||
) -> ElementBuilder<
|
||||
|
||||
@@ -13,7 +13,7 @@ use bumpalo::Bump;
|
||||
use std::{
|
||||
any::Any,
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Arguments, Debug},
|
||||
fmt::{Arguments, Debug, Formatter},
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
};
|
||||
@@ -127,8 +127,8 @@ impl<'a> VNode<'a> {
|
||||
|
||||
pub fn get_mounted_id(&self) -> Option<RealDomNode> {
|
||||
match self {
|
||||
VNode::Element(_) => todo!(),
|
||||
VNode::Text(_) => todo!(),
|
||||
VNode::Element(el) => Some(el.dom_id.get()),
|
||||
VNode::Text(te) => Some(te.dom_id.get()),
|
||||
VNode::Fragment(_) => todo!(),
|
||||
VNode::Suspended => todo!(),
|
||||
VNode::Component(_) => todo!(),
|
||||
@@ -136,6 +136,18 @@ impl<'a> VNode<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VNode<'_> {
|
||||
fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
VNode::Element(el) => write!(s, "element, {}", el.tag_name),
|
||||
VNode::Text(t) => write!(s, "text, {}", t.text),
|
||||
VNode::Fragment(_) => write!(s, "fragment"),
|
||||
VNode::Suspended => write!(s, "suspended"),
|
||||
VNode::Component(_) => write!(s, "component"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VText<'src> {
|
||||
pub text: &'src str,
|
||||
@@ -201,11 +213,14 @@ pub struct Listener<'bump> {
|
||||
/// The type of event to listen for.
|
||||
pub(crate) event: &'static str,
|
||||
|
||||
/// Which scope?
|
||||
/// This might not actually be relevant
|
||||
pub scope: ScopeIdx,
|
||||
pub id: usize,
|
||||
|
||||
pub mounted_node: &'bump Cell<RealDomNode>,
|
||||
|
||||
/// The callback to invoke when the event happens.
|
||||
pub(crate) callback: &'bump (dyn Fn(VirtualEvent)),
|
||||
pub(crate) callback: &'bump dyn Fn(VirtualEvent),
|
||||
}
|
||||
|
||||
/// The key for keyed children.
|
||||
@@ -259,6 +274,7 @@ pub struct VComponent<'src> {
|
||||
pub key: NodeKey<'src>,
|
||||
|
||||
pub mounted_root: Cell<RealDomNode>,
|
||||
|
||||
pub ass_scope: RefCell<VCompAssociatedScope>,
|
||||
|
||||
// pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
|
||||
|
||||
@@ -24,7 +24,7 @@ use bumpalo::Bump;
|
||||
use generational_arena::Arena;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::RefCell,
|
||||
cell::{Cell, RefCell},
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
@@ -63,7 +63,7 @@ pub struct VirtualDom {
|
||||
_root_prop_type: std::any::TypeId,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct RealDomNode(pub u32);
|
||||
impl RealDomNode {
|
||||
pub fn new(id: u32) -> Self {
|
||||
@@ -109,7 +109,7 @@ impl VirtualDom {
|
||||
///
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
/// ```
|
||||
pub fn new(root: impl Fn(Context<()>) -> VNode + 'static) -> Self {
|
||||
pub fn new(root: FC<()>) -> Self {
|
||||
Self::new_with_props(root, ())
|
||||
}
|
||||
|
||||
@@ -141,10 +141,7 @@ impl VirtualDom {
|
||||
///
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
/// ```
|
||||
pub fn new_with_props<P: Properties + 'static>(
|
||||
root: impl Fn(Context<P>) -> VNode + 'static,
|
||||
root_props: P,
|
||||
) -> Self {
|
||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
let components = ScopeArena::new(Arena::new());
|
||||
|
||||
// Normally, a component would be passed as a child in the RSX macro which automatically produces OpaqueComponents
|
||||
@@ -260,11 +257,11 @@ impl VirtualDom {
|
||||
pub fn progress_with_event<Dom: RealDom>(
|
||||
&mut self,
|
||||
realdom: &mut Dom,
|
||||
event: EventTrigger,
|
||||
trigger: EventTrigger,
|
||||
) -> Result<()> {
|
||||
let id = event.component_id.clone();
|
||||
let id = trigger.component_id.clone();
|
||||
|
||||
self.components.try_get_mut(id)?.call_listener(event)?;
|
||||
self.components.try_get_mut(id)?.call_listener(trigger)?;
|
||||
|
||||
let mut diff_machine = DiffMachine::new(
|
||||
realdom,
|
||||
@@ -397,7 +394,12 @@ pub struct Scope {
|
||||
// - is self-refenrential and therefore needs to point into the bump
|
||||
// Stores references into the listeners attached to the vnodes
|
||||
// NEEDS TO BE PRIVATE
|
||||
pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
pub(crate) listeners: RefCell<Vec<(*const Cell<RealDomNode>, *const dyn Fn(VirtualEvent))>>,
|
||||
// pub(crate) listeners: RefCell<nohash_hasher::IntMap<u32, *const dyn Fn(VirtualEvent)>>,
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
// NoHashMap<RealDomNode, <*const dyn Fn(VirtualEvent)>
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
}
|
||||
|
||||
// We need to pin the hook so it doesn't move as we initialize the list of hooks
|
||||
@@ -450,7 +452,7 @@ impl Scope {
|
||||
let child_nodes = unsafe { std::mem::transmute(child_nodes) };
|
||||
|
||||
Self {
|
||||
child_nodes: child_nodes,
|
||||
child_nodes,
|
||||
caller,
|
||||
parent,
|
||||
arena_idx,
|
||||
@@ -490,12 +492,12 @@ impl Scope {
|
||||
self.frames.next().bump.reset();
|
||||
|
||||
// Remove all the outdated listeners
|
||||
//
|
||||
self.listeners
|
||||
.try_borrow_mut()
|
||||
.ok()
|
||||
.ok_or(Error::FatalInternal("Borrowing listener failed"))?
|
||||
.drain(..);
|
||||
self.listeners.borrow_mut().clear();
|
||||
// self.listeners
|
||||
// .try_borrow_mut()
|
||||
// .ok()
|
||||
// .ok_or(Error::FatalInternal("Borrowing listener failed"))?
|
||||
// .drain(..);
|
||||
|
||||
*self.hookidx.borrow_mut() = 0;
|
||||
|
||||
@@ -529,26 +531,35 @@ impl Scope {
|
||||
// The listener list will be completely drained because the next frame will write over previous listeners
|
||||
pub fn call_listener(&mut self, trigger: EventTrigger) -> Result<()> {
|
||||
let EventTrigger {
|
||||
listener_id, event, ..
|
||||
real_node_id,
|
||||
event,
|
||||
..
|
||||
} = trigger;
|
||||
|
||||
// todo: implement scanning for outdated events
|
||||
unsafe {
|
||||
// Convert the raw ptr into an actual object
|
||||
// This operation is assumed to be safe
|
||||
let listener_fn = self
|
||||
.listeners
|
||||
.try_borrow()
|
||||
.ok()
|
||||
.ok_or(Error::FatalInternal("Borrowing listener failed"))?
|
||||
.get(listener_id as usize)
|
||||
.ok_or(Error::FatalInternal("Event should exist if triggered"))?
|
||||
.as_ref()
|
||||
.ok_or(Error::FatalInternal("Raw event ptr is invalid"))?;
|
||||
|
||||
// Run the callback with the user event
|
||||
// Convert the raw ptr into an actual object
|
||||
// This operation is assumed to be safe
|
||||
|
||||
log::debug!("Calling listeners! {:?}", self.listeners.borrow().len());
|
||||
let listners = self.listeners.borrow();
|
||||
let (_, listener) = listners
|
||||
.iter()
|
||||
.find(|(domptr, _)| {
|
||||
let p = unsafe { &**domptr };
|
||||
p.get() == real_node_id
|
||||
})
|
||||
.expect(&format!(
|
||||
"Failed to find real node with ID {:?}",
|
||||
real_node_id
|
||||
));
|
||||
|
||||
// TODO: Don'tdo a linear scan! Do a hashmap lookup! It'll be faster!
|
||||
unsafe {
|
||||
let listener_fn = &**listener;
|
||||
listener_fn(event);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user