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.
|
/// Parses and renders the attributes of an element.
|
||||||
fn attrs(&mut self) -> PResult<()> {
|
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();
|
let mut ids = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let old_input = self.input;
|
let old_input = self.input;
|
||||||
|
@ -525,7 +526,18 @@ impl<'cx, 'a, 'i> Parser<'cx, 'a, 'i> {
|
||||||
(Err(_), &[dot!(), ident!(_, _), ..]) => {
|
(Err(_), &[dot!(), ident!(_, _), ..]) => {
|
||||||
// Class shorthand
|
// Class shorthand
|
||||||
self.shift(1);
|
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!(_, _), ..]) => {
|
(Err(_), &[pound!(), ident!(_, _), ..]) => {
|
||||||
// ID shorthand
|
// 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.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();
|
self.render.attribute_end();
|
||||||
}
|
}
|
||||||
if !ids.is_empty() {
|
if !ids.is_empty() {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
extern crate maud;
|
extern crate maud;
|
||||||
|
|
||||||
|
use maud::Markup;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literals() {
|
fn literals() {
|
||||||
let s = html!("du\tcks" "-23" "3.14\n" "geese").into_string();
|
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>"#);
|
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]
|
#[test]
|
||||||
fn colons_in_names() {
|
fn colons_in_names() {
|
||||||
let s = html!(pon-pon:controls-alpha a on:click="yay()" "Yay!").into_string();
|
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>"#);
|
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]
|
#[test]
|
||||||
fn ids_shorthand() {
|
fn ids_shorthand() {
|
||||||
let s = html!(p { "Hi, " span#thing { "Lyra" } "!" }).into_string();
|
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">"#);
|
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";
|
static BEST_PONY: &'static str = "Pinkie Pie";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Reference in a new issue