1use crate::*;
2
3impl Renderer {
5 pub fn new(root: Element) -> Self {
15 Renderer {
16 root,
17 current_tree: None,
18 }
19 }
20
21 pub fn render(&mut self, vnode: VirtualNode) {
27 let new_unwrapped: VirtualNode = self.unwrap_component(&vnode);
28 if let Some(old_vnode) = self.try_get_current_tree() {
29 let old_unwrapped: VirtualNode = self.unwrap_component(old_vnode);
30 self.patch_root(&old_unwrapped, &new_unwrapped);
31 } else {
32 let dom_node: Node = self.create_dom_node(&new_unwrapped);
33 while let Some(child) = self.get_root().first_child() {
34 self.get_root().remove_child(&child).unwrap();
35 }
36 self.get_root().append_child(&dom_node).unwrap();
37 }
38 self.set_current_tree(Some(vnode));
39 }
40
41 fn patch_root(&mut self, old_node: &VirtualNode, new_node: &VirtualNode) {
43 let dom_child: Option<Node> = self.get_root().first_child();
44 let is_element: bool = if let Some(ref dom_child) = dom_child {
45 dom_child.dyn_ref::<Element>().is_some()
46 } else {
47 false
48 };
49 if is_element {
50 let element: Element = dom_child.unwrap().dyn_into::<Element>().unwrap();
51 self.patch_node(old_node, new_node, &element);
52 } else if let Some(dom_child) = dom_child {
53 let new_dom: Node = self.create_dom_node(new_node);
54 self.get_root().replace_child(&new_dom, &dom_child).unwrap();
55 } else {
56 let new_dom: Node = self.create_dom_node(new_node);
57 self.get_root().append_child(&new_dom).unwrap();
58 }
59 }
60
61 fn patch_node(
63 &mut self,
64 old_node: &VirtualNode,
65 new_node: &VirtualNode,
66 dom_element: &Element,
67 ) {
68 match (old_node, new_node) {
69 (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) => {
70 if old_text.get_content() != new_text.get_content() {
71 dom_element.set_text_content(Some(new_text.get_content()));
72 }
73 }
74 (
75 VirtualNode::Element {
76 tag: old_tag,
77 attributes: old_attrs,
78 children: old_children,
79 key: _old_key,
80 },
81 VirtualNode::Element {
82 tag: new_tag,
83 attributes: new_attrs,
84 children: new_children,
85 key: _new_key,
86 },
87 ) => {
88 if !Self::tags_equal(old_tag, new_tag) {
89 let new_dom: Node = self.create_dom_node(new_node);
90 if let Some(parent) = dom_element.parent_node() {
91 parent.replace_child(&new_dom, dom_element).unwrap();
92 }
93 return;
94 }
95 self.patch_attributes(dom_element, old_attrs, new_attrs);
96 self.patch_children(dom_element, old_children, new_children);
97 }
98 (VirtualNode::Fragment(old_children), VirtualNode::Fragment(new_children)) => {
99 self.patch_children(dom_element, old_children, new_children);
100 }
101 (VirtualNode::Dynamic(_), VirtualNode::Dynamic(_)) => {}
102 _ => {
103 let new_dom: Node = self.create_dom_node(new_node);
104 if let Some(parent) = dom_element.parent_node() {
105 parent.replace_child(&new_dom, dom_element).unwrap();
106 }
107 }
108 }
109 }
110
111 fn patch_attributes(
113 &mut self,
114 element: &Element,
115 old_attrs: &[AttributeEntry],
116 new_attrs: &[AttributeEntry],
117 ) {
118 for old_attr in old_attrs {
119 let removed: bool = !new_attrs
120 .iter()
121 .any(|new_attr| new_attr.get_name() == old_attr.get_name());
122 if removed {
123 remove_dom_attribute_or_property(element, old_attr.get_name());
124 }
125 }
126 for new_attr in new_attrs {
127 let old_value: Option<&AttributeValue> = old_attrs
128 .iter()
129 .find(|old_attr| old_attr.get_name() == new_attr.get_name())
130 .map(AttributeEntry::get_value);
131 let should_set: bool = match old_value {
132 Some(old_val) => !Self::attribute_values_equal(old_val, new_attr.get_value()),
133 None => true,
134 };
135 if should_set {
136 match new_attr.get_value() {
137 AttributeValue::Text(value) => {
138 if value.is_empty() {
139 remove_dom_attribute_or_property(element, new_attr.get_name());
140 } else {
141 set_dom_attribute_or_property(element, new_attr.get_name(), value);
142 }
143 }
144 AttributeValue::Signal(signal) => {
145 let value: String = signal.get();
146 if value.is_empty() && !is_boolean_property(new_attr.get_name()) {
147 remove_dom_attribute_or_property(element, new_attr.get_name());
148 } else {
149 set_dom_attribute_or_property(element, new_attr.get_name(), &value);
150 }
151 }
152 AttributeValue::Event(handler) => {
153 self.attach_event_listener(element, handler);
154 }
155 AttributeValue::Dynamic(_) => {}
156 AttributeValue::Css(css_class) => {
157 css_class.inject_style();
158 set_dom_attribute_or_property(
159 element,
160 new_attr.get_name(),
161 css_class.get_name(),
162 );
163 }
164 }
165 }
166 }
167 }
168
169 fn tags_equal(a: &Tag, b: &Tag) -> bool {
171 match (a, b) {
172 (Tag::Element(a_name), Tag::Element(b_name)) => a_name == b_name,
173 (Tag::Component(a_name), Tag::Component(b_name)) => a_name == b_name,
174 _ => false,
175 }
176 }
177
178 fn attribute_values_equal(a: &AttributeValue, b: &AttributeValue) -> bool {
180 match (a, b) {
181 (AttributeValue::Text(a_val), AttributeValue::Text(b_val)) => a_val == b_val,
182 (AttributeValue::Signal(_a_sig), AttributeValue::Signal(_b_sig)) => false,
183 (AttributeValue::Event(_a_ev), AttributeValue::Event(_b_ev)) => false,
184 (AttributeValue::Dynamic(a_dyn), AttributeValue::Dynamic(b_dyn)) => a_dyn == b_dyn,
185 (AttributeValue::Css(a_css), AttributeValue::Css(b_css)) => {
186 a_css.get_name() == b_css.get_name()
187 }
188 _ => false,
189 }
190 }
191
192 fn get_child_node(parent: &Element, index: u32) -> Option<Node> {
194 let mut current: Option<Node> = parent.first_child();
195 let mut current_index: u32 = 0;
196 while let Some(node) = current {
197 if current_index == index {
198 return Some(node);
199 }
200 current = node.next_sibling();
201 current_index += 1;
202 }
203 None
204 }
205
206 fn patch_children(
208 &mut self,
209 parent: &Element,
210 old_children: &[VirtualNode],
211 new_children: &[VirtualNode],
212 ) {
213 let old_len: usize = old_children.len();
214 let new_len: usize = new_children.len();
215 let common_len: usize = old_len.min(new_len);
216 for index in 0..common_len {
217 let old_child: &VirtualNode = &old_children[index];
218 let new_child: &VirtualNode = &new_children[index];
219 if let Some(dom_child) = Self::get_child_node(parent, index as u32) {
220 if let Some(element) = dom_child.dyn_ref::<Element>() {
221 self.patch_node(old_child, new_child, element);
222 } else if let (VirtualNode::Text(old_text), VirtualNode::Text(new_text)) =
223 (old_child, new_child)
224 {
225 if old_text.get_content() != new_text.get_content() {
226 dom_child.set_text_content(Some(new_text.get_content()));
227 }
228 } else {
229 let new_dom: Node = self.create_dom_node(new_child);
230 if let Some(parent_node) = dom_child.parent_node() {
231 let _ = parent_node.replace_child(&new_dom, &dom_child);
232 }
233 }
234 }
235 }
236 if new_len > old_len {
237 for new_child in new_children.iter().skip(common_len) {
238 let new_dom: Node = self.create_dom_node(new_child);
239 parent.append_child(&new_dom).unwrap();
240 }
241 } else if old_len > new_len {
242 for _ in common_len..old_len {
243 if let Some(last_child) = parent.last_child() {
244 parent.remove_child(&last_child).unwrap();
245 }
246 }
247 }
248 }
249
250 fn create_dom_node(&mut self, node: &VirtualNode) -> Node {
252 let document: Document = window().unwrap().document().unwrap();
253 self.create_dom_node_with_document(node, &document)
254 }
255
256 fn create_dom_node_with_document(&mut self, node: &VirtualNode, document: &Document) -> Node {
258 match node {
259 VirtualNode::Element {
260 tag,
261 attributes,
262 children,
263 ..
264 } => {
265 let element: Element = match tag {
266 Tag::Element(name) => document.create_element(name).unwrap(),
267 Tag::Component(_) => {
268 let unwrapped: VirtualNode = self.unwrap_component(node);
269 return self.create_dom_node_with_document(&unwrapped, document);
270 }
271 };
272 for attr in attributes {
273 match attr.get_value() {
274 AttributeValue::Text(value) => {
275 if !value.is_empty() || is_boolean_property(attr.get_name()) {
276 set_dom_attribute_or_property(&element, attr.get_name(), value);
277 }
278 }
279 AttributeValue::Signal(signal) => {
280 let initial_value: String = signal.get();
281 if !initial_value.is_empty() || is_boolean_property(attr.get_name()) {
282 set_dom_attribute_or_property(
283 &element,
284 attr.get_name(),
285 &initial_value,
286 );
287 }
288 let attr_name: String = attr.get_name().clone();
289 let element_clone: Element = element.clone();
290 let signal_for_sub: Signal<String> = *signal;
291 let signal_inner: Signal<String> = signal_for_sub;
292 signal_for_sub.replace_subscribe(move || {
293 let new_value: String = signal_inner.get();
294 if new_value.is_empty() && !is_boolean_property(&attr_name) {
295 remove_dom_attribute_or_property(&element_clone, &attr_name);
296 } else {
297 set_dom_attribute_or_property(
298 &element_clone,
299 &attr_name,
300 &new_value,
301 );
302 }
303 });
304 }
305 AttributeValue::Event(handler) => {
306 self.attach_event_listener(&element, handler);
307 }
308 AttributeValue::Dynamic(_) => {}
309 AttributeValue::Css(css_class) => {
310 css_class.inject_style();
311 set_dom_attribute_or_property(
312 &element,
313 attr.get_name(),
314 css_class.get_name(),
315 );
316 }
317 }
318 }
319 for child in children {
320 let child_node: Node = self.create_dom_node_with_document(child, document);
321 element.append_child(&child_node).unwrap();
322 }
323 element.into()
324 }
325 VirtualNode::Text(text_node) => {
326 let text: Text = document.create_text_node(text_node.get_content());
327 if let Some(signal) = text_node.try_get_signal() {
328 let text_clone: Text = text.clone();
329 let signal_clone: Signal<String> = *signal;
330 signal_clone.replace_subscribe({
331 let signal_inner: Signal<String> = signal_clone;
332 move || {
333 let new_value: String = signal_inner.get();
334 text_clone.set_text_content(Some(&new_value));
335 }
336 });
337 }
338 text.into()
339 }
340 VirtualNode::Fragment(children) => {
341 let fragment: Element = document.create_element("div").unwrap();
342 for child in children {
343 let child_node: Node = self.create_dom_node_with_document(child, document);
344 fragment.append_child(&child_node).unwrap();
345 }
346 fragment.into()
347 }
348 VirtualNode::Dynamic(dynamic_node) => {
349 let placeholder: Element = document.create_element("div").unwrap();
350 let style: &str = "display: contents;";
351 let _ = placeholder.set_attribute("style", style);
352 let dynamic_id: usize = Self::assign_dynamic_id(&placeholder);
353 let initial_dom: Node =
354 self.setup_dynamic_node(dynamic_node, dynamic_id, &placeholder, true);
355 placeholder.append_child(&initial_dom).unwrap();
356 placeholder.into()
357 }
358 VirtualNode::Empty => document.create_text_node("").into(),
359 }
360 }
361
362 fn setup_dynamic_node(
365 &mut self,
366 dynamic_node: &DynamicNode,
367 dynamic_id: usize,
368 placeholder: &Element,
369 skip_equal: bool,
370 ) -> Node {
371 let mut hook_context: HookContext = dynamic_node.get_hook_context();
372 hook_context.reset_hook_index();
373 let initial_vnode: VirtualNode = with_hook_context(hook_context, || dynamic_node.render());
374 let initial_unwrapped: VirtualNode = self.unwrap_component(&initial_vnode);
375 let initial_dom: Node = self.create_dom_node(&initial_unwrapped);
376 let render_fn_addr: usize = usize::from(dynamic_node);
377 let placeholder_clone: Element = placeholder.clone();
378 let mut renderer_for_sub: Renderer = Renderer::new(placeholder_clone.clone());
379 renderer_for_sub.set_current_tree(Some(initial_unwrapped));
380 let renderer_addr: usize = Box::leak(Box::new(renderer_for_sub)) as *mut Renderer as usize;
381 let closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
382 if placeholder_clone.parent_node().is_none() {
383 return;
384 }
385 hook_context.reset_hook_index();
386 let new_vnode: VirtualNode = with_hook_context(hook_context, || {
387 let inner: &mut RenderFnInner = render_fn_addr.into();
388 (inner.render_fn)()
389 });
390 if skip_equal {
391 let renderer: &Renderer = renderer_addr.into();
392 if let Some(old_vnode) = renderer.try_get_current_tree() {
393 let new_unwrapped: VirtualNode = Renderer::unwrap_component_static(&new_vnode);
394 if old_vnode == &new_unwrapped {
395 return;
396 }
397 }
398 }
399 let renderer: &mut Renderer = renderer_addr.into();
400 renderer.render(new_vnode);
401 }));
402 register_dynamic_listener(dynamic_id, closure);
403 initial_dom
404 }
405
406 fn unwrap_component(&self, node: &VirtualNode) -> VirtualNode {
408 match node {
409 VirtualNode::Element {
410 tag: Tag::Component(_),
411 children,
412 ..
413 } => {
414 if children.len() == 1 {
415 self.unwrap_component(&children[0])
416 } else {
417 VirtualNode::Fragment(children.clone())
418 }
419 }
420 VirtualNode::Element {
421 tag,
422 attributes,
423 children,
424 key,
425 } => {
426 let unwrapped_children: Vec<VirtualNode> = children
427 .iter()
428 .map(|child| self.unwrap_component(child))
429 .collect();
430 VirtualNode::Element {
431 tag: tag.clone(),
432 attributes: attributes.clone(),
433 children: unwrapped_children,
434 key: key.clone(),
435 }
436 }
437 VirtualNode::Fragment(children) => {
438 let unwrapped_children: Vec<VirtualNode> = children
439 .iter()
440 .map(|child| self.unwrap_component(child))
441 .collect();
442 VirtualNode::Fragment(unwrapped_children)
443 }
444 other => other.clone(),
445 }
446 }
447
448 fn unwrap_component_static(node: &VirtualNode) -> VirtualNode {
452 match node {
453 VirtualNode::Element {
454 tag: Tag::Component(_),
455 children,
456 ..
457 } => {
458 if children.len() == 1 {
459 Self::unwrap_component_static(&children[0])
460 } else {
461 VirtualNode::Fragment(children.clone())
462 }
463 }
464 VirtualNode::Element {
465 tag,
466 attributes,
467 children,
468 key,
469 } => {
470 let unwrapped_children: Vec<VirtualNode> =
471 children.iter().map(Self::unwrap_component_static).collect();
472 VirtualNode::Element {
473 tag: tag.clone(),
474 attributes: attributes.clone(),
475 children: unwrapped_children,
476 key: key.clone(),
477 }
478 }
479 VirtualNode::Fragment(children) => {
480 let unwrapped_children: Vec<VirtualNode> =
481 children.iter().map(Self::unwrap_component_static).collect();
482 VirtualNode::Fragment(unwrapped_children)
483 }
484 other => other.clone(),
485 }
486 }
487
488 fn assign_dynamic_id(placeholder: &Element) -> usize {
490 let dynamic_id: usize = NEXT_EUV_DYNAMIC_ID.fetch_add(1, Ordering::Relaxed);
491 let _ = placeholder.set_attribute("data-euv-dynamic-id", &dynamic_id.to_string());
492 dynamic_id
493 }
494
495 fn attach_event_listener(&self, element: &Element, handler: &NativeEventHandler) {
497 let euv_id: usize = match element.get_attribute("data-euv-id") {
498 Some(id_str) => id_str.parse::<usize>().unwrap_or_else(|_| {
499 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
500 let _ = element.set_attribute("data-euv-id", &new_id.to_string());
501 new_id
502 }),
503 None => {
504 let new_id: usize = NEXT_EUV_ID.fetch_add(1, Ordering::Relaxed);
505 let _ = element.set_attribute("data-euv-id", &new_id.to_string());
506 new_id
507 }
508 };
509 let event_name: String = handler.get_event_name().clone();
510 let key: (usize, String) = (euv_id, event_name.clone());
511 let registry: &mut HashMap<(usize, String), HandlerEntry> = get_handler_registry();
512 if let Some(existing_ptr) = registry.get(&key) {
513 let existing: &mut HandlerSlot = (*existing_ptr as usize).into();
514 existing.handler = Some(handler.clone());
515 } else {
516 let handler_slot: Box<HandlerSlot> = Box::new(HandlerSlot {
517 handler: Some(handler.clone()),
518 });
519 let handler_entry: HandlerEntry = Box::leak(handler_slot) as *mut HandlerSlot;
520 let handler_addr: usize = handler_entry as usize;
521 let event_name_for_closure: String = event_name.clone();
522 let closure: Closure<dyn FnMut(Event)> =
523 Closure::wrap(Box::new(move |event: Event| {
524 let slot: &mut HandlerSlot = handler_addr.into();
525 if let Some(active_handler) = slot.handler.as_ref() {
526 let euv_event: NativeEvent =
527 convert_web_event(&event, &event_name_for_closure);
528 active_handler.handle(euv_event);
529 }
530 event.stop_propagation();
531 }));
532 element
533 .add_event_listener_with_callback(&event_name, closure.as_ref().unchecked_ref())
534 .unwrap();
535 closure.forget();
536 registry.insert(key, handler_entry);
537 }
538 }
539}
540
541impl Renderer {
543 pub(crate) fn get_root(&self) -> &Element {
549 &self.root
550 }
551
552 pub(crate) fn try_get_current_tree(&self) -> Option<&VirtualNode> {
558 self.current_tree.as_ref()
559 }
560
561 pub(crate) fn set_current_tree(&mut self, tree: Option<VirtualNode>) {
567 self.current_tree = tree;
568 }
569}
570
571impl From<usize> for &'static mut Renderer {
573 #[inline(always)]
588 fn from(address: usize) -> Self {
589 unsafe { &mut *(address as *mut Renderer) }
590 }
591}
592
593impl From<usize> for &'static Renderer {
595 #[inline(always)]
610 fn from(address: usize) -> Self {
611 unsafe { &*(address as *const Renderer) }
612 }
613}