feat: proper handling of events

This commit is contained in:
Jonathan Kelley 2021-09-22 02:44:01 -04:00
parent c7d2d9d050
commit d7940aa2ac
7 changed files with 116 additions and 62 deletions

View file

@ -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.);
}

View file

@ -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;
}
}

View file

@ -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::<Mutations<'static>>::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;
}
}

View file

@ -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");

View file

@ -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"
// }
// }
// }
// })
// };

View file

@ -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<UserEvent> {
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;

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
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;