write_scope_html 0.1.0

A write_scope front-end for HTML
Documentation
//! A [write_scope] library for HTML
//! 
//! # Example
//! 
//! ```
//! # use std::io::{self, stdout};
//! # use write_scope_html::{Body, Div, Html, HtmlElement, H1, P};
//! # use write_scope::{Open, WrapIO};
//! fn main() -> io::Result<()> {
//!     let w = WrapIO(stdout().lock());
//!     let html = w.open(Html)?;
//!     let mut body = html.open(Body)?;
//!     {
//!         let id = String::from("toto");
//!         let mut toto = body.ref_open(Div.id(&id).id("babar"))?.open(Div)?;
//!         drop(id);
//!         toto.ref_open(Div.id("toto_1"))?;
//!         toto.ref_open(Div.id("toto_2"))?;
//!         toto.close()?;
//!     }
//!     body.ref_open(Div.id("tata"))?;
//!     body.open_scope(Div.id("tutu"), |tutu| {
//!         tutu.open(H1)?.text("Hello!")?;
//!         tutu.open(P)?.text("Beautiful morning!")?;
//!         Ok(())
//!     })?;
//!     body.open(Div)?;
//!     Ok(())
//! }
//! ```

use std::fmt::Display;

use write_scope::{
    xml::{self, Element},
    Open,
};

pub trait HtmlElement: xml::Element {
    fn attr<K, V>(self, key: K, val: V) -> Attr<K, V, Self> {
        Attr {
            key,
            val,
            inner: self,
        }
    }

    fn id<S>(self, id: S) -> Id<S, Self> {
        Id {
            val: id,
            inner: self,
        }
    }

    fn class<S>(self, class: S) -> Class<S, Self> {
        Class {
            val: class,
            inner: self,
        }
    }
}

impl<E: xml::Element> HtmlElement for E {}

macro_rules! simples {
    ($(($t:ident,$id:ident)),*) => {
        $(
            pub struct $t;

            impl write_scope::xml::SimpleElement for $t {
                const TAG: &str = stringify!($id);
            }
        )*
    };
}

simples! {
    (Html, html),
    (Head,head),
    (Body, body),
    (Main, main),
    (Header, header),
    (Div, div),
    (P, p),
    (H1, h1),
    (H2, h2),
    (Ul, ul),
    (Ol, ol),
    (Li, li)
}

pub struct A<S> {
    pub href: S,
}

impl<S: Display> Element for A<S> {
    const TAG: &str = "a";

    fn tag_and_attributes<W: Open>(self, mut w: W) -> Result<(), W::Error> {
        write!(w, "a href={}", self.href)
    }
}

pub struct Img<S> {
    pub src: S,
}

impl<S: AsRef<str>> Element for Img<S> {
    const TAG: &str = "img";

    fn tag_and_attributes<W: Open>(self, mut w: W) -> Result<(), W::Error> {
        write!(w, "img src={}", self.src.as_ref())
    }
}

pub struct Attr<K, V, E> {
    key: K,
    val: V,
    inner: E,
}

impl<K: AsRef<str>, V: Display, E: Element> Element for Attr<K, V, E> {
    const TAG: &str = E::TAG;

    fn tag_and_attributes<W: Open>(self, mut w: W) -> Result<(), W::Error> {
        self.inner.tag_and_attributes(&mut w)?;
        write!(w, " {}=\"{}\"", self.key.as_ref(), self.val)
    }
}

pub struct Id<V, E> {
    val: V,
    inner: E,
}

impl<V: AsRef<str>, E: Element> Element for Id<V, E> {
    const TAG: &str = E::TAG;

    fn tag_and_attributes<W: Open>(self, mut w: W) -> Result<(), W::Error> {
        self.inner.tag_and_attributes(&mut w)?;
        write!(w, " id=\"{}\"", self.val.as_ref())
    }
}

pub struct Class<V, E> {
    val: V,
    inner: E,
}

impl<V: AsRef<str>, E: Element> Element for Class<V, E> {
    const TAG: &str = E::TAG;

    fn tag_and_attributes<W: Open>(self, mut w: W) -> Result<(), W::Error> {
        self.inner.tag_and_attributes(&mut w)?;
        write!(w, " class=\"{}\"", self.val.as_ref())
    }
}