Skip to content

Commit

Permalink
Enable media rules
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianRappl committed May 12, 2019
1 parent c39ac49 commit e3ad3b3
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 22 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ This will register a parser for CSS related content. The CSS parsing options and

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

Furthermore, for some CSSOM features (e.g., media queries) a render device is required.

```cs
var config = Configuration.Default
.WithCss()
.WithRenderDevice(new DefaultRenderDevice
{
DeviceHeight = 768,
DeviceWidth = 1024,
});
```

If no specific `IRenderDevice` (e.g., via creating an `DefaultRenderDevice` object) instance is created a default implementation will be set.

## Advantages of AngleSharp.Css

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:
Expand Down
1 change: 0 additions & 1 deletion src/AngleSharp.Css.Tests/Styling/CssSheet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ namespace AngleSharp.Css.Tests.Styling
using AngleSharp.Css.Converters;
using AngleSharp.Css.Dom;
using AngleSharp.Css.Parser;
using AngleSharp.Css.Values;
using NUnit.Framework;
using System;
using System.IO;
Expand Down
32 changes: 32 additions & 0 deletions src/AngleSharp.Css.Tests/Styling/HtmlCssIntegration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,5 +460,37 @@ public void MediaRuleCssCausesException_Issue20()
var style = document.Body.ComputeCurrentStyle();
Assert.IsNotNull(style);
}

[Test]
public void MediaRuleIsCalculatedIfScreenIsOkay()
{
var config = Configuration.Default
.WithCss()
.WithRenderDevice(new DefaultRenderDevice
{
ViewPortWidth = 1000,
});
var browsingContext = BrowsingContext.New(config);
var htmlParser = browsingContext.GetService<IHtmlParser>();
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>");
var style = document.Body.ComputeCurrentStyle();
Assert.AreEqual("rgba(0, 128, 0, 1)", style.GetColor());
}

[Test]
public void MediaRuleIsNotCalculatedIfScreenIsNotWideEnough()
{
var config = Configuration.Default
.WithCss()
.WithRenderDevice(new DefaultRenderDevice
{
ViewPortWidth = 599,
});
var browsingContext = BrowsingContext.New(config);
var htmlParser = browsingContext.GetService<IHtmlParser>();
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>");
var style = document.Body.ComputeCurrentStyle();
Assert.AreEqual("rgba(255, 0, 0, 1)", style.GetColor());
}
}
}
13 changes: 10 additions & 3 deletions src/AngleSharp.Css/CssConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ public static class CssConfigurationExtensions
/// <returns>The new instance with the service.</returns>
public static IConfiguration WithCss(this IConfiguration configuration, CssParserOptions options = default(CssParserOptions))
{
if (configuration == null)
throw new ArgumentNullException(nameof(configuration));

configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
var service = new CssStylingService();

if (!configuration.Has<ICssDefaultStyleSheetProvider>())
Expand Down Expand Up @@ -57,5 +55,14 @@ public static class CssConfigurationExtensions
.WithOnly(Factory.Observer)
.WithOnly<IStylingService>(service);
}

/// <summary>
/// Registers the render device for the given configuration.
/// </summary>
/// <param name="configuration">The configuration to extend.</param>
/// <param name="renderDevice">The custom device to register, if any.</param>
/// <returns>The new instance with the render device.</returns>
public static IConfiguration WithRenderDevice(this IConfiguration configuration, IRenderDevice renderDevice = null) =>
configuration.WithOnly<IRenderDevice>(renderDevice ?? new DefaultRenderDevice());
}
}
8 changes: 5 additions & 3 deletions src/AngleSharp.Css/Dom/Internal/MediaList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ internal MediaList(IBrowsingContext context)

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

public IFeatureValidatorFactory ValidatorFactory => _context.GetService<IFeatureValidatorFactory>();

