Docs and cleanups.

This commit is contained in:
Bodil Stokke 2018-11-17 14:19:37 +00:00
parent 001a7ba016
commit 28513b93e9
12 changed files with 355 additions and 307 deletions

View File

@ -9,10 +9,9 @@ use rocket::response::{Responder, Result};
use rocket::{get, routes, Request, Response}; use rocket::{get, routes, Request, Response};
use std::io::Cursor; use std::io::Cursor;
use typed_html::types::LinkType; use typed_html::types::LinkType;
use typed_html::{dom::Node, text}; use typed_html::{dom::DOMTree, html, text};
use typed_html_macros::html;
struct Html(Box<Node<String>>); struct Html(DOMTree<String>);
impl<'r> Responder<'r> for Html { impl<'r> Responder<'r> for Html {
fn respond_to(self, _request: &Request) -> Result<'r> { fn respond_to(self, _request: &Request) -> Result<'r> {

View File

@ -9,7 +9,6 @@ strum = "0.11.0"
strum_macros = "0.11.0" strum_macros = "0.11.0"
mime = "0.3.12" mime = "0.3.12"
language-tags = "0.2.2" language-tags = "0.2.2"
enumset = "0.3.12"
http = "0.1.13" http = "0.1.13"
htmlescape = "0.3.1" htmlescape = "0.3.1"
stdweb = "0.4.10" stdweb = "0.4.10"

View File

@ -3,11 +3,10 @@
#[macro_use] #[macro_use]
extern crate typed_html; extern crate typed_html;
extern crate typed_html_macros;
use typed_html::dom::TextNode; use typed_html::dom::TextNode;
use typed_html::html;
use typed_html::types::*; use typed_html::types::*;
use typed_html_macros::html;
struct Foo { struct Foo {
foo: &'static str, foo: &'static str,

View File

@ -8,6 +8,26 @@ use elements::{FlowContent, PhrasingContent};
use events::Events; use events::Events;
use htmlescape::encode_minimal; use htmlescape::encode_minimal;
/// A boxed DOM tree, as returned from the `html!` macro.
///
/// # Examples
///
/// ```
/// # #![feature(proc_macro_hygiene)]
/// # extern crate typed_html;
/// # use typed_html::html;
/// # use typed_html::dom::DOMTree;
/// # fn main() {
/// let tree: DOMTree<String> = html!(
/// <div class="hello">
/// <p>"Hello Joe!"</p>
/// </div>
/// );
/// let rendered_tree: String = tree.to_string();
/// # }
/// ```
pub type DOMTree<T> = Box<Node<T>>;
/// An untyped representation of an HTML node. /// An untyped representation of an HTML node.
/// ///
/// This structure is designed to be easily walked in order to render a DOM tree /// This structure is designed to be easily walked in order to render a DOM tree
@ -52,7 +72,7 @@ pub trait Node<T: OutputType>: Display {
/// Render the node into a [`VNode`][VNode] tree. /// Render the node into a [`VNode`][VNode] tree.
/// ///
/// [VNode]: enum.VNode.html /// [VNode]: enum.VNode.html
fn vnode<'a>(&'a mut self) -> VNode<'a, T>; fn vnode(&mut self) -> VNode<T>;
} }
/// Trait for querying a typed HTML element. /// Trait for querying a typed HTML element.

View File

@ -25,6 +25,26 @@ macro_rules! declare_events {
} }
} }
/// Iterate over the defined events on a DOM object.
///
/// # Examples
///
/// ```
/// # #![feature(proc_macro_hygiene)]
/// # extern crate typed_html;
/// # use typed_html::{html, for_events};
/// # use typed_html::dom::{DOMTree, VNode};
/// # fn main() {
/// let mut doc: DOMTree<String> = html!(
/// <button onclick="alert('clicked!')"/>
/// );
/// if let VNode::Element(element) = doc.vnode() {
/// for_events!(event in element.events => {
/// assert_eq!("alert('clicked!')", event.render().unwrap());
/// });
/// }
/// # }
/// ```
#[macro_export] #[macro_export]
macro_rules! for_events { macro_rules! for_events {
($event:ident in $events:expr => $body:block) => { ($event:ident in $events:expr => $body:block) => {

View File

@ -1,7 +1,5 @@
#![feature(try_from)] #![feature(try_from)]
#[macro_use]
extern crate enumset;
#[macro_use] #[macro_use]
extern crate strum_macros; extern crate strum_macros;
@ -13,6 +11,8 @@ extern crate stdweb;
extern crate strum; extern crate strum;
extern crate typed_html_macros; extern crate typed_html_macros;
pub use typed_html_macros::html;
pub mod dom; pub mod dom;
pub mod elements; pub mod elements;
pub mod events; pub mod events;

View File

@ -5,13 +5,22 @@ use std::str::FromStr;
use super::Id; use super::Id;
/// A valid CSS class.
///
/// A CSS class is a non-empty string that starts with an alphanumeric character
/// and is followed by any number of alphanumeric characters and the
/// `_`, `-` and `.` characters.
///
/// See also [`Id`][Id].
///
/// [Id]: struct.Id.html
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Class(String); pub struct Class(String);
impl Class { impl Class {
// Construct a new class name from a string. /// Construct a new class name from a string.
// ///
// Returns `None` if the provided string is invalid. /// Returns `Err` if the provided string is invalid.
pub fn try_new<S: Into<String>>(id: S) -> Result<Self, &'static str> { pub fn try_new<S: Into<String>>(id: S) -> Result<Self, &'static str> {
let id = id.into(); let id = id.into();
{ {
@ -34,9 +43,9 @@ impl Class {
Ok(Class(id)) Ok(Class(id))
} }
// Construct a new class name from a string. /// Construct a new class name from a string.
// ///
// Panics if the provided string is invalid. /// Panics if the provided string is invalid.
pub fn new<S: Into<String>>(id: S) -> Self { pub fn new<S: Into<String>>(id: S) -> Self {
let id = id.into(); let id = id.into();
Self::try_new(id.clone()).unwrap_or_else(|err| { Self::try_new(id.clone()).unwrap_or_else(|err| {

View File

@ -5,13 +5,22 @@ use std::str::FromStr;
use super::Class; use super::Class;
/// A valid HTML ID.
///
/// An ID is a non-empty string that starts with an alphanumeric character
/// and is followed by any number of alphanumeric characters and the
/// `_`, `-` and `.` characters.
///
/// See also [`Class`][Class].
///
/// [Class]: struct.Class.html
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Id(String); pub struct Id(String);
impl Id { impl Id {
// Construct a new ID from a string. /// Construct a new ID from a string.
// ///
// Returns `None` if the provided string is invalid. /// Returns `Err` if the provided string is invalid.
pub fn try_new<S: Into<String>>(id: S) -> Result<Self, &'static str> { pub fn try_new<S: Into<String>>(id: S) -> Result<Self, &'static str> {
let id = id.into(); let id = id.into();
{ {
@ -32,9 +41,9 @@ impl Id {
Ok(Id(id)) Ok(Id(id))
} }
// Construct a new ID from a string. /// Construct a new ID from a string.
// ///
// Panics if the provided string is invalid. /// Panics if the provided string is invalid.
pub fn new<S: Into<String>>(id: S) -> Self { pub fn new<S: Into<String>>(id: S) -> Self {
let id = id.into(); let id = id.into();
Self::try_new(id.clone()).unwrap_or_else(|err| { Self::try_new(id.clone()).unwrap_or_else(|err| {

View File

@ -25,320 +25,284 @@ pub type Integrity = String;
pub type Nonce = String; pub type Nonce = String;
pub type Target = String; pub type Target = String;
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum AreaShape {
pub enum AreaShape { #[strum(to_string = "rect")]
#[strum(to_string = "rect")] Rectangle,
Rectangle, #[strum(to_string = "circle")]
#[strum(to_string = "circle")] Circle,
Circle, #[strum(to_string = "poly")]
#[strum(to_string = "poly")] Polygon,
Polygon, #[strum(to_string = "default")]
#[strum(to_string = "default")] Default,
Default,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum BoolOrDefault {
pub enum BoolOrDefault { #[strum(to_string = "true")]
#[strum(to_string = "true")] True,
True, #[strum(to_string = "default")]
#[strum(to_string = "default")] Default,
Default, #[strum(to_string = "false")]
#[strum(to_string = "false")] False,
False,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum ButtonType {
pub enum ButtonType { #[strum(to_string = "submit")]
#[strum(to_string = "submit")] Submit,
Submit, #[strum(to_string = "reset")]
#[strum(to_string = "reset")] Reset,
Reset, #[strum(to_string = "button")]
#[strum(to_string = "button")] Button,
Button,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum CrossOrigin {
pub enum CrossOrigin { #[strum(to_string = "anonymous")]
#[strum(to_string = "anonymous")] Anonymous,
Anonymous, #[strum(to_string = "use-credentials")]
#[strum(to_string = "use-credentials")] UseCredentials,
UseCredentials,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum FormEncodingType {
pub enum FormEncodingType { #[strum(to_string = "application/x-www-form-urlencoded")]
#[strum(to_string = "application/x-www-form-urlencoded")] UrlEncoded,
UrlEncoded, #[strum(to_string = "multipart/form-data")]
#[strum(to_string = "multipart/form-data")] FormData,
FormData, #[strum(to_string = "text/plain")]
#[strum(to_string = "text/plain")] Text,
Text,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum FormMethod {
pub enum FormMethod { #[strum(to_string = "post")]
#[strum(to_string = "post")] Post,
Post, #[strum(to_string = "get")]
#[strum(to_string = "get")] Get,
Get,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum ImageDecoding {
pub enum ImageDecoding { #[strum(to_string = "sync")]
#[strum(to_string = "sync")] Sync,
Sync, #[strum(to_string = "async")]
#[strum(to_string = "async")] Async,
Async, #[strum(to_string = "auto")]
#[strum(to_string = "auto")] Auto,
Auto,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum InputType {
pub enum InputType { #[strum(to_string = "button")]
#[strum(to_string = "button")] Button,
Button, #[strum(to_string = "checkbox")]
#[strum(to_string = "checkbox")] Checkbox,
Checkbox, #[strum(to_string = "color")]
#[strum(to_string = "color")] Color,
Color, #[strum(to_string = "date")]
#[strum(to_string = "date")] Date,
Date, #[strum(to_string = "datetime-local")]
#[strum(to_string = "datetime-local")] DatetimeLocal,
DatetimeLocal, #[strum(to_string = "email")]
#[strum(to_string = "email")] Email,
Email, #[strum(to_string = "file")]
#[strum(to_string = "file")] File,
File, #[strum(to_string = "hidden")]
#[strum(to_string = "hidden")] Hidden,
Hidden, #[strum(to_string = "image")]
#[strum(to_string = "image")] Image,
Image, #[strum(to_string = "month")]
#[strum(to_string = "month")] Month,
Month, #[strum(to_string = "number")]
#[strum(to_string = "number")] Number,
Number, #[strum(to_string = "password")]
#[strum(to_string = "password")] Password,
Password, #[strum(to_string = "radio")]
#[strum(to_string = "radio")] Radio,
Radio, #[strum(to_string = "range")]
#[strum(to_string = "range")] Range,
Range, #[strum(to_string = "reset")]
#[strum(to_string = "reset")] Reset,
Reset, #[strum(to_string = "search")]
#[strum(to_string = "search")] Search,
Search, #[strum(to_string = "submit")]
#[strum(to_string = "submit")] Submit,
Submit, #[strum(to_string = "tel")]
#[strum(to_string = "tel")] Tel,
Tel, #[strum(to_string = "text")]
#[strum(to_string = "text")] Text,
Text, #[strum(to_string = "time")]
#[strum(to_string = "time")] Time,
Time, #[strum(to_string = "url")]
#[strum(to_string = "url")] Url,
Url, #[strum(to_string = "week")]
#[strum(to_string = "week")] Week,
Week,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum LinkType {
pub enum LinkType { #[strum(to_string = "alternate")]
#[strum(to_string = "alternate")] Alternate,
Alternate, #[strum(to_string = "author")]
#[strum(to_string = "author")] Author,
Author, #[strum(to_string = "bookmark")]
#[strum(to_string = "bookmark")] Bookmark,
Bookmark, #[strum(to_string = "canonical")]
#[strum(to_string = "canonical")] Canonical,
Canonical, #[strum(to_string = "external")]
#[strum(to_string = "external")] External,
External, #[strum(to_string = "help")]
#[strum(to_string = "help")] Help,
Help, #[strum(to_string = "icon")]
#[strum(to_string = "icon")] Icon,
Icon, #[strum(to_string = "license")]
#[strum(to_string = "license")] License,
License, #[strum(to_string = "manifest")]
#[strum(to_string = "manifest")] Manifest,
Manifest, #[strum(to_string = "modulepreload")]
#[strum(to_string = "modulepreload")] ModulePreload,
ModulePreload, #[strum(to_string = "next")]
#[strum(to_string = "next")] Next,
Next, #[strum(to_string = "nofollow")]
#[strum(to_string = "nofollow")] NoFollow,
NoFollow, #[strum(to_string = "noopener")]
#[strum(to_string = "noopener")] NoOpener,
NoOpener, #[strum(to_string = "noreferrer")]
#[strum(to_string = "noreferrer")] NoReferrer,
NoReferrer, #[strum(to_string = "pingback")]
#[strum(to_string = "pingback")] PingBack,
PingBack, #[strum(to_string = "prefetch")]
#[strum(to_string = "prefetch")] Prefetch,
Prefetch, #[strum(to_string = "preload")]
#[strum(to_string = "preload")] Preload,
Preload, #[strum(to_string = "prev")]
#[strum(to_string = "prev")] Prev,
Prev, #[strum(to_string = "search")]
#[strum(to_string = "search")] Search,
Search, #[strum(to_string = "shortlink")]
#[strum(to_string = "shortlink")] ShortLink,
ShortLink, #[strum(to_string = "stylesheet")]
#[strum(to_string = "stylesheet")] StyleSheet,
StyleSheet, #[strum(to_string = "tag")]
#[strum(to_string = "tag")] Tag,
Tag,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum OnOff {
pub enum OnOff { #[strum(to_string = "on")]
#[strum(to_string = "on")] On,
On, #[strum(to_string = "off")]
#[strum(to_string = "off")] Off,
Off,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum OrderedListType {
pub enum OrderedListType { #[strum(to_string = "a")]
#[strum(to_string = "a")] LowerCaseLetters,
LowerCaseLetters, #[strum(to_string = "A")]
#[strum(to_string = "A")] UpperCaseLetters,
UpperCaseLetters, #[strum(to_string = "i")]
#[strum(to_string = "i")] LowerCaseRomanNumerals,
LowerCaseRomanNumerals, #[strum(to_string = "I")]
#[strum(to_string = "I")] UpperCaseRomanNumerals,
UpperCaseRomanNumerals, #[strum(to_string = "1")]
#[strum(to_string = "1")] Numbers,
Numbers,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum Preload {
pub enum Preload { #[strum(to_string = "none")]
#[strum(to_string = "none")] None,
None, #[strum(to_string = "metadata")]
#[strum(to_string = "metadata")] Metadata,
Metadata, #[strum(to_string = "auto")]
#[strum(to_string = "auto")] Auto,
Auto,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum ReferrerPolicy {
pub enum ReferrerPolicy { #[strum(to_string = "no-referrer")]
#[strum(to_string = "no-referrer")] NoReferrer,
NoReferrer, #[strum(to_string = "no-referrer-when-downgrade")]
#[strum(to_string = "no-referrer-when-downgrade")] NoReferrerWhenDowngrade,
NoReferrerWhenDowngrade, #[strum(to_string = "origin")]
#[strum(to_string = "origin")] Origin,
Origin, #[strum(to_string = "origin-when-cross-origin")]
#[strum(to_string = "origin-when-cross-origin")] OriginWhenCrossOrigin,
OriginWhenCrossOrigin, #[strum(to_string = "unsafe-url")]
#[strum(to_string = "unsafe-url")] UnsafeUrl,
UnsafeUrl,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum Sandbox {
pub enum Sandbox { #[strum(to_string = "allow-forms")]
#[strum(to_string = "allow-forms")] AllowForms,
AllowForms, #[strum(to_string = "allow-modals")]
#[strum(to_string = "allow-modals")] AllowModals,
AllowModals, #[strum(to_string = "allow-orientation-lock")]
#[strum(to_string = "allow-orientation-lock")] AllowOrientationLock,
AllowOrientationLock, #[strum(to_string = "allow-pointer-lock")]
#[strum(to_string = "allow-pointer-lock")] AllowPointerLock,
AllowPointerLock, #[strum(to_string = "allow-popups")]
#[strum(to_string = "allow-popups")] AllowPopups,
AllowPopups, #[strum(to_string = "allow-popups-to-escape-sandbox")]
#[strum(to_string = "allow-popups-to-escape-sandbox")] AllowPopupsToEscapeSandbox,
AllowPopupsToEscapeSandbox, #[strum(to_string = "allow-presentation")]
#[strum(to_string = "allow-presentation")] AllowPresentation,
AllowPresentation, #[strum(to_string = "allow-same-origin")]
#[strum(to_string = "allow-same-origin")] AllowSameOrigin,
AllowSameOrigin, #[strum(to_string = "allow-scripts")]
#[strum(to_string = "allow-scripts")] AllowScripts,
AllowScripts, #[strum(to_string = "allow-top-navigation")]
#[strum(to_string = "allow-top-navigation")] AllowTopNavigation,
AllowTopNavigation, #[strum(to_string = "allow-top-navigation-by-user-navigation")]
#[strum(to_string = "allow-top-navigation-by-user-navigation")] AllowTopNavigationByUserNavigation,
AllowTopNavigationByUserNavigation,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum TableHeaderScope {
pub enum TableHeaderScope { #[strum(to_string = "row")]
#[strum(to_string = "row")] Row,
Row, #[strum(to_string = "col")]
#[strum(to_string = "col")] Column,
Column, #[strum(to_string = "rowgroup")]
#[strum(to_string = "rowgroup")] RowGroup,
RowGroup, #[strum(to_string = "colgroup")]
#[strum(to_string = "colgroup")] ColGroup,
ColGroup, #[strum(to_string = "auto")]
#[strum(to_string = "auto")] Auto,
Auto,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum TextDirection {
pub enum TextDirection { #[strum(to_string = "ltr")]
#[strum(to_string = "ltr")] LeftToRight,
LeftToRight, #[strum(to_string = "rtl")]
#[strum(to_string = "rtl")] RightToLeft,
RightToLeft,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum VideoKind {
pub enum VideoKind { #[strum(to_string = "subtitles")]
#[strum(to_string = "subtitles")] Subtitles,
Subtitles, #[strum(to_string = "captions")]
#[strum(to_string = "captions")] Captions,
Captions, #[strum(to_string = "descriptions")]
#[strum(to_string = "descriptions")] Descriptions,
Descriptions, #[strum(to_string = "chapters")]
#[strum(to_string = "chapters")] Chapters,
Chapters, #[strum(to_string = "metadata")]
#[strum(to_string = "metadata")] Metadata,
Metadata,
}
} }
enum_set_type! { #[derive(EnumString, Display, PartialEq, Eq, PartialOrd, Ord, AsRefStr, AsStaticStr)]
#[derive(EnumString, Display)] pub enum Wrap {
pub enum Wrap { #[strum(to_string = "hard")]
#[strum(to_string = "hard")] Hard,
Hard, #[strum(to_string = "soft")]
#[strum(to_string = "soft")] Soft,
Soft, #[strum(to_string = "off")]
#[strum(to_string = "off")] Off,
Off,
}
} }

View File

@ -3,10 +3,18 @@ use std::iter::FromIterator;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str::FromStr; use std::str::FromStr;
/// A space separated list of values.
///
/// This type represents a list of non-unique values represented as a string of
/// values separated by spaces in HTML attributes. This is rarely used; a
/// [`SpacedSet`][SpacedSet] of unique values is much more common.
///
/// [SpacedSet]: struct.SpacedSet.html
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct SpacedList<A>(Vec<A>); pub struct SpacedList<A>(Vec<A>);
impl<A> SpacedList<A> { impl<A> SpacedList<A> {
/// Construct an empty `SpacedList`.
pub fn new() -> Self { pub fn new() -> Self {
SpacedList(Vec::new()) SpacedList(Vec::new())
} }

View File

@ -4,10 +4,33 @@ use std::iter::FromIterator;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str::FromStr; use std::str::FromStr;
/// A space separated set of unique values.
///
/// This type represents a set of unique values represented as a string of
/// values separated by spaces in HTML attributes.
///
/// # Examples
///
/// ```
/// # extern crate typed_html;
/// # use std::convert::From;
/// use typed_html::types::{Class, SpacedSet};
///
/// # fn main() {
/// let classList: SpacedSet<Class> = "foo bar baz".into();
/// let classList: SpacedSet<Class> = ["foo", "bar", "baz"].into();
/// let classList: SpacedSet<Class> = ("foo", "bar", "baz").into();
///
/// let classList1: SpacedSet<Class> = "foo bar foo".into();
/// let classList2: SpacedSet<Class> = "bar foo bar".into();
/// assert_eq!(classList1, classList2);
/// # }
/// ```
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct SpacedSet<A: Ord>(BTreeSet<A>); pub struct SpacedSet<A: Ord>(BTreeSet<A>);
impl<A: Ord> SpacedSet<A> { impl<A: Ord> SpacedSet<A> {
/// Construct an empty `SpacedSet`.
pub fn new() -> Self { pub fn new() -> Self {
SpacedSet(BTreeSet::new()) SpacedSet(BTreeSet::new())
} }
@ -46,7 +69,7 @@ where
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let result: Result<Vec<A>, Self::Err> = let result: Result<Vec<A>, Self::Err> =
s.split_whitespace().map(|s| FromStr::from_str(s)).collect(); s.split_whitespace().map(|s| FromStr::from_str(s)).collect();
result.map(|items| Self::from_iter(items)) result.map(Self::from_iter)
} }
} }

View File

@ -8,9 +8,7 @@ extern crate typed_html_macros;
use stdweb::web::{self, Element, IElement, INode}; use stdweb::web::{self, Element, IElement, INode};
use typed_html::dom::{Node, VNode}; use typed_html::dom::{Node, VNode};
use typed_html::events::Events; use typed_html::events::Events;
use typed_html::for_events; use typed_html::{for_events, html, DOM};
use typed_html::DOM;
use typed_html_macros::html;
fn install_handlers(target: &Element, handlers: &mut Events<DOM>) { fn install_handlers(target: &Element, handlers: &mut Events<DOM>) {
for_events!(handler in handlers => { for_events!(handler in handlers => {