feat: proper handling of events

This commit is contained in:
Jonathan Kelley committed 2021-09-22 02:44:01 -04:00
1 parent c7d2d9d050
commit d7940aa2ac
7 files changed
+116 -62

No files matched your search

+3 -2
View File
@@ -4,12 +4,13 @@ use dioxus_core::prelude::*;
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
static App: FC<()> = |cx, props|cx.render(LazyNodes::new(|f| f.text(format_args!("hello")))); static App: FC<()> = |cx, props| cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
let mut dom = VirtualDom::new(App); let mut dom = VirtualDom::new(App);
dom.rebuild(); dom.rebuild();
let deadline = async_std::task::sleep(Duration::from_millis(50)); let deadline = async_std::task::sleep(Duration::from_millis(50));
let _fut = dom.run_with_deadline(deadline);
// let _fut = dom.run_with_deadline(|| deadline.);
} }
+2
View File
@@ -185,6 +185,7 @@ impl<'bump> DiffMachine<'bump> {
/// Returns a `bool` indicating that the work completed properly. /// Returns a `bool` indicating that the work completed properly.
pub fn work(&mut self, mut deadline_expired: impl FnMut() -> bool) -> bool { pub fn work(&mut self, mut deadline_expired: impl FnMut() -> bool) -> bool {
while let Some(instruction) = self.stack.pop() { while let Some(instruction) = self.stack.pop() {
log::debug!("working {:?}", instruction);
match instruction { match instruction {
DiffInstruction::Diff { old, new } => self.diff_node(old, new), DiffInstruction::Diff { old, new } => self.diff_node(old, new),
DiffInstruction::Create { node } => self.create_node(node), DiffInstruction::Create { node } => self.create_node(node),
@@ -194,6 +195,7 @@ impl<'bump> DiffMachine<'bump> {
}; };
if deadline_expired() { if deadline_expired() {
log::debug!("Deadling expired before we could finished!");
return false; return false;
} }
} }
+59 -19
View File
@@ -228,6 +228,12 @@ impl Scheduler {
ScopeId(0) ScopeId(0)
}) as FiberTask); }) as FiberTask);
let saved_state = SavedDiffWork {
mutations: Mutations::new(),
stack: DiffStack::new(),
seen_scopes: Default::default(),
};
Self { Self {
pool, pool,
@@ -250,7 +256,7 @@ impl Scheduler {
garbage_scopes: HashSet::new(), garbage_scopes: HashSet::new(),
dirty_scopes: Default::default(), dirty_scopes: Default::default(),
saved_state: None, saved_state: Some(saved_state),
in_progress: false, in_progress: false,
} }
} }
@@ -262,7 +268,7 @@ impl Scheduler {
if let Some(scope) = self.pool.get_scope_mut(event.scope) { if let Some(scope) = self.pool.get_scope_mut(event.scope) {
if let Some(element) = event.mounted_dom_id { if let Some(element) = event.mounted_dom_id {
// TODO: bubble properly here // TODO: bubble properly here
scope.call_listener(event.event, element); scope.call_listener(event, element);
while let Ok(Some(dirty_scope)) = self.receiver.try_next() { while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
// //
@@ -321,7 +327,7 @@ impl Scheduler {
if let Some(scope) = self.pool.get_scope_mut(event.scope) { if let Some(scope) = self.pool.get_scope_mut(event.scope) {
if let Some(element) = event.mounted_dom_id { if let Some(element) = event.mounted_dom_id {
// TODO: bubble properly here // TODO: bubble properly here
scope.call_listener(event.event, element); scope.call_listener(event, element);
while let Ok(Some(dirty_scope)) = self.receiver.try_next() { while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
// //
@@ -360,31 +366,55 @@ impl Scheduler {
h1.cmp(&h2) h1.cmp(&h2)
}); });
if let Some(scope) = self.dirty_scopes.pop() { if let Some(scopeid) = self.dirty_scopes.pop() {
let component = self.pool.get_scope(scope).unwrap(); let component = self.pool.get_scope(scopeid).unwrap();
let (old, new) = (component.frames.wip_head(), component.frames.fin_head()); let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
// let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
machine.stack.scope_stack.push(scopeid);
machine.stack.push(DiffInstruction::Diff { new, old }); machine.stack.push(DiffInstruction::Diff { new, old });
} }
} }
let deadline_expired = machine.work(deadline_reached); let work_completed = machine.work(deadline_reached);
let machine: DiffMachine<'static> = unsafe { std::mem::transmute(machine) }; log::debug!("Working finished? {:?}", work_completed);
let mut saved = machine.save();
if deadline_expired { log::debug!("raw edits {:?}", machine.mutations.edits);
self.save_work(saved);
false let mut machine: DiffMachine<'static> = unsafe { std::mem::transmute(machine) };
} else { // let mut saved = machine.save();
for node in saved.seen_scopes.drain() {
if work_completed {
for node in machine.seen_scopes.drain() {
// self.dirty_scopes.clear();
// self.ui_events.clear();
self.dirty_scopes.remove(&node); self.dirty_scopes.remove(&node);
// self.dirty_scopes.remove(&node);
} }
let mut new_mutations = Mutations::new(); let mut new_mutations = Mutations::new();
std::mem::swap(&mut new_mutations, &mut saved.mutations);
for edit in machine.mutations.edits.drain(..) {
new_mutations.edits.push(edit);
}
// for edit in saved.edits.drain(..) {
// new_mutations.edits.push(edit);
// }
// std::mem::swap(&mut new_mutations, &mut saved.mutations);
mutations.push(new_mutations); mutations.push(new_mutations);
log::debug!("saved edits {:?}", mutations);
let mut saved = machine.save();
self.save_work(saved); self.save_work(saved);
false
// self.save_work(saved);
// false
} else {
true true
} }
} }
@@ -429,18 +459,28 @@ impl Scheduler {
*/ */
let mut committed_mutations = Vec::<Mutations<'static>>::new(); let mut committed_mutations = Vec::<Mutations<'static>>::new();
loop { while self.has_any_work() {
// switch our priority, pop off any work // switch our priority, pop off any work
for event in self.ui_events.drain(..) { for event in self.ui_events.drain(..) {
if let Some(scope) = self.pool.get_scope_mut(event.scope) { if let Some(scope) = self.pool.get_scope_mut(event.scope) {
if let Some(element) = event.mounted_dom_id { if let Some(element) = event.mounted_dom_id {
log::info!("Calling listener {:?}, {:?}", event.scope, element);
// TODO: bubble properly here // TODO: bubble properly here
scope.call_listener(event.event, element); scope.call_listener(event, element);
while let Ok(Some(dirty_scope)) = self.receiver.try_next() { while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
match dirty_scope { match dirty_scope {
SchedulerMsg::Immediate(im) => { SchedulerMsg::Immediate(im) => {
self.dirty_scopes.insert(im); log::debug!("Handling immediate {:?}", im);
if let Some(scope) = self.pool.get_scope_mut(im) {
if scope.run_scope(&self.pool) {
self.dirty_scopes.insert(im);
} else {
todo!()
}
}
} }
_ => todo!(), _ => todo!(),
} }
@@ -449,10 +489,10 @@ impl Scheduler {
} }
} }
let finished_before_deadline = let deadline_expired =
self.work_on_current_lane(&mut deadline, &mut committed_mutations); self.work_on_current_lane(&mut deadline, &mut committed_mutations);
if !finished_before_deadline { if deadline_expired {
break; break;
} }
} }
+8 -6
View File
@@ -238,22 +238,24 @@ impl Scope {
} }
/// A safe wrapper around calling listeners /// A safe wrapper around calling listeners
pub(crate) fn call_listener(&mut self, event: SyntheticEvent, element: ElementId) { pub(crate) fn call_listener(&mut self, event: UserEvent, element: ElementId) {
let listners = self.listeners.borrow_mut(); let listners = self.listeners.borrow_mut();
let raw_listener = listners.iter().find(|lis| { let raw_listener = listners.iter().find(|lis| {
let search = unsafe { &***lis }; let search = unsafe { &***lis };
let search_id = search.mounted_node.get(); if search.event == event.name {
let search_id = search.mounted_node.get();
// this assumes the node might not be mounted - should we assume that though? search_id.map(|f| f == element).unwrap_or(false)
search_id.map(|f| f == element).unwrap_or(false) } else {
false
}
}); });
if let Some(raw_listener) = raw_listener { if let Some(raw_listener) = raw_listener {
let listener = unsafe { &**raw_listener }; let listener = unsafe { &**raw_listener };
let mut cb = listener.callback.borrow_mut(); let mut cb = listener.callback.borrow_mut();
if let Some(cb) = cb.as_mut() { if let Some(cb) = cb.as_mut() {
(cb)(event); (cb)(event.event);
} }
} else { } else {
log::warn!("An event was triggered but there was no listener to handle it"); log::warn!("An event was triggered but there was no listener to handle it");
+33 -26
View File
@@ -22,36 +22,43 @@ fn main() {
dioxus_web::launch(APP, |c| c) dioxus_web::launch(APP, |c| c)
} }
static APP: FC<()> = |cx, props|{ static APP: FC<()> = |cx, props| {
let mut count = use_state(cx, || 3); let mut count = use_state(cx, || 3);
cx.render(rsx! { cx.render(rsx! {
div { button {
button { // onclick: move |_| count += 1,
onclick: move |_| count += 1, onmouseover: move |_| count += 5,
"Click to add." onmouseout: move |_| count -= 5,
"Current count: {count}" "Click to add."
} "Current count: {count}"
ul {
{(0..*count).map(|f| rsx!{
li { "a - {f}" }
li { "b - {f}" }
li { "c - {f}" }
})}
}
Child {}
} }
// div {
// button {
// onclick: move |_| count += 1,
// "Click to add."
// "Current count: {count}"
// }
// ul {
// {(0..*count).map(|f| rsx!{
// li { "a - {f}" }
// li { "b - {f}" }
// li { "c - {f}" }
// })}
// }
// Child {}
// }
}) })
}; };
static Child: FC<()> = |cx, props|{ // static Child: FC<()> = |cx, props| {
cx.render(rsx! { // cx.render(rsx! {
div { // div {
div { // div {
div { // div {
"hello child" // "hello child"
} // }
} // }
} // }
}) // })
}; // };
+9 -9
View File
@@ -7,9 +7,9 @@ use dioxus_core::{
DomEdit, ElementId, ScopeId, DomEdit, ElementId, ScopeId,
}; };
use fxhash::FxHashMap; use fxhash::FxHashMap;
use wasm_bindgen::{closure::Closure, JsCast}; use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use web_sys::{ use web_sys::{
window, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement, window, Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement,
HtmlOptionElement, Node, NodeList, UiEvent, HtmlOptionElement, Node, NodeList, UiEvent,
}; };
@@ -264,8 +264,8 @@ impl WebsysDom {
) )
.unwrap(); .unwrap();
el.set_attribute(&format!("dioxus-event"), &format!("{}", event)) // el.set_attribute(&format!("dioxus-event"), &format!("{}", event))
.unwrap(); // .unwrap();
// Register the callback to decode // Register the callback to decode
@@ -532,11 +532,11 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result<UserEvent> {
log::debug!("Event type is {:?}", typ); log::debug!("Event type is {:?}", typ);
// let attrs = target.attributes(); let attrs = target.attributes();
// for x in 0..attrs.length() { for x in 0..attrs.length() {
// let attr = attrs.item(x).unwrap(); let attr: Attr = attrs.item(x).unwrap();
// log::debug!("attrs include: {:#?}", attr); log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value());
// } }
use anyhow::Context; use anyhow::Context;
+2
View File
@@ -152,6 +152,8 @@ pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T,
// run the virtualdom work phase until the frame deadline is reached // run the virtualdom work phase until the frame deadline is reached
let mutations = dom.run_with_deadline(|| (&mut deadline).now_or_never().is_some()); let mutations = dom.run_with_deadline(|| (&mut deadline).now_or_never().is_some());
log::debug!("received mutations {:#?}", mutations);
// wait for the animation frame to fire so we can apply our changes // wait for the animation frame to fire so we can apply our changes
work_loop.wait_for_raf().await; work_loop.wait_for_raf().await;