mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-27 06:30:20 +00:00
bugs: fix web list issue
This commit is contained in:
parent
4a0bb8cf84
commit
da4423c141
8 changed files with 112 additions and 48 deletions
|
@ -3,8 +3,8 @@ use dioxus::prelude::*;
|
||||||
use im_rc::HashMap;
|
use im_rc::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() {
|
||||||
dioxus::desktop::launch(App, |c| c)
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
|
|
@ -330,9 +330,6 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !children.is_empty() {
|
if !children.is_empty() {
|
||||||
// self.stack.element_id_stack.push(real_id);
|
|
||||||
// push our element_id onto the stack
|
|
||||||
// drop our element off the stack
|
|
||||||
self.stack.create_children(children, MountType::Append);
|
self.stack.create_children(children, MountType::Append);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,11 +540,15 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_comitted {
|
if old.children.len() == 0 && new.children.len() != 0 {
|
||||||
self.mutations.pop();
|
please_commit(&mut self.mutations.edits);
|
||||||
|
self.stack.create_children(new.children, MountType::Append);
|
||||||
|
} else {
|
||||||
|
self.diff_children(old.children, new.children);
|
||||||
|
if has_comitted {
|
||||||
|
self.mutations.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.diff_children(old.children, new.children);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_component_nodes(
|
fn diff_component_nodes(
|
||||||
|
@ -601,6 +602,9 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_assert!(old.children.len() != 0);
|
||||||
|
debug_assert!(new.children.len() != 0);
|
||||||
|
|
||||||
self.diff_children(old.children, new.children);
|
self.diff_children(old.children, new.children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,6 +637,7 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
match (old, new) {
|
match (old, new) {
|
||||||
([], []) => {}
|
([], []) => {}
|
||||||
([], _) => {
|
([], _) => {
|
||||||
|
// we need to push the
|
||||||
self.stack.create_children(new, MountType::Append);
|
self.stack.create_children(new, MountType::Append);
|
||||||
}
|
}
|
||||||
(_, []) => {
|
(_, []) => {
|
||||||
|
@ -761,13 +766,57 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
right_offset,
|
right_offset,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
log::debug!("stack before lo is {:#?}", self.stack.instructions);
|
||||||
// Ok, we now hopefully have a smaller range of children in the middle
|
// Ok, we now hopefully have a smaller range of children in the middle
|
||||||
// within which to re-order nodes with the same keys, remove old nodes with
|
// within which to re-order nodes with the same keys, remove old nodes with
|
||||||
// now-unused keys, and create new nodes with fresh keys.
|
// now-unused keys, and create new nodes with fresh keys.
|
||||||
self.diff_keyed_middle(
|
|
||||||
&old[left_offset..(old.len() - right_offset)],
|
let old_middle = &old[left_offset..(old.len() - right_offset)];
|
||||||
&new[left_offset..(new.len() - right_offset)],
|
let new_middle = &new[left_offset..(new.len() - right_offset)];
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
!((old_middle.len() == new_middle.len()) && old_middle.len() == 0),
|
||||||
|
"keyed children must have the same number of children"
|
||||||
);
|
);
|
||||||
|
if new_middle.len() == 0 {
|
||||||
|
// remove the old elements
|
||||||
|
self.remove_nodes(old_middle);
|
||||||
|
} else if old_middle.len() == 0 {
|
||||||
|
// there were no old elements, so just create the new elements
|
||||||
|
// we need to find the right "foothold" though - we shouldnt use the "append" at all
|
||||||
|
if left_offset == 0 {
|
||||||
|
// insert at the beginning of the old list
|
||||||
|
let foothold = &old[old.len() - right_offset];
|
||||||
|
self.stack.create_children(
|
||||||
|
new_middle,
|
||||||
|
MountType::InsertBefore {
|
||||||
|
other_node: foothold,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if right_offset == 0 {
|
||||||
|
// insert at the end the old list
|
||||||
|
let foothold = old.last().unwrap();
|
||||||
|
self.stack.create_children(
|
||||||
|
new_middle,
|
||||||
|
MountType::InsertAfter {
|
||||||
|
other_node: foothold,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// inserting in the middle
|
||||||
|
let foothold = &old[left_offset - 1];
|
||||||
|
self.stack.create_children(
|
||||||
|
new_middle,
|
||||||
|
MountType::InsertAfter {
|
||||||
|
other_node: foothold,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.diff_keyed_middle(old_middle, new_middle);
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("stack after km is {:#?}", self.stack.instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Diff both ends of the children that share keys.
|
/// Diff both ends of the children that share keys.
|
||||||
|
@ -893,6 +942,14 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
// If none of the old keys are reused by the new children, then we remove all the remaining old children and
|
// If none of the old keys are reused by the new children, then we remove all the remaining old children and
|
||||||
// create the new children afresh.
|
// create the new children afresh.
|
||||||
if shared_keys.is_empty() {
|
if shared_keys.is_empty() {
|
||||||
|
log::debug!(
|
||||||
|
"no shared keys, replacing and creating many with many, {:#?}, {:#?}",
|
||||||
|
old,
|
||||||
|
new
|
||||||
|
);
|
||||||
|
log::debug!("old_key_to_old_index, {:#?}", old_key_to_old_index);
|
||||||
|
log::debug!("new_index_to_old_index, {:#?}", new_index_to_old_index);
|
||||||
|
log::debug!("shared_keys, {:#?}", shared_keys);
|
||||||
self.replace_and_create_many_with_many(old, new);
|
self.replace_and_create_many_with_many(old, new);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub enum MountType<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DiffStack<'bump> {
|
pub(crate) struct DiffStack<'bump> {
|
||||||
instructions: Vec<DiffInstruction<'bump>>,
|
pub(crate) instructions: Vec<DiffInstruction<'bump>>,
|
||||||
nodes_created_stack: SmallVec<[usize; 10]>,
|
nodes_created_stack: SmallVec<[usize; 10]>,
|
||||||
pub scope_stack: SmallVec<[ScopeId; 5]>,
|
pub scope_stack: SmallVec<[ScopeId; 5]>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,8 +107,6 @@ pub enum SchedulerMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TaskMsg {
|
pub enum TaskMsg {
|
||||||
// SubmitTask(FiberTask, u64),
|
|
||||||
// SubmitTask(FiberTask, u64),
|
|
||||||
ToggleTask(u64),
|
ToggleTask(u64),
|
||||||
PauseTask(u64),
|
PauseTask(u64),
|
||||||
ResumeTask(u64),
|
ResumeTask(u64),
|
||||||
|
@ -322,6 +320,9 @@ impl Scheduler {
|
||||||
unsafe fn load_work(&mut self) -> SavedDiffWork<'static> {
|
unsafe fn load_work(&mut self) -> SavedDiffWork<'static> {
|
||||||
self.saved_state.take().unwrap().extend()
|
self.saved_state.take().unwrap().extend()
|
||||||
}
|
}
|
||||||
|
pub fn handle_task(&mut self, evt: TaskMsg) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
|
pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
|
||||||
match msg {
|
match msg {
|
||||||
|
@ -480,6 +481,18 @@ impl Scheduler {
|
||||||
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
||||||
|
|
||||||
while self.has_any_work() {
|
while self.has_any_work() {
|
||||||
|
while let Ok(Some(msg)) = self.receiver.try_next() {
|
||||||
|
match msg {
|
||||||
|
SchedulerMsg::Task(t) => todo!(),
|
||||||
|
SchedulerMsg::Immediate(im) => {
|
||||||
|
self.dirty_scopes.insert(im);
|
||||||
|
}
|
||||||
|
SchedulerMsg::UiEvent(evt) => {
|
||||||
|
self.ui_events.push_back(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// switch our priority, pop off any work
|
// switch our priority, pop off any work
|
||||||
while let Some(event) = self.ui_events.pop_front() {
|
while let Some(event) = self.ui_events.pop_front() {
|
||||||
if let Some(scope) = self.pool.get_scope_mut(event.scope) {
|
if let Some(scope) = self.pool.get_scope_mut(event.scope) {
|
||||||
|
|
|
@ -360,25 +360,21 @@ impl VirtualDom {
|
||||||
/// Waits for the scheduler to have work
|
/// Waits for the scheduler to have work
|
||||||
/// This lets us poll async tasks during idle periods without blocking the main thread.
|
/// This lets us poll async tasks during idle periods without blocking the main thread.
|
||||||
pub async fn wait_for_work(&mut self) {
|
pub async fn wait_for_work(&mut self) {
|
||||||
|
// todo: poll the events once even if there is work to do to prevent starvation
|
||||||
if self.scheduler.has_any_work() {
|
if self.scheduler.has_any_work() {
|
||||||
log::debug!("No need to wait for work, we already have some");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("No active work.... waiting for some...");
|
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
|
|
||||||
// right now this won't poll events if there is ongoing work
|
|
||||||
// in the future we want to prioritize some events over ongoing work
|
|
||||||
// this is coming in the "priorities" PR
|
|
||||||
|
|
||||||
// Wait for any new events if we have nothing to do
|
// Wait for any new events if we have nothing to do
|
||||||
// todo: poll the events once even if there is work to do to prevent starvation
|
|
||||||
futures_util::select! {
|
futures_util::select! {
|
||||||
_ = self.scheduler.async_tasks.next() => {}
|
_ = self.scheduler.async_tasks.next() => {}
|
||||||
msg = self.scheduler.receiver.next() => {
|
msg = self.scheduler.receiver.next() => {
|
||||||
match msg.unwrap() {
|
match msg.unwrap() {
|
||||||
SchedulerMsg::Task(t) => todo!(),
|
SchedulerMsg::Task(t) => {
|
||||||
|
self.scheduler.handle_task(t);
|
||||||
|
},
|
||||||
SchedulerMsg::Immediate(im) => {
|
SchedulerMsg::Immediate(im) => {
|
||||||
self.scheduler.dirty_scopes.insert(im);
|
self.scheduler.dirty_scopes.insert(im);
|
||||||
}
|
}
|
||||||
|
@ -388,18 +384,6 @@ impl VirtualDom {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Ok(Some(msg)) = self.scheduler.receiver.try_next() {
|
|
||||||
match msg {
|
|
||||||
SchedulerMsg::Task(t) => todo!(),
|
|
||||||
SchedulerMsg::Immediate(im) => {
|
|
||||||
self.scheduler.dirty_scopes.insert(im);
|
|
||||||
}
|
|
||||||
SchedulerMsg::UiEvent(evt) => {
|
|
||||||
self.scheduler.ui_events.push_back(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,8 +121,8 @@ impl<'a, T: 'static> UseState<'a, T> {
|
||||||
self.inner.wip.borrow_mut()
|
self.inner.wip.borrow_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn classic(self) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
pub fn classic(self) -> (&'a T, Rc<dyn Fn(T)>) {
|
||||||
todo!()
|
(&self.inner.current_val, self.setter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setter(&self) -> Rc<dyn Fn(T)> {
|
pub fn setter(&self) -> Rc<dyn Fn(T)> {
|
||||||
|
|
|
@ -1530,7 +1530,7 @@ builder_constructors! {
|
||||||
// This has a manual implementation below
|
// This has a manual implementation below
|
||||||
// r#type: InputType,
|
// r#type: InputType,
|
||||||
|
|
||||||
value: String,
|
// value: String,
|
||||||
width: isize,
|
width: isize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1538,7 +1538,7 @@ builder_constructors! {
|
||||||
/// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
|
/// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
|
||||||
/// element.
|
/// element.
|
||||||
label {
|
label {
|
||||||
r#for: Id,
|
// r#for: Id,
|
||||||
form: Id,
|
form: Id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1694,6 +1694,10 @@ impl input {
|
||||||
pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
pub fn r#type<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||||
cx.attr("type", val, None, false)
|
cx.attr("type", val, None, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn value<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||||
|
cx.attr("value", val, None, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1717,6 +1721,11 @@ impl textarea {
|
||||||
cx.attr("value", val, None, true)
|
cx.attr("value", val, None, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl label {
|
||||||
|
pub fn r#for<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
|
||||||
|
cx.attr("for", val, None, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait SvgAttributes {
|
pub trait SvgAttributes {
|
||||||
aria_trait_methods! {
|
aria_trait_methods! {
|
||||||
|
|
|
@ -211,7 +211,7 @@ impl WebsysDom {
|
||||||
|
|
||||||
fn create_placeholder(&mut self, id: u64) {
|
fn create_placeholder(&mut self, id: u64) {
|
||||||
self.create_element("pre", None, id);
|
self.create_element("pre", None, id);
|
||||||
self.set_attribute("hidden", "", None);
|
// self.set_attribute("hidden", "", None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_text_node(&mut self, text: &str, id: u64) {
|
fn create_text_node(&mut self, text: &str, id: u64) {
|
||||||
|
@ -244,6 +244,9 @@ impl WebsysDom {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let el2 = el.dyn_ref::<Element>().unwrap();
|
||||||
|
el2.set_attribute("dioxus-id", &format!("{}", id)).unwrap();
|
||||||
|
|
||||||
self.stack.push(el.clone());
|
self.stack.push(el.clone());
|
||||||
self.nodes[(id as usize)] = Some(el);
|
self.nodes[(id as usize)] = Some(el);
|
||||||
}
|
}
|
||||||
|
@ -400,18 +403,16 @@ impl WebsysDom {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_before(&mut self, n: u32, root: u64) {
|
fn insert_before(&mut self, n: u32, root: u64) {
|
||||||
let after = self.nodes[root as usize].as_ref().unwrap();
|
let anchor = self.nodes[root as usize].as_ref().unwrap();
|
||||||
|
|
||||||
if n == 1 {
|
if n == 1 {
|
||||||
let before = self.stack.pop();
|
let before = self.stack.pop();
|
||||||
|
|
||||||
after
|
anchor
|
||||||
.parent_node()
|
.parent_node()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert_before(&before, Some(&after))
|
.insert_before(&before, Some(&anchor))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
after.insert_before(&before, None).unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
let arr: js_sys::Array = self
|
let arr: js_sys::Array = self
|
||||||
.stack
|
.stack
|
||||||
|
@ -419,11 +420,11 @@ impl WebsysDom {
|
||||||
.drain((self.stack.list.len() - n as usize)..)
|
.drain((self.stack.list.len() - n as usize)..)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some(el) = after.dyn_ref::<Element>() {
|
if let Some(el) = anchor.dyn_ref::<Element>() {
|
||||||
el.before_with_node(&arr).unwrap();
|
el.before_with_node(&arr).unwrap();
|
||||||
} else if let Some(el) = after.dyn_ref::<web_sys::CharacterData>() {
|
} else if let Some(el) = anchor.dyn_ref::<web_sys::CharacterData>() {
|
||||||
el.before_with_node(&arr).unwrap();
|
el.before_with_node(&arr).unwrap();
|
||||||
} else if let Some(el) = after.dyn_ref::<web_sys::DocumentType>() {
|
} else if let Some(el) = anchor.dyn_ref::<web_sys::DocumentType>() {
|
||||||
el.before_with_node(&arr).unwrap();
|
el.before_with_node(&arr).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue