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