Skip to content

Commit 6bfb510

Browse files
committed
feat: Option to control whether remote stylesheets should be loaded
1 parent 313b594 commit 6bfb510

File tree

6 files changed

+114
-47
lines changed

6 files changed

+114
-47
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
### Added
66

77
- `CSSInliner` and customization options. [#9](https://github.com/Stranger6667/css-inline/issues/9)
8-
- Option to remove "style" tags. [#11](https://github.com/Stranger6667/css-inline/issues/11)
8+
- Option to remove "style" tags (`remove_style_tags`). Disabled by default. [#11](https://github.com/Stranger6667/css-inline/issues/11)
99
- `CSSInliner::compact()` constructor for producing smaller HTML output.
1010
- `CSSInliner.inline_to` that writes the output to a generic writer. [#24](https://github.com/Stranger6667/css-inline/issues/24)
1111
- Implement `Error` for `InlineError`.
1212
- Loading external stylesheets. [#8](https://github.com/Stranger6667/css-inline/issues/8)
13+
- Option to control whether remote stylesheets should be loaded (`load_remote_stylesheets`). Enabled by default.
1314

1415
### Changed
1516

README.md

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,10 @@ For example, this HTML:
1212
<html>
1313
<head>
1414
<title>Test</title>
15-
<style>
16-
h1, h2 { color:blue; }
17-
strong { text-decoration:none }
18-
p { font-size:2px }
19-
p.footer { font-size: 1px}
20-
</style>
15+
<style>h1 { color:blue; }</style>
2116
</head>
2217
<body>
2318
<h1>Big Text</h1>
24-
<p>
25-
<strong>Solid</strong>
26-
</p>
27-
<p class="footer">Foot notes</p>
2819
</body>
2920
</html>
3021
```
@@ -33,15 +24,9 @@ Will be turned into this:
3324

3425
```html
3526
<html>
36-
<head>
37-
<title>Test</title>
38-
</head>
27+
<head><title>Test</title></head>
3928
<body>
4029
<h1 style="color:blue;">Big Text</h1>
41-
<p style="font-size:2px;">
42-
<strong style="text-decoration:none;">Solid</strong>
43-
</p>
44-
<p style="font-size:1px;">Foot notes</p>
4530
</body>
4631
</html>
4732
```
@@ -52,33 +37,56 @@ To use it in your project add the following line to your `dependencies` section
5237
css-inline = "0.1"
5338
```
5439

55-
## Example:
40+
## Usage
5641

5742
```rust
5843
use css_inline;
5944

6045
const HTML: &str = r#"<html>
6146
<head>
6247
<title>Test</title>
63-
<style>
64-
h1, h2 { color:blue; }
65-
strong { text-decoration:none }
66-
p { font-size:2px }
67-
p.footer { font-size: 1px}
68-
</style>
48+
<style>h1 { color:blue; }</style>
6949
</head>
7050
<body>
7151
<h1>Big Text</h1>
72-
<p>
73-
<strong>Solid</strong>
74-
</p>
75-
<p class="footer">Foot notes</p>
7652
</body>
7753
</html>"#;
7854

7955
fn main() -> Result<(), css_inline::InlineError> {
80-
let inlined = css_inline::inline(HTML)?;
81-
// Do something with inlined HTML, e.g. send an email
82-
Ok(())
56+
let inlined = css_inline::inline(HTML)?;
57+
// Do something with inlined HTML, e.g. send an email
58+
Ok(())
8359
}
8460
```
61+
62+
### Features
63+
64+
`css-inline` does minimum work by default:
65+
66+
- No CSS transformation;
67+
- No "style" or "link" tags removal;
68+
69+
It also loads external stylesheets via network or filesystem, but this behavior is configurable.
70+
71+
### Configuration
72+
73+
`css-inline` can be configured by using `InlineOptions` and `CSSInliner`:
74+
75+
```rust
76+
use css_inline;
77+
78+
fn main() -> Result<(), css_inline::InlineError> {
79+
let options = css_inline::InlineOptions {
80+
load_remote_stylesheets: false,
81+
..Default::default()
82+
};
83+
let inliner = css_inline::CSSInliner(options);
84+
let inlined = inliner.inline(HTML);
85+
// Do something with inlined HTML, e.g. send an email
86+
Ok(())
87+
}
88+
```
89+
90+
- `remove_style_tags`. Remove "style" tags after inlining.
91+
- `base_url`. Base URL to resolve relative URLs
92+
- `load_remote_stylesheets`. Whether remote stylesheets should be loaded or not

python/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66

77
- Loading external stylesheets. [#8](https://github.com/Stranger6667/css-inline/issues/8)
8+
- Option to control whether remote stylesheets should be loaded (`load_remote_stylesheets`). Enabled by default.
89

910
### Changed
1011

python/src/lib.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,23 @@ fn to_pyerr(error: rust_inline::InlineError) -> PyErr {
1717

1818
/// Customizable CSS inliner.
1919
#[pyclass]
20-
#[text_signature = "(remove_style_tags=False, base_url=None)"]
20+
#[text_signature = "(remove_style_tags=False, base_url=None, load_remote_stylesheets=True)"]
2121
struct CSSInliner {
2222
inner: rust_inline::CSSInliner,
2323
}
2424

2525
#[pymethods]
2626
impl CSSInliner {
2727
#[new]
28-
fn new(remove_style_tags: Option<bool>, base_url: Option<String>) -> Self {
28+
fn new(
29+
remove_style_tags: Option<bool>,
30+
base_url: Option<String>,
31+
load_remote_stylesheets: Option<bool>,
32+
) -> Self {
2933
let options = rust_inline::InlineOptions {
3034
remove_style_tags: remove_style_tags.unwrap_or(false),
3135
base_url,
36+
load_remote_stylesheets: load_remote_stylesheets.unwrap_or(true),
3237
};
3338
CSSInliner {
3439
inner: rust_inline::CSSInliner::new(options),
@@ -52,37 +57,41 @@ impl CSSInliner {
5257
}
5358
}
5459

55-
/// inline(html, remove_style_tags=False, base_url=None)
60+
/// inline(html, remove_style_tags=False, base_url=None, load_remote_stylesheets=True)
5661
///
5762
/// Inline CSS in the given HTML document
5863
#[pyfunction]
59-
#[text_signature = "(html, remove_style_tags=False, base_url=None)"]
64+
#[text_signature = "(html, remove_style_tags=False, base_url=None, load_remote_stylesheets=True)"]
6065
fn inline(
6166
html: &str,
6267
remove_style_tags: Option<bool>,
6368
base_url: Option<String>,
69+
load_remote_stylesheets: Option<bool>,
6470
) -> PyResult<String> {
6571
let options = rust_inline::InlineOptions {
6672
remove_style_tags: remove_style_tags.unwrap_or(false),
6773
base_url,
74+
load_remote_stylesheets: load_remote_stylesheets.unwrap_or(true),
6875
};
6976
let inliner = rust_inline::CSSInliner::new(options);
7077
Ok(inliner.inline(html).map_err(to_pyerr)?)
7178
}
7279

73-
/// inline_many(htmls, remove_style_tags=False, base_url=None)
80+
/// inline_many(htmls, remove_style_tags=False, base_url=None, load_remote_stylesheets=True)
7481
///
7582
/// Inline CSS in multiple HTML documents
7683
#[pyfunction]
77-
#[text_signature = "(htmls, remove_style_tags=False, base_url=None)"]
84+
#[text_signature = "(htmls, remove_style_tags=False, base_url=None, load_remote_stylesheets=True)"]
7885
fn inline_many(
7986
htmls: &PyList,
8087
remove_style_tags: Option<bool>,
8188
base_url: Option<String>,
89+
load_remote_stylesheets: Option<bool>,
8290
) -> PyResult<Vec<String>> {
8391
let options = rust_inline::InlineOptions {
8492
remove_style_tags: remove_style_tags.unwrap_or(false),
8593
base_url,
94+
load_remote_stylesheets: load_remote_stylesheets.unwrap_or(true),
8695
};
8796
let inliner = rust_inline::CSSInliner::new(options);
8897
inline_many_impl(&inliner, htmls)

src/lib.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ pub struct InlineOptions {
162162
pub remove_style_tags: bool,
163163
/// Used for loading external stylesheets via relative URLs
164164
pub base_url: Option<String>,
165+
/// Whether remote stylesheets should be loaded or not
166+
pub load_remote_stylesheets: bool,
165167
}
166168

167169
impl InlineOptions {
@@ -171,6 +173,7 @@ impl InlineOptions {
171173
InlineOptions {
172174
remove_style_tags: true,
173175
base_url: None,
176+
load_remote_stylesheets: true,
174177
}
175178
}
176179
}
@@ -181,6 +184,7 @@ impl Default for InlineOptions {
181184
InlineOptions {
182185
remove_style_tags: false,
183186
base_url: None,
187+
load_remote_stylesheets: true,
184188
}
185189
}
186190
}
@@ -234,14 +238,16 @@ impl CSSInliner {
234238
style_tag.as_node().detach()
235239
}
236240
}
237-
for link_tag in document
238-
.select("link[rel~=stylesheet]")
239-
.map_err(|_| error::InlineError::ParseError("Unknown error".to_string()))?
240-
{
241-
if let Some(href) = &link_tag.attributes.borrow().get("href") {
242-
let url = self.get_full_url(href);
243-
let css = self.load_external(url.as_str())?;
244-
process_css(&document, css.as_str())?;
241+
if self.options.load_remote_stylesheets {
242+
for link_tag in document
243+
.select("link[rel~=stylesheet]")
244+
.map_err(|_| error::InlineError::ParseError("Unknown error".to_string()))?
245+
{
246+
if let Some(href) = &link_tag.attributes.borrow().get("href") {
247+
let url = self.get_full_url(href);
248+
let css = self.load_external(url.as_str())?;
249+
process_css(&document, css.as_str())?;
250+
}
245251
}
246252
}
247253
document.serialize(target)?;

tests/test_inlining.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use css_inline::{inline, CSSInliner};
1+
use css_inline::{inline, CSSInliner, InlineOptions};
22

33
macro_rules! html {
44
($style: expr, $body: expr) => {
@@ -135,6 +135,37 @@ h2 { color: red; }
135135
))
136136
}
137137

138+
#[test]
139+
fn remote_file_stylesheet_disable() {
140+
let html = r#"
141+
<html>
142+
<head>
143+
<link href="tests/external.css" rel="stylesheet" type="text/css">
144+
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml">
145+
<style type="text/css">
146+
h2 { color: red; }
147+
</style>
148+
</head>
149+
<body>
150+
<h1>Big Text</h1>
151+
<h2>Smaller Text</h2>
152+
</body>
153+
</html>"#;
154+
let options = InlineOptions {
155+
remove_style_tags: false,
156+
base_url: None,
157+
load_remote_stylesheets: false,
158+
};
159+
let result = inline(&html).unwrap();
160+
assert!(result.ends_with(
161+
r#"<body>
162+
<h1 style="color: blue;">Big Text</h1>
163+
<h2 style="color: red;">Smaller Text</h2>
164+
165+
</body></html>"#
166+
))
167+
}
168+
138169
#[test]
139170
fn remote_network_stylesheet() {
140171
let html = r#"
@@ -160,3 +191,14 @@ h2 { color: red; }
160191
</body></html>"#
161192
))
162193
}
194+
195+
#[test]
196+
fn customize_inliner() {
197+
let options = InlineOptions {
198+
load_remote_stylesheets: false,
199+
..Default::default()
200+
};
201+
assert_eq!(options.load_remote_stylesheets, false);
202+
assert_eq!(options.remove_style_tags, false);
203+
assert_eq!(options.base_url, None);
204+
}

0 commit comments

Comments
 (0)