From d7940aa2ac2017316d62e0f2eac0701dc6ad1f09 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 22 Sep 2021 02:44:01 -0400 Subject: [PATCH] feat: proper handling of events --- packages/core/examples/vdom_usage.rs | 5 +- packages/core/src/diff.rs | 2 + packages/core/src/scheduler.rs | 78 +++++++++++++++++++++------- packages/core/src/scope.rs | 14 ++--- packages/web/examples/basic.rs | 59 +++++++++++---------- packages/web/src/dom.rs | 18 +++---- packages/web/src/lib.rs | 2 + 7 files changed, 116 insertions(+), 62 deletions(-) diff --git a/packages/core/examples/vdom_usage.rs b/packages/core/examples/vdom_usage.rs index 1793b030b..7175a167d 100644 --- a/packages/core/examples/vdom_usage.rs +++ b/packages/core/examples/vdom_usage.rs @@ -4,12 +4,13 @@ use dioxus_core::prelude::*; #[async_std::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); dom.rebuild(); let deadline = async_std::task::sleep(Duration::from_millis(50)); - let _fut = dom.run_with_deadline(deadline); + + // let _fut = dom.run_with_deadline(|| deadline.); } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 838359e82..b360cba35 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -185,6 +185,7 @@ impl<'bump> DiffMachine<'bump> { /// Returns a `bool` indicating that the work completed properly. pub fn work(&mut self, mut deadline_expired: impl FnMut() -> bool) -> bool { while let Some(instruction) = self.stack.pop() { + log::debug!("working {:?}", instruction); match instruction { DiffInstruction::Diff { old, new } => self.diff_node(old, new), DiffInstruction::Create { node } => self.create_node(node), @@ -194,6 +195,7 @@ impl<'bump> DiffMachine<'bump> { }; if deadline_expired() { + log::debug!("Deadling expired before we could finished!"); return false; } } diff --git a/packages/core/src/scheduler.rs b/packages/core/src/scheduler.rs index 922cfa2fa..588b496a4 100644 --- a/packages/core/src/scheduler.rs +++ b/packages/core/src/scheduler.rs @@ -228,6 +228,12 @@ impl Scheduler { ScopeId(0) }) as FiberTask); + let saved_state = SavedDiffWork { + mutations: Mutations::new(), + stack: DiffStack::new(), + seen_scopes: Default::default(), + }; + Self { pool, @@ -250,7 +256,7 @@ impl Scheduler { garbage_scopes: HashSet::new(), dirty_scopes: Default::default(), - saved_state: None, + saved_state: Some(saved_state), in_progress: false, } } @@ -262,7 +268,7 @@ impl Scheduler { if let Some(scope) = self.pool.get_scope_mut(event.scope) { if let Some(element) = event.mounted_dom_id { // 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() { // @@ -321,7 +327,7 @@ impl Scheduler { if let Some(scope) = self.pool.get_scope_mut(event.scope) { if let Some(element) = event.mounted_dom_id { // 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() { // @@ -360,31 +366,55 @@ impl Scheduler { h1.cmp(&h2) }); - if let Some(scope) = self.dirty_scopes.pop() { - let component = self.pool.get_scope(scope).unwrap(); + if let Some(scopeid) = self.dirty_scopes.pop() { + 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()); + machine.stack.scope_stack.push(scopeid); 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) }; - let mut saved = machine.save(); + log::debug!("Working finished? {:?}", work_completed); - if deadline_expired { - self.save_work(saved); - false - } else { - for node in saved.seen_scopes.drain() { + log::debug!("raw edits {:?}", machine.mutations.edits); + + let mut machine: DiffMachine<'static> = unsafe { std::mem::transmute(machine) }; + // let mut saved = machine.save(); + + 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); } 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); + + log::debug!("saved edits {:?}", mutations); + + let mut saved = machine.save(); self.save_work(saved); + false + + // self.save_work(saved); + // false + } else { true } } @@ -429,18 +459,28 @@ impl Scheduler { */ let mut committed_mutations = Vec::>::new(); - loop { + while self.has_any_work() { // switch our priority, pop off any work for event in self.ui_events.drain(..) { if let Some(scope) = self.pool.get_scope_mut(event.scope) { if let Some(element) = event.mounted_dom_id { + log::info!("Calling listener {:?}, {:?}", event.scope, element); + // 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() { match dirty_scope { 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!(), } @@ -449,10 +489,10 @@ impl Scheduler { } } - let finished_before_deadline = + let deadline_expired = self.work_on_current_lane(&mut deadline, &mut committed_mutations); - if !finished_before_deadline { + if deadline_expired { break; } } diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index 4ae5d0d1a..19006042e 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -238,22 +238,24 @@ impl Scope { } /// 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 raw_listener = listners.iter().find(|lis| { let search = unsafe { &***lis }; - 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) + 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(raw_listener) = raw_listener { let listener = unsafe { &**raw_listener }; let mut cb = listener.callback.borrow_mut(); if let Some(cb) = cb.as_mut() { - (cb)(event); + (cb)(event.event); } } else { log::warn!("An event was triggered but there was no listener to handle it"); diff --git a/packages/web/examples/basic.rs b/packages/web/examples/basic.rs index 56eb1f74d..2badc320a 100644 --- a/packages/web/examples/basic.rs +++ b/packages/web/examples/basic.rs @@ -22,36 +22,43 @@ fn main() { dioxus_web::launch(APP, |c| c) } -static APP: FC<()> = |cx, props|{ +static APP: FC<()> = |cx, props| { let mut count = use_state(cx, || 3); cx.render(rsx! { - 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 {} + button { + // onclick: move |_| count += 1, + onmouseover: move |_| count += 5, + onmouseout: move |_| count -= 5, + "Click to add." + "Current count: {count}" } + // 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|{ - cx.render(rsx! { - div { - div { - div { - "hello child" - } - } - } - }) -}; +// static Child: FC<()> = |cx, props| { +// cx.render(rsx! { +// div { +// div { +// div { +// "hello child" +// } +// } +// } +// }) +// }; diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 3957a1f74..80c87f967 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -7,9 +7,9 @@ use dioxus_core::{ DomEdit, ElementId, ScopeId, }; use fxhash::FxHashMap; -use wasm_bindgen::{closure::Closure, JsCast}; +use wasm_bindgen::{closure::Closure, JsCast, JsValue}; use web_sys::{ - window, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement, + window, Attr, CssStyleDeclaration, Document, Element, Event, HtmlElement, HtmlInputElement, HtmlOptionElement, Node, NodeList, UiEvent, }; @@ -264,8 +264,8 @@ impl WebsysDom { ) .unwrap(); - el.set_attribute(&format!("dioxus-event"), &format!("{}", event)) - .unwrap(); + // el.set_attribute(&format!("dioxus-event"), &format!("{}", event)) + // .unwrap(); // Register the callback to decode @@ -532,11 +532,11 @@ fn decode_trigger(event: &web_sys::Event) -> anyhow::Result { log::debug!("Event type is {:?}", typ); - // let attrs = target.attributes(); - // for x in 0..attrs.length() { - // let attr = attrs.item(x).unwrap(); - // log::debug!("attrs include: {:#?}", attr); - // } + let attrs = target.attributes(); + for x in 0..attrs.length() { + let attr: Attr = attrs.item(x).unwrap(); + log::debug!("attrs include: {:#?}, {:#?}", attr.name(), attr.value()); + } use anyhow::Context; diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 6c4054b77..c4ae4e9bf 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -152,6 +152,8 @@ pub async fn run_with_props(root: FC, root_props: T, // run the virtualdom work phase until the frame deadline is reached 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 work_loop.wait_for_raf().await;