Skip to content

Commit 54d6dbf

Browse files
Merge pull request #275 from MIG-Global/master
2 parents 1756f74 + 22ad181 commit 54d6dbf

File tree

3 files changed

+67
-12
lines changed

3 files changed

+67
-12
lines changed

PreMailer.Net/PreMailer.Net.Tests/PreMailerTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,26 @@ public void MoveCssInline_KeepStyleElementsIgnoreElementsMatchesStyleElement_Doe
137137
Assert.Contains("<style id=\"ignore\" type=\"text/css\">", premailedOutput.Html);
138138
}
139139

140+
[Fact]
141+
public void MoveCssInline_PreserveMediaQueries_RemovesStyleElementsWithoutMediaQueries()
142+
{
143+
string input = "<html><head><style>div { width: 42px; }</style></head><body><div>test</div></body></html>";
144+
145+
var premailedOutput = PreMailer.MoveCssInline(input, removeStyleElements: true, preserveMediaQueries: true);
146+
147+
Assert.DoesNotContain("<style>", premailedOutput.Html);
148+
}
149+
150+
[Fact]
151+
public void MoveCssInline_PreserveMediaQueries_PreservesStyleElementsWithMediaQueries()
152+
{
153+
string input = "<html><head><style>div { width: 42px; } @media (max-width: 250px) { div { width: 20px; } }</style></head><body><div>test</div></body></html>";
154+
155+
var premailedOutput = PreMailer.MoveCssInline(input, removeStyleElements: true, preserveMediaQueries: true);
156+
157+
Assert.Contains("<style>@media (max-width: 250px) { div { width: 20px; } }</style>", premailedOutput.Html);
158+
}
159+
140160
[Fact]
141161
public void MoveCssInline_MultipleSelectors_HonorsIndividualSpecificity()
142162
{

PreMailer.Net/PreMailer.Net/CssParser.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,20 @@ private static string CleanupMediaQueries(string s)
125125
{
126126
return MediaQueryRegex.Replace(s, m => SupportedMediaQueriesRegex.IsMatch(m.Groups["query"].Value.Trim()) ? m.Groups["styles"].Value.Trim() : string.Empty);
127127
}
128+
129+
public static IEnumerable<string> GetUnsupportedMediaQueries(string s)
130+
{
131+
if (string.IsNullOrWhiteSpace(s))
132+
{
133+
yield break;
134+
}
135+
foreach (Match match in MediaQueryRegex.Matches(s))
136+
{
137+
if (!SupportedMediaQueriesRegex.IsMatch(match.Value))
138+
{
139+
yield return match.Value;
140+
}
141+
}
142+
}
128143
}
129144
}

PreMailer.Net/PreMailer.Net/PreMailer.cs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,11 @@ public PreMailer(Stream stream, Uri baseUri = null)
7373
/// <param name="css">A string containing a style-sheet for inlining.</param>
7474
/// <param name="stripIdAndClassAttributes">True to strip ID and class attributes</param>
7575
/// <param name="removeComments">True to remove comments, false to leave them intact</param>
76+
/// <param name="preserveMediaQueries">If set to true and removeStyleElements is true, it will instead preserve unsupported media queries in the style node and remove the other css, instead of removing the whole style node</param>
7677
/// <returns>Returns the html input, with styles moved to inline attributes.</returns>
77-
public static InlineResult MoveCssInline(string html, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null)
78+
public static InlineResult MoveCssInline(string html, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null, bool preserveMediaQueries = false)
7879
{
79-
return new PreMailer(html).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter);
80+
return new PreMailer(html).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter, preserveMediaQueries);
8081
}
8182

8283
/// <summary>
@@ -88,10 +89,11 @@ public static InlineResult MoveCssInline(string html, bool removeStyleElements =
8889
/// <param name="css">A string containing a style-sheet for inlining.</param>
8990
/// <param name="stripIdAndClassAttributes">True to strip ID and class attributes</param>
9091
/// <param name="removeComments">True to remove comments, false to leave them intact</param>
92+
/// <param name="preserveMediaQueries">If set to true and removeStyleElements is true, it will instead preserve unsupported media queries in the style node and remove the other css, instead of removing the whole style node</param>
9193
/// <returns>Returns the html input, with styles moved to inline attributes.</returns>
92-
public static InlineResult MoveCssInline(Stream stream, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null)
94+
public static InlineResult MoveCssInline(Stream stream, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null, bool preserveMediaQueries = false)
9395
{
94-
return new PreMailer(stream).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter);
96+
return new PreMailer(stream).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter, preserveMediaQueries);
9597
}
9698

