File tree Expand file tree Collapse file tree 6 files changed +79
-5
lines changed Expand file tree Collapse file tree 6 files changed +79
-5
lines changed Original file line number Diff line number Diff line change 4
4
5
5
- Update to support axum 0.2
6
6
[ #303 ] ( https://github.com/lambda-fairy/maud/pull/303 )
7
+ - Add support for ` Option<T> ` attributes using the ` attr=[value] ` syntax.
8
+ [ #306 ] ( https://github.com/lambda-fairy/maud/pull/306 )
7
9
8
10
## [ 0.22.3] - 2021-09-27
9
11
Original file line number Diff line number Diff line change @@ -101,6 +101,26 @@ html! {
101
101
# ;
102
102
```
103
103
104
+ ## Optional attributes: ` title=[Some("value")] `
105
+
106
+ Add optional attributes to an element using ` attr=[value] ` syntax, with * square*
107
+ brackets. These are only rendered if the value is ` Some<T> ` , and entirely
108
+ omitted if the value is ` None ` .
109
+
110
+ ``` rust
111
+ # let _ = maud ::
112
+ html! {
113
+ p title = [Some (" Good password" )] { " Correct horse" }
114
+
115
+ @ let value = Some (42 );
116
+ input value = [value ];
117
+
118
+ @ let title : Option <& str > = None ;
119
+ p title = [title ] { " Battery staple" }
120
+ }
121
+ # ;
122
+ ```
123
+
104
124
## Empty attributes: ` checked `
105
125
106
126
Declare an empty attribute by omitting the value.
Original file line number Diff line number Diff line change @@ -118,6 +118,40 @@ fn empty_attributes_question_mark() {
118
118
assert_eq ! ( result. into_string( ) , "<input checked disabled>" ) ;
119
119
}
120
120
121
+ #[ test]
122
+ fn optional_attribute_some ( ) {
123
+ let result = html ! { input value=[ Some ( "value" ) ] ; } ;
124
+ assert_eq ! ( result. into_string( ) , r#"<input value="value">"# ) ;
125
+ }
126
+
127
+ #[ test]
128
+ fn optional_attribute_none ( ) {
129
+ let result = html ! { input value=[ None as Option <& str >] ; } ;
130
+ assert_eq ! ( result. into_string( ) , r#"<input>"# ) ;
131
+ }
132
+
133
+ #[ test]
134
+ fn optional_attribute_non_string_some ( ) {
135
+ let result = html ! { input value=[ Some ( 42 ) ] ; } ;
136
+ assert_eq ! ( result. into_string( ) , r#"<input value="42">"# ) ;
137
+ }
138
+
139
+ #[ test]
140
+ fn optional_attribute_variable ( ) {
141
+ let result = html ! {
142
+ @let x = Some ( 42 ) ;
143
+ input value=[ x] ;
144
+ } ;
145
+ assert_eq ! ( result. into_string( ) , r#"<input value="42">"# ) ;
146
+ }
147
+
148
+ #[ test]
149
+ fn optional_attribute_inner_value_evaluated_only_once ( ) {
150
+ let mut count = 0 ;
151
+ html ! { input value=[ { count += 1 ; Some ( "picklebarrelkumquat" ) } ] ; } ;
152
+ assert_eq ! ( count, 1 ) ;
153
+ }
154
+
121
155
#[ test]
122
156
fn colons_in_names ( ) {
123
157
let result = html ! { pon-pon: controls-alpha { a on: click="yay()" { "Yay!" } } } ;
Original file line number Diff line number Diff line change @@ -170,13 +170,15 @@ impl Attribute {
170
170
#[ derive( Debug ) ]
171
171
pub enum AttrType {
172
172
Normal { value : Markup } ,
173
+ Optional { toggler : Toggler } ,
173
174
Empty { toggler : Option < Toggler > } ,
174
175
}
175
176
176
177
impl AttrType {
177
178
fn span ( & self ) -> Option < SpanRange > {
178
179
match * self {
179
180
AttrType :: Normal { ref value } => Some ( value. span ( ) ) ,
181
+ AttrType :: Optional { ref toggler } => Some ( toggler. span ( ) ) ,
180
182
AttrType :: Empty { ref toggler } => toggler. as_ref ( ) . map ( Toggler :: span) ,
181
183
}
182
184
}
Original file line number Diff line number Diff line change @@ -124,6 +124,19 @@ impl Generator {
124
124
self . markup ( value, build) ;
125
125
build. push_str ( "\" " ) ;
126
126
}
127
+ AttrType :: Optional { toggler } => build. push_tokens ( {
128
+ // `inner_value` is the unpacked Some() from `toggler.cond`, see below.
129
+ let markup = Markup :: Splice { expr : quote ! ( inner_value) , outer_span : toggler. cond_span } ;
130
+ let mut build = self . builder ( ) ;
131
+ build. push_str ( " " ) ;
132
+ self . name ( name, & mut build) ;
133
+ build. push_str ( "=\" " ) ;
134
+ self . markup ( markup, & mut build) ;
135
+ build. push_str ( "\" " ) ;
136
+ let body = build. finish ( ) ;
137
+ let cond = toggler. cond ;
138
+ quote ! ( if let Some ( inner_value) = #cond { #body } )
139
+ } ) ,
127
140
AttrType :: Empty { toggler : None } => {
128
141
build. push_str ( " " ) ;
129
142
self . name ( name, build) ;
Original file line number Diff line number Diff line change @@ -571,13 +571,16 @@ impl Parser {
571
571
// Parse a value under an attribute context
572
572
assert ! ( self . current_attr. is_none( ) ) ;
573
573
self . current_attr = Some ( ast:: name_to_string ( name. clone ( ) ) ) ;
574
- let value = self . markup ( ) ;
574
+ let attr_type = match self . attr_toggler ( ) {
575
+ Some ( toggler) => ast:: AttrType :: Optional { toggler } ,
576
+ None => {
577
+ let value = self . markup ( ) ;
578
+ ast:: AttrType :: Normal { value }
579
+ }
580
+ } ;
575
581
self . current_attr = None ;
576
582
attrs. push ( ast:: Attr :: Attribute {
577
- attribute : ast:: Attribute {
578
- name,
579
- attr_type : ast:: AttrType :: Normal { value } ,
580
- } ,
583
+ attribute : ast:: Attribute { name, attr_type } ,
581
584
} ) ;
582
585
}
583
586
// Empty attribute (legacy syntax)
You can’t perform that action at this time.
0 commit comments