diff --git a/examples/rocket/src/main.rs b/examples/rocket/src/main.rs index f47580d..2116227 100644 --- a/examples/rocket/src/main.rs +++ b/examples/rocket/src/main.rs @@ -10,7 +10,8 @@ use rocket::response::{Responder, Result}; use rocket::{get, routes, Request, Response}; use std::io::Cursor; use typed_html::types::LinkType; -use typed_html::{dom::DOMTree, html, text}; +use typed_html::elements::FlowContent; +use typed_html::{dom::DOMTree, html, text, OutputType}; struct Html(DOMTree); @@ -24,32 +25,46 @@ impl<'r> Responder<'r> for Html { } } -#[get("/")] -fn index() -> Html { - let a = false; - Html(html!( +// Function that wraps a DOM node in an HTML document, to demonstrate how you'd +// do this sort of templating. +// +// It's a bit more complicated than you'd hope because you need to take an input +// argument of the type that the element that you're inserting it into expects, +// which in the case of `` is `FlowContent`, not just `Node`, so you can't +// pass it a `DOMTree` or you'll get a type error. +fn doc(tree: Box>) -> DOMTree { + html!( "Hello Kitty!" -
-

"Hello Kitty!"

-

- "She is not a ""cat"". She is a ""human girl""." -

-

"But how does she eat?"

- { - (1..4).map(|i| { - html!(

{ text!("{}. Ceci n'est pas une chatte.", i) }

) - }) - } -

""

- + { tree } - )) + ) +} + +#[get("/")] +fn index() -> Html { + let a = false; + Html(doc(html!( +
+

"Hello Kitty!"

+

+ "She is not a ""cat"". She is a ""human girl""." +

+

"But how does she eat?"

+ { + (1..4).map(|i| { + html!(

{ text!("{}. Ceci n'est pas une chatte.", i) }

) + }) + } +

""

+ +
+ ))) } fn main() { diff --git a/typed-html/src/dom.rs b/typed-html/src/dom.rs index 6541dbe..596e29a 100644 --- a/typed-html/src/dom.rs +++ b/typed-html/src/dom.rs @@ -73,6 +73,15 @@ pub trait Node: Display { fn vnode(&mut self) -> VNode; } +impl IntoIterator for Box> where T: OutputType { + type Item = Box>; + type IntoIter = std::vec::IntoIter>>; + + fn into_iter(self) -> Self::IntoIter { + vec![self].into_iter() + } +} + /// Trait for querying a typed HTML element. /// /// All [HTML elements][elements] implement this. diff --git a/typed-html/src/elements.rs b/typed-html/src/elements.rs index e735f95..56e4960 100644 --- a/typed-html/src/elements.rs +++ b/typed-html/src/elements.rs @@ -8,24 +8,43 @@ use types::*; // Marker traits for element content groups -pub trait MetadataContent: Node {} -pub trait FlowContent: Node {} -pub trait SectioningContent: Node {} -pub trait HeadingContent: Node {} +macro_rules! marker_trait { + ($trait:ident) => { + marker_trait!($trait, Node); + }; + + ($trait:ident, $parent:ident) => { + pub trait $trait: $parent {} + + impl IntoIterator for Box> where T: OutputType { + type Item = Box>; + type IntoIter = std::vec::IntoIter>>; + + fn into_iter(self) -> Self::IntoIter { + vec![self].into_iter() + } + } + }; +} + +marker_trait!(MetadataContent); +marker_trait!(FlowContent); +marker_trait!(SectioningContent); +marker_trait!(HeadingContent); // Phrasing content seems to be entirely a subclass of FlowContent -pub trait PhrasingContent: FlowContent {} -pub trait EmbeddedContent: Node {} -pub trait InteractiveContent: Node {} -pub trait FormContent: Node {} +marker_trait!(PhrasingContent, FlowContent); +marker_trait!(EmbeddedContent); +marker_trait!(InteractiveContent); +marker_trait!(FormContent); // Traits for elements that are more picky about their children -pub trait DescriptionListContent: Node {} -pub trait HGroupContent: Node {} -pub trait MapContent: Node {} -pub trait MediaContent: Node {} //