[fizzler] r265 committed - Implemented issue #27, "Support nth-last-child pseudo-class selector",...

8 views
Skip to first unread message

fiz...@googlecode.com

unread,
Oct 6, 2010, 7:16:30 PM10/6/10
to fizzler...@googlegroups.com
Revision: 265
Author: azizatif
Date: Wed Oct 6 16:15:18 2010
Log: Implemented issue #27, "Support nth-last-child pseudo-class selector",
thanks to patch submitted by edin.dazdarevic [1].

[1] http://code.google.com/u/edin.dazdarevic/

http://code.google.com/p/fizzler/source/detail?r=265

Added:
/trunk/Fizzler.Tests/NthLastChild.cs
Modified:
/trunk/Fizzler/HumanReadableSelectorGenerator.cs
/trunk/Fizzler/IElementOps.cs
/trunk/Fizzler/ISelectorGenerator.cs
/trunk/Fizzler/Parser.cs
/trunk/Fizzler/SelectorGenerator.cs
/trunk/Fizzler/SelectorGeneratorTee.cs
/trunk/Fizzler.Sandbox/WinForms/ControlOps.cs
/trunk/Fizzler.Sandbox/Xml/XmlNodeOps.cs
/trunk/Fizzler.Systems.HtmlAgilityPack/HtmlNodeOps.cs
/trunk/Fizzler.Tests/Fizzler.Tests.csproj
/trunk/Fizzler.Tests/ParserTests.cs
/trunk/Fizzler.Tests/SelectorGeneratorTeeTests.cs

