Permalink
Browse files

WIP getting multiple CSS Selectors

  • Loading branch information...
1 parent 8fc685f commit 27bd39e7d601ec627aa447aac710c691e32fcaa1 @dpp dpp committed Jun 23, 2012
@@ -20,27 +20,46 @@ package util
import scala.util.parsing.combinator.{Parsers, ImplicitConversions}
import scala.xml.NodeSeq
import net.liftweb.common._
+import util.EnclosedSelector
sealed trait CssSelector {
def subNodes: Box[SubNode]
+ def withSubnode(sn: SubNode): CssSelector
}
final case class ElemSelector(elem: String, subNodes: Box[SubNode]) extends
- CssSelector
+ CssSelector {
+ def withSubnode(sn: SubNode): CssSelector = this.copy(subNodes = Full(sn))
+}
-final case class StarSelector(subNodes: Box[SubNode]) extends CssSelector
+final case class StarSelector(subNodes: Box[SubNode]) extends CssSelector {
+ def withSubnode(sn: SubNode): CssSelector = this.copy(subNodes = Full(sn))
+}
final case class IdSelector(id: String, subNodes: Box[SubNode]) extends
- CssSelector
+ CssSelector {
+ def withSubnode(sn: SubNode): CssSelector = this.copy(subNodes = Full(sn))
+}
final case class ClassSelector(clss: String, subNodes: Box[SubNode]) extends
- CssSelector
+ CssSelector {
+ def withSubnode(sn: SubNode): CssSelector = this.copy(subNodes = Full(sn))
+}
final case class NameSelector(name: String, subNodes: Box[SubNode]) extends
- CssSelector
+ CssSelector {
+ def withSubnode(sn: SubNode): CssSelector = this.copy(subNodes = Full(sn))
+}
+
+final case class EnclosedSelector(selector: CssSelector, kid: CssSelector) extends CssSelector {
+ def subNodes: Box[SubNode] = Empty
+ def withSubnode(sn: SubNode): CssSelector = this
+}
final case class AttrSelector(name: String, value: String,
-subNodes: Box[SubNode]) extends CssSelector
+subNodes: Box[SubNode]) extends CssSelector {
+ def withSubnode(sn: SubNode): CssSelector = this.copy(subNodes = Full(sn))
+}
sealed trait SubNode
@@ -121,7 +140,7 @@ object CssSelectorParser extends Parsers with ImplicitConversions {
private implicit def str2chars(s: String): List[Char] = new scala.collection.immutable.WrappedString(s).toList
- private lazy val topParser: Parser[CssSelector] = {
+ private lazy val _topParser: Parser[CssSelector] = {
phrase(idMatch |
nameMatch |
classMatch |
@@ -130,6 +149,33 @@ object CssSelectorParser extends Parsers with ImplicitConversions {
starMatch |
colonMatch)
}
+
+ private def fixAll(all: List[CssSelector], sn: Option[SubNode]): CssSelector = (all, sn) match {
+ case (r :: Nil, None) => r
+ case (r :: Nil, Some(sn)) => r.withSubnode(sn)
+ case (lst, None) => lst.reduceRight((b, a) => EnclosedSelector(a, b))
+ case (lst, Some(sn)) => (lst.dropRight(1) ::: lst.takeRight(1).map(_.withSubnode(sn))).reduceRight((b, a) => EnclosedSelector(a, b))
+ }
+
+ private lazy val topParser: Parser[CssSelector] =
+ phrase(rep1(_idMatch | _nameMatch | _classMatch | _attrMatch | _elemMatch |
+ _colonMatch | _starMatch) ~ opt(subNode)) ^^ {
+ case all ~ None if all.takeRight(1).head == StarSelector(Empty) =>
+ fixAll(all.dropRight(1), Some(KidsSubNode()))
+ case all ~ sn => fixAll(all, sn)
+ }
+
+ private lazy val _colonMatch: Parser[CssSelector] =
+ (':' ~> id) ^? {
+ case "button" => AttrSelector("type", "button", Empty)
+ case "checkbox" => AttrSelector("type", "checkbox", Empty)
+ case "file" => AttrSelector("type", "file", Empty)
+ case "password" => AttrSelector("type", "password", Empty)
+ case "radio" => AttrSelector("type", "radio", Empty)
+ case "reset" => AttrSelector("type", "reset", Empty)
+ case "submit" => AttrSelector("type", "submit", Empty)
+ case "text" => AttrSelector("type", "text", Empty)
+ }
private lazy val colonMatch: Parser[CssSelector] =
':' ~> id ~ opt(subNode) ^? {
@@ -143,22 +189,63 @@ object CssSelectorParser extends Parsers with ImplicitConversions {
case "text" ~ sn => AttrSelector("type", "text", sn)
}
+
private lazy val idMatch: Parser[CssSelector] = '#' ~> id ~ opt(subNode) ^^ {
case id ~ sn => IdSelector(id, sn)
}
+ private lazy val _idMatch: Parser[CssSelector] = '#' ~> id ^^ {
+ case id => IdSelector(id, Empty)
+ }
+
private lazy val nameMatch: Parser[CssSelector] = '@' ~> id ~ opt(subNode) ^^ {
case name ~ sn => NameSelector(name, sn)
}
+ private lazy val _nameMatch: Parser[CssSelector] = '@' ~> id ^^ {
+ case name => NameSelector(name, Empty)
+ }
+
private lazy val elemMatch: Parser[CssSelector] = id ~ opt(subNode) ^^ {
case elem ~ sn => ElemSelector(elem, sn)
}
+ private lazy val _elemMatch: Parser[CssSelector] = id ^^ {
+ case elem => ElemSelector(elem, Empty)
+ }
+
private lazy val starMatch: Parser[CssSelector] = '*' ~> opt(subNode) ^^ {
case sn => StarSelector(sn)
}
+ private lazy val _starMatch: Parser[CssSelector] = '*' ^^ {
+ case sn => StarSelector(Empty)
+ }
+
+ private lazy val classMatch: Parser[CssSelector] =
+ '.' ~> attrName ~ opt(subNode) ^^ {
+ case cls ~ sn => ClassSelector(cls, sn)
+ }
+
+ private lazy val attrMatch: Parser[CssSelector] =
+ attrName ~ '=' ~ attrConst ~ opt(subNode) ^^ {
+ case "id" ~ _ ~ const ~ sn => IdSelector(const, sn)
+ case "name" ~ _ ~ const ~ sn => NameSelector(const, sn)
+ case n ~ _ ~ v ~ sn => AttrSelector(n, v, sn)
+ }
+
+ private lazy val _classMatch: Parser[CssSelector] =
+ '.' ~> attrName ^^ {
+ case cls => ClassSelector(cls, Empty)
+ }
+
+ private lazy val _attrMatch: Parser[CssSelector] =
+ attrName ~ '=' ~ attrConst ^^ {
+ case "id" ~ _ ~ const => IdSelector(const, Empty)
+ case "name" ~ _ ~ const => NameSelector(const, Empty)
+ case n ~ _ ~ v => AttrSelector(n, v, Empty)
+ }
+
private lazy val id: Parser[String] = letter ~
rep(letter | number | '-' | '_' | ':' | '.') ^^ {
@@ -173,17 +260,6 @@ object CssSelectorParser extends Parsers with ImplicitConversions {
private lazy val letter: Parser[Char] = elem("letter", isLetter)
private lazy val number: Parser[Char] = elem("number", isNumber)
- private lazy val classMatch: Parser[CssSelector] =
- '.' ~> attrName ~ opt(subNode) ^^ {
- case cls ~ sn => ClassSelector(cls, sn)
- }
-
- private lazy val attrMatch: Parser[CssSelector] =
- attrName ~ '=' ~ attrConst ~ opt(subNode) ^^ {
- case "id" ~ _ ~ const ~ sn => IdSelector(const, sn)
- case "name" ~ _ ~ const ~ sn => NameSelector(const, sn)
- case n ~ _ ~ v ~ sn => AttrSelector(n, v, sn)
- }
private lazy val subNode: Parser[SubNode] = rep1(' ') ~>
((opt('*') ~ '[' ~> attrName <~ '+' ~ ']' ^^ {
@@ -21,6 +21,7 @@ import org.specs2.mutable.Specification
import common._
import BindHelpers._
+import util.{ElemSelector, ClassSelector}
/**
@@ -116,8 +117,6 @@ object CssSelectorSpec extends Specification {
IdSelector("foo", Full(AttrRemoveSubNode("woof")))
}
-
-
"select attr/val pair" in {
CssSelectorParser.parse("frog=dog") must_==
Full(AttrSelector("frog", "dog", Empty))
@@ -200,6 +199,13 @@ object CssSelectorSpec extends Specification {
CssSelectorParser.parse(".foo [woof] ").open_! must_==
ClassSelector("foo", Full(AttrSubNode("woof")))
}
+
+ "select multiple depth" in {
+ CssSelectorParser.parse("div .foo [woof] ").open_! must_==
+ EnclosedSelector(ElemSelector("div", Empty), ClassSelector("foo", Full(AttrSubNode("woof"))))
+ }
+
+
}
}

0 comments on commit 27bd39e

Please sign in to comment.