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
use crate::{KeyedElement, Mailbox, NonKeyedElement, Text};
use std::rc::Rc;
use web_sys as web;

#[derive(Debug)]
pub enum Node<Message: 'static> {
    Element(NonKeyedElement<Message>),
    KeyedElement(KeyedElement<Message>),
    Text(Text),
}

impl<Message: 'static> Node<Message> {
    pub fn create(&mut self, mailbox: Mailbox<Message>) -> web::Node {
        match self {
            Node::Element(element) => element.create(mailbox).into(),
            Node::KeyedElement(keyed_element) => keyed_element.create(mailbox).into(),
            Node::Text(text) => text.create().into(),
        }
    }

    pub fn patch(&mut self, old: &mut Self, mailbox: Mailbox<Message>) -> web::Node {
        match (self, old) {
            (Node::Element(ref mut e1), Node::Element(ref mut e2)) => e1.patch(e2, mailbox).into(),
            (Node::KeyedElement(ref mut e1), Node::KeyedElement(ref mut e2)) => {
                e1.patch(e2, mailbox).into()
            }
            (Node::Text(ref mut t1), Node::Text(ref mut t2)) => t1.patch(t2).into(),
            (self_, old) => {
                let old_node = old.node().expect("old.node");
                let parent_node = old_node.parent_node().expect("old_node.parent_node");
                let node = self_.create(mailbox);
                parent_node
                    .replace_child(&node, &old_node)
                    .expect("replace_child");
                node
            }
        }
    }

    pub fn node(&self) -> Option<web::Node> {
        match self {
            Node::Element(element) => element.node().map(Into::into),
            Node::KeyedElement(keyed_element) => keyed_element.node().map(Into::into),
            Node::Text(text) => text.node().map(Into::into),
        }
    }

    pub fn remove(&self) {
        if let Some(node) = self.node() {
            if let Some(parent_node) = node.parent_node() {
                parent_node.remove_child(&node).unwrap();
            }
        }
    }

    pub fn map<NewMessage: 'static>(
        self,
        f: impl Fn(Message) -> NewMessage + 'static,
    ) -> Node<NewMessage> {
        self.do_map(Rc::new(f))
    }

    pub(crate) fn do_map<NewMessage: 'static>(
        self,
        f: Rc<impl Fn(Message) -> NewMessage + 'static>,
    ) -> Node<NewMessage> {
        match self {
            Node::Element(element) => Node::Element(element.do_map(f)),
            Node::KeyedElement(keyed_element) => Node::KeyedElement(keyed_element.do_map(f)),
            Node::Text(text) => Node::Text(text),
        }
    }
}

impl<Message> From<Text> for Node<Message> {
    fn from(text: Text) -> Self {
        Node::Text(text)
    }
}

impl<Message: 'static> From<NonKeyedElement<Message>> for Node<Message> {
    fn from(element: NonKeyedElement<Message>) -> Self {
        Node::Element(element)
    }
}

impl<Message: 'static> From<KeyedElement<Message>> for Node<Message> {
    fn from(keyed_element: KeyedElement<Message>) -> Self {
        Node::KeyedElement(keyed_element)
    }
}

impl<Message, T: std::fmt::Display> From<T> for Node<Message> {
    fn from(t: T) -> Self {
        Text::new(t.to_string()).into()
    }
}