Merge branch 'master' into pr/atty303/1349
This commit is contained in:
commit
e5df83ceec
278 files changed
+11299
-3674
No files matched your search
+88
-48
@@ -1,6 +1,7 @@
|
||||
use crate::any_props::AnyProps;
|
||||
use crate::innerlude::{
|
||||
AttributeType, BorrowedAttributeValue, MountedAttribute, VComponent, VPlaceholder, VText,
|
||||
AttributeType, BorrowedAttributeValue, ElementPath, ElementRef, MountedAttribute, VComponent,
|
||||
VPlaceholder, VText,
|
||||
};
|
||||
use crate::mutations::Mutation;
|
||||
use crate::mutations::Mutation::*;
|
||||
@@ -96,6 +97,9 @@ impl<'b> VirtualDom {
|
||||
nodes_mut.resize(len, ElementId::default());
|
||||
};
|
||||
|
||||
// Set this node id
|
||||
node.stable_id.set(Some(self.next_vnode_ref(node)));
|
||||
|
||||
// The best renderers will have templates prehydrated and registered
|
||||
// Just in case, let's create the template using instructions anyways
|
||||
self.register_template(node.template.get());
|
||||
@@ -183,15 +187,30 @@ impl<'b> VirtualDom {
|
||||
use DynamicNode::*;
|
||||
match &template.dynamic_nodes[idx] {
|
||||
node @ Component { .. } | node @ Fragment(_) => {
|
||||
self.create_dynamic_node(template, node, idx)
|
||||
let template_ref = ElementRef {
|
||||
path: ElementPath {
|
||||
path: template.template.get().node_paths[idx],
|
||||
},
|
||||
template: template.stable_id().unwrap(),
|
||||
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
|
||||
};
|
||||
self.create_dynamic_node(template_ref, node)
|
||||
}
|
||||
Placeholder(VPlaceholder { id }) => {
|
||||
let id = self.set_slot(template, id, idx);
|
||||
Placeholder(VPlaceholder { id, parent }) => {
|
||||
let template_ref = ElementRef {
|
||||
path: ElementPath {
|
||||
path: template.template.get().node_paths[idx],
|
||||
},
|
||||
template: template.stable_id().unwrap(),
|
||||
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
|
||||
};
|
||||
parent.set(Some(template_ref));
|
||||
let id = self.set_slot(id);
|
||||
self.mutations.push(CreatePlaceholder { id });
|
||||
1
|
||||
}
|
||||
Text(VText { id, value }) => {
|
||||
let id = self.set_slot(template, id, idx);
|
||||
let id = self.set_slot(id);
|
||||
self.create_static_text(value, id);
|
||||
1
|
||||
}
|
||||
@@ -207,7 +226,7 @@ impl<'b> VirtualDom {
|
||||
});
|
||||
}
|
||||
|
||||
/// We write all the descndent data for this element
|
||||
/// We write all the descendent data for this element
|
||||
///
|
||||
/// Elements can contain other nodes - and those nodes can be dynamic or static
|
||||
///
|
||||
@@ -267,7 +286,14 @@ impl<'b> VirtualDom {
|
||||
.map(|sorted_index| dynamic_nodes[sorted_index].0);
|
||||
|
||||
for idx in reversed_iter {
|
||||
let m = self.create_dynamic_node(template, &template.dynamic_nodes[idx], idx);
|
||||
let boundary_ref = ElementRef {
|
||||
path: ElementPath {
|
||||
path: template.template.get().node_paths[idx],
|
||||
},
|
||||
template: template.stable_id().unwrap(),
|
||||
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
|
||||
};
|
||||
let m = self.create_dynamic_node(boundary_ref, &template.dynamic_nodes[idx]);
|
||||
if m > 0 {
|
||||
// The path is one shorter because the top node is the root
|
||||
let path = &template.template.get().node_paths[idx][1..];
|
||||
@@ -281,15 +307,15 @@ impl<'b> VirtualDom {
|
||||
attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
|
||||
root_idx: u8,
|
||||
root: ElementId,
|
||||
node: &VNode,
|
||||
node: &'b VNode<'b>,
|
||||
) {
|
||||
while let Some((mut attr_id, path)) =
|
||||
attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx))
|
||||
{
|
||||
let id = self.assign_static_node_as_dynamic(path, root, node, attr_id);
|
||||
let id = self.assign_static_node_as_dynamic(path, root);
|
||||
|
||||
loop {
|
||||
self.write_attribute_type(&node.dynamic_attrs[attr_id], id);
|
||||
self.write_attribute_type(node, &node.dynamic_attrs[attr_id], attr_id, id);
|
||||
|
||||
// Only push the dynamic attributes forward if they match the current path (same element)
|
||||
match attrs.next_if(|(_, p)| *p == path) {
|
||||
@@ -300,25 +326,44 @@ impl<'b> VirtualDom {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_attribute_type(&mut self, attribute: &'b MountedAttribute<'b>, id: ElementId) {
|
||||
fn write_attribute_type(
|
||||
&mut self,
|
||||
vnode: &'b VNode<'b>,
|
||||
attribute: &'b MountedAttribute<'b>,
|
||||
idx: usize,
|
||||
id: ElementId,
|
||||
) {
|
||||
// Make sure we set the attribute's associated id
|
||||
attribute.mounted_element.set(id);
|
||||
match &attribute.ty {
|
||||
AttributeType::Single(attribute) => self.write_attribute(attribute, id),
|
||||
AttributeType::Single(attribute) => self.write_attribute(vnode, attribute, idx, id),
|
||||
AttributeType::Many(attribute) => {
|
||||
for attribute in *attribute {
|
||||
self.write_attribute(attribute, id);
|
||||
self.write_attribute(vnode, attribute, idx, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_attribute(&mut self, attribute: &'b crate::Attribute<'b>, id: ElementId) {
|
||||
pub(crate) fn write_attribute(
|
||||
&mut self,
|
||||
vnode: &'b VNode<'b>,
|
||||
attribute: &'b crate::Attribute<'b>,
|
||||
idx: usize,
|
||||
id: ElementId,
|
||||
) {
|
||||
// Safety: we promise not to re-alias this text later on after committing it to the mutation
|
||||
let unbounded_name: &str = unsafe { std::mem::transmute(attribute.name) };
|
||||
|
||||
match &attribute.value {
|
||||
AttributeValue::Listener(_) => {
|
||||
let path = &vnode.template.get().attr_paths[idx];
|
||||
let element_ref = ElementRef {
|
||||
path: ElementPath { path },
|
||||
template: vnode.stable_id().unwrap(),
|
||||
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
|
||||
};
|
||||
self.elements[id.0] = Some(element_ref);
|
||||
self.mutations.push(NewEventListener {
|
||||
// all listeners start with "on"
|
||||
name: &unbounded_name[2..],
|
||||
@@ -342,7 +387,7 @@ impl<'b> VirtualDom {
|
||||
|
||||
fn load_template_root(&mut self, template: &VNode, root_idx: usize) -> ElementId {
|
||||
// Get an ID for this root since it's a real root
|
||||
let this_id = self.next_root(template, root_idx);
|
||||
let this_id = self.next_element();
|
||||
template.root_ids.borrow_mut()[root_idx] = this_id;
|
||||
|
||||
self.mutations.push(LoadTemplate {
|
||||
@@ -365,8 +410,6 @@ impl<'b> VirtualDom {
|
||||
&mut self,
|
||||
path: &'static [u8],
|
||||
this_id: ElementId,
|
||||
template: &VNode,
|
||||
attr_id: usize,
|
||||
) -> ElementId {
|
||||
if path.len() == 1 {
|
||||
return this_id;
|
||||
@@ -374,7 +417,7 @@ impl<'b> VirtualDom {
|
||||
|
||||
// if attribute is on a root node, then we've already created the element
|
||||
// Else, it's deep in the template and we should create a new id for it
|
||||
let id = self.next_element(template, template.template.get().attr_paths[attr_id]);
|
||||
let id = self.next_element();
|
||||
|
||||
self.mutations.push(Mutation::AssignId {
|
||||
path: &path[1..],
|
||||
@@ -417,6 +460,7 @@ impl<'b> VirtualDom {
|
||||
#[allow(unused_mut)]
|
||||
pub(crate) fn register_template(&mut self, mut template: Template<'static>) {
|
||||
let (path, byte_index) = template.name.rsplit_once(':').unwrap();
|
||||
|
||||
let byte_index = byte_index.parse::<usize>().unwrap();
|
||||
// First, check if we've already seen this template
|
||||
if self
|
||||
@@ -451,27 +495,21 @@ impl<'b> VirtualDom {
|
||||
|
||||
pub(crate) fn create_dynamic_node(
|
||||
&mut self,
|
||||
template: &'b VNode<'b>,
|
||||
parent: ElementRef,
|
||||
node: &'b DynamicNode<'b>,
|
||||
idx: usize,
|
||||
) -> usize {
|
||||
use DynamicNode::*;
|
||||
match node {
|
||||
Text(text) => self.create_dynamic_text(template, text, idx),
|
||||
Placeholder(place) => self.create_placeholder(place, template, idx),
|
||||
Component(component) => self.create_component_node(template, component),
|
||||
Fragment(frag) => frag.iter().map(|child| self.create(child)).sum(),
|
||||
Text(text) => self.create_dynamic_text(parent, text),
|
||||
Placeholder(place) => self.create_placeholder(place, parent),
|
||||
Component(component) => self.create_component_node(Some(parent), component),
|
||||
Fragment(frag) => self.create_children(*frag, Some(parent)),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_dynamic_text(
|
||||
&mut self,
|
||||
template: &'b VNode<'b>,
|
||||
text: &'b VText<'b>,
|
||||
idx: usize,
|
||||
) -> usize {
|
||||
fn create_dynamic_text(&mut self, parent: ElementRef, text: &'b VText<'b>) -> usize {
|
||||
// Allocate a dynamic element reference for this text node
|
||||
let new_id = self.next_element(template, template.template.get().node_paths[idx]);
|
||||
let new_id = self.next_element();
|
||||
|
||||
// Make sure the text node is assigned to the correct element
|
||||
text.id.set(Some(new_id));
|
||||
@@ -482,7 +520,7 @@ impl<'b> VirtualDom {
|
||||
// Add the mutation to the list
|
||||
self.mutations.push(HydrateText {
|
||||
id: new_id,
|
||||
path: &template.template.get().node_paths[idx][1..],
|
||||
path: &parent.path.path[1..],
|
||||
value,
|
||||
});
|
||||
|
||||
@@ -493,18 +531,20 @@ impl<'b> VirtualDom {
|
||||
pub(crate) fn create_placeholder(
|
||||
&mut self,
|
||||
placeholder: &VPlaceholder,
|
||||
template: &'b VNode<'b>,
|
||||
idx: usize,
|
||||
parent: ElementRef,
|
||||
) -> usize {
|
||||
// Allocate a dynamic element reference for this text node
|
||||
let id = self.next_element(template, template.template.get().node_paths[idx]);
|
||||
let id = self.next_element();
|
||||
|
||||
// Make sure the text node is assigned to the correct element
|
||||
placeholder.id.set(Some(id));
|
||||
|
||||
// Assign the placeholder's parent
|
||||
placeholder.parent.set(Some(parent));
|
||||
|
||||
// Assign the ID to the existing node in the template
|
||||
self.mutations.push(AssignId {
|
||||
path: &template.template.get().node_paths[idx][1..],
|
||||
path: &parent.path.path[1..],
|
||||
id,
|
||||
});
|
||||
|
||||
@@ -514,7 +554,7 @@ impl<'b> VirtualDom {
|
||||
|
||||
pub(super) fn create_component_node(
|
||||
&mut self,
|
||||
template: &'b VNode<'b>,
|
||||
parent: Option<ElementRef>,
|
||||
component: &'b VComponent<'b>,
|
||||
) -> usize {
|
||||
use RenderReturn::*;
|
||||
@@ -526,8 +566,11 @@ impl<'b> VirtualDom {
|
||||
|
||||
match unsafe { self.run_scope(scope).extend_lifetime_ref() } {
|
||||
// Create the component's root element
|
||||
Ready(t) => self.create_scope(scope, t),
|
||||
Aborted(t) => self.mount_aborted(template, t),
|
||||
Ready(t) => {
|
||||
self.assign_boundary_ref(parent, t);
|
||||
self.create_scope(scope, t)
|
||||
}
|
||||
Aborted(t) => self.mount_aborted(t, parent),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,20 +586,17 @@ impl<'b> VirtualDom {
|
||||
.unwrap_or_else(|| component.scope.get().unwrap())
|
||||
}
|
||||
|
||||
fn mount_aborted(&mut self, parent: &'b VNode<'b>, placeholder: &VPlaceholder) -> usize {
|
||||
let id = self.next_element(parent, &[]);
|
||||
fn mount_aborted(&mut self, placeholder: &VPlaceholder, parent: Option<ElementRef>) -> usize {
|
||||
let id = self.next_element();
|
||||
self.mutations.push(Mutation::CreatePlaceholder { id });
|
||||
placeholder.id.set(Some(id));
|
||||
placeholder.parent.set(parent);
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
fn set_slot(
|
||||
&mut self,
|
||||
template: &'b VNode<'b>,
|
||||
slot: &'b Cell<Option<ElementId>>,
|
||||
id: usize,
|
||||
) -> ElementId {
|
||||
let id = self.next_element(template, template.template.get().node_paths[id]);
|
||||
fn set_slot(&mut self, slot: &'b Cell<Option<ElementId>>) -> ElementId {
|
||||
let id = self.next_element();
|
||||
slot.set(Some(id));
|
||||
id
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user