parent
8f77990e8c
commit
585ed3851b
3 changed files with 67 additions and 20 deletions
maud_macros
|
@ -481,7 +481,8 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
|
|||
|
||||
/// Parses and renders the attributes of an element.
|
||||
fn attrs(&mut self) -> PResult<()> {
|
||||
let mut classes = Vec::new();
|
||||
let mut classes_static = Vec::new();
|
||||
let mut classes_toggled = Vec::new();
|
||||
let mut ids = Vec::new();
|
||||
loop {
|
||||
let old_input = self.input;
|
||||
|
@ -525,7 +526,18 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
|
|||
(Err(_), &[dot!(), ident!(_, _), ..]) => {
|
||||
// Class shorthand
|
||||
self.shift(1);
|
||||
classes.push(self.name().unwrap());
|
||||
let class_name = self.name().unwrap();
|
||||
match *self.input {
|
||||
[TokenTree::Delimited(_, ref d), ..] if d.delim == DelimToken::Bracket => {
|
||||
// Toggle the class based on a boolean expression
|
||||
self.shift(1);
|
||||
let cond = self.with_rust_parser(d.tts.clone(), RustParser::parse_expr)?;
|
||||
let cond = cond.to_tokens(self.render.cx);
|
||||
classes_toggled.push((cond, class_name));
|
||||
},
|
||||
// Emit the class unconditionally
|
||||
_ => classes_static.push(class_name),
|
||||
}
|
||||
},
|
||||
(Err(_), &[pound!(), ident!(_, _), ..]) => {
|
||||
// ID shorthand
|
||||
|
@ -538,9 +550,22 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
|
|||
},
|
||||
}
|
||||
}
|
||||
if !classes.is_empty() {
|
||||
if !classes_static.is_empty() || !classes_toggled.is_empty() {
|
||||
self.render.attribute_start("class");
|
||||
self.render.string(&classes.join(" "));
|
||||
self.render.string(&classes_static.join(" "));
|
||||
for (i, (cond, mut class_name)) in classes_toggled.into_iter().enumerate() {
|
||||
// If a class comes first in the list, then it shouldn't be
|
||||
// prefixed by a space
|
||||
if i > 0 || !classes_static.is_empty() {
|
||||
class_name = format!(" {}", class_name);
|
||||
}
|
||||
let body = {
|
||||
let mut r = self.render.fork();
|
||||
r.string(&class_name);
|
||||
r.into_stmts()
|
||||
};
|
||||
self.render.emit_if(cond, body, None);
|
||||
}
|
||||
self.render.attribute_end();
|
||||
}
|
||||
if !ids.is_empty() {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
extern crate maud;
|
||||
|
||||
use maud::Markup;
|
||||
|
||||
#[test]
|
||||
fn literals() {
|
||||
let s = html!("du\tcks" "-23" "3.14\n" "geese").into_string();
|
||||
|
@ -76,6 +78,22 @@ fn empty_attributes() {
|
|||
assert_eq!(s, r#"<div readonly><input type="checkbox" checked></div>"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn toggle_empty_attributes() {
|
||||
let rocks = true;
|
||||
let s = html!({
|
||||
input checked?[true] /
|
||||
input checked?[false] /
|
||||
input checked?[rocks] /
|
||||
input checked?[!rocks] /
|
||||
}).into_string();
|
||||
assert_eq!(s, concat!(
|
||||
r#"<input checked>"#,
|
||||
r#"<input>"#,
|
||||
r#"<input checked>"#,
|
||||
r#"<input>"#));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colons_in_names() {
|
||||
let s = html!(pon-pon:controls-alpha a on:click="yay()" "Yay!").into_string();
|
||||
|
@ -121,6 +139,26 @@ fn hyphens_in_class_names() {
|
|||
assert_eq!(s, r#"<p class="rocks-these are--my--rocks">yes</p>"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn toggle_classes() {
|
||||
fn test(is_cupcake: bool, is_muffin: bool) -> Markup {
|
||||
html!(p.cupcake[is_cupcake].muffin[is_muffin] "Testing!")
|
||||
}
|
||||
assert_eq!(test(true, true).into_string(), r#"<p class="cupcake muffin">Testing!</p>"#);
|
||||
assert_eq!(test(false, true).into_string(), r#"<p class=" muffin">Testing!</p>"#);
|
||||
assert_eq!(test(true, false).into_string(), r#"<p class="cupcake">Testing!</p>"#);
|
||||
assert_eq!(test(false, false).into_string(), r#"<p class="">Testing!</p>"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_classes() {
|
||||
fn test(is_muffin: bool) -> Markup {
|
||||
html!(p.cupcake.muffin[is_muffin].lamington "Testing!")
|
||||
}
|
||||
assert_eq!(test(true).into_string(), r#"<p class="cupcake lamington muffin">Testing!</p>"#);
|
||||
assert_eq!(test(false).into_string(), r#"<p class="cupcake lamington">Testing!</p>"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ids_shorthand() {
|
||||
let s = html!(p { "Hi, " span#thing { "Lyra" } "!" }).into_string();
|
||||
|
|
|
@ -37,22 +37,6 @@ fn attributes() {
|
|||
assert_eq!(s, r#"<img src="pinkie.jpg" alt="Pinkie Pie">"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_attributes() {
|
||||
let rocks = true;
|
||||
let s = html!({
|
||||
input checked?[true] /
|
||||
input checked?[false] /
|
||||
input checked?[rocks] /
|
||||
input checked?[!rocks] /
|
||||
}).into_string();
|
||||
assert_eq!(s, concat!(
|
||||
r#"<input checked>"#,
|
||||
r#"<input>"#,
|
||||
r#"<input checked>"#,
|
||||
r#"<input>"#));
|
||||
}
|
||||
|
||||
static BEST_PONY: &'static str = "Pinkie Pie";
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Reference in a new issue