@@ -105,6 +105,7 @@ pub mod error;
105
105
mod parse;
106
106
107
107
pub use error:: InlineError ;
108
+ use std:: collections:: HashMap ;
108
109
109
110
#[ derive( Debug ) ]
110
111
struct Rule {
@@ -151,14 +152,16 @@ pub fn inline(html: &str) -> Result<String, InlineError> {
151
152
. filter_map ( |node| node. into_element_ref ( ) )
152
153
. filter ( |element| rule. selectors . matches ( element) ) ;
153
154
for matching_element in matching_elements {
154
- let style = rule
155
- . declarations
156
- . iter ( )
157
- . map ( |& ( ref key, ref value) | format ! ( "{}:{};" , key, value) ) ;
158
- matching_element
159
- . attributes
160
- . borrow_mut ( )
161
- . insert ( "style" , style. collect ( ) ) ;
155
+ let mut attributes = matching_element. attributes . borrow_mut ( ) ;
156
+ let style = if let Some ( existing_style) = attributes. get ( "style" ) {
157
+ merge_styles ( existing_style, & rule. declarations ) ?
158
+ } else {
159
+ rule. declarations
160
+ . iter ( )
161
+ . map ( |& ( ref key, ref value) | format ! ( "{}:{};" , key, value) )
162
+ . collect ( )
163
+ } ;
164
+ attributes. insert ( "style" , style) ;
162
165
}
163
166
}
164
167
@@ -173,6 +176,28 @@ pub fn inline(html: &str) -> Result<String, InlineError> {
173
176
Ok ( String :: from_utf8_lossy ( & out) . to_string ( ) )
174
177
}
175
178
179
+ fn merge_styles ( existing_style : & str , new_styles : & [ Declaration ] ) -> Result < String , InlineError > {
180
+ // Parse existing declarations in "style" attribute
181
+ let mut input = cssparser:: ParserInput :: new ( existing_style) ;
182
+ let mut parser = cssparser:: Parser :: new ( & mut input) ;
183
+ let declarations =
184
+ cssparser:: DeclarationListParser :: new ( & mut parser, parse:: CSSDeclarationListParser ) ;
185
+ // Merge existing with the new ones
186
+ let mut styles: HashMap < String , String > = HashMap :: new ( ) ;
187
+ for declaration in declarations. into_iter ( ) {
188
+ let ( property, value) = declaration?;
189
+ styles. insert ( property. to_string ( ) , value. to_string ( ) ) ;
190
+ }
191
+ for ( property, value) in new_styles. iter ( ) {
192
+ styles. insert ( property. to_string ( ) , value. to_string ( ) ) ;
193
+ }
194
+ // Create a new declarations list
195
+ Ok ( styles
196
+ . iter ( )
197
+ . map ( |( key, value) | format ! ( "{}:{};" , key, value) )
198
+ . collect :: < String > ( ) )
199
+ }
200
+
176
201
#[ cfg( test) ]
177
202
mod tests {
178
203
use crate :: * ;
@@ -190,9 +215,9 @@ p.footer { font-size: 1px}
190
215
</style>
191
216
</head>
192
217
<body>
193
- <h1>Hi! </h1>
218
+ <h1>Big Text </h1>
194
219
<p><strong>Yes!</strong></p>
195
- <p class="footer">Feetnuts </p>
220
+ <p class="footer">Foot notes </p>
196
221
</body>
197
222
</html>"# ;
198
223
@@ -213,12 +238,51 @@ p.footer { font-size: 1px}
213
238
</style>
214
239
</head>
215
240
<body>
216
- <h1 style="color:red;">Hi! </h1>
241
+ <h1 style="color:red;">Big Text </h1>
217
242
<p style="font-size:2px ;"><strong style="text-decoration:none
218
243
;">Yes!</strong></p>
219
- <p class="footer" style="font-size: 1px;">Feetnuts </p>
244
+ <p class="footer" style="font-size: 1px;">Foot notes </p>
220
245
221
246
</body></html>"#
222
247
)
223
248
}
249
+
250
+ #[ test]
251
+ fn test_merge_styles ( ) {
252
+ let html = r#"<html>
253
+ <head>
254
+ <title>Test</title>
255
+ <style>
256
+ h1 { color:red; }
257
+ </style>
258
+ </head>
259
+ <body>
260
+ <h1 style="font-size: 1px">Big Text</h1>
261
+ </body>
262
+ </html>"# ;
263
+ let inlined = inline ( html) . expect ( "Should be valid" ) ;
264
+ let valid = ( inlined
265
+ == r#"<html><head>
266
+ <title>Test</title>
267
+ <style>
268
+ h1 { color:red; }
269
+ </style>
270
+ </head>
271
+ <body>
272
+ <h1 style="color:red;font-size: 1px;">Big Text</h1>
273
+
274
+ </body></html>"# )
275
+ || ( inlined
276
+ == r#"<html><head>
277
+ <title>Test</title>
278
+ <style>
279
+ h1 { color:red; }
280
+ </style>
281
+ </head>
282
+ <body>
283
+ <h1 style="font-size: 1px;color:red;">Big Text</h1>
284
+
285
+ </body></html>"# ) ;
286
+ assert ! ( valid, inlined)
287
+ }
224
288
}
0 commit comments