1use crate::*;
2
3impl Renderer {
5 pub fn render(&mut self, vnode: VirtualNode) {
14 let new_unwrapped: VirtualNode = self.unwrap_component(&vnode);
15 let old_tree: Option<VirtualNode> = self.try_get_current_tree().clone();
16 if let Some(old_vnode) = old_tree {
17 self.patch_root(&old_vnode, &new_unwrapped);
18 } else {
19 while let Some(child) = self.get_root().first_child() {
20 if let Some(element) = child.dyn_ref::<Element>() {
21 self.cleanup_dom_subtree(element);
22 }
23 self.get_root().remove_child(&child).unwrap();
24 }
25 let dom_node: Node = self.create_dom_node(&new_unwrapped);
26 self.get_root().append_child(&dom_node).unwrap();
27 }
28 self.set_current_tree(Some(new_unwrapped));
29 }
30
31 pub fn render_full_replace(&mut self, vnode: VirtualNode) {
40 let new_unwrapped: VirtualNode = self.unwrap_component(&vnode);
41 while let Some(child) = self.get_root().first_child() {
42 if let Some(element) = child.dyn_ref::<Element>() {
43 self.cleanup_dom_subtree(element);
44 }
45 self.get_root().remove_child(&child).unwrap();
46 }
47 let dom_node: Node = self.create_dom_node(&new_unwrapped);
48 self.get_root().append_child(&dom_node).unwrap();
49 self.set_current_tree(Some(new_unwrapped));
50 }
51
52 fn patch_root(&mut self, old_node: &VirtualNode, new_node: &VirtualNode) {
59 let dom_child: Option<Node> = self.get_root().first_child();
60 let is_element: bool = if let Some(ref dom_child) = dom_child {
61 dom_child.dyn_ref::<Element>().is_some()
62 } else {
63 false
64 };
65 if is_element {
66 let element: Element = dom_child.unwrap().dyn_into::<Element>().unwrap();
67 self.patch_node(old_node, new_node, &element);
68 } else if let Some(dom_child) = dom_child {
69 if let Some(element) = dom_child.dyn_ref::<Element>() {
70 self.cleanup_dom_subtree(element);
71 }
72 let new_dom: Node = self.create_dom_node(new_node);
73 self.get_root().replace_child(&new_dom, &dom_child).unwrap();
74 } else {
75 let new_dom: Node = self.create_dom_node(new_node);
76 self.get_root().append_child(&new_dom).unwrap();
77 }
78 }
79
80 fn patch_node(
88 &mut self,
89 old_node: &VirtualNode,
90 new_node: &VirtualNode,
91 dom_element: &Element,
92 ) {
93 match (old_node, new_node) {
94 (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => {
95 if old_text != new_text {
96 dom_element.set_text_content(Some(new_text.get_content()));
97 }
98 }
99 (
100 VirtualNode::Element {
101 tag: old_tag,
102 attributes: old_attrs,
103 children: old_children,
104 key: _old_key,
105 },
106 VirtualNode::Element {
107 tag: new_tag,
108 attributes: new_attrs,
109 children: new_children,
110 key: _new_key,
111 },
112 ) => {
113 if old_tag != new_tag {
114 let new_dom: Node = self.create_dom_node(new_node);
115 if let Some(parent) = dom_element.parent_node() {
116 self.cleanup_dom_subtree(dom_element);
117 parent.replace_child(&new_dom, dom_element).unwrap();
118 }
119 return;
120 }
121 self.patch_attributes(dom_element, old_attrs, new_attrs);
122 self.patch_children(dom_element, old_children, new_children);
123 }
124 (VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
125 self.patch_children(dom_element, old_children, new_children);
126 }
127 (VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => {}
128 (VirtualNode::Dynamic(_), _) => {
129 let new_dom: Node = self.create_dom_node(new_node);
130 if let Some(parent) = dom_element.parent_node() {
131 self.cleanup_dom_subtree(dom_element);
132 parent.replace_child(&new_dom, dom_element).unwrap();
133 }
134 }
135 (_, VirtualNode::Dynamic(_)) => {
136 let new_dom: Node = self.create_dom_node(new_node);
137 if let Some(parent) = dom_element.parent_node() {
138 self.cleanup_dom_subtree(dom_element);
139 parent.replace_child(&new_dom, dom_element).unwrap();
140 }
141 }
142 _ => {
143 let new_dom: Node = self.create_dom_node(new_node);
144 if let Some(parent) = dom_element.parent_node() {
145 self.cleanup_dom_subtree(dom_element);
146 parent.replace_child(&new_dom, dom_element).unwrap();
147 }
148 }
149 }
150 }
151
152 fn patch_attributes(
160 &mut self,
161 element: &Element,
162 old_attrs: &[AttributeEntry],
163 new_attrs: &[AttributeEntry],
164 ) {
165 let old_map: HashMap<&str, &AttributeValue> = old_attrs
166 .iter()
167 .map(|attr: &AttributeEntry| (attr.get_name().as_str(), attr.get_value()))
168 .collect();
169 let new_map: HashMap<&str, ()> = new_attrs
170 .iter()
171 .map(|attr: &AttributeEntry| (attr.get_name().as_str(), ()))
172 .collect();
173 for old_attr in old_attrs {
174 if !new_map.contains_key(old_attr.get_name().as_str()) {
175 if let AttributeValue::Event(_) = old_attr.get_value()
176 && let Some(euv_id_str) = element.get_attribute(DATA_EUV_ID)
177 && let Ok(euv_id) = euv_id_str.parse::<usize>()
178 {
179 cleanup_event_handler(euv_id, old_attr.get_name());
180 }
181 remove_dom_attribute_or_property(element, old_attr.get_name());
182 }
183 }
184 for new_attr in new_attrs {
185 let old_value: Option<&AttributeValue> =
186 old_map.get(new_attr.get_name().as_str()).copied();
187 let should_set: bool = match old_value {
188 Some(old_val) => old_val != new_attr.get_value(),
189 None => true,
190 };
191 if should_set {
192 match new_attr.get_value() {
193 AttributeValue::Text(value) => {
194 if value.is_empty() {
195 remove_dom_attribute_or_property(element, new_attr.get_name());
196 } else {
197 set_dom_attribute_or_property(element, new_attr.get_name(), value);
198 }
199 }
200 AttributeValue::Signal(signal) => {
201 let value: String = signal.get();
202 if value.is_empty() && !is_boolean_property(new_attr.get_name()) {
203 remove_dom_attribute_or_property(element, new_attr.get_name());
204 } else {
205 set_dom_attribute_or_property(element, new_attr.get_name(), &value);
206 }
207 }
208 AttributeValue::Event(handler) => {
209 self.attach_event_listener(element, handler);
210 }
211 AttributeValue::Dynamic(_) => {}
212 AttributeValue::Css(css_class) => {
213 css_class.inject_style();
214 set_dom_attribute_or_property(
215 element,
216 new_attr.get_name(),
217 css_class.get_name(),
218 );
219 }
220 }
221 }
222 }
223 }
224
225 fn get_child_node(parent: &Element, index: u32) -> Option<Node> {
236 parent.child_nodes().get(index)
237 }
238
239 fn patch_children(
253 &mut self,
254 parent: &Element,
255 old_children: &[VirtualNode],
256 new_children: &[VirtualNode],
257 ) {
258 let old_has_keys: bool =
259 !old_children.is_empty() && old_children.iter().all(Self::node_has_key);
260 let new_has_keys: bool =
261 !new_children.is_empty() && new_children.iter().all(Self::node_has_key);
262 if old_has_keys && new_has_keys {
263 self.patch_children_keyed(parent, old_children, new_children);
264 } else {
265 self.patch_children_positional(parent, old_children, new_children);
266 }
267 }
268
269 fn node_has_key(node: &VirtualNode) -> bool {
279 match node {
280 VirtualNode::Element { key, .. } => key.is_some(),
281 _ => false,
282 }
283 }
284
285 fn get_node_key(node: &VirtualNode) -> Option<&str> {
295 match node {
296 VirtualNode::Element { key, .. } => key.as_deref(),
297 _ => None,
298 }
299 }
300
301 fn patch_children_keyed(
318 &mut self,
319 parent: &Element,
320 old_children: &[VirtualNode],
321 new_children: &[VirtualNode],
322 ) {
323 let mut old_key_map: HashMap<&str, usize> = HashMap::with_capacity(old_children.len());
324 for (index, old_child) in old_children.iter().enumerate() {
325 if let Some(key) = Self::get_node_key(old_child) {
326 old_key_map.insert(key, index);
327 }
328 }
329 let mut reused_indices: HashSet<usize> = HashSet::with_capacity(new_children.len());
330 let child_nodes: NodeList = parent.child_nodes();
331 let dom_child_count: u32 = child_nodes.length();
332 for (new_index, new_child) in new_children.iter().enumerate() {
333 let new_key: &str = Self::get_node_key(new_child).unwrap_or("");
334 if let Some(&old_index) = old_key_map.get(new_key) {
335 reused_indices.insert(old_index);
336 let old_child: &VirtualNode = &old_children[old_index];
337 let mapped_dom_index: u32 = old_index as u32;
338 if mapped_dom_index < dom_child_count
339 && let Some(dom_node) = child_nodes.get(mapped_dom_index)
340 && let Some(element) = dom_node.dyn_ref::<Element>()
341 {
342 self.patch_node(old_child, new_child, element);
343 }
344 let current_dom_index: u32 = new_index as u32;
345 if mapped_dom_index != current_dom_index
346 && current_dom_index < dom_child_count
347 && let Some(dom_node) = child_nodes.get(mapped_dom_index)
348 {
349 if let Some(reference_node) = child_nodes.get(current_dom_index) {
350 let _ = parent.insert_before(&dom_node, Some(&reference_node));
351 } else {
352 let _ = parent.append_child(&dom_node);
353 }
354 }
355 } else {
356 let new_dom: Node = self.create_dom_node(new_child);
357 if (new_index as u32) < dom_child_count
358 && let Some(reference_node) = child_nodes.get(new_index as u32)
359 {
360 let _ = parent.insert_before(&new_dom, Some(&reference_node));
361 } else {
362 let _ = parent.append_child(&new_dom);
363 }
364 }
365 }
366 let mut indices_to_remove: Vec<usize> = Vec::new();
367 for (index, old_child) in old_children.iter().enumerate() {
368 if !reused_indices.contains(&index) {
369 indices_to_remove.push(index);
370 }
371 let _ = old_child;
372 }
373 indices_to_remove.sort_unstable_by(|a: &usize, b: &usize| b.cmp(a));
374 for old_index in indices_to_remove {
375 let mapped_dom_index: u32 = old_index as u32;
376 if mapped_dom_index < parent.child_nodes().length()
377 && let Some(dom_node) = parent.child_nodes().get(mapped_dom_index)
378 {
379 if let Some(element) = dom_node.dyn_ref::<Element>() {
380 self.cleanup_dom_subtree(element);
381 }
382 let _ = parent.remove_child(&dom_node);
383 }
384 }
385 }
386
387 fn patch_children_positional(
398 &mut self,
399 parent: &Element,
400 old_children: &[VirtualNode],
401 new_children: &[VirtualNode],
402 ) {
403 let old_len: usize = old_children.len();
404 let new_len: usize = new_children.len();
405 let common_len: usize = old_len.min(new_len);
406 for index in 0..common_len {
407 let old_child: &VirtualNode = &old_children[index];
408 let new_child: &VirtualNode = &new_children[index];
409 if let Some(dom_child) = Self::get_child_node(parent, index as u32) {
410 if let Some(element) = dom_child.dyn_ref::<Element>() {
411 self.patch_node(old_child, new_child, element);
412 } else if let (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) =
413 (old_child, new_child)
414 {
415 if old_text != new_text {
416 dom_child.set_text_content(Some(new_text.get_content()));
417 }
418 } else {
419 let new_dom: Node = self.create_dom_node(new_child);
420 if let Some(parent_node) = dom_child.parent_node() {
421 if let Some(child_element) = dom_child.dyn_ref::<Element>() {
422 self.cleanup_dom_subtree(child_element);
423 }
424 let _ = parent_node.replace_child(&new_dom, &dom_child);
425 }
426 }
427 }
428 }
429 if new_len > old_len {
430 for new_child in new_children.iter().skip(common_len) {
431 let new_dom: Node = self.create_dom_node(new_child);
432 parent.append_child(&new_dom).unwrap();
433 }
434 } else if old_len > new_len {
435 for _ in common_len..old_len {
436 if let Some(last_child) = parent.last_child()
437 && let Some(element) = last_child.dyn_ref::<Element>()
438 {
439 self.cleanup_dom_subtree(element);
440 }
441 if let Some(last_child) = parent.last_child() {
442 parent.remove_child(&last_child).unwrap();
443 }
444 }
445 }
446 }
447
448 fn create_dom_node(&mut self, node: &VirtualNode) -> Node {
462 let document: Document = window().unwrap().document().unwrap();
463 self.create_dom_node_with_document(node, &document)
464 }
465
466 fn create_dom_node_with_document(&mut self, node: &VirtualNode, document: &Document) -> Node {
477 match node {
478 VirtualNode::Element {
479 tag,
480 attributes,
481 children,
482 ..
483 } => {
484 let element: Element = match tag {
485 Tag::Element(name) => document.create_element(name).unwrap(),
486 Tag::Component(_) => {
487 let unwrapped: VirtualNode = self.unwrap_component(node);
488 return self.create_dom_node_with_document(&unwrapped, document);
489 }
490 };
491 for attr in attributes {
492 match attr.get_value() {
493 AttributeValue::Text(value) => {
494 if !value.is_empty() || is_boolean_property(attr.get_name()) {
495 set_dom_attribute_or_property(&element, attr.get_name(), value);
496 }
497 }
498 AttributeValue::Signal(signal) => {
499 let initial_value: String = signal.get();
500 if !initial_value.is_empty() || is_boolean_property(attr.get_name()) {
501 set_dom_attribute_or_property(
502 &element,
503 attr.get_name(),
504 &initial_value,
505 );
506 }
507 let signal_addr: usize = signal.get_inner_addr();
508 let existing_addrs: String = element
509 .get_attribute("data-euv-signal-addrs")
510 .unwrap_or_default();
511 let updated_addrs: String = if existing_addrs.is_empty() {
512 signal_addr.to_string()
513 } else {
514 format!("{},{}", existing_addrs, signal_addr)
515 };
516 let _ = element.set_attribute("data-euv-signal-addrs", &updated_addrs);
517 let attr_name: String = attr.get_name().clone();
518 let element_clone: Element = element.clone();
519 let signal_for_sub: Signal<String> = *signal;
520 let sub_signal: Signal<String> = signal_for_sub;
521 signal_for_sub.replace_subscribe(move || {
522 if !is_node_connected(&element_clone) {
523 sub_signal.clear_listeners();
524 return;
525 }
526 let new_value: String = sub_signal.get();
527 if new_value.is_empty() && !is_boolean_property(&attr_name) {
528 remove_dom_attribute_or_property(&element_clone, &attr_name);
529 } else {
530 set_dom_attribute_or_property(
531 &element_clone,
532 &attr_name,
533 &new_value,
534 );
535 }
536 });
537 }
538 AttributeValue::Event(handler) => {
539 self.attach_event_listener(&element, handler);
540 }
541 AttributeValue::Dynamic(_) => {}
542 AttributeValue::Css(css_class) => {
543 css_class.inject_style();
544 set_dom_attribute_or_property(
545 &element,
546 attr.get_name(),
547 css_class.get_name(),
548 );
549 }
550 }
551 }
552 for child in children {
553 let child_node: Node = self.create_dom_node_with_document(child, document);
554 element.append_child(&child_node).unwrap();
555 }
556 element.into()
557 }
558 VirtualNode::Text(text_node) => {
559 let text: Text = document.create_text_node(text_node.get_content());
560 if let Some(signal) = text_node.try_get_signal() {
561 let text_clone: Text = text.clone();
562 let signal_clone: Signal<String> = *signal;
563 let sub_signal: Signal<String> = signal_clone;
564 signal_clone.replace_subscribe({
565 move || {
566 if !is_node_connected(&text_clone) {
567 sub_signal.clear_listeners();
568 return;
569 }
570 let new_value: String = sub_signal.get();
571 text_clone.set_text_content(Some(&new_value));
572 }
573 });
574 }
575 text.into()
576 }
577 VirtualNode::Fragment(children) => {
578 let fragment: Element = document.create_element("slot").unwrap();
579 let _ = fragment.set_attribute("style", "display:contents");
580 for child in children {
581 let child_node: Node = self.create_dom_node_with_document(child, document);
582 fragment.append_child(&child_node).unwrap();
583 }
584 fragment.into()
585 }
586 VirtualNode::Dynamic(dynamic_node) => {
587 let placeholder: Element = document.create_element("div").unwrap();
588 let style: &str = "display: contents;";
589 let _ = placeholder.set_attribute("style", style);
590 let dynamic_id: usize = Self::assign_dynamic_id(&placeholder);
591 let initial_dom: Node =
592 self.setup_dynamic_node(dynamic_node, dynamic_id, &placeholder, true);
593 placeholder.append_child(&initial_dom).unwrap();
594 placeholder.into()
595 }
596 VirtualNode::Empty => document.create_text_node("").into(),
597 }
598 }
599
600 fn setup_dynamic_node(
614 &mut self,
615 dynamic_node: &DynamicNode,
616 dynamic_id: usize,
617 placeholder: &Element,
618 skip_equal: bool,
619 ) -> Node {
620 let mut hook_context: HookContext = dynamic_node.get_hook_context_value();
621 hook_context.reset_hook_index();
622 let initial_vnode: VirtualNode =
623 with_hook_context(hook_context.clone(), || dynamic_node.render());
624 let initial_unwrapped: VirtualNode = self.unwrap_component(&initial_vnode);
625 let initial_dom: Node = self.create_dom_node(&initial_unwrapped);
626 let render_fn: Rc<RefCell<RenderFnInner>> = dynamic_node.get_render_fn().clone();
627 let placeholder_clone: Element = placeholder.clone();
628 let mut renderer_for_sub: Renderer = Renderer::new(placeholder_clone.clone());
629 renderer_for_sub.set_current_tree(Some(initial_unwrapped));
630 let renderer_rc: Rc<RefCell<Renderer>> = Rc::new(RefCell::new(renderer_for_sub));
631 let initial_arm: usize = hook_context.get_inner().borrow().get_arm_changed();
632 let last_arm: Rc<RefCell<usize>> = Rc::new(RefCell::new(initial_arm));
633 let callback: Box<dyn FnMut()> = Box::new(move || {
634 if placeholder_clone.parent_node().is_none() {
635 return;
636 }
637 hook_context.reset_hook_index();
638 let prev_arm: usize = *last_arm.borrow();
639 let new_vnode: VirtualNode = with_hook_context(hook_context.clone(), || {
640 let mut inner: RefMut<RenderFnInner> = render_fn.borrow_mut();
641 (inner.get_mut_render_fn())()
642 });
643 let current_arm: usize = hook_context.get_inner().borrow().get_arm_changed();
644 let arm_switched: bool = prev_arm != current_arm;
645 *last_arm.borrow_mut() = current_arm;
646 if skip_equal && !arm_switched {
647 let renderer_ref: Ref<Renderer> = renderer_rc.borrow();
648 if let Some(old_vnode) = renderer_ref.try_get_current_tree() {
649 let new_unwrapped: VirtualNode = Renderer::unwrap_component_static(&new_vnode);
650 if Renderer::visual_eq(old_vnode, &new_unwrapped) {
651 return;
652 }
653 }
654 }
655 let mut renderer_mut: RefMut<Renderer> = renderer_rc.borrow_mut();
656 if arm_switched {
657 renderer_mut.render_full_replace(new_vnode);
658 } else {
659 renderer_mut.render(new_vnode);
660 }
661 });
662 register_dynamic_listener(dynamic_id, callback);
663 initial_dom
664 }
665
666 fn unwrap_component(&self, node: &VirtualNode) -> VirtualNode {
676 match node {
677 VirtualNode::Element {
678 tag: Tag::Component(_),
679 children,
680 ..
681 } => {
682 if children.len() == 1 {
683 self.unwrap_component(&children[0])
684 } else {
685 VirtualNode::Fragment(children.clone())
686 }
687 }
688 VirtualNode::Element {
689 tag,
690 attributes,
691 children,
692 key,
693 } => {
694 if !children.iter().any(Self::subtree_has_component) {
695 return node.clone();
696 }
697 let unwrapped_children: Vec<VirtualNode> = children
698 .iter()
699 .map(|child| self.unwrap_component(child))
700 .collect();
701 VirtualNode::Element {
702 tag: tag.clone(),
703 attributes: attributes.clone(),
704 children: unwrapped_children,
705 key: key.clone(),
706 }
707 }
708 VirtualNode::Fragment(children) => {
709 if !children.iter().any(Self::subtree_has_component) {
710 return node.clone();
711 }
712 let unwrapped_children: Vec<VirtualNode> = children
713 .iter()
714 .map(|child| self.unwrap_component(child))
715 .collect();
716 VirtualNode::Fragment(unwrapped_children)
717 }
718 other => other.clone(),
719 }
720 }
721
722 fn unwrap_component_static(node: &VirtualNode) -> VirtualNode {
732 match node {
733 VirtualNode::Element {
734 tag: Tag::Component(_),
735 children,
736 ..
737 } => {
738 if children.len() == 1 {
739 Self::unwrap_component_static(&children[0])
740 } else {
741 VirtualNode::Fragment(children.clone())
742 }
743 }
744 VirtualNode::Element {
745 tag,
746 attributes,
747 children,
748 key,
749 } => {
750 if !children.iter().any(Self::subtree_has_component) {
751 return node.clone();
752 }
753 let unwrapped_children: Vec<VirtualNode> =
754 children.iter().map(Self::unwrap_component_static).collect();
755 VirtualNode::Element {
756 tag: tag.clone(),
757 attributes: attributes.clone(),
758 children: unwrapped_children,
759 key: key.clone(),
760 }
761 }
762 VirtualNode::Fragment(children) => {
763 if !children.iter().any(Self::subtree_has_component) {
764 return node.clone();
765 }
766 let unwrapped_children: Vec<VirtualNode> =
767 children.iter().map(Self::unwrap_component_static).collect();
768 VirtualNode::Fragment(unwrapped_children)
769 }
770 other => other.clone(),
771 }
772 }
773
774 fn subtree_has_component(node: &VirtualNode) -> bool {
785 match node {
786 VirtualNode::Element {
787 tag: Tag::Component(_),
788 ..
789 } => true,
790 VirtualNode::Element { children, .. } => {
791 children.iter().any(Self::subtree_has_component)
792 }
793 VirtualNode::Fragment(children) => children.iter().any(Self::subtree_has_component),
794 _ => false,
795 }
796 }
797
798 fn visual_eq(old_node: &VirtualNode, new_node: &VirtualNode) -> bool {
814 match (old_node, new_node) {
815 (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => old_text == new_text,
816 (
817 VirtualNode::Element {
818 tag: old_tag,
819 attributes: old_attrs,
820 children: old_children,
821 ..
822 },
823 VirtualNode::Element {
824 tag: new_tag,
825 attributes: new_attrs,
826 children: new_children,
827 ..
828 },
829 ) => {
830 old_tag == new_tag
831 && old_attrs.len() == new_attrs.len()
832 && old_attrs
833 .iter()
834 .zip(new_attrs.iter())
835 .all(|(old_attr, new_attr)| old_attr == new_attr)
836 && old_children.len() == new_children.len()
837 && old_children
838 .iter()
839 .zip(new_children.iter())
840 .all(|(old_child, new_child)| Self::visual_eq(old_child, new_child))
841 }
842 (VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
843 old_children.len() == new_children.len()
844 && old_children
845 .iter()
846 .zip(new_children.iter())
847 .all(|(old_child, new_child)| Self::visual_eq(old_child, new_child))
848 }
849 (VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => true,
850 (VirtualNode::Empty, VirtualNode::Empty) => true,
851 _ => false,
852 }
853 }
854
855 fn assign_dynamic_id(placeholder: &Element) -> usize {
865 let dynamic_id: usize = NEXT_EUV_DYNAMIC_ID.fetch_add(1, Ordering::Relaxed);
866 let _ = placeholder.set_attribute("data-euv-dynamic-id", &dynamic_id.to_string());
867 dynamic_id
868 }
869
870 fn cleanup_dom_subtree(&self, element: &Element) {
879 if let Some(euv_id_str) = element.get_attribute(DATA_EUV_ID)
880 && let Ok(euv_id) = euv_id_str.parse::<usize>()
881 {
882 cleanup_element_handlers(euv_id);
883 }
884 if let Some(dynamic_id_str) = element.get_attribute("data-euv-dynamic-id")
885 && let Ok(dynamic_id) = dynamic_id_str.parse::<usize>()
886 {
887 cleanup_dynamic_node(dynamic_id);
888 }
889 if let Some(signal_addrs_str) = element.get_attribute("data-euv-signal-addrs") {
890 for addr_str in signal_addrs_str.split(',') {
891 if let Ok(addr) = addr_str.parse::<usize>() {
892 clear_signal_listeners_by_addr(addr);
893 }
894 }
895 }
896 let child_nodes: NodeList = element.child_nodes();
897 let length: u32 = child_nodes.length();
898 for i in 0..length {
899 if let Some(child) = child_nodes.get(i) {
900 if let Some(child_element) = child.dyn_ref::<Element>() {
901 self.cleanup_dom_subtree(child_element);
902 } else if let Some(text) = child.dyn_ref::<Text>() {
903 cleanup_text_signal_listeners(text);
904 }
905 }
906 }
907 }
908
909 fn attach_event_listener(&self, element: &Element, handler: &NativeEventHandler) {
916 let euv_id: usize = match element.get_attribute(DATA_EUV_ID) {
917 Some(id_str) => id_str.parse::<usize>().unwrap_or_else(|_| {
918 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
919 let _ = element.set_attribute(DATA_EUV_ID, &new_id.to_string());
920 new_id
921 }),
922 None => {
923 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
924 let _ = element.set_attribute(DATA_EUV_ID, &new_id.to_string());
925 new_id
926 }
927 };
928 let event_name: Cow<'static, str> = handler.get_event_name().clone();
929 if !NativeEventName::DELEGATABLE_EVENT_NAMES.contains(&&*event_name) {
930 ensure_delegated_listener(event_name.clone());
931 }
932 let key: (usize, Cow<'static, str>) = (euv_id, event_name);
933 let registry_ref: &mut HashMap<(usize, Cow<'static, str>), HandlerEntry> =
934 ensure_handler_registry_mut();
935 if let Some(existing_entry) = registry_ref.get(&key) {
936 let mut slot: RefMut<HandlerSlot> = existing_entry.borrow_mut();
937 slot.set_handler(Some(handler.clone()));
938 } else {
939 let handler_slot: HandlerEntry =
940 Rc::new(RefCell::new(HandlerSlot::new(Some(handler.clone()))));
941 registry_ref.insert(key, handler_slot);
942 }
943 }
944}