feat: proper handling of events
This commit is contained in:
1 parent
c7d2d9d050
commit
d7940aa2ac
7 files changed
+116
-62
No files matched your search
@@ -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.);
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
};
|
// };
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user