use std::{
borrow::Cow,
collections::HashMap,
fmt::{self, Display},
};
pub struct HtmlNode<'a> {
name: Cow<'a, str>,
params: HashMap<Cow<'a, str>, Cow<'a, str>>,
text: Cow<'a, str>,
childs: Vec<HtmlNode<'a>>,
}
impl<'a> HtmlNode<'a> {
pub fn new() -> Self {
Self {
text: "".into(),
params: HashMap::new(),
childs: Vec::new(),
name: "".into(),
}
}
#[inline]
pub fn append(&mut self, node: HtmlNode<'a>) -> &mut Self {
self.childs.push(node);
self
}
#[inline]
pub fn append_iter<I>(&mut self, node: I) -> &mut Self
where
I: Iterator<Item = HtmlNode<'a>>,
{
node.for_each(|n| {
self.append(n);
});
self
}
#[inline]
pub fn append_to(self, other: &mut Self) -> &mut Self {
other.append(self);
other
}
#[inline]
pub fn with_name(name: impl Into<Cow<'a, str>>) -> Self {
let mut node = HtmlNode::new();
node.name = name.into();
node
}
#[inline]
pub fn text(&mut self, text: impl Into<Cow<'a, str>>) -> &mut Self {
self.text = text.into();
self
}
#[inline]
pub fn attr(
&mut self,
name: impl Into<Cow<'a, str>>,
value: impl Into<Cow<'a, str>>,
) -> &mut Self {
self.params.insert(name.into(), value.into());
self
}
#[inline]
pub fn nth(&mut self, i: usize) -> Option<&mut HtmlNode<'a>> {
self.childs.get_mut(i)
}
pub(crate) fn write_to(&self, buf: &mut dyn fmt::Write) -> fmt::Result {
buf.write_char('<')?;
buf.write_str(&self.name)?;
for (k, v) in &self.params {
buf.write_char(' ')?;
buf.write_str(k)?;
buf.write_str("=\"")?;
buf.write_str(v)?;
buf.write_char('"')?;
}
buf.write_char('>')?;
if !self.text.is_empty() {
buf.write_str(&self.text)?;
}
for child in &self.childs {
child.write_to(buf)?;
}
buf.write_str("</")?;
buf.write_str(&self.name)?;
buf.write_char('>')?;
Ok(())
}
}
impl Default for HtmlNode<'_> {
fn default() -> Self {
Self::new()
}
}
impl Display for HtmlNode<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.write_to(f)
}
}