duid-core 0.1.0

Core crate used for Duid
Documentation
use indextree::{Arena, NodeId};
use crate::{
    core::{
        v_node::VirtualNode,
        duid_events::Dispatch
    },
    dom::dom_builder::DomBuilder
};
use web_sys::{
    Document, Element, Node
};
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use super::patch::Patch;
use wasm_bindgen::JsCast;



pub(crate) trait ApplyPatch<DSP, MSG> 
where
    DSP: Dispatch<MSG> + Clone + 'static,
    MSG: std::fmt::Debug + Clone + 'static
{
    fn apply_patches(&self, patches: &[Patch<MSG>], new_arena: &Arena<VirtualNode<MSG>>, program: &DSP, doc: &Document, style_map: &mut HashMap<String, String>);
}

impl<DSP, MSG> ApplyPatch<DSP, MSG> for Rc<RefCell<Arena<VirtualNode<MSG>>>> 
where
    DSP: Dispatch<MSG> + Clone + 'static,
    MSG: std::fmt::Debug + Clone + 'static
{
    fn apply_patches(&self, patches: &[Patch<MSG>], new_arena: &Arena<VirtualNode<MSG>>, program: &DSP, doc: &Document, style_map: &mut HashMap<String, String>)
    {
        patches.iter().for_each(|patch| {
            match patch {
                Patch::Replace(old_id, new_id) => {
                    let new_node = new_arena.get(*new_id).expect(&format!("The {new_id:?} node does not exists")).get();
                    let new_node_to_insert = self.borrow_mut().new_node(VirtualNode {
                        tag: new_node.tag,
                        node_type: new_node.node_type.clone(),
                        namespace: new_node.namespace,
                        props: new_node.props.clone(),
                        value: new_node.value.clone(),
                        real_node: Rc::clone(&new_node.real_node),
                        active_closures: Rc::clone(&new_node.active_closures)
                    });

                    for child_id in new_id.children(&new_arena).into_iter() {
                        let child = new_arena.get(child_id).expect(&format!("The {child_id:?} node does not exists")).get();
                        
                        let child_node_to_insert = self.borrow_mut().new_node(VirtualNode {
                            tag: child.tag,
                            node_type: child.node_type.clone(),
                            namespace: child.namespace,
                            props: child.props.clone(),
                            value: child.value.clone(),
                            real_node: Rc::clone(&child.real_node),
                            active_closures: Rc::clone(&child.active_closures)
                        });
                        
                        new_node_to_insert.append(child_node_to_insert, &mut self.borrow_mut());
                        create_child(
                            &new_node_to_insert,
                            &mut self.borrow_mut(),
                            &new_arena
                        );

                    }

                    old_id.insert_before(new_node_to_insert, &mut self.borrow_mut());
                    old_id.remove_subtree(&mut self.borrow_mut());

                    self.build(program, &doc, &new_node_to_insert, style_map);
                    let borrow = self.borrow();
                    if let Some(parent_id) = borrow[new_node_to_insert].parent() {
                        let parent = borrow.get(parent_id).expect(&format!("The {parent_id:?} node does not exists")).get();
                        let root = borrow.get(new_node_to_insert).expect(&format!("The {new_node_to_insert:?} node does not exists")).get();
                        
                        let parent_real_node = parent.real_node.borrow();
                        let root_real_node = root.real_node.borrow();
                        let _ = parent_real_node.as_ref().unwrap().append_child(root_real_node.as_ref().unwrap());
                    }

                },
                Patch::AddAttribute(old_id, attr) => {
                    let mut borrow = self.borrow_mut();
                    let old_node = borrow.get_mut(*old_id).expect(&format!("The {old_id:?} node does not exists")).get_mut();
                    old_node.props.push(attr.clone());
                    let real_node_clone = Rc::clone(&old_node.real_node);
                    
                    if let Some(root) = &*real_node_clone.borrow() {
                        let element: Element = root.to_owned().unchecked_into();
                        VirtualNode::set_element_attributes(
                            program,
                            &element,
                            &[attr],
                            &mut old_node.active_closures.borrow_mut(),
                            style_map,
                            <NodeId as Into<usize>>::into(*old_id)
                        );
                        *old_node.real_node.borrow_mut() = Some(element.unchecked_into::<Node>());
                    };
                
                },
                Patch::RemoveAttribute(old_id, attr_name) => {
                    let mut borrow = self.borrow_mut();
                    let old_node = borrow.get_mut(*old_id).expect(&format!("The {old_id:?} node does not exists")).get_mut();
                    old_node.props.retain(|prop| !(prop.name == attr_name));
                    let real_node_clone = Rc::clone(&old_node.real_node);
                    if let Some(root) = &*real_node_clone.borrow() {
                        let element: Element = root.to_owned().unchecked_into();
                        let _ = VirtualNode::<MSG>::remove_element_attribute(&element, attr_name);
                        *old_node.real_node.borrow_mut() = Some(element.unchecked_into::<Node>());
                    };
                },
                Patch::UpdateAttribute(old_id, (attr_name, new_attribute)) => {
                    let mut borrow = self.borrow_mut();
                    let old_node = borrow.get_mut(*old_id).expect(&format!("The {old_id:?} node does not exists")).get_mut();
                    old_node.props.retain(|prop| !(prop.name == *attr_name));
                    
                    let real_node_clone = Rc::clone(&old_node.real_node);
                    if let Some(root) = &*real_node_clone.borrow() {
                        let element: Element = root.to_owned().unchecked_into();
                        let _ = VirtualNode::<MSG>::remove_element_attribute(&element, attr_name);
                        VirtualNode::set_element_attribute(
                            program,
                            &element,
                            new_attribute,
                            &mut old_node.active_closures.borrow_mut(),
                            style_map,
                            <NodeId as Into<usize>>::into(*old_id)
                        );
                        *old_node.real_node.borrow_mut() = Some(element.unchecked_into::<Node>());
                    };
                },
                Patch::ChangeText(old_id, value) => {
                    if let Some(text_value) = value {
                        let mut borrow = self.borrow_mut();
                        let mut text_node = borrow.get_mut(*old_id).expect(&format!("The {old_id:?} node does not exists")).get_mut();
                        text_node.value = Some(text_value.to_owned());
                        let text_real_node = text_node.real_node.borrow();
                        let _ = text_real_node.as_ref().unwrap().set_text_content(Some(text_node.value.as_ref().unwrap()));
                    }
                }
            }
        });
    }
}


