Synchronous prevent default (#2792)
* add prevent default methods to the event * sync prevent default almost working * sync prevent default working * Move event handling into the runtime * update core tests * restore desktop file dialog * implement prevent default on web * add a hint about the new prevent default method * fix web prevent default * Fix CTRL+click on links * fix values memorize in place test * Fix a few more tests * Add a playwright test for sync prevent default * Fix core doc tests * create a deprecated VirtualDom::handle_event * fix macos imports in desktop * Fix onmounted event * Fix liveview support * switch to RefCell for metadata * Remove println * remove prevent default attribute * remove web specific link behavior * Fix liveview links * more liveview fixes for link * Fix merge conflicts * Fix clippy * use the new prevent default in the file upload example
This commit is contained in:
1 parent
8b62b71e2d
commit
cab573eefd
54 files changed
+940
-729
No files matched your search
@@ -19,13 +19,19 @@ impl VNode {
|
||||
mut to: Option<&mut impl WriteMutations>,
|
||||
) {
|
||||
// The node we are diffing from should always be mounted
|
||||
debug_assert!(dom.mounts.get(self.mount.get().0).is_some() || to.is_none());
|
||||
debug_assert!(
|
||||
dom.runtime
|
||||
.mounts
|
||||
.borrow()
|
||||
.get(self.mount.get().0)
|
||||
.is_some()
|
||||
|| to.is_none()
|
||||
);
|
||||
|
||||
// If the templates are different, we need to replace the entire template
|
||||
if self.template != new.template {
|
||||
let mount_id = self.mount.get();
|
||||
let mount = &dom.mounts[mount_id.0];
|
||||
let parent = mount.parent;
|
||||
let parent = dom.get_mounted_parent(mount_id);
|
||||
return self.replace(std::slice::from_ref(new), parent, dom, to);
|
||||
}
|
||||
|
||||
@@ -62,7 +68,8 @@ impl VNode {
|
||||
new.mount.set(mount_id);
|
||||
|
||||
if mount_id.mounted() {
|
||||
let mount = &mut dom.mounts[mount_id.0];
|
||||
let mut mounts = dom.runtime.mounts.borrow_mut();
|
||||
let mount = &mut mounts[mount_id.0];
|
||||
|
||||
// Update the reference to the node for bubbling events
|
||||
mount.node = new.clone_mounted();
|
||||
@@ -83,8 +90,8 @@ impl VNode {
|
||||
(Text(old), Text(new)) => {
|
||||
// Diffing text is just a side effect, if we are diffing suspended nodes and are not outputting mutations, we can skip it
|
||||
if let Some(to) = to {
|
||||
let mount = &dom.mounts[mount.0];
|
||||
self.diff_vtext(to, mount, idx, old, new)
|
||||
let id = ElementId(dom.get_mounted_dyn_node(mount, idx));
|
||||
self.diff_vtext(to, id, old, new)
|
||||
}
|
||||
}
|
||||
(Placeholder(_), Placeholder(_)) => {}
|
||||
@@ -95,7 +102,7 @@ impl VNode {
|
||||
Some(self.reference_to_dynamic_node(mount, idx)),
|
||||
),
|
||||
(Component(old), Component(new)) => {
|
||||
let scope_id = ScopeId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]);
|
||||
let scope_id = ScopeId(dom.get_mounted_dyn_node(mount, idx));
|
||||
self.diff_vcomponent(
|
||||
mount,
|
||||
idx,
|
||||
@@ -114,20 +121,20 @@ impl VNode {
|
||||
// Mark the mount as unused. When a scope is created, it reads the mount and
|
||||
// if it is the placeholder value, it will create the scope, otherwise it will
|
||||
// reuse the scope
|
||||
let old_mount = dom.mounts[mount.0].mounted_dynamic_nodes[idx];
|
||||
dom.mounts[mount.0].mounted_dynamic_nodes[idx] = usize::MAX;
|
||||
let old_mount = dom.get_mounted_dyn_node(mount, idx);
|
||||
dom.set_mounted_dyn_node(mount, idx, usize::MAX);
|
||||
|
||||
let new_nodes_on_stack =
|
||||
self.create_dynamic_node(new, mount, idx, dom, to.as_deref_mut());
|
||||
|
||||
// Restore the mount for the scope we are removing
|
||||
let new_mount = dom.mounts[mount.0].mounted_dynamic_nodes[idx];
|
||||
dom.mounts[mount.0].mounted_dynamic_nodes[idx] = old_mount;
|
||||
let new_mount = dom.get_mounted_dyn_node(mount, idx);
|
||||
dom.set_mounted_dyn_node(mount, idx, old_mount);
|
||||
|
||||
self.remove_dynamic_node(mount, dom, to, true, idx, old, Some(new_nodes_on_stack));
|
||||
|
||||
// Restore the mount for the node we created
|
||||
dom.mounts[mount.0].mounted_dynamic_nodes[idx] = new_mount;
|
||||
dom.set_mounted_dyn_node(mount, idx, new_mount);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -143,12 +150,14 @@ impl VNode {
|
||||
}
|
||||
|
||||
pub(crate) fn find_first_element(&self, dom: &VirtualDom) -> ElementId {
|
||||
let mount = &dom.mounts[self.mount.get().0];
|
||||
let mount_id = self.mount.get();
|
||||
let first = match self.get_dynamic_root_node_and_id(0) {
|
||||
// This node is static, just get the root id
|
||||
None => mount.root_ids[0],
|
||||
None => dom.get_mounted_root_node(mount_id, 0),
|
||||
// If it is dynamic and shallow, grab the id from the mounted dynamic nodes
|
||||
Some((idx, Placeholder(_) | Text(_))) => ElementId(mount.mounted_dynamic_nodes[idx]),
|
||||
Some((idx, Placeholder(_) | Text(_))) => {
|
||||
ElementId(dom.get_mounted_dyn_node(mount_id, idx))
|
||||
}
|
||||
// The node is a fragment, so we need to find the first element in the fragment
|
||||
Some((_, Fragment(children))) => {
|
||||
let child = children.first().unwrap();
|
||||
@@ -156,7 +165,7 @@ impl VNode {
|
||||
}
|
||||
// The node is a component, so we need to find the first element in the component
|
||||
Some((id, Component(_))) => {
|
||||
let scope = ScopeId(mount.mounted_dynamic_nodes[id]);
|
||||
let scope = ScopeId(dom.get_mounted_dyn_node(mount_id, id));
|
||||
dom.get_scope(scope)
|
||||
.unwrap()
|
||||
.root_node()
|
||||
@@ -171,13 +180,15 @@ impl VNode {
|
||||
}
|
||||
|
||||
pub(crate) fn find_last_element(&self, dom: &VirtualDom) -> ElementId {
|
||||
let mount = &dom.mounts[self.mount.get().0];
|
||||
let mount_id = self.mount.get();
|
||||
let last_root_index = self.template.roots.len() - 1;
|
||||
let last = match self.get_dynamic_root_node_and_id(last_root_index) {
|
||||
// This node is static, just get the root id
|
||||
None => mount.root_ids[last_root_index],
|
||||
None => dom.get_mounted_root_node(mount_id, last_root_index),
|
||||
// If it is dynamic and shallow, grab the id from the mounted dynamic nodes
|
||||
Some((idx, Placeholder(_) | Text(_))) => ElementId(mount.mounted_dynamic_nodes[idx]),
|
||||
Some((idx, Placeholder(_) | Text(_))) => {
|
||||
ElementId(dom.get_mounted_dyn_node(mount_id, idx))
|
||||
}
|
||||
// The node is a fragment, so we need to find the first element in the fragment
|
||||
Some((_, Fragment(children))) => {
|
||||
let child = children.first().unwrap();
|
||||
@@ -185,7 +196,7 @@ impl VNode {
|
||||
}
|
||||
// The node is a component, so we need to find the first element in the component
|
||||
Some((id, Component(_))) => {
|
||||
let scope = ScopeId(mount.mounted_dynamic_nodes[id]);
|
||||
let scope = ScopeId(dom.get_mounted_dyn_node(mount_id, id));
|
||||
dom.get_scope(scope)
|
||||
.unwrap()
|
||||
.root_node()
|
||||
@@ -202,16 +213,8 @@ impl VNode {
|
||||
/// Diff the two text nodes
|
||||
///
|
||||
/// This just sets the text of the node if it's different.
|
||||
fn diff_vtext(
|
||||
&self,
|
||||
to: &mut impl WriteMutations,
|
||||
mount: &VNodeMount,
|
||||
idx: usize,
|
||||
left: &VText,
|
||||
right: &VText,
|
||||
) {
|
||||
fn diff_vtext(&self, to: &mut impl WriteMutations, id: ElementId, left: &VText, right: &VText) {
|
||||
if left.value != right.value {
|
||||
let id = ElementId(mount.mounted_dynamic_nodes[idx]);
|
||||
to.set_node_text(&right.value, id);
|
||||
}
|
||||
}
|
||||
@@ -291,7 +294,7 @@ impl VNode {
|
||||
|
||||
if destroy_component_state {
|
||||
// Remove the mount information
|
||||
dom.mounts.remove(mount.0);
|
||||
dom.runtime.mounts.borrow_mut().remove(mount.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,8 +321,7 @@ impl VNode {
|
||||
replace_with.filter(|_| last_node),
|
||||
);
|
||||
} else if let Some(to) = to.as_deref_mut() {
|
||||
let mount = &dom.mounts[mount.0];
|
||||
let id = mount.root_ids[idx];
|
||||
let id = dom.get_mounted_root_node(mount, idx);
|
||||
if let (true, Some(replace_with)) = (last_node, replace_with) {
|
||||
to.replace_node_with(id, replace_with);
|
||||
} else {
|
||||
@@ -366,11 +368,11 @@ impl VNode {
|
||||
) {
|
||||
match node {
|
||||
Component(_comp) => {
|
||||
let scope_id = ScopeId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]);
|
||||
let scope_id = ScopeId(dom.get_mounted_dyn_node(mount, idx));
|
||||
dom.remove_component_node(to, destroy_component_state, scope_id, replace_with);
|
||||
}
|
||||
Text(_) | Placeholder(_) => {
|
||||
let id = ElementId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]);
|
||||
let id = ElementId(dom.get_mounted_dyn_node(mount, idx));
|
||||
if let Some(to) = to {
|
||||
if let Some(replace_with) = replace_with {
|
||||
to.replace_node_with(id, replace_with);
|
||||
@@ -400,7 +402,7 @@ impl VNode {
|
||||
}
|
||||
|
||||
// only reclaim the new element if it's different from the previous one
|
||||
let new_id = dom.mounts[mount.0].mounted_attributes[idx];
|
||||
let new_id = dom.get_mounted_dyn_attr(mount, idx);
|
||||
if Some(new_id) != next_id {
|
||||
dom.reclaim(new_id);
|
||||
next_id = Some(new_id);
|
||||
@@ -423,7 +425,7 @@ impl VNode {
|
||||
{
|
||||
let mut old_attributes_iter = old_attrs.iter().peekable();
|
||||
let mut new_attributes_iter = new_attrs.iter().peekable();
|
||||
let attribute_id = dom.mounts[mount_id.0].mounted_attributes[idx];
|
||||
let attribute_id = dom.get_mounted_dyn_attr(mount_id, idx);
|
||||
let path = self.template.attr_paths[idx];
|
||||
|
||||
loop {
|
||||
@@ -505,7 +507,8 @@ impl VNode {
|
||||
path: ElementPath { path },
|
||||
mount,
|
||||
};
|
||||
dom.elements[id.0] = Some(element_ref);
|
||||
let mut elements = dom.runtime.elements.borrow_mut();
|
||||
elements[id.0] = Some(element_ref);
|
||||
to.create_event_listener(&attribute.name[2..], id);
|
||||
}
|
||||
_ => {
|
||||
@@ -526,7 +529,8 @@ impl VNode {
|
||||
|
||||
// Initialize the mount information for this vnode if it isn't already mounted
|
||||
if !self.mount.get().mounted() {
|
||||
let entry = dom.mounts.vacant_entry();
|
||||
let mut mounts = dom.runtime.mounts.borrow_mut();
|
||||
let entry = mounts.vacant_entry();
|
||||
let mount = MountId(entry.key());
|
||||
self.mount.set(mount);
|
||||
tracing::trace!(?self, ?mount, "creating template");
|
||||
@@ -549,7 +553,7 @@ impl VNode {
|
||||
// Get the mounted id of this block
|
||||
// At this point, we should have already mounted the block
|
||||
debug_assert!(
|
||||
dom.mounts.contains(
|
||||
dom.runtime.mounts.borrow().contains(
|
||||
self.mount
|
||||
.get()
|
||||
.as_usize()
|
||||
@@ -752,7 +756,7 @@ impl VNode {
|
||||
|
||||
for attr in &**attribute {
|
||||
self.write_attribute(attribute_path, attr, id, mount, dom, to);
|
||||
dom.mounts[mount.0].mounted_attributes[attribute_idx] = id;
|
||||
dom.set_mounted_dyn_attr(mount, attribute_idx, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -766,7 +770,7 @@ impl VNode {
|
||||
) -> ElementId {
|
||||
// Get an ID for this root since it's a real root
|
||||
let this_id = dom.next_element();
|
||||
dom.mounts[mount.0].root_ids[root_idx] = this_id;
|
||||
dom.set_mounted_root_node(mount, root_idx, this_id);
|
||||
|
||||
to.load_template(self.template, root_idx, this_id);
|
||||
|
||||
@@ -789,7 +793,7 @@ impl VNode {
|
||||
) -> ElementId {
|
||||
// This is just the root node. We already know it's id
|
||||
if let [root_idx] = path {
|
||||
return dom.mounts[mount.0].root_ids[*root_idx as usize];
|
||||
return dom.get_mounted_root_node(mount, *root_idx as usize);
|
||||
}
|
||||
|
||||
// The node is deeper in the template and we should create a new id for it
|
||||
@@ -835,7 +839,7 @@ impl VNode {
|
||||
impl MountId {
|
||||
fn mount_node(self, node_index: usize, dom: &mut VirtualDom) -> ElementId {
|
||||
let id = dom.next_element();
|
||||
dom.mounts[self.0].mounted_dynamic_nodes[node_index] = id.0;
|
||||
dom.set_mounted_dyn_node(self, node_index, id.0);
|
||||
id
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user