use crate::*;
#[derive(Debug, Clone)]
pub struct Element {
pub classes: Vec<ClassName>,
pub content: ElementContent,
}
#[derive(Debug, Clone)]
pub enum ElementContent {
DomLeaf {
tag: String,
text: Option<Text>,
raw_html: Option<String>,
attributes: Attributes,
},
DomTree {
tag: String,
children: Vec<Element>,
},
Link(NavLink),
Menu(Menu),
Toc(Toc),
Main,
PageTitle, }
impl Element {
pub fn try_merge(
&mut self,
other: &Element,
) -> bool {
match (&mut self.content, &other.content) {
(
ElementContent::DomTree {
children: children1,
..
},
ElementContent::DomTree {
children: children2,
..
},
) => {
for element in children2 {
let mut merged = false;
let selector2 = element.selector();
for element1 in children1.iter_mut() {
if element1.selector() == selector2 {
merged |= element1.try_merge(element);
break;
}
}
if !merged {
children1.push(element.clone());
}
}
true
}
_ => false,
}
}
pub fn tag(&self) -> &str {
match &self.content {
ElementContent::DomLeaf { tag, .. } => tag,
ElementContent::DomTree { tag, .. } => tag,
ElementContent::Link(_) => "ddoc-link",
ElementContent::Menu(_) => "ddoc-menu",
ElementContent::Toc(_) => "ddoc-toc",
ElementContent::Main => "ddoc-main",
ElementContent::PageTitle => "ddoc-page-title",
}
}
pub fn children(&self) -> Option<&Vec<Element>> {
match &self.content {
ElementContent::DomTree { children, .. } => Some(children),
_ => None,
}
}
pub fn new_composite(
key: &str, children: Vec<Element>,
) -> Self {
let mut tokens = key.split('.');
let tag = tokens.next().unwrap_or("div").to_string();
let classes = tokens.map(|s| s.to_string()).collect();
Self {
classes,
content: ElementContent::DomTree { tag, children },
}
}
pub fn visit<F>(
&self,
f: &mut F,
) where
F: FnMut(&Element),
{
f(self);
if let Some(children) = self.children() {
for child in children {
child.visit(f);
}
}
}
pub fn has<F>(
&self,
f: &mut F,
) -> bool
where
F: FnMut(&Element) -> bool,
{
if f(self) {
return true;
}
if let Some(children) = self.children() {
for child in children {
if child.has(f) {
return true;
}
}
}
false
}
pub fn selector(&self) -> String {
let mut selector = self.tag().to_string();
for class in &self.classes {
selector.push('.');
selector.push_str(class.as_str());
}
selector
}
}
impl From<ElementContent> for Element {
fn from(content: ElementContent) -> Self {
Self {
classes: vec![],
content,
}
}
}