1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use velement::VElement;
use vlist::VList;
use vtext::VText;
use std::fmt::Display;
use std::fmt::{Formatter, self};
use vcomponent::VComponent;
#[cfg(not(target_arch = "wasm32"))]
use traits::ServerRender;

#[derive(Debug, Eq, PartialEq)]
pub enum VNode {
    Text(VText),
    Element(VElement),
    List(VList),
    Component(VComponent)
}

impl VNode {
    pub fn new<T: Into<VNode>>(content: T) -> VNode {
        content.into()
    }
}

impl Display for VNode {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            VNode::Text(ref text) => write!(f, "{}", text),
            VNode::Element(ref element) => write!(f, "{}", element),
            VNode::List(ref list) => write!(f, "{}", list),
            VNode::Component(ref component) => write!(f, "{}", component)
        }
    }
}

macro_rules! impl_conversion_to_vnode {
    ($variant:ident, $inner:ty) => {
        impl From<$inner> for VNode {
            fn from(item: $inner) -> Self {
                VNode::$variant(item)
            }
        }
    };
}

impl_conversion_to_vnode!(Text, VText);
impl_conversion_to_vnode!(Element, VElement);
impl_conversion_to_vnode!(List, VList);
impl_conversion_to_vnode!(Component, VComponent);

#[cfg(not(target_arch = "wasm32"))]
impl ServerRender for VNode {
    fn server_render(&mut self) {
        match *self {
            VNode::Component(ref mut component) => component.server_render(),
            VNode::List(ref mut list) => list.server_render(),
            VNode::Element(ref mut element) => element.server_render(),
            VNode::Text(_) => {}
        }
    }
}

#[cfg(target_arch = "wasm32")]
mod wasm {
    use vdiff::{DOMPatch, DOMRemove};
    use stdweb::web::Element;
    use super::VNode;
    use vdiff::DOMReorder;
    use vdiff::DOMNode;
    use stdweb::web::Node;
    use traits::DOMRender;
    use events::RenderRequestSender;

    macro_rules! match_for_vnode_patch {
        ($against:ident, $parent:ident, $next:ident, $old_vnode:ident, $render_req:ident, [$( $variant:ident ),*] ) => {
            match $against {
                $(
                    VNode::$variant(node_like) => {
                        if let Some(VNode::$variant(old_node_like)) = $old_vnode {
                            node_like.patch($parent, $next, Some(old_node_like), $render_req).into()
                        } else {
                            $old_vnode.remove($parent);
                            node_like.patch($parent, $next, None, $render_req).into()
                        }
                    }
                )*
            }
        };
    }

    impl DOMPatch<VNode> for VNode {
        fn patch(self, parent: &Element, next: Option<&Node>, old_vnode: Option<VNode>, render_req: RenderRequestSender) -> Self {
            match_for_vnode_patch!(self, parent, next, old_vnode, render_req, [Text, Element, List, Component])
        }
    }

    impl DOMRemove for VNode {
        fn remove(self, parent: &Element) {
            match self {
                VNode::Text(text) => text.remove(parent),
                VNode::Element(element) => element.remove(parent),
                VNode::List(list) => list.remove(parent),
                VNode::Component(component) => component.remove(parent)
            }
        }
    }

    impl DOMReorder for VNode {
        fn move_to_last(&self, parent: &Element) {
            match *self {
                VNode::Text(ref text) => text.move_to_last(parent),
                VNode::Element(ref element) => element.move_to_last(parent),
                VNode::List(ref list) => list.move_to_last(parent),
                VNode::Component(ref component) => component.move_to_last(parent)
            }
        }

        fn move_before(&self, parent: &Element, next: &Node) {
            match *self {
                VNode::Text(ref text) => text.move_before(parent, next),
                VNode::Element(ref element) => element.move_before(parent, next),
                VNode::List(ref list) => list.move_before(parent, next),
                VNode::Component(ref component) => component.move_before(parent, next)
            }
        }
    }

    impl DOMNode for VNode {
        fn dom_node(&self) -> Option<Node> {
            match *self {
                VNode::Text(ref text) => text.dom_node(),
                VNode::Element(ref element) => element.dom_node(),
                VNode::List(ref list) => list.dom_node(),
                VNode::Component(ref component) => component.dom_node()
            }
        }
    }

    impl DOMRender for VNode {
        fn dom_render(&mut self, parent: &Element, next: Option<&Node>, render_req: RenderRequestSender) {
            match *self {
                VNode::Component(ref mut component) => component.dom_render(parent, next, render_req),
                VNode::List(ref mut list) => list.dom_render(parent, next, render_req),
                VNode::Element(ref mut element) => element.dom_render(parent, next, render_req),
                VNode::Text(_) => {}
            }
        }
    }
}