Skip to content

Commit

Permalink
Working on child-parent values
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianRappl committed Dec 31, 2018
1 parent 7659885 commit f898a36
Show file tree
Hide file tree
Showing 15 changed files with 571 additions and 50 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

# AngleSharp.Css

[![Build status](https://img.shields.io/appveyor/ci/FlorianRappl/AngleSharp-Css.svg?style=flat-square)](https://ci.appveyor.com/project/FlorianRappl/AngleSharp-Css)
[![GitHub tag](https://img.shields.io/github/tag/AngleSharp/AngleSharp.Css.svg?style=flat-square)](https://github.com/AngleSharp/AngleSharp.Css/releases)
[![Build Status](https://img.shields.io/appveyor/ci/FlorianRappl/AngleSharp-Css.svg?style=flat-square)](https://ci.appveyor.com/project/FlorianRappl/AngleSharp-Css)
[![GitHub Tag](https://img.shields.io/github/tag/AngleSharp/AngleSharp.Css.svg?style=flat-square)](https://github.com/AngleSharp/AngleSharp.Css/releases)
[![NuGet Count](https://img.shields.io/nuget/dt/AngleSharp.Css.svg?style=flat-square)](https://www.nuget.org/packages/AngleSharp.Css/)
[![Issues Open](https://img.shields.io/github/issues/AngleSharp/AngleSharp.Css.svg?style=flat-square)](https://github.com/AngleSharp/AngleSharp.Css/issues)
[![CLA assistant](https://cla-assistant.io/readme/badge/AngleSharp/AngleSharp.Css?style=flat-square)](https://cla-assistant.io/AngleSharp/AngleSharp.Css)
[![StackOverflow Questions](https://img.shields.io/stackexchange/stackoverflow/t/anglesharp.svg?style=flat-square)](https://stackoverflow.com/tags/anglesharp)
[![CLA Assistant](https://cla-assistant.io/readme/badge/AngleSharp/AngleSharp.Css?style=flat-square)](https://cla-assistant.io/AngleSharp/AngleSharp.Css)

AngleSharp.Css extends the core AngleSharp library with some more powerful CSS capabilities. This repository is the home of the source for the AngleSharp.Css NuGet package.

Expand All @@ -20,6 +21,7 @@ The core library already contains the CSS selector parser and the most basic cla
* Cascades of stylesheets
* Validation (and property-based exposure) of CSS declarations
* Responsive design considerations
* Full access to the value with different converters

The main idea behind AngleSharp.Css is to expose the CSSOM as it would be in the browser (and potentially beyond, i.e., useful for being used by editors). Originally, most of the code found here was embedded in the AngleSharp.Core library, however, due to the overhead for HTML use cases it was decided to transfer the code into its own repository.

Expand Down
21 changes: 12 additions & 9 deletions src/AngleSharp.Css.Tests/Declarations/CssVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ public void LegitVariableReferenceWithoutFallback()
var source = @"padding-bottom: var(--foo)";
var property = ParseDeclaration(source);
Assert.IsNotNull(property);
var variable = property.RawValue as VarReference;
var variable = property.RawValue as VarReferences;
Assert.IsNotNull(variable);
Assert.AreEqual("--foo", variable.Name);
Assert.IsNull(variable.DefaultValue);
Assert.AreEqual(1, variable.References.Length);
Assert.AreEqual("--foo", variable.References[0].Name);
Assert.IsNull(variable.References[0].DefaultValue);
}

[Test]
Expand All @@ -54,10 +55,11 @@ public void LegitVariableReferenceWithFallback()
var source = @"padding-bottom: var(--my-bar, 24px)";
var property = ParseDeclaration(source);
Assert.IsNotNull(property);
var variable = property.RawValue as VarReference;
var variable = property.RawValue as VarReferences;
Assert.IsNotNull(variable);
Assert.AreEqual("--my-bar", variable.Name);
Assert.AreEqual("24px", variable.DefaultValue);
Assert.AreEqual(1, variable.References.Length);
Assert.AreEqual("--my-bar", variable.References[0].Name);
Assert.AreEqual("24px", variable.References[0].DefaultValue);
}

[Test]
Expand All @@ -66,10 +68,11 @@ public void LegitVariableReferenceWithFallbackContainingComma()
var source = @"border-top-color: var(--color, red, blue)";
var property = ParseDeclaration(source);
Assert.IsNotNull(property);
var variable = property.RawValue as VarReference;
var variable = property.RawValue as VarReferences;
Assert.IsNotNull(variable);
Assert.AreEqual("--color", variable.Name);
Assert.AreEqual("red, blue", variable.DefaultValue);
Assert.AreEqual(1, variable.References.Length);
Assert.AreEqual("--color", variable.References[0].Name);
Assert.AreEqual("red, blue", variable.References[0].DefaultValue);
}

[Test]
Expand Down
13 changes: 10 additions & 3 deletions src/AngleSharp.Css/Converters/ValueConverterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ public static ICssValue Convert(this IValueConverter converter, String value)
{
var source = new StringSource(value);
source.SkipSpacesAndComments();
var result = converter.Convert(source);
source.SkipSpacesAndComments();
return source.IsDone ? result : null;
var varRefs = source.ParseVars();

if (varRefs == null)
{
var result = converter.Convert(source);
source.SkipSpacesAndComments();
return source.IsDone ? result : null;
}

return varRefs;
}

public static IValueConverter Many(this IValueConverter converter, Int32 min = 1, Int32 max = UInt16.MaxValue)
Expand Down
9 changes: 8 additions & 1 deletion src/AngleSharp.Css/DeclarationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,25 @@ public class DeclarationInfo
/// <summary>
/// Constructs a new declaration info.
/// </summary>
/// <param name="name">The name of the declaration.</param>
/// <param name="converter">The value converter.</param>
/// <param name="flags">The property flags.</param>
/// <param name="shorthands">The names of the associated shorthand declarations, if any.</param>
/// <param name="longhands">The names of the associated longhand declarations, if any.</param>
public DeclarationInfo(IValueConverter converter, PropertyFlags flags = PropertyFlags.None, String[] shorthands = null, String[] longhands = null)
public DeclarationInfo(String name, IValueConverter converter, PropertyFlags flags = PropertyFlags.None, String[] shorthands = null, String[] longhands = null)
{
Name = name;
Converter = converter;
Flags = flags;
Shorthands = shorthands ?? new String[0];
Longhands = longhands ?? new String[0];
}

/// <summary>
/// Gets the declaration name.
/// </summary>
public String Name { get; }

/// <summary>
/// Gets the associated value converter.
/// </summary>
Expand Down
41 changes: 31 additions & 10 deletions src/AngleSharp.Css/Declarations/BackgroundDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,32 @@ public ICssValue Convert(StringSource source)
public ICssValue Collect(IEnumerable<ICssProperty> properties)
{
var color = properties.Where(m => m.Name == BackgroundColorDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var image = properties.Where(m => m.Name == BackgroundImageDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var attachment = properties.Where(m => m.Name == BackgroundAttachmentDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var clip = properties.Where(m => m.Name == BackgroundClipDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var positionX = properties.Where(m => m.Name == BackgroundPositionXDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var positionY = properties.Where(m => m.Name == BackgroundPositionYDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var origin = properties.Where(m => m.Name == BackgroundOriginDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var repeatX = properties.Where(m => m.Name == BackgroundRepeatXDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var repeatY = properties.Where(m => m.Name == BackgroundRepeatYDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var size = properties.Where(m => m.Name == BackgroundSizeDeclaration.Name).Select(m => m.RawValue).FirstOrDefault() as CssListValue;
var layers = CreateLayers(image, attachment, clip, positionX, positionY, origin, repeatX, repeatY, size);
var image = properties.Where(m => m.Name == BackgroundImageDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var attachment = properties.Where(m => m.Name == BackgroundAttachmentDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var clip = properties.Where(m => m.Name == BackgroundClipDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var positionX = properties.Where(m => m.Name == BackgroundPositionXDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var positionY = properties.Where(m => m.Name == BackgroundPositionYDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var origin = properties.Where(m => m.Name == BackgroundOriginDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var repeatX = properties.Where(m => m.Name == BackgroundRepeatXDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var repeatY = properties.Where(m => m.Name == BackgroundRepeatYDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var size = properties.Where(m => m.Name == BackgroundSizeDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var child = color as CssChildValue ??
image as CssChildValue ??
attachment as CssChildValue ??
clip as CssChildValue ??
positionX as CssChildValue ??
positionY as CssChildValue ??
origin as CssChildValue ??
repeatX as CssChildValue ??
repeatY as CssChildValue ??
size as CssChildValue;

if (child != null)
{
return child.Parent;
}

var layers = CreateLayers(image as CssListValue, attachment as CssListValue, clip as CssListValue, positionX as CssListValue, positionY as CssListValue, origin as CssListValue, repeatX as CssListValue, repeatY as CssListValue, size as CssListValue);

if (color != null || layers != null)
{
Expand Down Expand Up @@ -165,6 +181,11 @@ public IEnumerable<ICssProperty> Distribute(ICssValue value)
CreateMultiple(background, m => m.Repeat.HasValue ? m.Repeat.Value.Vertical : null),
CreateMultiple(background, m => m.Size));
}
else if (value is VarReferences)
{
var child = new CssChildValue(value);
return CreateProperties(child, child, child, child, child, child, child, child, child, child);
}

return null;
}
Expand Down
30 changes: 24 additions & 6 deletions src/AngleSharp.Css/Declarations/BorderDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public ICssValue Collect(IEnumerable<ICssProperty> properties)
var width = properties.Where(m => m.Name == BorderWidthDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var style = properties.Where(m => m.Name == BorderStyleDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var color = properties.Where(m => m.Name == BorderColorDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var child = width as CssChildValue ??
style as CssChildValue ??
color as CssChildValue;

if (child != null)
{
return child.Parent;
}

if (width != null && style != null && color != null)
{
Expand All @@ -66,16 +74,26 @@ public IEnumerable<ICssProperty> Distribute(ICssValue value)

if (options != null)
{
return new[]
{
new CssProperty(BorderWidthDeclaration.Name, BorderWidthDeclaration.Converter, BorderWidthDeclaration.Flags, options.Items[0]),
new CssProperty(BorderStyleDeclaration.Name, BorderStyleDeclaration.Converter, BorderStyleDeclaration.Flags, options.Items[1]),
new CssProperty(BorderColorDeclaration.Name, BorderColorDeclaration.Converter, BorderColorDeclaration.Flags, options.Items[2]),
};
return CreateProperties(options.Items[0], options.Items[1], options.Items[2]);
}
else if (value is VarReferences)
{
var child = new CssChildValue(value);
return CreateProperties(child, child, child);
}

return null;
}

private static IEnumerable<ICssProperty> CreateProperties(ICssValue width, ICssValue style, ICssValue color)
{
return new[]
{
new CssProperty(BorderWidthDeclaration.Name, BorderWidthDeclaration.Converter, BorderWidthDeclaration.Flags, width),
new CssProperty(BorderStyleDeclaration.Name, BorderStyleDeclaration.Converter, BorderStyleDeclaration.Flags, style),
new CssProperty(BorderColorDeclaration.Name, BorderColorDeclaration.Converter, BorderColorDeclaration.Flags, color),
};
}
}
}
}
100 changes: 99 additions & 1 deletion src/AngleSharp.Css/Declarations/GridTemplateDeclaration.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
namespace AngleSharp.Css.Declarations
{
using AngleSharp.Css.Dom;
using AngleSharp.Css.Parser;
using AngleSharp.Css.Values;
using AngleSharp.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using static ValueConverters;

static class GridTemplateDeclaration
Expand All @@ -14,8 +20,100 @@ static class GridTemplateDeclaration
PropertyNames.GridTemplateRows,
};

public static readonly IValueConverter Converter = AssignInitial();
public static readonly IValueConverter Converter = new GridTemplateAggregator();

public static readonly PropertyFlags Flags = PropertyFlags.Shorthand;

sealed class GridTemplateConverter : IValueConverter
{
public ICssValue Convert(StringSource source)
{
if (source.IsIdentifier(CssKeywords.None))
{
return new Identifier(CssKeywords.None);
}


var rows = source.ParseTrackList() ?? source.ParseAutoTrackList();

if (rows != null)
{
var c = source.SkipSpacesAndComments();

if (c == Symbols.Solidus)
{
source.SkipCurrentAndSpaces();
var cols = source.ParseTrackList() ?? source.ParseAutoTrackList();

if (cols != null)
{
source.SkipSpacesAndComments();
return new GridTemplate(rows, cols, null);
}
}

}
else
{

}

return null;
}
}

sealed class GridTemplateAggregator : IValueConverter, IValueAggregator
{
private static readonly IValueConverter converter = Or(new GridTemplateConverter(), AssignInitial());

public ICssValue Convert(StringSource source)
{
return converter.Convert(source);
}

public ICssValue Collect(IEnumerable<ICssProperty> properties)
{
var cols = properties.Where(m => m.Name == GridTemplateColumnsDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var rows = properties.Where(m => m.Name == GridTemplateRowsDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();
var areas = properties.Where(m => m.Name == GridTemplateAreasDeclaration.Name).Select(m => m.RawValue).FirstOrDefault();

if (cols == rows && cols == areas)
{
return cols;
}
else if (cols != null || rows != null || areas != null)
{
return new GridTemplate(cols, rows, areas);
}

return null;
}

public IEnumerable<ICssProperty> Distribute(ICssValue value)
{
var template = value as GridTemplate;

if (template != null)
{
return CreateProperties(template.TemplateColumns, template.TemplateRows, template.TemplateAreas);
}
else if (value is Identifier)
{
return CreateProperties(value, value, value);
}

return null;
}

private IEnumerable<ICssProperty> CreateProperties(ICssValue columns, ICssValue rows, ICssValue areas)
{
return new[]
{
new CssProperty(GridTemplateColumnsDeclaration.Name, GridTemplateColumnsDeclaration.Converter, GridTemplateColumnsDeclaration.Flags, columns),
new CssProperty(GridTemplateRowsDeclaration.Name, GridTemplateRowsDeclaration.Converter, GridTemplateRowsDeclaration.Flags, rows),
new CssProperty(GridTemplateAreasDeclaration.Name, GridTemplateAreasDeclaration.Converter, GridTemplateAreasDeclaration.Flags, areas),
};
}
}
}
}
Loading

0 comments on commit f898a36

Please sign in to comment.