public String MediaText
{
get => this.ToCss();
Expand All @@ -54,7 +56,7 @@ public String MediaText
public void SetMediaText(String value, Boolean throwOnError)
{
_media.Clear();
var media = MediaParser.Parse(value);
var media = MediaParser.Parse(value, ValidatorFactory);

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

public void Add(String newMedium)
{
var medium = MediumParser.Parse(newMedium) ?? throw new DomException(DomError.Syntax);
var medium = MediumParser.Parse(newMedium, ValidatorFactory) ?? throw new DomException(DomError.Syntax);
_media.Add(medium);
}

public void Remove(String oldMedium)
{
var medium = MediumParser.Parse(oldMedium) ?? throw new DomException(DomError.Syntax);
var medium = MediumParser.Parse(oldMedium, ValidatorFactory) ?? throw new DomException(DomError.Syntax);

for (var i = 0; i < _media.Count; i++)
{
Expand Down
6 changes: 2 additions & 4 deletions src/AngleSharp.Css/Dom/StyleCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,8 @@ public static ICssStyleDeclaration ComputeCascadedStyle(this StyleCollection sty

#region Helpers

private static IEnumerable<ICssStyleRule> SortBySpecificity(this IEnumerable<ICssStyleRule> rules, IElement element)
{
return rules.Where(m => m.Selector.Match(element)).OrderBy(m => m.Selector.Specificity);
}
private static IEnumerable<ICssStyleRule> SortBySpecificity(this IEnumerable<ICssStyleRule> rules, IElement element) =>
rules.Where(m => m.Selector.Match(element)).OrderBy(m => m.Selector.Specificity);

#endregion
}
Expand Down
3 changes: 1 addition & 2 deletions src/AngleSharp.Css/Extensions/MediaListExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ public static void AssociateValidator(this IMediaFeature feature, IFeatureValida

public static Boolean Validate(this IMediaFeature feature, IRenderDevice device)
{
var validator = default(IFeatureValidator);
AssociatedValidators.TryGetValue(feature, out validator);
AssociatedValidators.TryGetValue(feature, out var validator);
return validator?.Validate(feature, device) ?? false;
}

Expand Down
10 changes: 5 additions & 5 deletions src/AngleSharp.Css/Parser/Micro/MediaParser.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AngleSharp.Css.Parser
namespace AngleSharp.Css.Parser
{
using AngleSharp.Css.Dom;
using AngleSharp.Text;
Expand All @@ -7,14 +7,14 @@

static class MediaParser
{
public static IEnumerable<CssMedium> Parse(String str)
public static IEnumerable<CssMedium> Parse(String str, IFeatureValidatorFactory factory)
{
var source = new StringSource(str);
var result = source.ParseMedia();
var result = source.ParseMedia(factory);
return source.IsDone ? result : null;
}

public static IEnumerable<CssMedium> ParseMedia(this StringSource source)
public static IEnumerable<CssMedium> ParseMedia(this StringSource source, IFeatureValidatorFactory factory)
{
var current = source.SkipSpacesAndComments();
var media = new List<CssMedium>();
Expand All @@ -29,7 +29,7 @@ public static IEnumerable<CssMedium> ParseMedia(this StringSource source)
source.SkipCurrentAndSpaces();
}

var medium = source.ParseMedium();
var medium = source.ParseMedium(factory);

if (medium == null)
return null;
Expand Down
10 changes: 6 additions & 4 deletions src/AngleSharp.Css/Parser/Micro/MediumParser.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AngleSharp.Css.Parser
namespace AngleSharp.Css.Parser
{
using AngleSharp.Css.Dom;
using AngleSharp.Text;
Expand All @@ -7,14 +7,14 @@

static class MediumParser
{
public static CssMedium Parse(String str)
public static CssMedium Parse(String str, IFeatureValidatorFactory factory)
{
var source = new StringSource(str);
var result = source.ParseMedium();
var result = source.ParseMedium(factory);
return source.IsDone ? result : null;
}

public static CssMedium ParseMedium(this StringSource source)
public static CssMedium ParseMedium(this StringSource source, IFeatureValidatorFactory factory)
{
source.SkipSpacesAndComments();
var ident = source.ParseIdent();
Expand Down Expand Up @@ -70,6 +70,8 @@ public static CssMedium ParseMedium(this StringSource source)
return null;
}

var validator = factory?.Create(feature.Name);
feature.AssociateValidator(validator);
features.Add(feature);
source.SkipCurrentAndSpaces();
var position = source.Index;
Expand Down

0 comments on commit e3ad3b3

Please sign in to comment.