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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
use crate::node::{Attribute, Node};
use alloc::vec;
use alloc::vec::Vec;
use core::fmt::Debug;
/// Represents an element of the virtual node
/// An element has a generic tag, this tag could be a static str tag, such as usage in html dom.
/// Example of which are `div`, `a`, `input`, `img`, etc.
///
/// Tag is a generic type, which can represent a different DOM tree other than the html dom
/// such as widgets in native platform such as gtk, example of which are `Hpane`, `Vbox`, `Image`,
///
/// An element can have an optional namespace, such in the case for html dom where namespace like
/// HTML and SVG, which needs to specified in order to create the DOM element to work on the
/// browser.
///
/// The namespace is also needed in attributes where namespace are necessary such as `xlink:href`
/// where the namespace `xlink` is needed in order for the linked element in an svg image to work.
#[derive(Clone, Debug, PartialEq, Default)]
pub struct Element<Ns, Tag, Leaf, Att, Val>
where
Ns: PartialEq + Clone + Debug,
Tag: PartialEq + Debug,
Leaf: PartialEq + Clone + Debug,
Att: PartialEq + Clone + Debug,
Val: PartialEq + Clone + Debug,
{
/// namespace of this element,
/// svg elements requires namespace to render correcly in the browser
pub namespace: Option<Ns>,
/// the element tag, such as div, a, button
pub tag: Tag,
/// attributes for this element
pub attrs: Vec<Attribute<Ns, Att, Val>>,
/// children elements of this element
pub children: Vec<Node<Ns, Tag, Leaf, Att, Val>>,
/// is the element has a self closing tag
pub self_closing: bool,
}
impl<Ns, Tag, Leaf, Att, Val> Element<Ns, Tag, Leaf, Att, Val>
where
Ns: PartialEq + Clone + Debug,
Tag: PartialEq + Debug,
Leaf: PartialEq + Clone + Debug,
Att: PartialEq + Clone + Debug,
Val: PartialEq + Clone + Debug,
{
/// create a new instance of an element
pub fn new(
namespace: Option<Ns>,
tag: Tag,
attrs: impl IntoIterator<Item = Attribute<Ns, Att, Val>>,
children: impl IntoIterator<Item = Node<Ns, Tag, Leaf, Att, Val>>,
self_closing: bool,
) -> Self {
//unroll the nodelist
let children = children
.into_iter()
.flat_map(|child| match child {
Node::NodeList(node_list) => node_list,
_ => vec![child],
})
.collect();
Self {
namespace,
tag,
attrs: attrs.into_iter().collect(),
children,
self_closing,
}
}
/// add attributes to this element
pub fn add_attributes(
&mut self,
attrs: impl IntoIterator<Item = Attribute<Ns, Att, Val>>,
) {
self.attrs.extend(attrs)
}
/// add children virtual node to this element
pub fn add_children(
&mut self,
children: impl IntoIterator<Item = Node<Ns, Tag, Leaf, Att, Val>>,
) {
self.children.extend(children.into_iter());
}
/// returns a refernce to the children of this node
pub fn children(&self) -> &[Node<Ns, Tag, Leaf, Att, Val>] {
&self.children
}
/// returns a mutable reference to the children of this node
pub fn children_mut(&mut self) -> &mut [Node<Ns, Tag, Leaf, Att, Val>] {
&mut self.children
}
/// Removes an child node from this element and returns it.
///
/// The removed child is replaced by the last child of the element's children.
///
/// # Panics
/// Panics if index is out of bounds in children
///
pub fn swap_remove_child(
&mut self,
index: usize,
) -> Node<Ns, Tag, Leaf, Att, Val> {
self.children.swap_remove(index)
}
/// Swaps the 2 child node in this element
///
/// # Arguments
/// * a - The index of the first child node
/// * b - The index of the second child node
///
/// # Panics
/// Panics if both `a` and `b` are out of bounds
///
pub fn swap_children(&mut self, a: usize, b: usize) {
self.children.swap(a, b)
}
/// consume self and return the children
pub fn take_children(self) -> Vec<Node<Ns, Tag, Leaf, Att, Val>> {
self.children
}
/// return a reference to the attribute of this element
pub fn attributes(&self) -> &[Attribute<Ns, Att, Val>] {
&self.attrs
}
/// consume self and return the attributes
pub fn take_attributes(self) -> Vec<Attribute<Ns, Att, Val>> {
self.attrs
}
/// return the namespace of this element
pub fn namespace(&self) -> Option<&Ns> {
self.namespace.as_ref()
}
/// return the tag of this element
pub fn tag(&self) -> &Tag {
&self.tag
}
/// consume self and return the tag of this element
pub fn take_tag(self) -> Tag {
self.tag
}
/// change the tag of this element
pub fn set_tag(&mut self, tag: Tag) {
self.tag = tag;
}
/// remove the attributes with this key
pub fn remove_attribute(&mut self, key: &Att) {
self.attrs.retain(|att| att.name != *key)
}
/// remove the existing values of this attribute
/// and add the new values
pub fn set_attributes(
&mut self,
attrs: impl IntoIterator<Item = Attribute<Ns, Att, Val>>,
) {
for attr in attrs {
self.remove_attribute(&attr.name);
self.attrs.push(attr);
}
}
/// merge to existing attributes if it exist
pub fn merge_attributes(
&mut self,
new_attrs: impl IntoIterator<Item = Attribute<Ns, Att, Val>>,
) {
for new_att in new_attrs {
if let Some(existing_attr) =
self.attrs.iter_mut().find(|att| att.name == new_att.name)
{
existing_attr.value.extend(new_att.value);
} else {
self.attrs.push(new_att);
}
}
}
/// return all the attribute values which the name &Att
pub fn attribute_value(&self, name: &Att) -> Option<Vec<&Val>> {
let result: Vec<&Val> = self
.attrs
.iter()
.filter(|att| att.name == *name)
.flat_map(|att| att.value())
.collect();
if result.is_empty() {
None
} else {
Some(result)
}
}
}