9799
/// <summary>
@@ -105,10 +107,11 @@ public static InlineResult MoveCssInline(Stream stream, bool removeStyleElements
105107
/// <param name="css">A string containing a style-sheet for inlining.</param>
106108
/// <param name="stripIdAndClassAttributes">True to strip ID and class attributes</param>
107109
/// <param name="removeComments">True to remove comments, false to leave them intact</param>
110+
/// <param name="preserveMediaQueries">If set to true and removeStyleElements is true, it will instead preserve unsupported media queries in the style node and remove the other css, instead of removing the whole style node</param>
108111
/// <returns>Returns the html input, with styles moved to inline attributes.</returns>
109-
public static InlineResult MoveCssInline(Uri baseUri, string html, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null)
112+
public static InlineResult MoveCssInline(Uri baseUri, string html, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null, bool preserveMediaQueries = false)
110113
{
111-
return new PreMailer(html, baseUri).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter);
114+
return new PreMailer(html, baseUri).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter, preserveMediaQueries);
112115
}
113116

114117
/// <summary>
@@ -122,10 +125,11 @@ public static InlineResult MoveCssInline(Uri baseUri, string html, bool removeSt
122125
/// <param name="css">A string containing a style-sheet for inlining.</param>
123126
/// <param name="stripIdAndClassAttributes">True to strip ID and class attributes</param>
124127
/// <param name="removeComments">True to remove comments, false to leave them intact</param>
128+
/// <param name="preserveMediaQueries">If set to true and removeStyleElements is true, it will instead preserve unsupported media queries in the style node and remove the other css, instead of removing the whole style node</param>
125129
/// <returns>Returns the html input, with styles moved to inline attributes.</returns>
126-
public static InlineResult MoveCssInline(Uri baseUri, Stream stream, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null)
130+
public static InlineResult MoveCssInline(Uri baseUri, Stream stream, bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null, bool preserveMediaQueries = false)
127131
{
128-
return new PreMailer(stream, baseUri).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter);
132+
return new PreMailer(stream, baseUri).MoveCssInline(removeStyleElements, ignoreElements, css, stripIdAndClassAttributes, removeComments, customFormatter, preserveMediaQueries);
129133
}
130134

131135
/// <summary>
@@ -136,8 +140,9 @@ public static InlineResult MoveCssInline(Uri baseUri, Stream stream, bool remove
136140
/// <param name="css">A string containing a style-sheet for inlining.</param>
137141
/// <param name="stripIdAndClassAttributes">True to strip ID and class attributes</param>
138142
/// <param name="removeComments">True to remove comments, false to leave them intact</param>
143+
/// <param name="preserveMediaQueries">If set to true and removeStyleElements is true, it will instead preserve unsupported media queries in the style node and remove the other css, instead of removing the whole style node</param>
139144
/// <returns>Returns the html input, with styles moved to inline attributes.</returns>
140-
public InlineResult MoveCssInline(bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null)
145+
public InlineResult MoveCssInline(bool removeStyleElements = false, string ignoreElements = null, string css = null, bool stripIdAndClassAttributes = false, bool removeComments = false, IMarkupFormatter customFormatter = null, bool preserveMediaQueries = false)
141146
{
142147
// Store the variables used for inlining the CSS
143148
_removeStyleElements = removeStyleElements;
@@ -155,7 +160,7 @@ public InlineResult MoveCssInline(bool removeStyleElements = false, string ignor
155160

156161
if (_removeStyleElements)
157162
{
158-
RemoveStyleElements(cssSourceNodes);
163+
RemoveStyleElements(cssSourceNodes, preserveMediaQueries);
159164
RemoveStyleElements(cssLinkNodes);
160165
}
161166

@@ -317,11 +322,26 @@ private IEnumerable<IElement> CssLinkNodes()
317322
}
318323

319324

320-
private void RemoveStyleElements(IEnumerable<IElement> cssSourceNodes)
325+
private void RemoveStyleElements(IEnumerable<IElement> cssSourceNodes, bool preserveMediaQueries = false)
321326
{
322327
foreach (var node in cssSourceNodes)
323328
{
324-
node.Remove();
329+
if (preserveMediaQueries)
330+
{
331+
var unsupportedMediaQueries = CssParser.GetUnsupportedMediaQueries(node.InnerHtml);
332+
if (unsupportedMediaQueries.Any())
333+
{
334+
node.InnerHtml = $"{string.Join("\n", unsupportedMediaQueries)}";
335+
}
336+
else
337+
{
338+
node.Remove();
339+
}
340+
}
341+
else
342+
{
343+
node.Remove();
344+
}
325345
}
326346
}
327347

0 commit comments

Comments
 (0)