fn create_child<MSG>(
    parent_node: &NodeId,
    old_arena: &mut Arena::<VirtualNode<MSG>>,
    new_arena: &Arena::<VirtualNode<MSG>>
) 
where
    MSG: std::fmt::Debug + Clone + 'static,
{
    let new_node = new_arena.get(*parent_node).expect(&format!("The {parent_node:?} node does not exists")).get();
    let new_node_to_insert = old_arena.new_node(VirtualNode {
        tag: new_node.tag,
        node_type: new_node.node_type.clone(),
        namespace: new_node.namespace,
        props: new_node.props.clone(),
        value: new_node.value.clone(),
        real_node: Rc::clone(&new_node.real_node),
        active_closures: Rc::clone(&new_node.active_closures)
    });

    for child_id in parent_node.children(&new_arena).into_iter() {
        let child = new_arena.get(child_id).expect(&format!("The {child_id:?} node does not exists")).get();
        
        let child_node_to_insert = old_arena.new_node(VirtualNode {
            tag: child.tag,
            node_type: child.node_type.clone(),
            namespace: child.namespace,
            props: child.props.clone(),
            value: child.value.clone(),
            real_node: Rc::clone(&child.real_node),
            active_closures: Rc::clone(&child.active_closures)
        });
        
        new_node_to_insert.append(child_node_to_insert, old_arena);
        create_child(
            &new_node_to_insert,
            old_arena,
            &new_arena
        );
    }
}