mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
feat: proper handling of events
This commit is contained in:
parent
c7d2d9d050
commit
d7940aa2ac
7 changed files with 116 additions and 62 deletions
|
@ -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.);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// };
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue