Skip to content

Commit e3ad3b3

Browse files
committed
Enable media rules
1 parent c39ac49 commit e3ad3b3

File tree

9 files changed

+75
-22
lines changed

9 files changed

+75
-22
lines changed

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ This will register a parser for CSS related content. The CSS parsing options and
2929

3030
For an interactive DOM (i.e., to handle `style` attribute changes in the HTML document) an observer needs to be registered as well.
3131

32+
Furthermore, for some CSSOM features (e.g., media queries) a render device is required.
33+
34+
```cs
35+
var config = Configuration.Default
36+
.WithCss()
37+
.WithRenderDevice(new DefaultRenderDevice
38+
{
39+
DeviceHeight = 768,
40+
DeviceWidth = 1024,
41+
});
42+
```
43+
44+
If no specific `IRenderDevice` (e.g., via creating an `DefaultRenderDevice` object) instance is created a default implementation will be set.
45+
3246
## Advantages of AngleSharp.Css
3347

3448
The core library already contains the CSS selector parser and the most basic classes and interfaces for dealing with the CSSOM. AngleSharp.Css brings the following advantages and use cases to life:

src/AngleSharp.Css.Tests/Styling/CssSheet.cs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ namespace AngleSharp.Css.Tests.Styling
33
using AngleSharp.Css.Converters;
44
using AngleSharp.Css.Dom;
55
using AngleSharp.Css.Parser;
6-
using AngleSharp.Css.Values;
76
using NUnit.Framework;
87
using System;
98
using System.IO;

src/AngleSharp.Css.Tests/Styling/HtmlCssIntegration.cs

+32
Original file line numberDiff line numberDiff line change
@@ -460,5 +460,37 @@ public void MediaRuleCssCausesException_Issue20()
460460
var style = document.Body.ComputeCurrentStyle();
461461
Assert.IsNotNull(style);
462462
}
463+
464+
[Test]
465+
public void MediaRuleIsCalculatedIfScreenIsOkay()
466+
{
467+
var config = Configuration.Default
468+
.WithCss()
469+
.WithRenderDevice(new DefaultRenderDevice
470+
{
471+
ViewPortWidth = 1000,
472+
});
473+
var browsingContext = BrowsingContext.New(config);
474+
var htmlParser = browsingContext.GetService<IHtmlParser>();
475+
var document = htmlParser.ParseDocument("<html><head><style>body { color: red } @media only screen and (min-width: 600px) { body { color: green } }</style></head><body></body></html>");
476+
var style = document.Body.ComputeCurrentStyle();
477+
Assert.AreEqual("rgba(0, 128, 0, 1)", style.GetColor());
478+
}
479+
480+
[Test]
481+
public void MediaRuleIsNotCalculatedIfScreenIsNotWideEnough()
482+
{
483+
var config = Configuration.Default
484+
.WithCss()
485+
.WithRenderDevice(new DefaultRenderDevice
486+
{
487+
ViewPortWidth = 599,
488+
});
489+
var browsingContext = BrowsingContext.New(config);
490+
var htmlParser = browsingContext.GetService<IHtmlParser>();
491+
var document = htmlParser.ParseDocument("<html><head><style>body { color: red } @media only screen and (min-width: 600px) { body { color: green } }</style></head><body></body></html>");
492+
var style = document.Body.ComputeCurrentStyle();
493+
Assert.AreEqual("rgba(255, 0, 0, 1)", style.GetColor());
494+
}
463495
}
464496
}

src/AngleSharp.Css/CssConfigurationExtensions.cs

+10-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ public static class CssConfigurationExtensions
1818
/// <returns>The new instance with the service.</returns>
1919
public static IConfiguration WithCss(this IConfiguration configuration, CssParserOptions options = default(CssParserOptions))
2020
{
21-
if (configuration == null)
22-
throw new ArgumentNullException(nameof(configuration));
23-
21+
configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
2422
var service = new CssStylingService();
2523

2624
if (!configuration.Has<ICssDefaultStyleSheetProvider>())
@@ -57,5 +55,14 @@ public static class CssConfigurationExtensions
5755
.WithOnly(Factory.Observer)
5856
.WithOnly<IStylingService>(service);
5957
}
58+
59+
/// <summary>
60+
/// Registers the render device for the given configuration.
61+
/// </summary>
62+
/// <param name="configuration">The configuration to extend.</param>
63+
/// <param name="renderDevice">The custom device to register, if any.</param>
64+
/// <returns>The new instance with the render device.</returns>
65+
public static IConfiguration WithRenderDevice(this IConfiguration configuration, IRenderDevice renderDevice = null) =>
66+
configuration.WithOnly<IRenderDevice>(renderDevice ?? new DefaultRenderDevice());
6067
}
6168
}

src/AngleSharp.Css/Dom/Internal/MediaList.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ internal MediaList(IBrowsingContext context)
4141

4242
public ICssParser Parser => _context.GetService<ICssParser>();
4343

44+
public IFeatureValidatorFactory ValidatorFactory => _context.GetService<IFeatureValidatorFactory>();
45+
4446
public String MediaText
4547
{
4648
get => this.ToCss();
@@ -54,7 +56,7 @@ public String MediaText
5456
public void SetMediaText(String value, Boolean throwOnError)
5557
{
5658
_media.Clear();
57-
var media = MediaParser.Parse(value);
59+
var media = MediaParser.Parse(value, ValidatorFactory);
5860

5961
if (media != null)
6062
{
@@ -73,13 +75,13 @@ public void SetMediaText(String value, Boolean throwOnError)
7375

7476
public void Add(String newMedium)
7577
{
76-
var medium = MediumParser.Parse(newMedium) ?? throw new DomException(DomError.Syntax);
78+
var medium = MediumParser.Parse(newMedium, ValidatorFactory) ?? throw new DomException(DomError.Syntax);
7779
_media.Add(medium);
7880
}
7981

8082
public void Remove(String oldMedium)
8183
{
82-
var medium = MediumParser.Parse(oldMedium) ?? throw new DomException(DomError.Syntax);
84+
var medium = MediumParser.Parse(oldMedium, ValidatorFactory) ?? throw new DomException(DomError.Syntax);
8385

8486
for (var i = 0; i < _media.Count; i++)
8587
{

src/AngleSharp.Css/Dom/StyleCollectionExtensions.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,8 @@ public static ICssStyleDeclaration ComputeCascadedStyle(this StyleCollection sty
9696

9797
#region Helpers
9898

99-
private static IEnumerable<ICssStyleRule> SortBySpecificity(this IEnumerable<ICssStyleRule> rules, IElement element)
100-
{
101-
return rules.Where(m => m.Selector.Match(element)).OrderBy(m => m.Selector.Specificity);
102-
}
99+
private static IEnumerable<ICssStyleRule> SortBySpecificity(this IEnumerable<ICssStyleRule> rules, IElement element) =>
100+
rules.Where(m => m.Selector.Match(element)).OrderBy(m => m.Selector.Specificity);
103101

104102
#endregion
105103
}

src/AngleSharp.Css/Extensions/MediaListExtensions.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ public static void AssociateValidator(this IMediaFeature feature, IFeatureValida
2727

2828
public static Boolean Validate(this IMediaFeature feature, IRenderDevice device)
2929
{
30-
var validator = default(IFeatureValidator);
31-
AssociatedValidators.TryGetValue(feature, out validator);
30+
AssociatedValidators.TryGetValue(feature, out var validator);
3231
return validator?.Validate(feature, device) ?? false;
3332
}
3433

src/AngleSharp.Css/Parser/Micro/MediaParser.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace AngleSharp.Css.Parser
1+
namespace AngleSharp.Css.Parser
22
{
33
using AngleSharp.Css.Dom;
44
using AngleSharp.Text;
@@ -7,14 +7,14 @@
77

88
static class MediaParser
99
{
10-
public static IEnumerable<CssMedium> Parse(String str)
10+
public static IEnumerable<CssMedium> Parse(String str, IFeatureValidatorFactory factory)
1111
{
1212
var source = new StringSource(str);
13-
var result = source.ParseMedia();
13+
var result = source.ParseMedia(factory);
1414
return source.IsDone ? result : null;
1515
}
1616

17-
public static IEnumerable<CssMedium> ParseMedia(this StringSource source)
17+
public static IEnumerable<CssMedium> ParseMedia(this StringSource source, IFeatureValidatorFactory factory)
1818
{
1919
var current = source.SkipSpacesAndComments();
2020
var media = new List<CssMedium>();
@@ -29,7 +29,7 @@ public static IEnumerable<CssMedium> ParseMedia(this StringSource source)
2929
source.SkipCurrentAndSpaces();
3030
}
3131

32-
var medium = source.ParseMedium();
32+
var medium = source.ParseMedium(factory);
3333

3434
if (medium == null)
3535
return null;

src/AngleSharp.Css/Parser/Micro/MediumParser.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace AngleSharp.Css.Parser
1+
namespace AngleSharp.Css.Parser
22
{
33
using AngleSharp.Css.Dom;
44
using AngleSharp.Text;
@@ -7,14 +7,14 @@
77

88
static class MediumParser
99
{
10-
public static CssMedium Parse(String str)
10+
public static CssMedium Parse(String str, IFeatureValidatorFactory factory)
1111
{
1212
var source = new StringSource(str);
13-
var result = source.ParseMedium();
13+
var result = source.ParseMedium(factory);
1414
return source.IsDone ? result : null;
1515
}
1616

17-
public static CssMedium ParseMedium(this StringSource source)
17+
public static CssMedium ParseMedium(this StringSource source, IFeatureValidatorFactory factory)
1818
{
1919
source.SkipSpacesAndComments();
2020
var ident = source.ParseIdent();
@@ -70,6 +70,8 @@ public static CssMedium ParseMedium(this StringSource source)
7070
return null;
7171
}
7272

73+
var validator = factory?.Create(feature.Name);
74+
feature.AssociateValidator(validator);
7375
features.Add(feature);
7476
source.SkipCurrentAndSpaces();
7577
var position = source.Index;

0 commit comments

Comments
 (0)