euv_core/renderer/render/
impl.rs1use crate::*;
2
3impl Renderer {
5 pub fn render(&mut self, vnode: VirtualNode) {
14 let new_unwrapped: VirtualNode = self.unwrap_component(&vnode);
15 if let Some(old_vnode) = self.try_get_current_tree() {
16 let old_unwrapped: VirtualNode = self.unwrap_component(old_vnode);
17 self.patch_root(&old_unwrapped, &new_unwrapped);
18 } else {
19 let dom_node: Node = self.create_dom_node(&new_unwrapped);
20 while let Some(child) = self.get_root().first_child() {
21 self.get_root().remove_child(&child).unwrap();
22 }
23 self.get_root().append_child(&dom_node).unwrap();
24 }
25 self.set_current_tree(Some(vnode));
26 }
27
28 fn patch_root(&mut self, old_node: &VirtualNode, new_node: &VirtualNode) {
35 let dom_child: Option<Node> = self.get_root().first_child();
36 let is_element: bool = if let Some(ref dom_child) = dom_child {
37 dom_child.dyn_ref::<Element>().is_some()
38 } else {
39 false
40 };
41 if is_element {
42 let element: Element = dom_child.unwrap().dyn_into::<Element>().unwrap();
43 self.patch_node(old_node, new_node, &element);
44 } else if let Some(dom_child) = dom_child {
45 let new_dom: Node = self.create_dom_node(new_node);
46 self.get_root().replace_child(&new_dom, &dom_child).unwrap();
47 } else {
48 let new_dom: Node = self.create_dom_node(new_node);
49 self.get_root().append_child(&new_dom).unwrap();
50 }
51 }
52
53 fn patch_node(
61 &mut self,
62 old_node: &VirtualNode,
63 new_node: &VirtualNode,
64 dom_element: &Element,
65 ) {
66 match (old_node, new_node) {
67 (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => {
68 if old_text != new_text {
69 dom_element.set_text_content(Some(new_text.get_content()));
70 }
71 }
72 (
73 VirtualNode::Element {
74 tag: old_tag,
75 attributes: old_attrs,
76 children: old_children,
77 key: _old_key,
78 },
79 VirtualNode::Element {
80 tag: new_tag,
81 attributes: new_attrs,
82 children: new_children,
83 key: _new_key,
84 },
85 ) => {
86 if old_tag != new_tag {
87 let new_dom: Node = self.create_dom_node(new_node);
88 if let Some(parent) = dom_element.parent_node() {
89 self.cleanup_dom_subtree(dom_element);
90 parent.replace_child(&new_dom, dom_element).unwrap();
91 }
92 return;
93 }
94 self.patch_attributes(dom_element, old_attrs, new_attrs);
95 self.patch_children(dom_element, old_children, new_children);
96 }
97 (VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
98 self.patch_children(dom_element, old_children, new_children);
99 }
100 (VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => {}
101 _ => {
102 let new_dom: Node = self.create_dom_node(new_node);
103 if let Some(parent) = dom_element.parent_node() {
104 self.cleanup_dom_subtree(dom_element);
105 parent.replace_child(&new_dom, dom_element).unwrap();
106 }
107 }
108 }
109 }
110
111 fn patch_attributes(
119 &mut self,
120 element: &Element,
121 old_attrs: &[AttributeEntry],
122 new_attrs: &[AttributeEntry],
123 ) {
124 let old_map: HashMap<&str, &AttributeValue> = old_attrs
125 .iter()
126 .map(|attr: &AttributeEntry| (attr.get_name().as_str(), attr.get_value()))
127 .collect();
128 let new_map: HashMap<&str, ()> = new_attrs
129 .iter()
130 .map(|attr: &AttributeEntry| (attr.get_name().as_str(), ()))
131 .collect();
132 for old_attr in old_attrs {
133 if !new_map.contains_key(old_attr.get_name().as_str()) {
134 if let AttributeValue::Event(_) = old_attr.get_value()
135 && let Some(euv_id_str) = element.get_attribute(DATA_EUV_ID)
136 && let Ok(euv_id) = euv_id_str.parse::<usize>()
137 {
138 cleanup_event_handler(euv_id, old_attr.get_name());
139 }
140 remove_dom_attribute_or_property(element, old_attr.get_name());
141 }
142 }
143 for new_attr in new_attrs {
144 let old_value: Option<&AttributeValue> =
145 old_map.get(new_attr.get_name().as_str()).copied();
146 let should_set: bool = match old_value {
147 Some(old_val) => old_val != new_attr.get_value(),
148 None => true,
149 };
150 if should_set {
151 match new_attr.get_value() {
152 AttributeValue::Text(value) => {
153 if value.is_empty() {
154 remove_dom_attribute_or_property(element, new_attr.get_name());
155 } else {
156 set_dom_attribute_or_property(element, new_attr.get_name(), value);
157 }
158 }
159 AttributeValue::Signal(signal) => {
160 let value: String = signal.get();
161 if value.is_empty() && !is_boolean_property(new_attr.get_name()) {
162 remove_dom_attribute_or_property(element, new_attr.get_name());
163 } else {
164 set_dom_attribute_or_property(element, new_attr.get_name(), &value);
165 }
166 }
167 AttributeValue::Event(handler) => {
168 self.attach_event_listener(element, handler);
169 }
170 AttributeValue::Dynamic(_) => {}
171 AttributeValue::Css(css_class) => {
172 css_class.inject_style();
173 set_dom_attribute_or_property(
174 element,
175 new_attr.get_name(),
176 css_class.get_name(),
177 );
178 }
179 }
180 }
181 }
182 }
183
184 fn get_child_node(parent: &Element, index: u32) -> Option<Node> {
195 parent.child_nodes().get(index)
196 }
197
198 fn patch_children(
206 &mut self,
207 parent: &Element,
208 old_children: &[VirtualNode],
209 new_children: &[VirtualNode],
210 ) {
211 let old_len: usize = old_children.len();
212 let new_len: usize = new_children.len();
213 let common_len: usize = old_len.min(new_len);
214 for index in 0..common_len {
215 let old_child: &VirtualNode = &old_children[index];
216 let new_child: &VirtualNode = &new_children[index];
217 if let Some(dom_child) = Self::get_child_node(parent, index as u32) {
218 if let Some(element) = dom_child.dyn_ref::<Element>() {
219 self.patch_node(old_child, new_child, element);
220 } else if let (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) =
221 (old_child, new_child)
222 {
223 if old_text != new_text {
224 dom_child.set_text_content(Some(new_text.get_content()));
225 }
226 } else {
227 let new_dom: Node = self.create_dom_node(new_child);
228 if let Some(parent_node) = dom_child.parent_node() {
229 if let Some(child_element) = dom_child.dyn_ref::<Element>() {
230 self.cleanup_dom_subtree(child_element);
231 }
232 let _ = parent_node.replace_child(&new_dom, &dom_child);
233 }
234 }
235 }
236 }
237 if new_len > old_len {
238 for new_child in new_children.iter().skip(common_len) {
239 let new_dom: Node = self.create_dom_node(new_child);
240 parent.append_child(&new_dom).unwrap();
241 }
242 } else if old_len > new_len {
243 for _ in common_len..old_len {
244 if let Some(last_child) = parent.last_child()
245 && let Some(element) = last_child.dyn_ref::<Element>()
246 {
247 self.cleanup_dom_subtree(element);
248 }
249 if let Some(last_child) = parent.last_child() {
250 parent.remove_child(&last_child).unwrap();
251 }
252 }
253 }
254 }
255
256 fn create_dom_node(&mut self, node: &VirtualNode) -> Node {
270 let document: Document = window().unwrap().document().unwrap();
271 self.create_dom_node_with_document(node, &document)
272 }
273
274 fn create_dom_node_with_document(&mut self, node: &VirtualNode, document: &Document) -> Node {
285 match node {
286 VirtualNode::Element {
287 tag,
288 attributes,
289 children,
290 ..
291 } => {
292 let element: Element = match tag {
293 Tag::Element(name) => document.create_element(name).unwrap(),
294 Tag::Component(_) => {
295 let unwrapped: VirtualNode = self.unwrap_component(node);
296 return self.create_dom_node_with_document(&unwrapped, document);
297 }
298 };
299 for attr in attributes {
300 match attr.get_value() {
301 AttributeValue::Text(value) => {
302 if !value.is_empty() || is_boolean_property(attr.get_name()) {
303 set_dom_attribute_or_property(&element, attr.get_name(), value);
304 }
305 }
306 AttributeValue::Signal(signal) => {
307 let initial_value: String = signal.get();
308 if !initial_value.is_empty() || is_boolean_property(attr.get_name()) {
309 set_dom_attribute_or_property(
310 &element,
311 attr.get_name(),
312 &initial_value,
313 );
314 }
315 let signal_addr: usize = signal.get_inner_addr();
316 let existing_addrs: String = element
317 .get_attribute("data-euv-signal-addrs")
318 .unwrap_or_default();
319 let updated_addrs: String = if existing_addrs.is_empty() {
320 signal_addr.to_string()
321 } else {
322 format!("{},{}", existing_addrs, signal_addr)
323 };
324 let _ = element.set_attribute("data-euv-signal-addrs", &updated_addrs);
325 let attr_name: String = attr.get_name().clone();
326 let element_clone: Element = element.clone();
327 let signal_for_sub: Signal<String> = *signal;
328 let sub_signal: Signal<String> = signal_for_sub;
329 signal_for_sub.replace_subscribe(move || {
330 if !is_node_connected(&element_clone) {
331 sub_signal.clear_listeners();
332 return;
333 }
334 let new_value: String = sub_signal.get();
335 if new_value.is_empty() && !is_boolean_property(&attr_name) {
336 remove_dom_attribute_or_property(&element_clone, &attr_name);
337 } else {
338 set_dom_attribute_or_property(
339 &element_clone,
340 &attr_name,
341 &new_value,
342 );
343 }
344 });
345 }
346 AttributeValue::Event(handler) => {
347 self.attach_event_listener(&element, handler);
348 }
349 AttributeValue::Dynamic(_) => {}
350 AttributeValue::Css(css_class) => {
351 css_class.inject_style();
352 set_dom_attribute_or_property(
353 &element,
354 attr.get_name(),
355 css_class.get_name(),
356 );
357 }
358 }
359 }
360 for child in children {
361 let child_node: Node = self.create_dom_node_with_document(child, document);
362 element.append_child(&child_node).unwrap();
363 }
364 element.into()
365 }
366 VirtualNode::Text(text_node) => {
367 let text: Text = document.create_text_node(text_node.get_content());
368 if let Some(signal) = text_node.try_get_signal() {
369 let text_clone: Text = text.clone();
370 let signal_clone: Signal<String> = *signal;
371 let sub_signal: Signal<String> = signal_clone;
372 signal_clone.replace_subscribe({
373 move || {
374 if !is_node_connected(&text_clone) {
375 sub_signal.clear_listeners();
376 return;
377 }
378 let new_value: String = sub_signal.get();
379 text_clone.set_text_content(Some(&new_value));
380 }
381 });
382 }
383 text.into()
384 }
385 VirtualNode::Fragment(children) => {
386 let fragment: Element = document.create_element("slot").unwrap();
387 let _ = fragment.set_attribute("style", "display:contents");
388 for child in children {
389 let child_node: Node = self.create_dom_node_with_document(child, document);
390 fragment.append_child(&child_node).unwrap();
391 }
392 fragment.into()
393 }
394 VirtualNode::Dynamic(dynamic_node) => {
395 let placeholder: Element = document.create_element("div").unwrap();
396 let style: &str = "display: contents;";
397 let _ = placeholder.set_attribute("style", style);
398 let dynamic_id: usize = Self::assign_dynamic_id(&placeholder);
399 let initial_dom: Node =
400 self.setup_dynamic_node(dynamic_node, dynamic_id, &placeholder, true);
401 placeholder.append_child(&initial_dom).unwrap();
402 placeholder.into()
403 }
404 VirtualNode::Empty => document.create_text_node("").into(),
405 }
406 }
407
408 fn setup_dynamic_node(
422 &mut self,
423 dynamic_node: &DynamicNode,
424 dynamic_id: usize,
425 placeholder: &Element,
426 skip_equal: bool,
427 ) -> Node {
428 let mut hook_context: HookContext = dynamic_node.get_hook_context_value();
429 hook_context.reset_hook_index();
430 let initial_vnode: VirtualNode =
431 with_hook_context(hook_context.clone(), || dynamic_node.render());
432 let initial_unwrapped: VirtualNode = self.unwrap_component(&initial_vnode);
433 let initial_dom: Node = self.create_dom_node(&initial_unwrapped);
434 let render_fn: Rc<RefCell<RenderFnInner>> = dynamic_node.get_render_fn().clone();
435 let placeholder_clone: Element = placeholder.clone();
436 let mut renderer_for_sub: Renderer = Renderer::new(placeholder_clone.clone());
437 renderer_for_sub.set_current_tree(Some(initial_unwrapped));
438 let renderer_rc: Rc<RefCell<Renderer>> = Rc::new(RefCell::new(renderer_for_sub));
439 let callback: Box<dyn FnMut()> = Box::new(move || {
440 if placeholder_clone.parent_node().is_none() {
441 return;
442 }
443 hook_context.reset_hook_index();
444 let new_vnode: VirtualNode = with_hook_context(hook_context.clone(), || {
445 let mut inner: std::cell::RefMut<RenderFnInner> = render_fn.borrow_mut();
446 (inner.get_mut_render_fn())()
447 });
448 if skip_equal {
449 let renderer_ref: std::cell::Ref<Renderer> = renderer_rc.borrow();
450 if let Some(old_vnode) = renderer_ref.try_get_current_tree() {
451 let new_unwrapped: VirtualNode = Renderer::unwrap_component_static(&new_vnode);
452 if old_vnode == &new_unwrapped {
453 return;
454 }
455 }
456 }
457 let mut renderer_mut: std::cell::RefMut<Renderer> = renderer_rc.borrow_mut();
458 renderer_mut.render(new_vnode);
459 });
460 register_dynamic_listener(dynamic_id, callback);
461 initial_dom
462 }
463
464 fn unwrap_component(&self, node: &VirtualNode) -> VirtualNode {
474 match node {
475 VirtualNode::Element {
476 tag: Tag::Component(_),
477 children,
478 ..
479 } => {
480 if children.len() == 1 {
481 self.unwrap_component(&children[0])
482 } else {
483 VirtualNode::Fragment(children.clone())
484 }
485 }
486 VirtualNode::Element {
487 tag,
488 attributes,
489 children,
490 key,
491 } => {
492 if !children.iter().any(Self::subtree_has_component) {
493 return node.clone();
494 }
495 let unwrapped_children: Vec<VirtualNode> = children
496 .iter()
497 .map(|child| self.unwrap_component(child))
498 .collect();
499 VirtualNode::Element {
500 tag: tag.clone(),
501 attributes: attributes.clone(),
502 children: unwrapped_children,
503 key: key.clone(),
504 }
505 }
506 VirtualNode::Fragment(children) => {
507 if !children.iter().any(Self::subtree_has_component) {
508 return node.clone();
509 }
510 let unwrapped_children: Vec<VirtualNode> = children
511 .iter()
512 .map(|child| self.unwrap_component(child))
513 .collect();
514 VirtualNode::Fragment(unwrapped_children)
515 }
516 other => other.clone(),
517 }
518 }
519
520 fn unwrap_component_static(node: &VirtualNode) -> VirtualNode {
530 match node {
531 VirtualNode::Element {
532 tag: Tag::Component(_),
533 children,
534 ..
535 } => {
536 if children.len() == 1 {
537 Self::unwrap_component_static(&children[0])
538 } else {
539 VirtualNode::Fragment(children.clone())
540 }
541 }
542 VirtualNode::Element {
543 tag,
544 attributes,
545 children,
546 key,
547 } => {
548 if !children.iter().any(Self::subtree_has_component) {
549 return node.clone();
550 }
551 let unwrapped_children: Vec<VirtualNode> =
552 children.iter().map(Self::unwrap_component_static).collect();
553 VirtualNode::Element {
554 tag: tag.clone(),
555 attributes: attributes.clone(),
556 children: unwrapped_children,
557 key: key.clone(),
558 }
559 }
560 VirtualNode::Fragment(children) => {
561 if !children.iter().any(Self::subtree_has_component) {
562 return node.clone();
563 }
564 let unwrapped_children: Vec<VirtualNode> =
565 children.iter().map(Self::unwrap_component_static).collect();
566 VirtualNode::Fragment(unwrapped_children)
567 }
568 other => other.clone(),
569 }
570 }
571
572 fn subtree_has_component(node: &VirtualNode) -> bool {
582 match node {
583 VirtualNode::Element {
584 tag: Tag::Component(_),
585 ..
586 } => true,
587 VirtualNode::Element { children, .. } => {
588 children.iter().any(Self::subtree_has_component)
589 }
590 VirtualNode::Fragment(children) => children.iter().any(Self::subtree_has_component),
591 _ => false,
592 }
593 }
594
595 fn assign_dynamic_id(placeholder: &Element) -> usize {
605 let dynamic_id: usize = NEXT_EUV_DYNAMIC_ID.fetch_add(1, Ordering::Relaxed);
606 let _ = placeholder.set_attribute("data-euv-dynamic-id", &dynamic_id.to_string());
607 dynamic_id
608 }
609
610 fn cleanup_dom_subtree(&self, element: &Element) {
619 if let Some(euv_id_str) = element.get_attribute(DATA_EUV_ID)
620 && let Ok(euv_id) = euv_id_str.parse::<usize>()
621 {
622 cleanup_element_handlers(euv_id);
623 }
624 if let Some(dynamic_id_str) = element.get_attribute("data-euv-dynamic-id")
625 && let Ok(dynamic_id) = dynamic_id_str.parse::<usize>()
626 {
627 cleanup_dynamic_node(dynamic_id);
628 }
629 if let Some(signal_addrs_str) = element.get_attribute("data-euv-signal-addrs") {
630 for addr_str in signal_addrs_str.split(',') {
631 if let Ok(addr) = addr_str.parse::<usize>() {
632 clear_signal_listeners_by_addr(addr);
633 }
634 }
635 }
636 let child_nodes: NodeList = element.child_nodes();
637 let length: u32 = child_nodes.length();
638 for i in 0..length {
639 if let Some(child) = child_nodes.get(i) {
640 if let Some(child_element) = child.dyn_ref::<Element>() {
641 self.cleanup_dom_subtree(child_element);
642 } else if let Some(text) = child.dyn_ref::<Text>() {
643 cleanup_text_signal_listeners(text);
644 }
645 }
646 }
647 }
648
649 fn attach_event_listener(&self, element: &Element, handler: &NativeEventHandler) {
656 let euv_id: usize = match element.get_attribute(DATA_EUV_ID) {
657 Some(id_str) => id_str.parse::<usize>().unwrap_or_else(|_| {
658 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
659 let _ = element.set_attribute(DATA_EUV_ID, &new_id.to_string());
660 new_id
661 }),
662 None => {
663 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
664 let _ = element.set_attribute(DATA_EUV_ID, &new_id.to_string());
665 new_id
666 }
667 };
668 let event_name: Cow<'static, str> = handler.get_event_name().clone();
669 if !NativeEventName::DELEGATABLE_EVENT_NAMES.contains(&&*event_name) {
670 ensure_delegated_listener(event_name.clone());
671 }
672 let key: (usize, Cow<'static, str>) = (euv_id, event_name);
673 let registry_ref: &mut HashMap<(usize, Cow<'static, str>), HandlerEntry> =
674 ensure_handler_registry_mut();
675 if let Some(existing_entry) = registry_ref.get(&key) {
676 let mut slot: std::cell::RefMut<HandlerSlot> = existing_entry.borrow_mut();
677 slot.set_handler(Some(handler.clone()));
678 } else {
679 let handler_slot: HandlerEntry =
680 Rc::new(RefCell::new(HandlerSlot::new(Some(handler.clone()))));
681 registry_ref.insert(key, handler_slot);
682 }
683 }
684}