=======================================
--- /dev/null
+++ /trunk/Fizzler.Tests/NthLastChild.cs Wed Oct 6 16:15:18 2010
@@ -0,0 +1,48 @@
+
+namespace Fizzler.Tests
+{
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class NthLastChild : SelectorBaseTest
+ {
+ [Test]
+ public void No_Prefix_With_Digit()
+ {
+ var result = SelectList(":nth-last-child(2)");
+
+ Assert.AreEqual(4, result.Count);
+ Assert.AreEqual("head", result[0].Name);
+ Assert.AreEqual("div", result[1].Name);
+ Assert.AreEqual("span", result[2].Name);
+ Assert.AreEqual("div", result[3].Name);
+ }
+
+ [Test]
+ public void Id_Prefix_With_Digit()
+ {
+ var result = SelectList("#myDiv :nth-last-child(2)");
+
+ Assert.AreEqual(2, result.Count);
+ Assert.AreEqual("div", result[0].Name);
+ Assert.AreEqual("span", result[1].Name);
+ }
+
+ [Test]
+ public void Element_Prefix_With_Digit()
+ {
+ var result = SelectList("span:nth-last-child(3)");
+
+ Assert.AreEqual(0, result.Count);
+ }
+
+ [Test]
+ public void Element_Prefix_With_Digit2()
+ {
+ var result = SelectList("span:nth-last-child(2)");
+
+ Assert.AreEqual(1, result.Count);
+ Assert.AreEqual("span", result[0].Name);
+ }
+ }
+}
=======================================
--- /trunk/Fizzler/HumanReadableSelectorGenerator.cs Tue Feb 2 14:28:39
2010
+++ /trunk/Fizzler/HumanReadableSelectorGenerator.cs Wed Oct 6 16:15:18
2010
@@ -228,5 +228,13 @@
{
Add(", then take their siblings which are");
}
+
+ /// <summary>
+ /// Generates human-readable text of this combinator.
+ /// </summary>
+ public void NthLastChild(int a, int b)
+ {
+ Add(string.Format(" where the element has {0}n+{1}-1 sibling after it",
a, b));
+ }
}
}
=======================================
--- /trunk/Fizzler/IElementOps.cs Tue Jun 2 10:20:51 2009
+++ /trunk/Fizzler/IElementOps.cs Wed Oct 6 16:15:18 2010
@@ -159,5 +159,11 @@
/// immediately) the element represented by the second one.
/// </summary>
Selector<TElement> GeneralSibling();
+
+ /// <summary>
+ /// Generates a <a
href="http://www.w3.org/TR/css3-selectors/#pseudo-classes">pseudo-class
selector</a>,
+ /// which represents an element that is the N-th child from bottom up of
some other element.
+ /// </summary>
+ Selector<TElement> NthLastChild(int a, int b);
}
}
=======================================
--- /trunk/Fizzler/ISelectorGenerator.cs Tue Jun 2 10:20:51 2009
+++ /trunk/Fizzler/ISelectorGenerator.cs Wed Oct 6 16:15:18 2010
@@ -175,5 +175,11 @@
/// immediately) the element represented by the second one.
/// </summary>
void GeneralSibling();
+
+ /// <summary>
+ /// Generates a <a
href="http://www.w3.org/TR/css3-selectors/#pseudo-classes">pseudo-class
selector</a>,
+ /// which represents an element that is the N-th child from bottom up of
some other element.
+ /// </summary>
+ void NthLastChild(int a, int b);
}
}
=======================================
--- /trunk/Fizzler/Parser.cs Tue Feb 2 14:28:39 2010
+++ /trunk/Fizzler/Parser.cs Wed Oct 6 16:15:18 2010
@@ -238,10 +238,11 @@
switch (func)
{
case "nth-child": Nth(); break;
+ case "nth-last-child": NthLast(); break;
default:
{
throw new FormatException(string.Format(
- "Unknown functional pseudo '{0}'. Only nth-child
is supported.", func));
+ "Unknown functional pseudo '{0}'. Only nth-child
and nth-last-child is supported.", func));
}
}

@@ -262,6 +263,20 @@
var b = int.Parse(Read(ToTokenSpec(TokenKind.Integer)).Text,
CultureInfo.InvariantCulture);
_generator.NthChild(1, b);
}
+
+ private void NthLast()
+ {
+ //nth
+ // : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? |
+ // ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*
+ // ;
+
+ // TODO Add support for the full syntax
+ // At present, only INTEGER is allowed
+
+ var b = int.Parse(Read(ToTokenSpec(TokenKind.Integer)).Text,
CultureInfo.InvariantCulture);
+ _generator.NthLastChild(1, b);
+ }

private void Attrib()
{
=======================================
--- /trunk/Fizzler/SelectorGenerator.cs Tue Feb 2 14:28:39 2010
+++ /trunk/Fizzler/SelectorGenerator.cs Wed Oct 6 16:15:18 2010
@@ -307,5 +307,14 @@
{
Add(Ops.GeneralSibling());
}
+
+ /// <summary>
+ /// Generates a <a
href="http://www.w3.org/TR/css3-selectors/#pseudo-classes">pseudo-class
selector</a>,
+ /// which represents an element that is the N-th child from bottom up of
some other element.
+ /// </summary>
+ public void NthLastChild(int a, int b)
+ {
+ Add(Ops.NthLastChild(a, b));
+ }
}
}
=======================================
--- /trunk/Fizzler/SelectorGeneratorTee.cs Tue Feb 2 14:28:39 2010
+++ /trunk/Fizzler/SelectorGeneratorTee.cs Wed Oct 6 16:15:18 2010
@@ -239,5 +239,14 @@
Primary.GeneralSibling();
Secondary.GeneralSibling();
}
+
+ /// <summary>
+ /// Delegates to <see cref="Primary"/> then <see cref="Secondary"/>
generator.
+ /// </summary>
+ public void NthLastChild(int a, int b)
+ {
+ Primary.NthLastChild(a, b);
+ Secondary.NthLastChild(a, b);
+ }
}
}
=======================================
--- /trunk/Fizzler.Sandbox/WinForms/ControlOps.cs Tue Feb 2 14:28:39 2010
+++ /trunk/Fizzler.Sandbox/WinForms/ControlOps.cs Wed Oct 6 16:15:18 2010
@@ -247,5 +247,10 @@
{
return nodes => nodes.SelectMany(n => n.ControlsAfterSelf());
}
+
+ public Selector<Control> NthLastChild(int a, int b)
+ {
+ throw new NotImplementedException();
+ }
}
}
=======================================
--- /trunk/Fizzler.Sandbox/Xml/XmlNodeOps.cs Tue Feb 2 14:28:39 2010
+++ /trunk/Fizzler.Sandbox/Xml/XmlNodeOps.cs Wed Oct 6 16:15:18 2010
@@ -190,5 +190,20 @@
{
return nodes => nodes.SelectMany(n => n.ElementsAfterSelf());
}
+
+ /// <summary>
+ /// Generates a <a
href="http://www.w3.org/TR/css3-selectors/#pseudo-classes">pseudo-class
selector</a>,
+ /// which represents an element that is the N-th child from bottom up of
some other element.
+ /// </summary>
+ public Selector<XmlNode> NthLastChild(int a, int b)
+ {
+ if (a != 1)
+ throw new NotSupportedException("The nth-last-child(an+b) selector
where a in is not 1 are not supported.");
+
+ return nodes => from n in nodes
+ let elements = n.ParentNode.Elements().Skip(Math.Max(0,
n.ParentNode.Elements().Count() - b)).Take(b).ToArray()
+ where elements.Length == b && elements.First().Equals(n)
+ select n;
+ }
}
}
=======================================
--- /trunk/Fizzler.Systems.HtmlAgilityPack/HtmlNodeOps.cs Tue Feb 2
14:28:39 2010
+++ /trunk/Fizzler.Systems.HtmlAgilityPack/HtmlNodeOps.cs Wed Oct 6
16:15:18 2010
@@ -258,5 +258,20 @@
{
return nodes => nodes.SelectMany(n => n.ElementsAfterSelf());
}
+
+ /// <summary>
+ /// Generates a <a
href="http://www.w3.org/TR/css3-selectors/#pseudo-classes">pseudo-class
selector</a>,
+ /// which represents an element that is the N-th child from bottom up of
some other element.
+ /// </summary>
+ public Selector<HtmlNode> NthLastChild(int a, int b)
+ {
+ if (a != 1)
+ throw new NotSupportedException("The nth-last-child(an+b) selector
where a in is not 1 are not supported.");
+
+ return nodes => from n in nodes
+ let elements = n.ParentNode.Elements().Skip(Math.Max(0,
n.ParentNode.Elements().Count() - b)).Take(b).ToArray()
+ where elements.Length == b && elements.First().Equals(n)
+ select n;
+ }
}
}
=======================================
--- /trunk/Fizzler.Tests/Fizzler.Tests.csproj Wed Sep 30 10:53:50 2009
+++ /trunk/Fizzler.Tests/Fizzler.Tests.csproj Wed Oct 6 16:15:18 2010
@@ -49,6 +49,7 @@
<Compile Include="AttributeSelectors.cs" />
<Compile Include="ChildAndAdjacentSelectors.cs" />
<Compile Include="ClassSelector.cs" />
+ <Compile Include="NthLastChild.cs" />
<Compile Include="ParserTests.cs" />
<Compile Include="HumanReadableSelectorGeneratorTests.cs" />
<Compile Include="IDSelector.cs" />
=======================================
--- /trunk/Fizzler.Tests/ParserTests.cs Tue Feb 2 14:28:39 2010
+++ /trunk/Fizzler.Tests/ParserTests.cs Wed Oct 6 16:15:18 2010
@@ -484,7 +484,12 @@
throw new NotImplementedException();
}

- #endregion
+ public void NthLastChild(int a, int b)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
}
}
}
=======================================
--- /trunk/Fizzler.Tests/SelectorGeneratorTeeTests.cs Tue Feb 2 14:28:39
2010
+++ /trunk/Fizzler.Tests/SelectorGeneratorTeeTests.cs Wed Oct 6 16:15:18
2010
@@ -369,8 +369,13 @@
{
OnInvoked(MethodBase.GetCurrentMethod());
}
-
- private void OnInvoked(MethodBase method, params object[] args)
+
+ public void NthLastChild(int a, int b)
+ {
+ OnInvoked(MethodBase.GetCurrentMethod(), a, b);
+ }
+
+ private void OnInvoked(MethodBase method, params object[] args)
{
Recorder(new CallRecording<ISelectorGenerator>(this,
(MethodInfo) method, args));
}

Reply all
Reply to author
Forward
0 new messages