sauron_core/vdom/
element.rs

1use super::attribute::{AttributeName, Namespace, Tag};
2use super::{Attribute, Node};
3
4use crate::vdom::AttributeValue;
5use crate::vdom::Leaf;
6use crate::vdom::Value;
7use derive_where::derive_where;
8use indexmap::IndexMap;
9
10/// Represents an element of the virtual node
11/// An element has a generic tag, this tag could be a static str tag, such as usage in html dom.
12///     Example of which are `div`, `a`, `input`, `img`, etc.
13///
14/// Tag is a generic type, which can represent a different DOM tree other than the html dom
15/// such as widgets in native platform such as gtk, example of which are `Hpane`, `Vbox`, `Image`,
16///
17/// An element can have an optional namespace, such in the case for html dom where namespace like
18/// HTML and SVG, which needs to specified in order to create the DOM element to work on the
19/// browser.
20///
21/// The namespace is also needed in attributes where namespace are necessary such as `xlink:href`
22/// where the namespace `xlink` is needed in order for the linked element in an svg image to work.
23#[derive_where(Clone, Debug, PartialEq, Eq)]
24pub struct Element<MSG> {
25    /// namespace of this element,
26    /// svg elements requires namespace to render correcly in the browser
27    pub namespace: Option<Namespace>,
28    /// the element tag, such as div, a, button
29    pub tag: Tag,
30    /// attributes for this element
31    pub(crate) attrs: Vec<Attribute<MSG>>,
32    /// children elements of this element
33    pub(crate) children: Vec<Node<MSG>>,
34    /// is the element has a self closing tag
35    pub self_closing: bool,
36}
37
38impl<MSG> Element<MSG> {
39    /// create a new instance of an element
40    pub fn new(
41        namespace: Option<Namespace>,
42        tag: Tag,
43        attrs: impl IntoIterator<Item = Attribute<MSG>>,
44        children: impl IntoIterator<Item = Node<MSG>>,
45        self_closing: bool,
46    ) -> Self {
47        //unroll the nodelist
48        let children = children
49            .into_iter()
50            .flat_map(|child| match child {
51                Node::Leaf(Leaf::NodeList(node_list)) => node_list,
52                _ => vec![child],
53            })
54            .collect();
55        Self {
56            namespace,
57            tag,
58            attrs: attrs.into_iter().collect(),
59            children,
60            self_closing,
61        }
62    }
63
64    /// add attributes to this element
65    pub fn add_attributes(&mut self, attrs: impl IntoIterator<Item = Attribute<MSG>>) {
66        self.attrs.extend(attrs)
67    }
68
69    /// add children virtual node to this element
70    pub fn add_children(&mut self, children: impl IntoIterator<Item = Node<MSG>>) {
71        self.children.extend(children);
72    }
73
74    /// returns a refernce to the children of this node
75    pub fn children(&self) -> &[Node<MSG>] {
76        &self.children
77    }
78
79    /// returns a mutable reference to the children of this node
80    pub fn children_mut(&mut self) -> &mut [Node<MSG>] {
81        &mut self.children
82    }
83
84    /// Removes an child node  from this element and returns it.
85    ///
86    /// The removed child is replaced by the last child of the element's children.
87    ///
88    /// # Panics
89    /// Panics if index is out of bounds in children
90    ///
91    pub fn swap_remove_child(&mut self, index: usize) -> Node<MSG> {
92        self.children.swap_remove(index)
93    }
94
95    /// Swaps the 2 child node in this element
96    ///
97    /// # Arguments
98    /// * a - The index of the first child node
99    /// * b - The index of the second child node
100    ///
101    /// # Panics
102    /// Panics if both `a` and `b` are out of bounds
103    ///
104    pub fn swap_children(&mut self, a: usize, b: usize) {
105        self.children.swap(a, b)
106    }
107
108    /// consume self and return the children
109    pub fn take_children(self) -> Vec<Node<MSG>> {
110        self.children
111    }
112
113    /// return a reference to the attribute of this element
114    pub fn attributes(&self) -> &[Attribute<MSG>] {
115        &self.attrs
116    }
117
118    /// consume self and return the attributes
119    pub fn take_attributes(self) -> Vec<Attribute<MSG>> {
120        self.attrs
121    }
122
123    /// return the namespace of this element
124    pub fn namespace(&self) -> Option<&Namespace> {
125        self.namespace.as_ref()
126    }
127
128    /// return the tag of this element
129    pub fn tag(&self) -> &Tag {
130        &self.tag
131    }
132
133    /// consume self and return the tag of this element
134    pub fn take_tag(self) -> Tag {
135        self.tag
136    }
137
138    /// change the tag of this element
139    pub fn set_tag(&mut self, tag: Tag) {
140        self.tag = tag;
141    }
142
143    /// remove the attributes with this key
144    pub fn remove_attribute(&mut self, name: &AttributeName) {
145        self.attrs.retain(|att| att.name != *name)
146    }
147
148    /// remove the existing values of this attribute
149    /// and add the new values
150    pub fn set_attributes(&mut self, attrs: impl IntoIterator<Item = Attribute<MSG>>) {
151        for attr in attrs {
152            self.remove_attribute(&attr.name);
153            self.attrs.push(attr);
154        }
155    }
156
157    /// merge to existing attributes if it exist
158    pub fn merge_attributes(&mut self, new_attrs: impl IntoIterator<Item = Attribute<MSG>>) {
159        for new_att in new_attrs {
160            if let Some(existing_attr) = self.attrs.iter_mut().find(|att| att.name == new_att.name)
161            {
162                existing_attr.value.extend(new_att.value);
163            } else {
164                self.attrs.push(new_att);
165            }
166        }
167    }
168
169    /// return all the attribute values which the name &AttributeName
170    pub fn attribute_value(&self, name: &AttributeName) -> Option<Vec<&AttributeValue<MSG>>> {
171        let result: Vec<&AttributeValue<MSG>> = self
172            .attrs
173            .iter()
174            .filter(|att| att.name == *name)
175            .flat_map(|att| att.value())
176            .collect();
177
178        if result.is_empty() {
179            None
180        } else {
181            Some(result)
182        }
183    }
184
185    /// get the first value of the attribute which has the name `att_name` of this element
186    pub fn first_value(&self, att_name: &AttributeName) -> Option<&Value> {
187        self.attribute_value(att_name)
188            .and_then(|att_values| att_values.first().and_then(|v| v.get_simple()))
189    }
190
191    /// grouped the attributes, but retain the index of the attribute
192    /// relative to its location in the element
193    pub fn group_indexed_attributes_per_name<'a>(
194        attrs: &'a [Attribute<MSG>],
195    ) -> IndexMap<&'a AttributeName, Vec<(usize, &'a Attribute<MSG>)>> {
196        let mut grouped: IndexMap<&'a AttributeName, Vec<(usize, &'a Attribute<MSG>)>> =
197            IndexMap::new();
198        for (i, attr) in attrs.iter().enumerate() {
199            if let Some(existing) = grouped.get_mut(&attr.name) {
200                existing.push((i, attr));
201            } else {
202                grouped.insert(&attr.name, vec![(i, attr)]);
203            }
204        }
205        grouped
206    }
207
208    /// return true if this element has a mount callback
209    pub fn has_mount_callback(&self) -> bool {
210        self.attributes().iter().any(|a| a.is_mount_callback())
211    }
212}