create node watcher API
This commit is contained in:
1 parent
93f64d91c9
commit
bd07d7754c
9 files changed
+294
-339
No files matched your search
@@ -77,14 +77,14 @@ impl DioxusState {
|
|||||||
}
|
}
|
||||||
CreatePlaceholder { id } => {
|
CreatePlaceholder { id } => {
|
||||||
let node = NodeType::Placeholder;
|
let node = NodeType::Placeholder;
|
||||||
let node = rdom.create_node(node, true);
|
let node = rdom.create_node(node);
|
||||||
let node_id = node.id();
|
let node_id = node.id();
|
||||||
self.set_element_id(node, id);
|
self.set_element_id(node, id);
|
||||||
self.stack.push(node_id);
|
self.stack.push(node_id);
|
||||||
}
|
}
|
||||||
CreateTextNode { value, id } => {
|
CreateTextNode { value, id } => {
|
||||||
let node_data = NodeType::Text(value.to_string());
|
let node_data = NodeType::Text(value.to_string());
|
||||||
let node = rdom.create_node(node_data, true);
|
let node = rdom.create_node(node_data);
|
||||||
let node_id = node.id();
|
let node_id = node.id();
|
||||||
self.set_element_id(node, id);
|
self.set_element_id(node, id);
|
||||||
self.stack.push(node_id);
|
self.stack.push(node_id);
|
||||||
@@ -228,20 +228,16 @@ fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId {
|
|||||||
.collect(),
|
.collect(),
|
||||||
listeners: FxHashSet::default(),
|
listeners: FxHashSet::default(),
|
||||||
});
|
});
|
||||||
let node_id = rdom.create_node(node, true).id();
|
let node_id = rdom.create_node(node).id();
|
||||||
for child in *children {
|
for child in *children {
|
||||||
let child_id = create_template_node(rdom, child);
|
let child_id = create_template_node(rdom, child);
|
||||||
rdom.add_child(node_id, child_id);
|
rdom.add_child(node_id, child_id);
|
||||||
}
|
}
|
||||||
node_id
|
node_id
|
||||||
}
|
}
|
||||||
TemplateNode::Text { text } => rdom
|
TemplateNode::Text { text } => rdom.create_node(NodeType::Text(text.to_string())).id(),
|
||||||
.create_node(NodeType::Text(text.to_string()), true)
|
TemplateNode::Dynamic { .. } => rdom.create_node(NodeType::Placeholder).id(),
|
||||||
.id(),
|
TemplateNode::DynamicText { .. } => rdom.create_node(NodeType::Text(String::new())).id(),
|
||||||
TemplateNode::Dynamic { .. } => rdom.create_node(NodeType::Placeholder, true).id(),
|
|
||||||
TemplateNode::DynamicText { .. } => {
|
|
||||||
rdom.create_node(NodeType::Text(String::new()), true).id()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ pub mod dioxus;
|
|||||||
pub mod layout_attributes;
|
pub mod layout_attributes;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod node_ref;
|
pub mod node_ref;
|
||||||
|
pub mod node_watcher;
|
||||||
mod passes;
|
mod passes;
|
||||||
pub mod real_dom;
|
pub mod real_dom;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
@@ -22,7 +23,7 @@ pub mod prelude {
|
|||||||
pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView};
|
pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView};
|
||||||
pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
|
||||||
pub use crate::passes::{Dependancy, Pass};
|
pub use crate::passes::{Dependancy, Pass};
|
||||||
pub use crate::real_dom::{NodeImmutable, NodeMut, NodeMutRaw, NodeMutable, NodeRef, RealDom};
|
pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom};
|
||||||
pub use crate::tree::NodeId;
|
pub use crate::tree::NodeId;
|
||||||
pub use crate::SendAnyMap;
|
pub use crate::SendAnyMap;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
use crate::{node::FromAnyValue, NodeMut};
|
||||||
|
|
||||||
|
/// A trait for watching for changes in the DOM tree.
|
||||||
|
pub trait NodeWatcher<V: FromAnyValue + Send + Sync> {
|
||||||
|
/// Called after a node is added to the tree.
|
||||||
|
fn on_node_added(&self, _node: NodeMut<V>) {}
|
||||||
|
/// Called before a node is removed from the tree.
|
||||||
|
fn on_node_removed(&self, _node: NodeMut<V>) {}
|
||||||
|
/// Called after a node is moved to a new parent.
|
||||||
|
fn on_node_moved(&self, _node: NodeMut<V>) {}
|
||||||
|
// /// Called after the text content of a node is changed.
|
||||||
|
// fn on_text_changed(&self, _node: NodeMut<V>) {}
|
||||||
|
// /// Called after an attribute of an element is changed.
|
||||||
|
// fn on_attribute_changed(&self, _node: NodeMut<V>, attribute: &str) {}
|
||||||
|
}
|
||||||
@@ -380,12 +380,12 @@ impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
|||||||
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||||
|
|
||||||
pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
|
pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
|
||||||
tree: &mut RealDom<V>,
|
dom: &mut RealDom<V>,
|
||||||
dirty_nodes: DirtyNodeStates,
|
dirty_nodes: DirtyNodeStates,
|
||||||
ctx: SendAnyMap,
|
ctx: SendAnyMap,
|
||||||
parallel: bool,
|
parallel: bool,
|
||||||
) -> FxDashSet<NodeId> {
|
) -> FxDashSet<NodeId> {
|
||||||
let passes = &tree.passes;
|
let passes = &dom.dirty_nodes.passes;
|
||||||
let mut resolved_passes: FxHashSet<TypeId> = FxHashSet::default();
|
let mut resolved_passes: FxHashSet<TypeId> = FxHashSet::default();
|
||||||
let mut resolving = Vec::new();
|
let mut resolving = Vec::new();
|
||||||
let nodes_updated = Arc::new(FxDashSet::default());
|
let nodes_updated = Arc::new(FxDashSet::default());
|
||||||
@@ -393,7 +393,7 @@ pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
|
|||||||
let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::<Vec<_>>();
|
let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::<Vec<_>>();
|
||||||
while !pass_indexes_remaining.is_empty() {
|
while !pass_indexes_remaining.is_empty() {
|
||||||
let mut currently_in_use = FxHashSet::<TypeId>::default();
|
let mut currently_in_use = FxHashSet::<TypeId>::default();
|
||||||
let dynamically_borrowed_tree = tree.tree.dynamically_borrowed();
|
let dynamically_borrowed_tree = dom.tree.dynamically_borrowed();
|
||||||
rayon::in_place_scope(|s| {
|
rayon::in_place_scope(|s| {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < pass_indexes_remaining.len() {
|
while i < pass_indexes_remaining.len() {
|
||||||
|
|||||||
@@ -2,20 +2,22 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
|||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use crate::node::{
|
use crate::node::{
|
||||||
ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue,
|
ElementNode, FromAnyValue, NodeType, OwnedAttributeDiscription, OwnedAttributeValue,
|
||||||
};
|
};
|
||||||
use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
use crate::node_ref::{NodeMask, NodeMaskBuilder};
|
||||||
|
use crate::node_watcher::NodeWatcher;
|
||||||
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
|
||||||
use crate::prelude::AttributeMaskBuilder;
|
use crate::prelude::AttributeMaskBuilder;
|
||||||
use crate::tree::{NodeId, Tree};
|
use crate::tree::{NodeId, Tree};
|
||||||
use crate::{FxDashSet, SendAnyMap};
|
use crate::{FxDashSet, SendAnyMap};
|
||||||
|
|
||||||
struct NodesDirty<V: FromAnyValue + Send + Sync> {
|
pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
|
||||||
passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
|
passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
|
||||||
nodes_updated: FxHashMap<NodeId, NodeMask>,
|
nodes_updated: FxHashMap<NodeId, NodeMask>,
|
||||||
passes: Rc<Box<[TypeErasedPass<V>]>>,
|
pub(crate) passes: Box<[TypeErasedPass<V>]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
||||||
@@ -35,7 +37,7 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
|||||||
|
|
||||||
fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
|
fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
|
||||||
let hm = self.passes_updated.entry(node_id).or_default();
|
let hm = self.passes_updated.entry(node_id).or_default();
|
||||||
for pass in &**self.passes {
|
for pass in &*self.passes {
|
||||||
if pass.parent_dependant {
|
if pass.parent_dependant {
|
||||||
hm.insert(pass.this_type_id);
|
hm.insert(pass.this_type_id);
|
||||||
}
|
}
|
||||||
@@ -44,7 +46,7 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
|||||||
|
|
||||||
fn mark_child_changed(&mut self, node_id: NodeId) {
|
fn mark_child_changed(&mut self, node_id: NodeId) {
|
||||||
let hm = self.passes_updated.entry(node_id).or_default();
|
let hm = self.passes_updated.entry(node_id).or_default();
|
||||||
for pass in &**self.passes {
|
for pass in &*self.passes {
|
||||||
if pass.child_dependant {
|
if pass.child_dependant {
|
||||||
hm.insert(pass.this_type_id);
|
hm.insert(pass.this_type_id);
|
||||||
}
|
}
|
||||||
@@ -52,6 +54,8 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeWatchers<V> = Rc<RwLock<Vec<Box<dyn NodeWatcher<V>>>>>;
|
||||||
|
|
||||||
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
||||||
/// The render state passes from parent to children and or accumulates state from children to parents.
|
/// The render state passes from parent to children and or accumulates state from children to parents.
|
||||||
/// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes.
|
/// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes.
|
||||||
@@ -61,8 +65,8 @@ impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
|
|||||||
pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
|
pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
|
||||||
pub(crate) tree: Tree,
|
pub(crate) tree: Tree,
|
||||||
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
|
||||||
pub(crate) passes: Rc<Box<[TypeErasedPass<V>]>>,
|
pub(crate) dirty_nodes: NodesDirty<V>,
|
||||||
dirty_nodes: NodesDirty<V>,
|
node_watchers: NodeWatchers<V>,
|
||||||
phantom: std::marker::PhantomData<V>,
|
phantom: std::marker::PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +98,6 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let passes = Rc::new(passes);
|
|
||||||
|
|
||||||
let mut passes_updated = FxHashMap::default();
|
let mut passes_updated = FxHashMap::default();
|
||||||
let mut nodes_updated = FxHashMap::default();
|
let mut nodes_updated = FxHashMap::default();
|
||||||
@@ -106,34 +109,32 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
RealDom {
|
RealDom {
|
||||||
tree,
|
tree,
|
||||||
nodes_listening: FxHashMap::default(),
|
nodes_listening: FxHashMap::default(),
|
||||||
passes: passes.clone(),
|
|
||||||
dirty_nodes: NodesDirty {
|
dirty_nodes: NodesDirty {
|
||||||
passes_updated,
|
passes_updated,
|
||||||
nodes_updated,
|
nodes_updated,
|
||||||
passes,
|
passes,
|
||||||
},
|
},
|
||||||
|
node_watchers: Default::default(),
|
||||||
phantom: std::marker::PhantomData,
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_node(&mut self, node: NodeType<V>, mark_dirty: bool) -> NodeMut<'_, V> {
|
pub fn create_node(&mut self, node: NodeType<V>) -> NodeMut<'_, V> {
|
||||||
let mut node_entry = self.tree.create_node();
|
let mut node_entry = self.tree.create_node();
|
||||||
let id = node_entry.id();
|
let id = node_entry.id();
|
||||||
if mark_dirty {
|
self.dirty_nodes
|
||||||
self.dirty_nodes
|
.passes_updated
|
||||||
.passes_updated
|
.entry(id)
|
||||||
.entry(id)
|
.or_default()
|
||||||
.or_default()
|
.extend(self.dirty_nodes.passes.iter().map(|x| x.this_type_id));
|
||||||
.extend(self.passes.iter().map(|x| x.this_type_id));
|
|
||||||
}
|
|
||||||
node_entry.insert(node);
|
node_entry.insert(node);
|
||||||
|
let watchers = self.node_watchers.clone();
|
||||||
|
for watcher in &*watchers.read().unwrap() {
|
||||||
|
watcher.on_node_added(NodeMut::new(id, self));
|
||||||
|
}
|
||||||
NodeMut::new(id, self)
|
NodeMut::new(id, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_child(&mut self, node_id: NodeId, child_id: NodeId) {
|
|
||||||
self.tree.add_child(node_id, child_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
|
/// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
|
||||||
/// This can be useful to avoid creating duplicate events.
|
/// This can be useful to avoid creating duplicate events.
|
||||||
pub fn get_listening_sorted(&self, event: &str) -> Vec<NodeRef<V>> {
|
pub fn get_listening_sorted(&self, event: &str) -> Vec<NodeRef<V>> {
|
||||||
@@ -166,12 +167,12 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
pub fn clone_node(&mut self, node_id: NodeId) -> NodeId {
|
pub fn clone_node(&mut self, node_id: NodeId) -> NodeId {
|
||||||
let node = self.get(node_id).unwrap();
|
let node = self.get(node_id).unwrap();
|
||||||
let new_node = node.node_type().clone();
|
let new_node = node.node_type().clone();
|
||||||
let new_id = self.create_node(new_node, true).id();
|
let new_id = self.create_node(new_node).id();
|
||||||
|
|
||||||
let children = self.tree.children_ids(node_id).unwrap().to_vec();
|
let children = self.tree.children_ids(node_id).unwrap().to_vec();
|
||||||
for child in children {
|
for child in children {
|
||||||
let child_id = self.clone_node(child);
|
let child_id = self.clone_node(child);
|
||||||
self.add_child(new_id, child_id);
|
self.get_mut(new_id).unwrap().add_child(child_id);
|
||||||
}
|
}
|
||||||
new_id
|
new_id
|
||||||
}
|
}
|
||||||
@@ -187,11 +188,9 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
/// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
|
||||||
pub fn get_mut_raw(&mut self, id: NodeId) -> Option<NodeMutRaw<V>> {
|
pub fn get_state_mut_raw<T: Any + Send + Sync>(&mut self, id: NodeId) -> Option<&mut T> {
|
||||||
let id = id.into_node_id(self);
|
let id = id.into_node_id(self);
|
||||||
self.tree
|
self.tree.get_mut(id)
|
||||||
.contains(id)
|
|
||||||
.then_some(NodeMutRaw { id, dom: self })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
|
/// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
|
||||||
@@ -202,7 +201,8 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
|
) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
|
||||||
let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
|
let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
|
||||||
let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
|
let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
|
||||||
let dirty_nodes = DirtyNodeStates::with_passes(self.passes.iter().map(|p| p.this_type_id));
|
let dirty_nodes =
|
||||||
|
DirtyNodeStates::with_passes(self.dirty_nodes.passes.iter().map(|p| p.this_type_id));
|
||||||
for (node_id, passes) in passes {
|
for (node_id, passes) in passes {
|
||||||
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
// remove any nodes that were created and then removed in the same mutations from the dirty nodes list
|
||||||
if let Some(height) = self.tree.height(node_id) {
|
if let Some(height) = self.tree.height(node_id) {
|
||||||
@@ -218,21 +218,6 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, id: NodeId) {
|
|
||||||
if let Some(parent_id) = self.tree.parent_id(id) {
|
|
||||||
self.dirty_nodes.mark_child_changed(parent_id);
|
|
||||||
}
|
|
||||||
self.tree.remove(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn replace(&mut self, old: NodeId, new: NodeId) {
|
|
||||||
if let Some(parent_id) = self.tree.parent_id(old) {
|
|
||||||
self.dirty_nodes.mark_child_changed(parent_id);
|
|
||||||
self.dirty_nodes.mark_parent_added_or_removed(new);
|
|
||||||
}
|
|
||||||
self.tree.replace(old, new);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
|
pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
|
||||||
let mut stack = vec![self.root_id()];
|
let mut stack = vec![self.root_id()];
|
||||||
while let Some(id) = stack.pop() {
|
while let Some(id) = stack.pop() {
|
||||||
@@ -293,6 +278,10 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
|
|||||||
pub fn insert_slab<T: Any + Send + Sync>(&mut self) {
|
pub fn insert_slab<T: Any + Send + Sync>(&mut self) {
|
||||||
self.tree.insert_slab::<T>();
|
self.tree.insert_slab::<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_node_watcher(&mut self, watcher: impl NodeWatcher<V> + 'static) {
|
||||||
|
self.node_watchers.write().unwrap().push(Box::new(watcher));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntoNodeId<V: FromAnyValue + Send + Sync> {
|
pub trait IntoNodeId<V: FromAnyValue + Send + Sync> {
|
||||||
@@ -343,40 +332,52 @@ pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
|
|||||||
dom: self.real_dom(),
|
dom: self.real_dom(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next(&self) -> Option<NodeRef<V>> {
|
||||||
|
let parent = self.parent_id()?;
|
||||||
|
let children = self.real_dom().tree.children_ids(parent)?;
|
||||||
|
let index = children.iter().position(|id| *id == self.id())?;
|
||||||
|
if index + 1 < children.len() {
|
||||||
|
Some(NodeRef {
|
||||||
|
id: children[index + 1],
|
||||||
|
dom: self.real_dom(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prev(&self) -> Option<NodeRef<V>> {
|
||||||
|
let parent = self.parent_id()?;
|
||||||
|
let children = self.real_dom().tree.children_ids(parent)?;
|
||||||
|
let index = children.iter().position(|id| *id == self.id())?;
|
||||||
|
if index > 0 {
|
||||||
|
Some(NodeRef {
|
||||||
|
id: children[index - 1],
|
||||||
|
dom: self.real_dom(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait NodeMutable<V: FromAnyValue + Send + Sync>: Sized + NodeImmutable<V> {
|
|
||||||
fn real_dom_mut(&mut self) -> &mut RealDom<V>;
|
|
||||||
fn get_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut T> {
|
|
||||||
let id = self.id();
|
|
||||||
self.real_dom_mut().tree.get_mut(id)
|
|
||||||
}
|
|
||||||
fn insert<T: Any + Sync + Send>(&mut self, value: T) {
|
|
||||||
let id = self.id();
|
|
||||||
self.real_dom_mut().tree.insert(id, value);
|
|
||||||
}
|
|
||||||
fn add_child(&mut self, child: NodeId) {
|
|
||||||
let id = self.id();
|
|
||||||
self.real_dom_mut().tree.add_child(id, child);
|
|
||||||
}
|
|
||||||
fn insert_after(&mut self, old: NodeId) {
|
|
||||||
let id = self.id();
|
|
||||||
self.real_dom_mut().tree.insert_after(old, id);
|
|
||||||
}
|
|
||||||
fn insert_before(&mut self, old: NodeId) {
|
|
||||||
let id = self.id();
|
|
||||||
self.real_dom_mut().tree.insert_before(old, id);
|
|
||||||
}
|
|
||||||
fn add_event_listener(&mut self, event: &str);
|
|
||||||
fn remove_event_listener(&mut self, event: &str);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
|
pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
dom: &'a RealDom<V>,
|
dom: &'a RealDom<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send + Sync> Clone for NodeRef<'a, V> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
id: self.id,
|
||||||
|
dom: self.dom,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, V: FromAnyValue + Send + Sync> Copy for NodeRef<'a, V> {}
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'a, V> {
|
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'a, V> {
|
||||||
fn real_dom(&self) -> &RealDom<V> {
|
fn real_dom(&self) -> &RealDom<V> {
|
||||||
self.dom
|
self.dom
|
||||||
@@ -408,12 +409,12 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMut<'a, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
|
impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
||||||
fn real_dom_mut(&mut self) -> &mut RealDom<V> {
|
pub fn real_dom_mut(&mut self) -> &mut RealDom<V> {
|
||||||
self.dom
|
self.dom
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut T> {
|
pub fn get_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut T> {
|
||||||
// mark the node state as dirty
|
// mark the node state as dirty
|
||||||
self.dom
|
self.dom
|
||||||
.dirty_nodes
|
.dirty_nodes
|
||||||
@@ -424,7 +425,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
|
|||||||
self.dom.tree.get_mut(self.id)
|
self.dom.tree.get_mut(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert<T: Any + Sync + Send>(&mut self, value: T) {
|
pub fn insert<T: Any + Sync + Send>(&mut self, value: T) {
|
||||||
// mark the node state as dirty
|
// mark the node state as dirty
|
||||||
self.dom
|
self.dom
|
||||||
.dirty_nodes
|
.dirty_nodes
|
||||||
@@ -435,25 +436,87 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
|
|||||||
self.dom.tree.insert(self.id, value);
|
self.dom.tree.insert(self.id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_after(&mut self, old: NodeId) {
|
pub fn next_mut(self) -> Option<NodeMut<'a, V>> {
|
||||||
|
let parent = self.parent_id()?;
|
||||||
|
let children = self.dom.tree.children_ids(parent)?;
|
||||||
|
let index = children.iter().position(|id| *id == self.id)?;
|
||||||
|
if index + 1 < children.len() {
|
||||||
|
Some(NodeMut::new(children[index + 1], self.dom))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prev_mut(self) -> Option<NodeMut<'a, V>> {
|
||||||
|
let parent = self.parent_id()?;
|
||||||
|
let children = self.dom.tree.children_ids(parent)?;
|
||||||
|
let index = children.iter().position(|id| *id == self.id)?;
|
||||||
|
if index > 0 {
|
||||||
|
Some(NodeMut::new(children[index - 1], self.dom))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_child(&mut self, child: NodeId) {
|
||||||
|
self.dom.dirty_nodes.mark_child_changed(self.id);
|
||||||
|
self.dom.dirty_nodes.mark_parent_added_or_removed(child);
|
||||||
|
self.dom.tree.add_child(self.id, child);
|
||||||
|
NodeMut::new(child, self.dom).mark_moved();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_after(&mut self, old: NodeId) {
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
if let Some(parent_id) = self.dom.tree.parent_id(old) {
|
if let Some(parent_id) = self.dom.tree.parent_id(old) {
|
||||||
self.dom.dirty_nodes.mark_child_changed(parent_id);
|
self.dom.dirty_nodes.mark_child_changed(parent_id);
|
||||||
self.dom.dirty_nodes.mark_parent_added_or_removed(id);
|
self.dom.dirty_nodes.mark_parent_added_or_removed(id);
|
||||||
}
|
}
|
||||||
self.dom.tree.insert_after(old, id);
|
self.dom.tree.insert_after(old, id);
|
||||||
|
self.mark_moved();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_before(&mut self, old: NodeId) {
|
pub fn insert_before(&mut self, old: NodeId) {
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
if let Some(parent_id) = self.dom.tree.parent_id(old) {
|
if let Some(parent_id) = self.dom.tree.parent_id(old) {
|
||||||
self.dom.dirty_nodes.mark_child_changed(parent_id);
|
self.dom.dirty_nodes.mark_child_changed(parent_id);
|
||||||
self.dom.dirty_nodes.mark_parent_added_or_removed(id);
|
self.dom.dirty_nodes.mark_parent_added_or_removed(id);
|
||||||
}
|
}
|
||||||
self.dom.tree.insert_before(old, id);
|
self.dom.tree.insert_before(old, id);
|
||||||
|
self.mark_moved();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_event_listener(&mut self, event: &str) {
|
pub fn remove(&mut self) {
|
||||||
|
let id = self.id();
|
||||||
|
self.mark_removed();
|
||||||
|
if let Some(parent_id) = self.real_dom_mut().tree.parent_id(id) {
|
||||||
|
self.real_dom_mut()
|
||||||
|
.dirty_nodes
|
||||||
|
.mark_child_changed(parent_id);
|
||||||
|
}
|
||||||
|
if let Some(children_ids) = self.child_ids() {
|
||||||
|
let children_ids_vec = children_ids.to_vec();
|
||||||
|
for child in children_ids_vec {
|
||||||
|
self.dom.get_mut(child).unwrap().remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.dom.tree.remove_single(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace(&mut self, new: NodeId) {
|
||||||
|
self.mark_removed();
|
||||||
|
if let Some(parent_id) = self.parent_id() {
|
||||||
|
self.real_dom_mut()
|
||||||
|
.dirty_nodes
|
||||||
|
.mark_child_changed(parent_id);
|
||||||
|
self.real_dom_mut()
|
||||||
|
.dirty_nodes
|
||||||
|
.mark_parent_added_or_removed(new);
|
||||||
|
}
|
||||||
|
let id = self.id();
|
||||||
|
self.dom.tree.replace(id, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_event_listener(&mut self, event: &str) {
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
|
let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
|
||||||
if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
|
if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
|
||||||
@@ -474,7 +537,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_event_listener(&mut self, event: &str) {
|
pub fn remove_event_listener(&mut self, event: &str) {
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
|
let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
|
||||||
if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
|
if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
|
||||||
@@ -486,9 +549,21 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
|
|||||||
self.dom.nodes_listening.get_mut(event).unwrap().remove(&id);
|
self.dom.nodes_listening.get_mut(event).unwrap().remove(&id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
fn mark_removed(&mut self) {
|
||||||
|
let watchers = self.dom.node_watchers.clone();
|
||||||
|
for watcher in &*watchers.read().unwrap() {
|
||||||
|
watcher.on_node_removed(NodeMut::new(self.id(), self.dom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_moved(&mut self) {
|
||||||
|
let watchers = self.dom.node_watchers.clone();
|
||||||
|
for watcher in &*watchers.read().unwrap() {
|
||||||
|
watcher.on_node_moved(NodeMut::new(self.id(), self.dom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
|
||||||
let Self { id, dom } = self;
|
let Self { id, dom } = self;
|
||||||
let RealDom {
|
let RealDom {
|
||||||
@@ -503,6 +578,7 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
|
|||||||
}),
|
}),
|
||||||
NodeType::Text(text) => {
|
NodeType::Text(text) => {
|
||||||
dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
|
dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
|
||||||
|
|
||||||
NodeTypeMut::Text(text)
|
NodeTypeMut::Text(text)
|
||||||
}
|
}
|
||||||
NodeType::Placeholder => NodeTypeMut::Placeholder,
|
NodeType::Placeholder => NodeTypeMut::Placeholder,
|
||||||
@@ -554,18 +630,6 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
|||||||
&self.element.attributes
|
&self.element.attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attributes_mut(
|
|
||||||
&mut self,
|
|
||||||
) -> &mut FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue<V>> {
|
|
||||||
self.dirty_nodes.mark_dirty(
|
|
||||||
self.id,
|
|
||||||
NodeMaskBuilder::new()
|
|
||||||
.with_attrs(AttributeMaskBuilder::All)
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
&mut self.element.attributes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_attribute(
|
pub fn set_attribute(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: OwnedAttributeDiscription,
|
name: OwnedAttributeDiscription,
|
||||||
@@ -610,55 +674,3 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
|
|||||||
&self.element.listeners
|
&self.element.listeners
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NodeMutRaw<'a, V: FromAnyValue + Send + Sync = ()> {
|
|
||||||
id: NodeId,
|
|
||||||
dom: &'a mut RealDom<V>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send + Sync> NodeMutRaw<'a, V> {
|
|
||||||
fn node_type_mut(&mut self) -> &mut NodeType<V> {
|
|
||||||
self.dom.tree.get_mut::<NodeType<V>>(self.id).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMutRaw<'a, V> {
|
|
||||||
fn real_dom(&self) -> &RealDom<V> {
|
|
||||||
self.dom
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> NodeId {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMutRaw<'a, V> {
|
|
||||||
fn real_dom_mut(&mut self) -> &mut RealDom<V> {
|
|
||||||
self.dom
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_event_listener(&mut self, event: &str) {
|
|
||||||
let id = self.id();
|
|
||||||
if let NodeType::Element(element) = self.node_type_mut() {
|
|
||||||
element.listeners.insert(event.to_string());
|
|
||||||
match self.dom.nodes_listening.get_mut(event) {
|
|
||||||
Some(hs) => {
|
|
||||||
hs.insert(id);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut hs = FxHashSet::default();
|
|
||||||
hs.insert(id);
|
|
||||||
self.dom.nodes_listening.insert(event.to_string(), hs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_event_listener(&mut self, event: &str) {
|
|
||||||
let id = self.id();
|
|
||||||
if let NodeType::Element(element) = self.node_type_mut() {
|
|
||||||
element.listeners.remove(event);
|
|
||||||
}
|
|
||||||
self.dom.nodes_listening.get_mut(event).unwrap().remove(&id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -80,6 +80,18 @@ impl Tree {
|
|||||||
recurse(self, id);
|
recurse(self, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_single(&mut self, id: NodeId) {
|
||||||
|
{
|
||||||
|
let node_data_mut = self.node_slab_mut();
|
||||||
|
if let Some(parent) = node_data_mut.get(id).unwrap().parent {
|
||||||
|
let parent = node_data_mut.get_mut(parent).unwrap();
|
||||||
|
parent.children.retain(|&child| child != id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.nodes.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
fn set_height(&mut self, node: NodeId, height: u16) {
|
fn set_height(&mut self, node: NodeId, height: u16) {
|
||||||
let children = {
|
let children = {
|
||||||
let mut node = self.get_node_data_mut(node);
|
let mut node = self.get_node_data_mut(node);
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// mod persistant_iterator;
|
mod persistant_iterator;
|
||||||
// pub use persistant_iterator::*;
|
pub use persistant_iterator::*;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
node::{ElementNode, FromAnyValue, NodeType},
|
node::FromAnyValue,
|
||||||
|
node_watcher::NodeWatcher,
|
||||||
real_dom::{NodeImmutable, RealDom},
|
real_dom::{NodeImmutable, RealDom},
|
||||||
NodeId,
|
NodeId, NodeRef,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use dioxus_core::{Mutation, Mutations};
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ElementProduced {
|
pub enum ElementProduced {
|
||||||
@@ -23,27 +28,36 @@ impl ElementProduced {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
struct PersistantElementIterUpdater<V> {
|
||||||
enum NodePosition {
|
stack: Arc<Mutex<smallvec::SmallVec<[NodeId; 5]>>>,
|
||||||
AtNode,
|
phantom: std::marker::PhantomData<V>,
|
||||||
InChild(usize),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodePosition {
|
impl<V: FromAnyValue + Sync + Send> NodeWatcher<V> for PersistantElementIterUpdater<V> {
|
||||||
fn map(&self, mut f: impl FnMut(usize) -> usize) -> Self {
|
fn on_node_moved(&self, node: crate::NodeMut<V>) {
|
||||||
match self {
|
// if any element is moved, update its parents in the stack
|
||||||
Self::AtNode => Self::AtNode,
|
let mut stack = self.stack.lock().unwrap();
|
||||||
Self::InChild(i) => Self::InChild(f(*i)),
|
let moved = node.id();
|
||||||
|
let rdom = node.real_dom();
|
||||||
|
if let Some(r) = stack.iter().position(|el_id| *el_id == moved) {
|
||||||
|
let back = &stack[r..];
|
||||||
|
let mut new = SmallVec::new();
|
||||||
|
let mut parent = node.parent_id();
|
||||||
|
while let Some(p) = parent.and_then(|id| rdom.get(id)) {
|
||||||
|
new.push(p.id());
|
||||||
|
parent = p.parent_id();
|
||||||
|
}
|
||||||
|
new.extend(back.iter().copied());
|
||||||
|
*stack = new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_or_insert(&mut self, child_idx: usize) -> usize {
|
fn on_node_removed(&self, node: crate::NodeMut<V>) {
|
||||||
match self {
|
// if any element is removed in the chain, remove it and its children from the stack
|
||||||
Self::AtNode => {
|
let mut stack = self.stack.lock().unwrap();
|
||||||
*self = Self::InChild(child_idx);
|
let removed = node.id();
|
||||||
child_idx
|
if let Some(r) = stack.iter().position(|el_id| *el_id == removed) {
|
||||||
}
|
stack.truncate(r);
|
||||||
Self::InChild(i) => *i,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,118 +67,47 @@ impl NodePosition {
|
|||||||
/// Iterate through it with [PersistantElementIter::next] [PersistantElementIter::prev], and update it with [PersistantElementIter::prune] (with data from [`dioxus_core::prelude::VirtualDom::work_with_deadline`]).
|
/// Iterate through it with [PersistantElementIter::next] [PersistantElementIter::prev], and update it with [PersistantElementIter::prune] (with data from [`dioxus_core::prelude::VirtualDom::work_with_deadline`]).
|
||||||
/// The iterator loops around when it reaches the end or the beginning.
|
/// The iterator loops around when it reaches the end or the beginning.
|
||||||
pub struct PersistantElementIter {
|
pub struct PersistantElementIter {
|
||||||
// stack of elements and fragments
|
// stack of elements and fragments, the last element is the last element that was yielded
|
||||||
stack: smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
|
stack: Arc<Mutex<smallvec::SmallVec<[NodeId; 5]>>>,
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PersistantElementIter {
|
|
||||||
fn default() -> Self {
|
|
||||||
PersistantElementIter {
|
|
||||||
stack: smallvec::smallvec![(NodeId(0), NodePosition::AtNode)],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PersistantElementIter {
|
impl PersistantElementIter {
|
||||||
pub fn new() -> Self {
|
pub fn create<V: FromAnyValue + Send + Sync>(rdom: &mut RealDom<V>) -> Self {
|
||||||
Self::default()
|
let inner = Arc::new(Mutex::new(smallvec::smallvec![NodeId(0)]));
|
||||||
}
|
|
||||||
|
|
||||||
/// remove stale element refreneces
|
rdom.add_node_watcher(PersistantElementIterUpdater {
|
||||||
/// returns true if the focused element is removed
|
stack: inner.clone(),
|
||||||
pub fn prune<V: FromAnyValue + Send + Sync>(
|
phantom: std::marker::PhantomData,
|
||||||
&mut self,
|
});
|
||||||
mutations: &Mutations,
|
|
||||||
rdom: &RealDom<V>,
|
PersistantElementIter { stack: inner }
|
||||||
) -> bool {
|
|
||||||
let mut changed = false;
|
|
||||||
let ids_removed: Vec<_> = mutations
|
|
||||||
.edits
|
|
||||||
.iter()
|
|
||||||
.filter_map(|m| {
|
|
||||||
// nodes within templates will never be removed
|
|
||||||
match m {
|
|
||||||
Mutation::Remove { id } => Some(rdom.element_to_node_id(*id)),
|
|
||||||
Mutation::ReplaceWith { id, .. } => Some(rdom.element_to_node_id(*id)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
// if any element is removed in the chain, remove it and its children from the stack
|
|
||||||
if let Some(r) = self
|
|
||||||
.stack
|
|
||||||
.iter()
|
|
||||||
.position(|(el_id, _)| ids_removed.iter().any(|id| el_id == id))
|
|
||||||
{
|
|
||||||
self.stack.truncate(r);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
// if a child is removed or inserted before or at the current element, update the child index
|
|
||||||
for (el_id, child_idx) in self.stack.iter_mut() {
|
|
||||||
if let NodePosition::InChild(child_idx) = child_idx {
|
|
||||||
if let Some(children) = &rdom.get(*el_id).unwrap().child_ids() {
|
|
||||||
for m in &mutations.edits {
|
|
||||||
match m {
|
|
||||||
Mutation::Remove { id } => {
|
|
||||||
let id = rdom.element_to_node_id(*id);
|
|
||||||
if children.iter().take(*child_idx + 1).any(|c| *c == id) {
|
|
||||||
*child_idx -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Mutation::InsertBefore { id, m } => {
|
|
||||||
let id = rdom.element_to_node_id(*id);
|
|
||||||
if children.iter().take(*child_idx + 1).any(|c| *c == id) {
|
|
||||||
*child_idx += *m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Mutation::InsertAfter { id, m } => {
|
|
||||||
let id = rdom.element_to_node_id(*id);
|
|
||||||
if children.iter().take(*child_idx).any(|c| *c == id) {
|
|
||||||
*child_idx += *m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the next element
|
/// get the next element
|
||||||
pub fn next<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
pub fn next<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
||||||
if self.stack.is_empty() {
|
let mut stack = self.stack.lock().unwrap();
|
||||||
|
if stack.is_empty() {
|
||||||
let id = NodeId(0);
|
let id = NodeId(0);
|
||||||
let new = (id, NodePosition::AtNode);
|
let new = id;
|
||||||
self.stack.push(new);
|
stack.push(new);
|
||||||
ElementProduced::Looped(id)
|
ElementProduced::Looped(id)
|
||||||
} else {
|
} else {
|
||||||
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
loop {
|
||||||
let node = rdom.get(*last).unwrap();
|
let last = stack.pop().unwrap();
|
||||||
match node.node_type() {
|
if let Some(current) = rdom.get(last) {
|
||||||
NodeType::Element(ElementNode { .. }) => {
|
if let Some(new) = current.next() {
|
||||||
let children = node.child_ids().unwrap();
|
// the next element exists, add it to the stack and return it
|
||||||
*old_child_idx = old_child_idx.map(|i| i + 1);
|
let new = new.id();
|
||||||
// if we have children, go to the next child
|
stack.push(new);
|
||||||
let child_idx = old_child_idx.get_or_insert(0);
|
return ElementProduced::Progressed(new);
|
||||||
if child_idx >= children.len() {
|
|
||||||
self.pop();
|
|
||||||
self.next(rdom)
|
|
||||||
} else {
|
|
||||||
let id = children[child_idx];
|
|
||||||
if let NodeType::Element(ElementNode { .. }) =
|
|
||||||
rdom.get(id).unwrap().node_type()
|
|
||||||
{
|
|
||||||
self.stack.push((id, NodePosition::AtNode));
|
|
||||||
}
|
|
||||||
ElementProduced::Progressed(id)
|
|
||||||
}
|
}
|
||||||
}
|
// otherwise, continue the loop and go to the parent
|
||||||
|
} else {
|
||||||
NodeType::Text { .. } | NodeType::Placeholder { .. } => {
|
// if there is no parent, loop back to the root
|
||||||
// we are at a leaf, so we are done
|
let new = NodeId(0);
|
||||||
ElementProduced::Progressed(self.pop())
|
stack.clear();
|
||||||
|
stack.push(new);
|
||||||
|
return ElementProduced::Looped(new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,68 +117,44 @@ impl PersistantElementIter {
|
|||||||
pub fn prev<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
pub fn prev<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
|
||||||
// recursively add the last child element to the stack
|
// recursively add the last child element to the stack
|
||||||
fn push_back<V: FromAnyValue + Send + Sync>(
|
fn push_back<V: FromAnyValue + Send + Sync>(
|
||||||
stack: &mut smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
|
stack: &mut smallvec::SmallVec<[NodeId; 5]>,
|
||||||
new_node: NodeId,
|
node: NodeRef<V>,
|
||||||
rdom: &RealDom<V>,
|
|
||||||
) -> NodeId {
|
) -> NodeId {
|
||||||
let node = rdom.get(new_node).unwrap();
|
stack.push(node.id());
|
||||||
match node.node_type() {
|
if let Some(children) = node.children() {
|
||||||
NodeType::Element(ElementNode { .. }) => {
|
if let Some(last) = children.last() {
|
||||||
let children = node.child_ids().unwrap();
|
push_back(stack, *last)
|
||||||
if children.is_empty() {
|
} else {
|
||||||
new_node
|
node.id()
|
||||||
} else {
|
|
||||||
stack.push((new_node, NodePosition::InChild(children.len() - 1)));
|
|
||||||
push_back(stack, *children.last().unwrap(), rdom)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => new_node,
|
} else {
|
||||||
|
node.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.stack.is_empty() {
|
let mut stack = self.stack.lock().unwrap();
|
||||||
let new_node = NodeId(0);
|
if stack.is_empty() {
|
||||||
ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
|
let id = NodeId(0);
|
||||||
|
let last = push_back(&mut stack, rdom.get(id).unwrap());
|
||||||
|
ElementProduced::Looped(last)
|
||||||
} else {
|
} else {
|
||||||
let (last, old_child_idx) = self.stack.last_mut().unwrap();
|
loop {
|
||||||
let node = rdom.get(*last).unwrap();
|
let last = stack.pop().unwrap();
|
||||||
match node.node_type() {
|
if let Some(current) = rdom.get(last) {
|
||||||
NodeType::Element(ElementNode { .. }) => {
|
if let Some(new) = current.prev() {
|
||||||
let children = node.child_ids().unwrap();
|
// the next element exists, add it to the stack and return it
|
||||||
// if we have children, go to the next child
|
let new = push_back(&mut stack, new);
|
||||||
if let NodePosition::InChild(0) = old_child_idx {
|
return ElementProduced::Progressed(new);
|
||||||
ElementProduced::Progressed(self.pop())
|
|
||||||
} else {
|
|
||||||
*old_child_idx = old_child_idx.map(|i| i - 1);
|
|
||||||
if let NodePosition::InChild(child_idx) = old_child_idx {
|
|
||||||
if *child_idx >= children.len() || children.is_empty() {
|
|
||||||
self.pop();
|
|
||||||
self.prev(rdom)
|
|
||||||
} else {
|
|
||||||
let new_node = children[*child_idx];
|
|
||||||
ElementProduced::Progressed(push_back(
|
|
||||||
&mut self.stack,
|
|
||||||
new_node,
|
|
||||||
rdom,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.pop();
|
|
||||||
self.prev(rdom)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
// otherwise, continue the loop and go to the parent
|
||||||
|
} else {
|
||||||
NodeType::Text { .. } | NodeType::Placeholder { .. } => {
|
// if there is no parent, loop back to the root
|
||||||
// we are at a leaf, so we are done
|
let id = NodeId(0);
|
||||||
ElementProduced::Progressed(self.pop())
|
let last = push_back(&mut stack, rdom.get(id).unwrap());
|
||||||
|
return ElementProduced::Looped(last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self) -> NodeId {
|
|
||||||
self.stack.pop().unwrap().0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -307,14 +307,14 @@ fn down_pass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut tree: RealDom = RealDom::new(Box::new([AddNumber::to_type_erased()]));
|
let mut tree: RealDom = RealDom::new(Box::new([AddNumber::to_type_erased()]));
|
||||||
let grandchild1 = tree.create_node(create_blank_element(), true);
|
let grandchild1 = tree.create_node(create_blank_element());
|
||||||
let grandchild1 = grandchild1.id();
|
let grandchild1 = grandchild1.id();
|
||||||
let mut child1 = tree.create_node(create_blank_element(), true);
|
let mut child1 = tree.create_node(create_blank_element());
|
||||||
child1.add_child(grandchild1);
|
child1.add_child(grandchild1);
|
||||||
let child1 = child1.id();
|
let child1 = child1.id();
|
||||||
let grandchild2 = tree.create_node(create_blank_element(), true);
|
let grandchild2 = tree.create_node(create_blank_element());
|
||||||
let grandchild2 = grandchild2.id();
|
let grandchild2 = grandchild2.id();
|
||||||
let mut child2 = tree.create_node(create_blank_element(), true);
|
let mut child2 = tree.create_node(create_blank_element());
|
||||||
child2.add_child(grandchild2);
|
child2.add_child(grandchild2);
|
||||||
let child2 = child2.id();
|
let child2 = child2.id();
|
||||||
let mut parent = tree.get_mut(tree.root_id()).unwrap();
|
let mut parent = tree.get_mut(tree.root_id()).unwrap();
|
||||||
@@ -395,14 +395,14 @@ fn up_pass() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut tree: RealDom = RealDom::new(Box::new([AddNumber::to_type_erased()]));
|
let mut tree: RealDom = RealDom::new(Box::new([AddNumber::to_type_erased()]));
|
||||||
let grandchild1 = tree.create_node(create_blank_element(), true);
|
let grandchild1 = tree.create_node(create_blank_element());
|
||||||
let grandchild1 = grandchild1.id();
|
let grandchild1 = grandchild1.id();
|
||||||
let mut child1 = tree.create_node(create_blank_element(), true);
|
let mut child1 = tree.create_node(create_blank_element());
|
||||||
child1.add_child(grandchild1);
|
child1.add_child(grandchild1);
|
||||||
let child1 = child1.id();
|
let child1 = child1.id();
|
||||||
let grandchild2 = tree.create_node(create_blank_element(), true);
|
let grandchild2 = tree.create_node(create_blank_element());
|
||||||
let grandchild2 = grandchild2.id();
|
let grandchild2 = grandchild2.id();
|
||||||
let mut child2 = tree.create_node(create_blank_element(), true);
|
let mut child2 = tree.create_node(create_blank_element());
|
||||||
child2.add_child(grandchild2);
|
child2.add_child(grandchild2);
|
||||||
let child2 = child2.id();
|
let child2 = child2.id();
|
||||||
let mut parent = tree.get_mut(tree.root_id()).unwrap();
|
let mut parent = tree.get_mut(tree.root_id()).unwrap();
|
||||||
|
|||||||
Reference in new issue
Block a user