fix: more panic resilience (#5489)

* fix: more panic resilience

* fix: panic typos
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2026-04-14 17:58:50 -07:00
1 parent cb5abb48dd
commit 51b0cd3313
1 file changed
+34 -29
+34 -29
View File
@@ -406,36 +406,44 @@ fn MyComponent() -> Element {{
name = "VirtualDom::handle_bubbling_event" name = "VirtualDom::handle_bubbling_event"
)] )]
fn handle_bubbling_event(&self, parent: ElementRef, name: &str, uievent: Event<dyn Any>) { fn handle_bubbling_event(&self, parent: ElementRef, name: &str, uievent: Event<dyn Any>) {
let mounts = self.mounts.borrow();
// If the event bubbles, we traverse through the tree until we find the target element. // If the event bubbles, we traverse through the tree until we find the target element.
// Loop through each dynamic attribute (in a depth first order) in this template before moving up to the template's parent. // Loop through each dynamic attribute (in a depth first order) in this template before moving up to the template's parent.
let mut parent = Some(parent); let mut parent = Some(parent);
while let Some(path) = parent { while let Some(path) = parent {
let mut listeners = vec![]; let mut listeners = vec![];
let mount_id;
let Some(mount) = mounts.get(path.mount.0) else { // We do this in its own block to prevent mounts from staying open while we call user code
// If the node is suspended and not mounted, we can just ignore the event {
return; let mounts = self.mounts.borrow();
}; let Some(mount) = mounts.get(path.mount.0) else {
let el_ref = &mount.node; // If the node is suspended and not mounted, we can just ignore the event
let node_template = el_ref.template; return;
let target_path = path.path; };
// Accumulate listeners into the listener list bottom to top let el_ref = &mount.node;
for (idx, this_path) in node_template.attr_paths.iter().enumerate() { let node_template = el_ref.template;
let attrs = &*el_ref.dynamic_attrs[idx]; let target_path = path.path;
mount_id = el_ref.mount.get().as_usize();
for attr in attrs.iter() { // Accumulate listeners into the listener list bottom to top
// Remove the "on" prefix if it exists, TODO, we should remove this and settle on one for (idx, this_path) in node_template.attr_paths.iter().enumerate() {
if attr.name.get(2..) == Some(name) && target_path.is_descendant(this_path) { let attrs = &*el_ref.dynamic_attrs[idx];
listeners.push(&attr.value);
// Break if this is the exact target element. for attr in attrs.iter() {
// This means we won't call two listeners with the same name on the same element. This should be // Remove the "on" prefix if it exists, TODO, we should remove this and settle on one
// documented, or be rejected from the rsx! macro outright if attr.name.get(2..) == Some(name) && target_path.is_descendant(this_path)
if target_path == this_path { {
break; if let AttributeValue::Listener(listener) = &attr.value {
listeners.push(listener.clone());
}
// Break if this is the exact target element.
// This means we won't call two listeners with the same name on the same element. This should be
// documented, or be rejected from the rsx! macro outright
if target_path == this_path {
break;
}
} }
} }
} }
@@ -449,18 +457,15 @@ fn MyComponent() -> Element {{
listeners.len() listeners.len()
); );
for listener in listeners.into_iter().rev() { for listener in listeners.into_iter().rev() {
if let AttributeValue::Listener(listener) = listener { listener.call(uievent.clone());
listener.call(uievent.clone()); let metadata = uievent.metadata.borrow();
let metadata = uievent.metadata.borrow();
if !metadata.propagates { if !metadata.propagates {
return; return;
}
} }
} }
let mount = el_ref.mount.get().as_usize(); parent = mount_id.and_then(|id| self.mounts.borrow().get(id).and_then(|el| el.parent));
parent = mount.and_then(|id| mounts.get(id).and_then(|el| el.parent));
} }
} }