ddoc 0.17.0

doc site generator
Documentation
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,
        // TODO support markdown ?
    },
    DomTree {
        tag: String,
        children: Vec<Element>,
    },
    Link(NavLink),
    Menu(Menu),
    Toc(Toc),
    Main,
    PageTitle, // this one is quite obsolete now with --current-page-title
}

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,
        }
    }
    /// The pseudo-tag of this element, as used in configuration
    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, // tag.class1.class2
        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,
        }
    }
}