use std::fmt::Display;
use std::marker::PhantomData;
use crate::OutputType;
use crate::elements::{FlowContent, PhrasingContent};
use htmlescape::encode_minimal;
pub type DOMTree<T> = Box<Node<T>>;
pub enum VNode<'a, T: OutputType + 'a> {
Text(&'a str),
Element(VElement<'a, T>),
}
pub struct VElement<'a, T: OutputType + 'a> {
pub name: &'static str,
pub attributes: Vec<(&'static str, String)>,
pub events: &'a mut T::Events,
pub children: Vec<VNode<'a, T>>,
}
pub trait Node<T: OutputType>: Display {
fn vnode(&mut self) -> VNode<T>;
}
impl<T> IntoIterator for Box<dyn Node<T>>
where
T: OutputType,
{
type Item = Box<dyn Node<T>>;
type IntoIter = std::vec::IntoIter<Box<dyn Node<T>>>;
fn into_iter(self) -> Self::IntoIter {
vec![self].into_iter()
}
}
pub trait Element<T: OutputType>: Node<T> {
fn name() -> &'static str;
fn attribute_names() -> &'static [&'static str];
fn required_children() -> &'static [&'static str];
fn attributes(&self) -> Vec<(&'static str, String)>;
}
pub struct TextNode<T: OutputType>(String, PhantomData<T>);
#[macro_export]
macro_rules! text {
($t:expr) => {
Box::new($crate::dom::TextNode::new($t))
};
($format:tt, $($tail:tt),*) => {
Box::new($crate::dom::TextNode::new(format!($format, $($tail),*)))
};
}
impl<T: OutputType> TextNode<T> {
pub fn new<S: Into<String>>(s: S) -> Self {
TextNode(s.into(), PhantomData)
}
}
impl<T: OutputType> Display for TextNode<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
f.write_str(&encode_minimal(&self.0))
}
}
impl<T: OutputType> Node<T> for TextNode<T> {
fn vnode(&'_ mut self) -> VNode<'_, T> {
VNode::Text(&self.0)
}
}
impl<T: OutputType> IntoIterator for TextNode<T> {
type Item = TextNode<T>;
type IntoIter = std::vec::IntoIter<TextNode<T>>;
fn into_iter(self) -> Self::IntoIter {
vec![self].into_iter()
}
}
impl<T: OutputType> IntoIterator for Box<TextNode<T>> {
type Item = Box<TextNode<T>>;
type IntoIter = std::vec::IntoIter<Box<TextNode<T>>>;
fn into_iter(self) -> Self::IntoIter {
vec![self].into_iter()
}
}
impl<T: OutputType> FlowContent<T> for TextNode<T> {}
impl<T: OutputType> PhrasingContent<T> for TextNode<T> {}