Skip to content

Commit 06b15e3

Browse files
committed
Updated nested implementation #148
1 parent bf4db74 commit 06b15e3

File tree

6 files changed

+150
-11
lines changed

6 files changed

+150
-11
lines changed

src/AngleSharp.Css.Tests/Extensions/Nesting.cs

+72-5
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,92 @@ namespace AngleSharp.Css.Tests.Extensions
99
public class NestingTests
1010
{
1111
[Test]
12-
public void SimpleSelectorNesting()
12+
public void SimpleSelectorNestingImplicit()
1313
{
1414
var source = @"<!doctype html><head><style>.foo {
1515
color: green;
16-
.bar {
16+
.bar {
1717
font-size: 1.4rem;
1818
}
1919
}</style></head><body class='foo'><div class='bar'>Larger and green";
2020
var document = ParseDocument(source);
2121
var window = document.DefaultView;
22-
Assert.IsNotNull(document);
22+
var element = document.QuerySelector(".bar");
23+
var style = window.GetComputedStyle(element);
2324

25+
Assert.AreEqual("1.4rem", style.GetFontSize());
26+
}
27+
28+
[Test]
29+
public void SimpleSelectorNestingExplicit()
30+
{
31+
var source = @"<!doctype html><head><style>.foo {
32+
color: green;
33+
& .bar {
34+
font-size: 1.4rem;
35+
}
36+
}</style></head><body class='foo'><div class='bar'>Larger and green";
37+
var document = ParseDocument(source);
38+
var window = document.DefaultView;
2439
var element = document.QuerySelector(".bar");
25-
Assert.IsNotNull(element);
40+
var style = window.GetComputedStyle(element);
41+
42+
Assert.AreEqual("1.4rem", style.GetFontSize());
43+
}
44+
45+
[Test]
46+
public void SimpleSelectorNestingOverwritten()
47+
{
48+
var source = @"<!doctype html><head><style>.foo .bar {
49+
font-size: 1rem;
50+
}
2651
52+
.foo {
53+
color: green;
54+
.bar {
55+
font-size: 1.4rem;
56+
}
57+
}</style></head><body class='foo'><div class='bar'>Larger and green";
58+
var document = ParseDocument(source);
59+
var window = document.DefaultView;
60+
var element = document.QuerySelector(".bar");
2761
var style = window.GetComputedStyle(element);
28-
Assert.IsNotNull(style);
2962

3063
Assert.AreEqual("1.4rem", style.GetFontSize());
3164
}
65+
66+
[Test]
67+
public void CombinedSelectorNesting()
68+
{
69+
var source = @"<!doctype html><head><style>.foo {
70+
color: red;
71+
&.bar {
72+
color: green;
73+
}
74+
}</style></head><body><div class='foo bar'>green";
75+
var document = ParseDocument(source);
76+
var window = document.DefaultView;
77+
var element = document.QuerySelector(".bar");
78+
var style = window.GetComputedStyle(element);
79+
80+
Assert.AreEqual("rgba(0, 128, 0, 1)", style.GetColor());
81+
}
82+
83+
[Test]
84+
public void ReversedSelectorNesting()
85+
{
86+
var source = @"<!doctype html><head><style>li {
87+
color: red;
88+
.list & {
89+
color: green;
90+
}
91+
}</style></head><body><ul class='list'><li>green";
92+
var document = ParseDocument(source);
93+
var window = document.DefaultView;
94+
var element = document.QuerySelector("li");
95+
var style = window.GetComputedStyle(element);
96+
97+
Assert.AreEqual("rgba(0, 128, 0, 1)", style.GetColor());
98+
}
3299
}
33100
}

src/AngleSharp.Css/AngleSharp.Css.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
</ItemGroup>
2222

2323
<ItemGroup>
24-
<PackageReference Include="AngleSharp" Version="1.0.3" />
24+
<PackageReference Include="AngleSharp" Version="1.1.0-alpha-379" />
2525
</ItemGroup>
2626

