Feat: a few bugs, but the event system works!
This commit is contained in:
1 parent
2041c88d07
commit
3b30fa61b8
13 files changed
+308
-117
No files matched your search
@@ -64,9 +64,9 @@ pub enum Edit<'d> {
|
|||||||
/// We can go back and forth between the two via methods on GI
|
/// We can go back and forth between the two via methods on GI
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct CbIdx {
|
pub struct CbIdx {
|
||||||
gi_id: usize,
|
pub gi_id: usize,
|
||||||
gi_gen: u64,
|
pub gi_gen: u64,
|
||||||
listener_idx: usize,
|
pub listener_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CbIdx {
|
impl CbIdx {
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ pub mod hooks {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Hook(pub Box<dyn std::any::Any>);
|
pub struct Hook(pub Box<dyn std::any::Any>);
|
||||||
|
|
||||||
impl Hook {
|
impl Hook {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pub struct DiffMachine<'a> {
|
|||||||
|
|
||||||
impl<'a> DiffMachine<'a> {
|
impl<'a> DiffMachine<'a> {
|
||||||
pub fn new(bump: &'a Bump) -> Self {
|
pub fn new(bump: &'a Bump) -> Self {
|
||||||
log::debug!("starting diff machine");
|
// log::debug!("starting diff machine");
|
||||||
Self {
|
Self {
|
||||||
change_list: EditMachine::new(bump),
|
change_list: EditMachine::new(bump),
|
||||||
immediate_queue: Vec::new(),
|
immediate_queue: Vec::new(),
|
||||||
@@ -88,7 +88,8 @@ impl<'a> DiffMachine<'a> {
|
|||||||
new: &VNode<'a>,
|
new: &VNode<'a>,
|
||||||
scope: Option<generational_arena::Index>,
|
scope: Option<generational_arena::Index>,
|
||||||
) {
|
) {
|
||||||
log::debug!("Diffing nodes");
|
log::debug!("old {:#?}", old);
|
||||||
|
log::debug!("new {:#?}", new);
|
||||||
|
|
||||||
// Set it while diffing
|
// Set it while diffing
|
||||||
// Reset it when finished diffing
|
// Reset it when finished diffing
|
||||||
@@ -131,7 +132,7 @@ impl<'a> DiffMachine<'a> {
|
|||||||
// compare elements
|
// compare elements
|
||||||
// if different, schedule different types of update
|
// if different, schedule different types of update
|
||||||
(VNode::Element(eold), VNode::Element(enew)) => {
|
(VNode::Element(eold), VNode::Element(enew)) => {
|
||||||
log::debug!("elements are different");
|
// log::debug!("elements are different");
|
||||||
// If the element type is completely different, the element needs to be re-rendered completely
|
// If the element type is completely different, the element needs to be re-rendered completely
|
||||||
if enew.tag_name != eold.tag_name || enew.namespace != eold.namespace {
|
if enew.tag_name != eold.tag_name || enew.namespace != eold.namespace {
|
||||||
self.change_list.commit_traversal();
|
self.change_list.commit_traversal();
|
||||||
@@ -894,7 +895,7 @@ impl<'a> DiffMachine<'a> {
|
|||||||
children,
|
children,
|
||||||
namespace,
|
namespace,
|
||||||
}) => {
|
}) => {
|
||||||
log::info!("Creating {:#?}", node);
|
// log::info!("Creating {:#?}", node);
|
||||||
if let Some(namespace) = namespace {
|
if let Some(namespace) = namespace {
|
||||||
self.change_list.create_element_ns(tag_name, namespace);
|
self.change_list.create_element_ns(tag_name, namespace);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,16 +6,29 @@
|
|||||||
//! The goal here is to provide a consistent event interface across all renderer types
|
//! The goal here is to provide a consistent event interface across all renderer types
|
||||||
use generational_arena::Index;
|
use generational_arena::Index;
|
||||||
|
|
||||||
|
use crate::innerlude::CbIdx;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EventTrigger {
|
pub struct EventTrigger {
|
||||||
pub component_id: Index,
|
pub component_id: Index,
|
||||||
pub listener_id: u32,
|
pub listener_id: usize,
|
||||||
pub event: VirtualEvent,
|
pub event: VirtualEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventTrigger {
|
impl EventTrigger {
|
||||||
pub fn new() -> Self {
|
pub fn new(event: VirtualEvent, cb: CbIdx) -> Self {
|
||||||
todo!()
|
let CbIdx {
|
||||||
|
gi_id,
|
||||||
|
gi_gen,
|
||||||
|
listener_idx,
|
||||||
|
} = cb;
|
||||||
|
|
||||||
|
let component_id = Index::from_raw_parts(gi_id, gi_gen);
|
||||||
|
Self {
|
||||||
|
component_id,
|
||||||
|
listener_id: listener_idx,
|
||||||
|
event,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ mod use_state_def {
|
|||||||
caller: Box::new(|_| println!("setter called!")),
|
caller: Box::new(|_| println!("setter called!")),
|
||||||
},
|
},
|
||||||
move |hook| {
|
move |hook| {
|
||||||
|
log::debug!("Use_state set called");
|
||||||
let inner = hook.new_val.clone();
|
let inner = hook.new_val.clone();
|
||||||
let scheduled_update = ctx.schedule_update();
|
let scheduled_update = ctx.schedule_update();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
events::VirtualEvent,
|
||||||
innerlude::VComponent,
|
innerlude::VComponent,
|
||||||
nodes::{Attribute, Listener, NodeKey, VNode},
|
nodes::{Attribute, Listener, NodeKey, VNode},
|
||||||
prelude::VElement,
|
prelude::VElement,
|
||||||
@@ -338,7 +339,7 @@ where
|
|||||||
/// .finish();
|
/// .finish();
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn on(mut self, event: &'static str, callback: impl Fn(()) + 'a) -> Self {
|
pub fn on(mut self, event: &'static str, callback: impl Fn(VirtualEvent) + 'a) -> Self {
|
||||||
self.listeners.push(Listener {
|
self.listeners.push(Listener {
|
||||||
event,
|
event,
|
||||||
callback: self.bump.alloc(callback),
|
callback: self.bump.alloc(callback),
|
||||||
@@ -1081,7 +1082,7 @@ pub fn on<'a, 'b>(
|
|||||||
// pub fn on<'a, 'b, F: 'static>(
|
// pub fn on<'a, 'b, F: 'static>(
|
||||||
bump: &'a Bump,
|
bump: &'a Bump,
|
||||||
event: &'static str,
|
event: &'static str,
|
||||||
callback: impl Fn(()) + 'a,
|
callback: impl Fn(VirtualEvent) + 'a,
|
||||||
) -> Listener<'a> {
|
) -> Listener<'a> {
|
||||||
Listener {
|
Listener {
|
||||||
event,
|
event,
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ mod vnode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod velement {
|
mod velement {
|
||||||
|
use crate::events::VirtualEvent;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@@ -188,7 +190,7 @@ mod velement {
|
|||||||
// pub(crate) _i: &'bump str,
|
// pub(crate) _i: &'bump str,
|
||||||
// #[serde(skip_serializing, skip_deserializing, default="")]
|
// #[serde(skip_serializing, skip_deserializing, default="")]
|
||||||
// /// The callback to invoke when the event happens.
|
// /// The callback to invoke when the event happens.
|
||||||
pub(crate) callback: &'bump (dyn Fn(())),
|
pub(crate) callback: &'bump (dyn Fn(VirtualEvent)),
|
||||||
}
|
}
|
||||||
impl Debug for Listener<'_> {
|
impl Debug for Listener<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@@ -197,7 +199,7 @@ mod velement {
|
|||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) type ListenerCallback<'a> = &'a (dyn Fn(()));
|
pub(crate) type ListenerCallback<'a> = &'a (dyn Fn(VirtualEvent));
|
||||||
union CallbackFatPtr<'a> {
|
union CallbackFatPtr<'a> {
|
||||||
callback: ListenerCallback<'a>,
|
callback: ListenerCallback<'a>,
|
||||||
parts: (u32, u32),
|
parts: (u32, u32),
|
||||||
|
|||||||
+50
-11
@@ -36,8 +36,10 @@ pub struct Scope {
|
|||||||
|
|
||||||
pub frames: ActiveFrame,
|
pub frames: ActiveFrame,
|
||||||
|
|
||||||
// IE Which listeners need to be woken up?
|
// List of listeners generated when CTX is evaluated
|
||||||
pub listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>>,
|
pub listeners: Vec<*const dyn Fn(crate::events::VirtualEvent)>,
|
||||||
|
// pub listeners: Vec<*const dyn Fn(crate::events::VirtualEvent)>,
|
||||||
|
// pub listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>>,
|
||||||
|
|
||||||
// lying, cheating reference >:(
|
// lying, cheating reference >:(
|
||||||
pub props: Box<dyn std::any::Any>,
|
pub props: Box<dyn std::any::Any>,
|
||||||
@@ -55,9 +57,8 @@ impl Scope {
|
|||||||
// Capture the caller
|
// Capture the caller
|
||||||
let caller = f as *const ();
|
let caller = f as *const ();
|
||||||
|
|
||||||
let listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>> = vec![Box::new(|_| {
|
let listeners = vec![];
|
||||||
log::info!("Base listener called");
|
// let listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>> = vec![];
|
||||||
})];
|
|
||||||
|
|
||||||
let old_frame = BumpFrame {
|
let old_frame = BumpFrame {
|
||||||
bump: Bump::new(),
|
bump: Bump::new(),
|
||||||
@@ -95,6 +96,7 @@ impl Scope {
|
|||||||
let frame = {
|
let frame = {
|
||||||
let frame = self.frames.next();
|
let frame = self.frames.next();
|
||||||
frame.bump.reset();
|
frame.bump.reset();
|
||||||
|
log::debug!("Rednering into frame {:?}", frame as *const _);
|
||||||
frame
|
frame
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -145,6 +147,20 @@ impl Scope {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.take()
|
.take()
|
||||||
.expect("Viewing did not happen");
|
.expect("Viewing did not happen");
|
||||||
|
|
||||||
|
// todo:
|
||||||
|
// make this so we dont have to iterate through the vnodes to get its listener
|
||||||
|
let mut listeners = vec![];
|
||||||
|
retrieve_listeners(&frame.head_node, &mut listeners);
|
||||||
|
self.listeners = listeners
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| {
|
||||||
|
let g = f.callback;
|
||||||
|
g as *const _
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// consume the listeners from the head_node into a list of boxed ref listeners
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +175,18 @@ impl Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn retrieve_listeners(node: &VNode<'static>, listeners: &mut Vec<&Listener>) {
|
||||||
|
if let VNode::Element(el) = *node {
|
||||||
|
for listener in el.listeners {
|
||||||
|
// let g = listener as *const Listener;
|
||||||
|
listeners.push(listener);
|
||||||
|
}
|
||||||
|
for child in el.children {
|
||||||
|
retrieve_listeners(child, listeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo, do better with the active frame stuff
|
// todo, do better with the active frame stuff
|
||||||
// somehow build this vnode with a lifetime tied to self
|
// somehow build this vnode with a lifetime tied to self
|
||||||
// This root node has "static" lifetime, but it's really not static.
|
// This root node has "static" lifetime, but it's really not static.
|
||||||
@@ -184,7 +212,7 @@ impl ActiveFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
||||||
let raw_node = match self.idx.borrow().load(Ordering::Relaxed) & 1 != 0 {
|
let raw_node = match self.idx.borrow().load(Ordering::Relaxed) & 1 == 0 {
|
||||||
true => &self.frames[0],
|
true => &self.frames[0],
|
||||||
false => &self.frames[1],
|
false => &self.frames[1],
|
||||||
};
|
};
|
||||||
@@ -196,7 +224,7 @@ impl ActiveFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prev_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
fn prev_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
||||||
let raw_node = match self.idx.borrow().load(Ordering::Relaxed) & 1 == 0 {
|
let raw_node = match self.idx.borrow().load(Ordering::Relaxed) & 1 != 0 {
|
||||||
true => &self.frames[0],
|
true => &self.frames[0],
|
||||||
false => &self.frames[1],
|
false => &self.frames[1],
|
||||||
};
|
};
|
||||||
@@ -211,11 +239,22 @@ impl ActiveFrame {
|
|||||||
fn next(&mut self) -> &mut BumpFrame {
|
fn next(&mut self) -> &mut BumpFrame {
|
||||||
self.idx.fetch_add(1, Ordering::Relaxed);
|
self.idx.fetch_add(1, Ordering::Relaxed);
|
||||||
let cur = self.idx.borrow().load(Ordering::Relaxed);
|
let cur = self.idx.borrow().load(Ordering::Relaxed);
|
||||||
match cur % 1 {
|
log::debug!("Next frame! {}", cur);
|
||||||
1 => &mut self.frames[1],
|
|
||||||
0 => &mut self.frames[0],
|
if cur % 2 == 0 {
|
||||||
_ => unreachable!("mod cannot by non-zero"),
|
log::debug!("Chosing frame 0");
|
||||||
|
&mut self.frames[0]
|
||||||
|
} else {
|
||||||
|
log::debug!("Chosing frame 1");
|
||||||
|
&mut self.frames[1]
|
||||||
}
|
}
|
||||||
|
// match cur % 1 {
|
||||||
|
// 0 => {
|
||||||
|
// }
|
||||||
|
// 1 => {
|
||||||
|
// }
|
||||||
|
// _ => unreachable!("mod cannot by non-zero"),
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,29 +140,63 @@ impl VirtualDom {
|
|||||||
|
|
||||||
let component = self
|
let component = self
|
||||||
.components
|
.components
|
||||||
.get(component_id)
|
.get_mut(component_id)
|
||||||
.expect("Component should exist if an event was triggered");
|
.expect("Component should exist if an event was triggered");
|
||||||
|
|
||||||
let listener = component
|
log::debug!("list: {}", component.listeners.len());
|
||||||
.listeners
|
|
||||||
.get(listener_id as usize)
|
let listener = unsafe {
|
||||||
.expect("Listener should exist if it was triggered")
|
component
|
||||||
.as_ref();
|
.listeners
|
||||||
|
.get(listener_id as usize)
|
||||||
|
.expect("Listener should exist if it was triggered")
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Run the callback with the user event
|
// Run the callback with the user event
|
||||||
listener(source);
|
listener(source);
|
||||||
|
|
||||||
|
// Reset and then build a new diff machine
|
||||||
|
// The previous edit list cannot be around while &mut is held
|
||||||
|
// Make sure variance doesnt break this
|
||||||
|
self.diff_bump.reset();
|
||||||
|
let mut diff_machine = DiffMachine::new(&self.diff_bump);
|
||||||
|
|
||||||
|
// this is still a WIP
|
||||||
|
// we'll need to re-fecth all the scopes that were changed and build the diff machine
|
||||||
|
// fetch the component again
|
||||||
|
// let component = self
|
||||||
|
// .components
|
||||||
|
// .get_mut(self.base_scope)
|
||||||
|
// .expect("Root should always exist");
|
||||||
|
|
||||||
|
component.run::<()>();
|
||||||
|
|
||||||
|
diff_machine.diff_node(
|
||||||
|
component.old_frame(),
|
||||||
|
component.new_frame(),
|
||||||
|
Some(self.base_scope),
|
||||||
|
);
|
||||||
|
// diff_machine.diff_node(
|
||||||
|
// component.old_frame(),
|
||||||
|
// component.new_frame(),
|
||||||
|
// Some(self.base_scope),
|
||||||
|
// );
|
||||||
|
|
||||||
|
Ok(diff_machine.consume())
|
||||||
|
// Err(crate::error::Error::NoEvent)
|
||||||
// Mark dirty components. Descend from the highest node until all dirty nodes are updated.
|
// Mark dirty components. Descend from the highest node until all dirty nodes are updated.
|
||||||
let mut affected_components = Vec::new();
|
// let mut affected_components = Vec::new();
|
||||||
|
|
||||||
while let Some(event) = self.pop_event() {
|
// while let Some(event) = self.pop_event() {
|
||||||
if let Some(component_idx) = event.index() {
|
// if let Some(component_idx) = event.index() {
|
||||||
affected_components.push(component_idx);
|
// affected_components.push(component_idx);
|
||||||
}
|
// }
|
||||||
self.process_lifecycle(event)?;
|
// self.process_lifecycle(event)?;
|
||||||
}
|
// }
|
||||||
|
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
|
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ use dioxus_web::*;
|
|||||||
fn main() {
|
fn main() {
|
||||||
// Setup logging
|
// Setup logging
|
||||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||||
// wasm_logger::init(wasm_logger::Config::with_prefix(
|
|
||||||
// log::Level::Debug,
|
|
||||||
// "dioxus_core",
|
|
||||||
// ));
|
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
// Run the app
|
// Run the app
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
use dioxus::prelude::bumpalo;
|
|
||||||
use dioxus::prelude::format_args_f;
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_core as dioxus;
|
use dioxus_core as dioxus;
|
||||||
use dioxus_core::prelude::html;
|
|
||||||
use dioxus_web::WebsysRenderer;
|
use dioxus_web::WebsysRenderer;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pretty_env_logger::init();
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||||
log::info!("Hello!");
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
|
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
|
||||||
}
|
}
|
||||||
@@ -15,11 +12,55 @@ fn main() {
|
|||||||
static Example: FC<()> = |ctx, props| {
|
static Example: FC<()> = |ctx, props| {
|
||||||
let (name, set_name) = use_state(&ctx, || "...?");
|
let (name, set_name) = use_state(&ctx, || "...?");
|
||||||
|
|
||||||
|
log::debug!("Running component....");
|
||||||
|
|
||||||
ctx.view(html! {
|
ctx.view(html! {
|
||||||
<div>
|
// <div>
|
||||||
<h1> "Hello, {name}" </h1>
|
// <h1> "Hello, {name}" </h1>
|
||||||
<button onclick={move |_| set_name("jack")}> "jack!" </button>
|
// <button onclick={move |_| set_name("jack")}> "jack!" </button>
|
||||||
<button onclick={move |_| set_name("jill")}> "jill!" </button>
|
// <button
|
||||||
</div>
|
// onclick={move |_| set_name("jill")}
|
||||||
})
|
// onclick={move |_| set_name("jill")}
|
||||||
|
// > "jill!" </button>
|
||||||
|
// </div>
|
||||||
|
<div>
|
||||||
|
<section class="py-12 px-4 text-center">
|
||||||
|
<div class="w-full max-w-2xl mx-auto">
|
||||||
|
// Tagline
|
||||||
|
<span class="text-sm font-semibold">
|
||||||
|
"Dioxus Example: Jack and Jill"
|
||||||
|
</span>
|
||||||
|
|
||||||
|
// Header
|
||||||
|
<h2 class="text-5xl mt-2 mb-6 leading-tight font-semibold font-heading">
|
||||||
|
"Hello, {name}"
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
// Control buttons
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-700 font-semibold rounded shadow"
|
||||||
|
// onclick={move |_| log::debug!("set jack")}>
|
||||||
|
onclick={move |_| set_name("jack")}>
|
||||||
|
"Jack!"
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-700 font-semibold rounded shadow"
|
||||||
|
// onclick={move |_| log::debug!("set jill")}>
|
||||||
|
onclick={move |_| set_name("jill")}
|
||||||
|
onclick={move |_| set_name("jill")}>
|
||||||
|
"Jill!"
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// <div>
|
||||||
|
// <h1> "Hello, {name}" </h1>
|
||||||
|
// <button onclick={move |_| set_name("jack .")}> "jack!" </button>
|
||||||
|
// <button onclick={move |_| set_name("jill .")}> "jill!" </button>
|
||||||
|
// </div>
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
use std::fmt::Debug;
|
use std::{borrow::Borrow, fmt::Debug, sync::Arc};
|
||||||
|
|
||||||
use dioxus_core::{changelist::Edit, events::EventTrigger};
|
use dioxus_core::{
|
||||||
|
changelist::{CbIdx, Edit},
|
||||||
|
events::{EventTrigger, MouseEvent, VirtualEvent},
|
||||||
|
};
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use wasm_bindgen::{closure::Closure, JsCast};
|
use wasm_bindgen::{closure::Closure, JsCast};
|
||||||
@@ -9,10 +12,13 @@ use web_sys::{window, Document, Element, Event, HtmlInputElement, HtmlOptionElem
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct CacheId(u32);
|
pub struct CacheId(u32);
|
||||||
|
|
||||||
struct RootCallback(Box<dyn Fn(EventTrigger)>);
|
#[derive(Clone)]
|
||||||
|
struct RootCallback(Arc<dyn Fn(EventTrigger)>);
|
||||||
impl std::fmt::Debug for RootCallback {
|
impl std::fmt::Debug for RootCallback {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
todo!()
|
Ok(())
|
||||||
|
// a no-op for now
|
||||||
|
// todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,15 +43,18 @@ pub(crate) struct EventDelegater {
|
|||||||
callback_id: usize,
|
callback_id: usize,
|
||||||
|
|
||||||
// map of listener types to number of those listeners
|
// map of listener types to number of those listeners
|
||||||
listeners: FxHashMap<&'static str, (usize, Closure<dyn Fn()>)>,
|
listeners: FxHashMap<String, (usize, Closure<dyn FnMut(&Event)>)>,
|
||||||
|
|
||||||
// Map of callback_id to component index and listener id
|
// Map of callback_id to component index and listener id
|
||||||
callback_map: FxHashMap<usize, (usize, usize)>,
|
callback_map: FxHashMap<usize, (usize, usize)>,
|
||||||
|
|
||||||
|
trigger: RootCallback,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventDelegater {
|
impl EventDelegater {
|
||||||
pub fn new(root: Element) -> Self {
|
pub fn new(root: Element, trigger: impl Fn(EventTrigger) + 'static) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
trigger: RootCallback(Arc::new(trigger)),
|
||||||
root,
|
root,
|
||||||
callback_id: 0,
|
callback_id: 0,
|
||||||
listeners: FxHashMap::default(),
|
listeners: FxHashMap::default(),
|
||||||
@@ -53,12 +62,55 @@ impl EventDelegater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_listener(
|
pub fn add_listener(&mut self, event: &str, cb: CbIdx) {
|
||||||
&mut self,
|
if let Some(entry) = self.listeners.get_mut(event) {
|
||||||
event: &'static str,
|
entry.0 += 1;
|
||||||
gi: generational_arena::Index,
|
} else {
|
||||||
listener_id: usize,
|
let trigger = self.trigger.clone();
|
||||||
) {
|
let handler = Closure::wrap(Box::new(move |event: &web_sys::Event| {
|
||||||
|
log::debug!("Handling event!");
|
||||||
|
|
||||||
|
let target = event
|
||||||
|
.target()
|
||||||
|
.expect("missing target")
|
||||||
|
.dyn_into::<Element>()
|
||||||
|
.expect("not a valid element");
|
||||||
|
|
||||||
|
let typ = event.type_();
|
||||||
|
|
||||||
|
let gi_id: usize = target
|
||||||
|
.get_attribute(&format!("dioxus-giid-{}", typ))
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let gi_gen: u64 = target
|
||||||
|
.get_attribute(&format!("dioxus-gigen-{}", typ))
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let li_idx: usize = target
|
||||||
|
.get_attribute(&format!("dioxus-lidx-{}", typ))
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Call the trigger
|
||||||
|
trigger.0.as_ref()(EventTrigger::new(
|
||||||
|
virtual_event_from_websys_event(event),
|
||||||
|
CbIdx {
|
||||||
|
gi_gen,
|
||||||
|
gi_id,
|
||||||
|
listener_idx: li_idx,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}) as Box<dyn FnMut(&Event)>);
|
||||||
|
|
||||||
|
self.root
|
||||||
|
.add_event_listener_with_callback(event, (&handler).as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Increment the listeners
|
||||||
|
self.listeners.insert(event.into(), (1, handler));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,14 +158,14 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PatchMachine {
|
impl PatchMachine {
|
||||||
pub fn new(root: Element, event_callback: impl Fn(EventTrigger)) -> Self {
|
pub fn new(root: Element, event_callback: impl Fn(EventTrigger) + 'static) -> Self {
|
||||||
let document = window()
|
let document = window()
|
||||||
.expect("must have access to the window")
|
.expect("must have access to the window")
|
||||||
.document()
|
.document()
|
||||||
.expect("must have access to the Document");
|
.expect("must have access to the Document");
|
||||||
|
|
||||||
// attach all listeners to the container element
|
// attach all listeners to the container element
|
||||||
let events = EventDelegater::new(root.clone());
|
let events = EventDelegater::new(root.clone(), event_callback);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
root,
|
root,
|
||||||
@@ -146,31 +198,6 @@ impl PatchMachine {
|
|||||||
// self.templates.get(&id)
|
// self.templates.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// On any listener wakeup, find the listener that generated the event from th e attribute
|
|
||||||
// pub fn init_events_trampoline(&mut self, _trampoline: ()) {
|
|
||||||
pub fn init_events_trampoline(&mut self, event_channel: impl Fn(EventTrigger)) {
|
|
||||||
// self.callback = Some(Closure::wrap(Box::new(move |event: &web_sys::Event| {
|
|
||||||
// let target = event
|
|
||||||
// .target()
|
|
||||||
// .expect("missing target")
|
|
||||||
// .dyn_into::<Element>()
|
|
||||||
// .expect("not a valid element");
|
|
||||||
// let typ = event.type_();
|
|
||||||
// let a: u32 = target
|
|
||||||
// .get_attribute(&format!("dioxus-a-{}", typ))
|
|
||||||
// .and_then(|v| v.parse().ok())
|
|
||||||
// .unwrap_or_default();
|
|
||||||
|
|
||||||
// let b: u32 = target
|
|
||||||
// .get_attribute(&format!("dioxus-b-{}", typ))
|
|
||||||
// .and_then(|v| v.parse().ok())
|
|
||||||
// .unwrap_or_default();
|
|
||||||
|
|
||||||
// // get a and b from the target
|
|
||||||
// trampoline(event.clone(), a, b);
|
|
||||||
// }) as Box<dyn FnMut(&Event)>));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_edit(&mut self, edit: &Edit) {
|
pub fn handle_edit(&mut self, edit: &Edit) {
|
||||||
match *edit {
|
match *edit {
|
||||||
// 0
|
// 0
|
||||||
@@ -319,11 +346,7 @@ impl PatchMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 11
|
// 11
|
||||||
Edit::NewEventListener {
|
Edit::NewEventListener { event_type, idx } => {
|
||||||
event_type,
|
|
||||||
idx: a,
|
|
||||||
b,
|
|
||||||
} => {
|
|
||||||
// attach the correct attributes to the element
|
// attach the correct attributes to the element
|
||||||
// these will be used by accessing the event's target
|
// these will be used by accessing the event's target
|
||||||
// This ensures we only ever have one handler attached to the root, but decide
|
// This ensures we only ever have one handler attached to the root, but decide
|
||||||
@@ -341,24 +364,33 @@ impl PatchMachine {
|
|||||||
// )
|
// )
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
debug!("adding attributes: {}, {}", a, b);
|
// debug!("adding attributes: {}, {}", a, b);
|
||||||
el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
|
||||||
|
let CbIdx {
|
||||||
|
gi_id,
|
||||||
|
gi_gen,
|
||||||
|
listener_idx: lidx,
|
||||||
|
} = idx;
|
||||||
|
|
||||||
|
el.set_attribute(&format!("dioxus-giid-{}", event_type), &gi_id.to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
el.set_attribute(&format!("dioxus-gigen-{}", event_type), &gi_gen.to_string())
|
||||||
|
.unwrap();
|
||||||
|
el.set_attribute(&format!("dioxus-lidx-{}", event_type), &lidx.to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
self.events.add_listener(event_type, gi, listener_id)
|
self.events.add_listener(event_type, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 12
|
// 12
|
||||||
Edit::UpdateEventListener { event_type, a, b } => {
|
Edit::UpdateEventListener { event_type, idx } => {
|
||||||
// update our internal mapping, and then modify the attribute
|
// update our internal mapping, and then modify the attribute
|
||||||
|
|
||||||
if let Some(el) = self.stack.top().dyn_ref::<Element>() {
|
if let Some(el) = self.stack.top().dyn_ref::<Element>() {
|
||||||
el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
// el.set_attribute(&format!("dioxus-a-{}", event_type), &a.to_string())
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
// el.set_attribute(&format!("dioxus-b-{}", event_type), &b.to_string())
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,3 +500,10 @@ impl PatchMachine {
|
|||||||
// // self.templates.contains_key(&id)
|
// // self.templates.contains_key(&id)
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
|
||||||
|
match event.type_().as_str() {
|
||||||
|
"click" => VirtualEvent::MouseEvent(MouseEvent {}),
|
||||||
|
_ => VirtualEvent::OtherEvent,
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
-10
@@ -59,12 +59,19 @@ impl WebsysRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
|
pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
|
||||||
let (sender, mut receiver) = mpsc::unbounded::<EventTrigger>();
|
let (mut sender, mut receiver) = mpsc::unbounded::<EventTrigger>();
|
||||||
|
|
||||||
let body_element = prepare_websys_dom();
|
let body_element = prepare_websys_dom();
|
||||||
let mut patch_machine = interpreter::PatchMachine::new(body_element.clone(), |_| {});
|
|
||||||
|
let mut patch_machine = interpreter::PatchMachine::new(body_element.clone(), move |ev| {
|
||||||
|
log::debug!("Event trigger! {:#?}", ev);
|
||||||
|
let mut c = sender.clone();
|
||||||
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
|
c.send(ev).await.unwrap();
|
||||||
|
});
|
||||||
|
});
|
||||||
let root_node = body_element.first_child().unwrap();
|
let root_node = body_element.first_child().unwrap();
|
||||||
patch_machine.stack.push(root_node);
|
patch_machine.stack.push(root_node.clone());
|
||||||
|
|
||||||
// todo: initialize the event registry properly on the root
|
// todo: initialize the event registry properly on the root
|
||||||
|
|
||||||
@@ -72,17 +79,32 @@ impl WebsysRenderer {
|
|||||||
log::debug!("patching with {:?}", edit);
|
log::debug!("patching with {:?}", edit);
|
||||||
patch_machine.handle_edit(edit);
|
patch_machine.handle_edit(edit);
|
||||||
});
|
});
|
||||||
|
log::debug!("patch stack size {:?}", patch_machine.stack);
|
||||||
|
|
||||||
// Event loop waits for the receiver to finish up
|
// Event loop waits for the receiver to finish up
|
||||||
// TODO! Connect the sender to the virtual dom's suspense system
|
// TODO! Connect the sender to the virtual dom's suspense system
|
||||||
// Suspense is basically an external event that can force renders to specific nodes
|
// Suspense is basically an external event that can force renders to specific nodes
|
||||||
while let Some(event) = receiver.next().await {
|
while let Some(event) = receiver.next().await {
|
||||||
|
log::debug!("patch stack size before {:#?}", patch_machine.stack);
|
||||||
|
// patch_machine.reset();
|
||||||
|
// patch_machine.stack.push(root_node.clone());
|
||||||
self.internal_dom
|
self.internal_dom
|
||||||
.progress_with_event(event)?
|
.progress_with_event(event)?
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|edit| {
|
.for_each(|edit| {
|
||||||
|
log::debug!("edit stream {:?}", edit);
|
||||||
patch_machine.handle_edit(edit);
|
patch_machine.handle_edit(edit);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
log::debug!("patch stack size after {:#?}", patch_machine.stack);
|
||||||
|
patch_machine.reset();
|
||||||
|
// our root node reference gets invalidated
|
||||||
|
// not sure why
|
||||||
|
// for now, just select the first child again.
|
||||||
|
// eventually, we'll just make our own root element instead of using body
|
||||||
|
// or just use body directly IDEK
|
||||||
|
let root_node = body_element.first_child().unwrap();
|
||||||
|
patch_machine.stack.push(root_node.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(()) // should actually never return from this, should be an error, rustc just cant see it
|
Ok(()) // should actually never return from this, should be an error, rustc just cant see it
|
||||||
@@ -146,13 +168,14 @@ mod tests {
|
|||||||
log::info!("Hello!");
|
log::info!("Hello!");
|
||||||
|
|
||||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|ctx, _| {
|
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|ctx, _| {
|
||||||
ctx.view(html! {
|
todo!()
|
||||||
<div>
|
// ctx.view(html! {
|
||||||
"Hello world"
|
// <div>
|
||||||
<button onclick={move |_| log::info!("button1 clicked!")}> "click me" </button>
|
// "Hello world"
|
||||||
<button onclick={move |_| log::info!("button2 clicked!")}> "click me" </button>
|
// <button onclick={move |_| log::info!("button1 clicked!")}> "click me" </button>
|
||||||
</div>
|
// <button onclick={move |_| log::info!("button2 clicked!")}> "click me" </button>
|
||||||
})
|
// </div>
|
||||||
|
// })
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user