2727
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace AngleSharp.Css.Dom
2+
{
3+
using AngleSharp.Dom;
4+
using System;
5+
6+
internal class ReferencedNestedSelector : ISelector
7+
{
8+
private readonly ISelector _referenced;
9+
10+
public ReferencedNestedSelector(ISelector referenced)
11+
{
12+
_referenced = referenced;
13+
}
14+
15+
public String Text => "&";
16+
17+
public Priority Specificity => _referenced.Specificity;
18+
19+
public void Accept(ISelectorVisitor visitor)
20+
{
21+
// Right now we have nothing here.
22+
}
23+
24+
public Boolean Match(IElement element, IElement scope)
25+
{
26+
return _referenced.Match(element, scope);
27+
}
28+
}
29+
}

src/AngleSharp.Css/Dom/Internal/Rules/CssStyleRule.cs

+34-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ sealed class CssStyleRule : CssRule, ICssStyleRule, ISelectorVisitor
2020
private readonly CssRuleList _rules;
2121
private ISelector _selector;
2222
private IEnumerable<ISelector> _selectorList;
23+
private Boolean _nested;
2324

2425
#endregion
2526

@@ -37,6 +38,12 @@ internal CssStyleRule(ICssStyleSheet owner)
3738

3839
#region Properties
3940

41+
public Boolean IsNested
42+
{
43+
get => _nested;
44+
set => _nested = value;
45+
}
46+
4047
public ISelector Selector
4148
{
4249
get => _selector;
@@ -85,25 +92,48 @@ protected override void ReplaceWith(ICssRule rule)
8592

8693
public Boolean TryMatch(IElement element, IElement? scope, out Priority specificity)
8794
{
95+
specificity = Priority.Zero;
96+
scope ??= element?.Owner!.DocumentElement;
97+
98+
if (!_nested && Parent is CssStyleRule parent)
99+
{
100+
var pe = element;
101+
102+
do
103+
{
104+
if (pe == scope)
105+
{
106+
return false;
107+
}
108+
109+
pe = pe.ParentElement;
110+
111+
if (pe is null)
112+
{
113+
return false;
114+
}
115+
}
116+
while (!parent.TryMatch(pe, scope, out specificity));
117+
}
118+
88119
if (_selectorList is not null)
89120
{
90121
foreach (var selector in _selectorList.OrderByDescending(m => m.Specificity))
91122
{
92123
if (selector.Match(element, scope))
93124
{
94-
specificity = selector.Specificity;
125+
specificity += selector.Specificity;
95126
return true;
96127
}
97128
}
98129
}
99130

100131
if (_selector is not null && _selector.Match(element, scope))
101132
{
102-
specificity = _selector.Specificity;
133+
specificity += _selector.Specificity;
103134
return true;
104135
}
105136

106-
specificity = default;
107137
return false;
108138
}
109139

@@ -117,7 +147,7 @@ public override void ToCss(TextWriter writer, IStyleFormatter formatter)
117147

118148
#region Selector
119149

120-
private void ChangeSelector(ISelector value)
150+
internal void ChangeSelector(ISelector value)
121151
{
122152
_selectorList = null;
123153
_selector = value;

src/AngleSharp.Css/Parser/CssBuilder.cs

+13
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,21 @@ public void CreateDeclarationWith(ICssProperties properties, ref CssToken token)
526526

527527
if (!_options.IsExcludingNesting && token.IsPotentiallyNested() && properties is ICssStyleDeclaration decl && decl.Parent is CssStyleRule style)
528528
{
529+
var factory = _context.GetService<DefaultAttributeSelectorFactory>();
529530
var rule = new CssStyleRule(style.Owner);
531+
var previous = factory.Unregister("&");
532+
factory.Register("&", (_, _, _, _) =>
533+
{
534+
rule.IsNested = true;
535+
return new ReferencedNestedSelector(style.Selector);
536+
});
530537
var result = CreateStyle(rule, token);
538+
factory.Unregister("&");
539+
540+
if (previous is not null)
541+
{
542+
factory.Register("&", previous);
543+
}
531544

532545
if (result is not null)
533546
{

src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
<ItemGroup>
2323
<PackageReference Include="Alba.CsCss" version="1.0.1.0" />
24-
<PackageReference Include="AngleSharp" Version="1.0.3" />
24+
<PackageReference Include="AngleSharp" Version="1.1.0-alpha-379" />
2525
<PackageReference Include="ExCSS" version="2.0.6" />
2626
</ItemGroup>
2727
</Project>

0 commit comments

Comments
 (0)