Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: Fashionbase/framework
...
head fork: lift/framework
Checking mergeability… Don't worry, you can still create the pull request.
  • 13 commits
  • 5 files changed
  • 0 commit comments
  • 1 contributor
View
400 core/util/src/main/scala/net/liftweb/util/BindHelpers.scala
@@ -20,7 +20,6 @@ package util
import scala.xml._
import common._
import scala.collection.mutable.ListBuffer
-import java.util.{List => JavaList}
/**
* This trait is used to identify an object that is representable as a {@link NodeSeq}.
@@ -61,7 +60,7 @@ trait AttrHelper[+Holder[X]] {
/**
* BindHelpers can be used to obtain additional information while a {@link bind} call is executing.
- * This informaiton includes node attributes of the current bound node or the entire NodeSeq that is
+ * This information includes node attributes of the current bound node or the entire NodeSeq that is
* to be bound. Since the context is created during bind execution and destroyed when bind terminates,
* you can benefit of these helpers in the context of FuncBindParam or FuncAttrBindParam. You can
* also provide your own implementation of BindParam and your BindParam#calcValue function will be called
@@ -694,7 +693,8 @@ trait BindHelpers {
* Remove all the <head> tags, just leaving the child tags
*/
def stripHead(in: NodeSeq): NodeSeq = {
- ("head" #> ((ns: NodeSeq) => ns.asInstanceOf[Elem].child))(in)
+ "head" #> ((ns: NodeSeq) => ns.asInstanceOf[Elem].child) apply in
+ /*
import scala.xml.transform._
val rewrite = new RewriteRule {
@@ -705,6 +705,7 @@ trait BindHelpers {
}
(new RuleTransformer(rewrite)).transform(in)
+ */
}
/**
@@ -712,7 +713,7 @@ trait BindHelpers {
* nodeseq.
*/
def replaceIdNode(in: NodeSeq, id: String, replacement: NodeSeq): NodeSeq = {
- (("#"+id) #> replacement)(in)
+ ("#"+id) #> replacement apply in
/*
import scala.xml.transform._
@@ -1338,7 +1339,7 @@ trait BindHelpers {
new ToCssBindPromoter(Full(str), CssSelectorParser.parse(str))
/**
- * promote a String to a ToCssBindPromotor
+ * promote a CssSelector to a ToCssBindPromotor
*/
implicit def cssSelectorToCssBindPromoter(sel: CssSelector): ToCssBindPromoter =
new ToCssBindPromoter(Empty, Full(sel))
@@ -1422,353 +1423,6 @@ trait BindHelpers {
}
/**
- * An intermediate class used to promote a String or a CssSelector to
- * something that can be associated with a value to apply to the selector
- */
-final class ToCssBindPromoter(stringSelector: Box[String], css: Box[CssSelector]) {
-
- /**
- * Inserts a String constant according to the CssSelector rules
- */
- def #>(str: String): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] =
- List(if (null eq str) NodeSeq.Empty else Text(str))
- }
-
-
- /**
- * Inserts a NodeSeq constant according to the CssSelector rules
- */
- def #>(ns: NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(ns)
- }
-
- /**
- * A function that transforms the content according to the CssSelector rules
- */
- def #>(nsFunc: NodeSeq => NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(nsFunc(in))
- }
-
- /**
- * Inserts a Bindable constant according to the CssSelector rules.
- * Mapper and Record fields implement Bindable.
- */
- def #>(bindable: Bindable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(bindable.asHtml)
- }
-
- /**
- * Inserts a StringPromotable constant according to the CssSelector rules.
- * StringPromotable includes Int, Long, Boolean, and Symbol
- */
- def #>(strPromo: StringPromotable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] =
- List(Text(strPromo.toString))
- }
-
- /**
- * Applies the N constants according to the CssSelector rules.
- * This allows for Seq[String], Seq[NodeSeq], Box[String],
- * Box[NodeSeq], Option[String], Option[NodeSeq]
- */
- def #>(itrConst: IterableConst): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrConst.constList(in)
- }
-
- /**
- * Apply the function and then apply the results account the the CssSelector
- * rules.
- * This allows for NodeSeq => Seq[String], NodeSeq =>Seq[NodeSeq],
- * NodeSeq => Box[String],
- * NodeSeq => Box[NodeSeq], NodeSeq => Option[String],
- * NodeSeq =>Option[NodeSeq]
- */
- def #>(itrFunc: IterableFunc): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrFunc(in)
- }
-
- /**
- * Inserts a String constant according to the CssSelector rules
- */
- def replaceWith(str: String): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] =
- List(if (null eq str) NodeSeq.Empty else Text(str))
- }
-
- /**
- * Inserts a NodeSeq constant according to the CssSelector rules
- */
- def replaceWith(ns: NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(ns)
- }
-
- /**
- * A function that transforms the content according to the CssSelector rules
- */
- def replaceWith(nsFunc: NodeSeq => NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(nsFunc(in))
- }
-
- /**
- * Inserts a Bindable constant according to the CssSelector rules.
- * Mapper and Record fields implement Bindable.
- */
- def replaceWith(bindable: Bindable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(bindable.asHtml)
- }
-
- /**
- * Inserts a StringPromotable constant according to the CssSelector rules.
- * StringPromotable includes Int, Long, Boolean, and Symbol
- */
- def replaceWith(strPromo: StringPromotable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = strPromo.toString match {
- case null => NodeSeq.Empty
- case str => List(Text(str))
- }
- }
-
- /**
- * Applies the N constants according to the CssSelector rules.
- * This allows for Seq[String], Seq[NodeSeq], Box[String],
- * Box[NodeSeq], Option[String], Option[NodeSeq]
- */
- def replaceWith(itrConst: IterableConst): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrConst.constList(in)
- }
-
- /**
- * Apply the function and then apply the results account the the CssSelector
- * rules.
- * This allows for NodeSeq => Seq[String], NodeSeq =>Seq[NodeSeq],
- * NodeSeq => Box[String],
- * NodeSeq => Box[NodeSeq], NodeSeq => Option[String],
- * NodeSeq =>Option[NodeSeq]
- */
- def replaceWith(itrFunc: IterableFunc): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrFunc(in)
- }
-}
-
-/**
- * A trait that has some helpful implicit conversions from
- * Iterable[NodeSeq], Seq[String], Box[String], and Option[String]
- */
-trait IterableConst {
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq]
-}
-
-import scala.collection.JavaConversions._
-
-/**
- * The implementation for a NodeSeq Iterable Const
- */
-final case class NodeSeqIterableConst(it: Iterable[NodeSeq]) extends IterableConst {
- def this(it: JavaList[NodeSeq]) = this(it: Iterable[NodeSeq])
-
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.toSeq
-}
-
-/**
- * The implementation for a NodeSeq => NodeSeq Iterable Const
- */
-final case class NodeSeqFuncIterableConst(it: Iterable[NodeSeq => NodeSeq]) extends IterableConst {
- def this(it: JavaList[NodeSeq => NodeSeq]) = this(it: Iterable[NodeSeq => NodeSeq])
-
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = Helpers.ensureUniqueId(it.map(_(nodeSeq)).toSeq)
-}
-
-/**
- * The implementation for a Box[NodeSeq => Node] Iterable Const
- */
-final case class BoxNodeSeqFuncIterableConst(it: Box[NodeSeq => NodeSeq]) extends IterableConst {
-
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.toList.map(_(nodeSeq))
-}
-
-/**
- * The implementation for a Option[NodeSeq => Node] Iterable Const
- */
-final case class OptionNodeSeqFuncIterableConst(it: Option[NodeSeq => NodeSeq]) extends IterableConst {
-
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.toList.map(_(nodeSeq))
-}
-
-/**
- * Sequence of String iterable const
- */
-final case class SeqStringIterableConst(it: Iterable[String]) extends IterableConst {
- def this(it: JavaList[String]) = this(it: Iterable[String])
-
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.map(a => Text(a)).toSeq
-}
-
-/**
- * Sequence of Bindable iterable const
- */
-final case class SeqBindableIterableConst(it: Iterable[Bindable]) extends IterableConst {
- def this(it: JavaList[Bindable]) = this(it: Iterable[Bindable])
-
- def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.map(_.asHtml).toSeq
-}
-
-/**
- * The companion object that does the helpful promotion of common
- * collection types into an IterableConst,
- * e.g. Iterable[NodeSeq], Seq[String], Box[String], and Option[String]
- */
-object IterableConst {
- /**
- * Converts anything that can be converted into an Iterable[NodeSeq]
- * into an IterableConst. This includes Seq[NodeSeq]
- */
- implicit def itNodeSeq(it: Iterable[NodeSeq]): IterableConst =
- NodeSeqIterableConst(it)
-
- /**
- * Converts anything that can be converted into an Box[NodeSeq]
- */
- implicit def boxNodeSeq(it: Box[NodeSeq]): IterableConst =
- NodeSeqIterableConst(it.toList)
-
- /**
- * Converts anything that can be converted into an Box[NodeSeq]
- */
- implicit def optionNodeSeq(it: Option[NodeSeq]): IterableConst =
- NodeSeqIterableConst(it.toList)
-
- /**
- * Converts anything that can be converted into an Iterable[NodeSeq]
- * into an IterableConst. This includes Seq[NodeSeq], Option[NodeSeq],
- * and Box[NodeSeq]
- */
- implicit def itNodeSeq(it: JavaList[NodeSeq]): IterableConst =
- new NodeSeqIterableConst(it)
-
- implicit def itNodeSeqFunc(it: Iterable[NodeSeq => NodeSeq]): IterableConst =
- NodeSeqFuncIterableConst(it)
-
- implicit def itNodeSeqFunc(it: JavaList[NodeSeq => NodeSeq]): IterableConst =
- new NodeSeqFuncIterableConst(it)
-
- implicit def boxNodeSeqFunc(it: Box[NodeSeq => NodeSeq]): IterableConst =
- BoxNodeSeqFuncIterableConst(it)
-
- implicit def optionNodeSeqFunc(it: Option[NodeSeq => NodeSeq]): IterableConst =
- OptionNodeSeqFuncIterableConst(it)
-
- implicit def itStringPromotable(it: Iterable[String]): IterableConst =
- SeqStringIterableConst(it)
-
- implicit def javaListStringPromotable(it: JavaList[String]): IterableConst =
- new SeqStringIterableConst(it)
-
- implicit def boxString(it: Box[String]): IterableConst =
- SeqStringIterableConst(it.toList)
-
- implicit def optionString(it: Option[String]): IterableConst =
- SeqStringIterableConst(it.toList)
-
- implicit def itBindable(it: Iterable[Bindable]): IterableConst =
- SeqBindableIterableConst(it)
-
- implicit def itBindable(it: JavaList[Bindable]): IterableConst =
- new SeqBindableIterableConst(it)
-
-
- implicit def boxBindablePromotable(it: Box[Bindable]): IterableConst =
- SeqBindableIterableConst(it.toList)
-
- implicit def optionBindablePromotable(it: Option[Bindable]): IterableConst =
- SeqBindableIterableConst(it.toList)
-
- implicit def optionStringPromotable[T](o: Option[T])(implicit view:T=>StringPromotable) = optionString(o.map(view(_).toString))
-}
-
-sealed trait IterableFunc extends Function1[NodeSeq, Seq[NodeSeq]] {
- def apply(ns: NodeSeq): Seq[NodeSeq]
-}
-
-object IterableFunc {
- implicit def itNodeSeq[C <% Iterable[NodeSeq]](it: NodeSeq => C): IterableFunc =
- new IterableFunc {
- def apply(in: NodeSeq): Seq[NodeSeq] = it(in).toSeq
- }
-
- implicit def itNodeSeqPromotable(it: NodeSeq => NodeSeq): IterableFunc =
- new IterableFunc {
- def apply(in: NodeSeq): Seq[NodeSeq] = List(it(in))
- }
-
-
- implicit def itStringFuncPromotable(it: NodeSeq => String): IterableFunc =
- new IterableFunc {
- def apply(in: NodeSeq): Seq[NodeSeq] = it(in) match {
- case null => List(NodeSeq.Empty)
- case str => List(Text(str))}
- }
-
-
- implicit def itStringPromotable(it: NodeSeq => Seq[String]): IterableFunc =
- new IterableFunc {
- def apply(in: NodeSeq): Seq[NodeSeq] = it(in).filter(_ ne null).map(a => Text(a))
- }
-
- implicit def boxStringPromotable(it: NodeSeq => Box[String]): IterableFunc =
- new IterableFunc {
- def apply(in: NodeSeq): Seq[NodeSeq] = it(in).filter(_ ne null).toList.map(a => Text(a))
- }
-
-
- implicit def optionStringPromotable(it: NodeSeq => Option[String]): IterableFunc =
- new IterableFunc {
- def apply(in: NodeSeq): Seq[NodeSeq] = it(in).filter(_ ne null).toList.map(a => Text(a))
- }
-}
-
-
-/**
- * This trait marks something that can be promoted into a String.
- * The companion object has helpful conversions from Int,
- * Symbol, Long, and Boolean
- */
-trait StringPromotable
-
-object StringPromotable {
- implicit def jsCmdToStrPromo(in: ToJsCmd): StringPromotable =
- new StringPromotable {
- override val toString = in.toJsCmd
- }
-
- implicit def jsCmdToStrPromo(in: (_, ToJsCmd)): StringPromotable =
- new StringPromotable {
- override val toString = in._2.toJsCmd
- }
-
-
- implicit def intToStrPromo(in: Int): StringPromotable =
- new StringPromotable {
- override val toString = in.toString
- }
-
- implicit def symbolToStrPromo(in: Symbol): StringPromotable =
- new StringPromotable {
- override val toString = in.name
- }
-
- implicit def longToStrPromo(in: Long): StringPromotable =
- new StringPromotable {
- override val toString = in.toString
- }
-
- implicit def booleanToStrPromo(in: Boolean): StringPromotable =
- new StringPromotable {
- override val toString = in.toString
- }
-}
-
-/**
* This trait is both a NodeSeq => NodeSeq and has the ability
* to chain CssSel instances so that they can be applied
* en masse to incoming NodeSeq and do the transformation.
@@ -1825,7 +1479,7 @@ sealed trait CssSel extends Function1[NodeSeq, NodeSeq] {
/**
* Inserts a String constant according to the CssSelector rules
*/
- def sel(selector: String, str: IterableConst): CssSel = this & (selector #> str)
+ //def sel(selector: String, str: IterableConst): CssSel = this & (selector #> str)
/**
* Inserts a String constant according to the CssSelector rules
@@ -1833,27 +1487,6 @@ sealed trait CssSel extends Function1[NodeSeq, NodeSeq] {
def sel(selector: String, str: IterableFunc): CssSel = this & (selector #> str)
}
-/**
- * A passthrough function that does not change the nodes
- *
- * @tag CssFunction
- */
-object PassThru extends Function1[NodeSeq, NodeSeq] {
- def apply(in: NodeSeq): NodeSeq = in
-}
-
-/**
- * Replaces the nodes with an Empty NodeSeq. Useful
- * for removing unused nodes
- *
- * @tag CssFunction
- */
-object ClearNodes extends Function1[NodeSeq, NodeSeq] {
- def apply(in: NodeSeq): NodeSeq = NodeSeq.Empty
-}
-
-
-
private final case class AggregatedCssBindFunc(binds: List[CssBind]) extends CssSel {
private lazy val (good, bad) = binds.partition{_.css.isDefined}
private lazy val selectorMap = new SelectorMap(good)
@@ -1864,23 +1497,6 @@ private final case class AggregatedCssBindFunc(binds: List[CssBind]) extends Css
}
}
-/**
- * This CssBind will clear all nodes marked with the class
- * clearable. Designers can mark extra nodes in markup with
- * class="clearable" and this Bind will make them go away
- */
-class ClearClearable extends CssBindImpl(Full(".clearable"), CssSelectorParser.parse(".clearable")) {
-
- def calculate(in: NodeSeq): Seq[NodeSeq] = Nil
-}
-
-/**
- * This CssBind will clear all nodes marked with the class
- * clearable. Designers can mark extra nodes in markup with
- * class="clearable" and this Bind will make them go away
- */
-object ClearClearable extends ClearClearable
-
private class SelectorMap(binds: List[CssBind]) extends Function1[NodeSeq, NodeSeq] {
// The KidsSubNode always has to go last or else we
@@ -2485,7 +2101,7 @@ final class CssJBridge {
/**
* Inserts a String constant according to the CssSelector rules
*/
- def sel(selector: String, str: IterableConst): CssSel = (selector #> str)
+ //def sel(selector: String, str: IterableConst): CssSel = (selector #> str)
/**
* Inserts a String constant according to the CssSelector rules
View
400 core/util/src/main/scala/net/liftweb/util/CssBinding.scala
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2007-2011 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package util
+
+
+import scala.xml._
+import common._
+import java.util.{List => JavaList}
+import scala.collection.mutable.ListBuffer
+
+
+
+/**
+ * A type class that creates a NodeSeq=>Seq[NodeSeq] for a value of some type.
+ * The apply method delegates to the function passed to the constructor.
+ * @param f a function T=>NodeSeq=>Seq[NodeSeq] that returns a NodeSeq=>NodeSeq for a T
+ */
+class CanBindN[-T](f: T => NodeSeq => Seq[NodeSeq]) extends (T => NodeSeq => Seq[NodeSeq]) {
+ /**
+ * Given a value of type T, return a function that can be used in Lift binding.
+ * The function takes a NodeSeq (the content from the template) and returns
+ * a Seq[NodeSeq]. The return value is collection-valued because some types repeatedly
+ * transform the same template content (e.g., "th *" #> List("Column Header 1", "Column Header 2"))
+ */
+ def apply(v: T) = f(v)
+}
+
+/**
+ * Defines the CanBindN implicits that are available by default
+ */
+object CanBindN {
+ /**
+ * Bind a single bindable value.
+ * Given a type that has an implicit CanBind, delegate to that CanBind,
+ * wrapping the result in a List is its single element
+ */
+ implicit def single[T](implicit canBind: CanBind[T]): CanBindN[T] =
+ new CanBindN[T](v => ns => List(canBind(v)(ns)))
+
+ /**
+ * Bind zero or more bindable values.
+ * Given a type that has an implicit CanBind, and a context viewable as an
+ * Iterable of that type, apply all the CanBinds
+ */
+ implicit def iterable[T, I[_]](implicit canBind: CanBind[T], toIter: I[T]=>Iterable[T]): CanBindN[I[T]] =
+ new CanBindN[I[T]](v => ns => Helpers.ensureUniqueId(toIter(v).toSeq map (_ apply ns)))
+
+ /**
+ * Bind a function that, given a NodeSeq, returns zero or more bindable values.
+ * Given a type that has an implicit CanBindN, and a context viewable as an
+ * Iterable of that type, apply all the CanBindNs.
+ */
+ implicit def iterableFunc[T, I[_]](implicit canBindN: CanBindN[T], toIter: I[T]=>Iterable[T]): CanBindN[NodeSeq=>I[T]] =
+ new CanBindN[NodeSeq=>I[T]](v => ns => toIter(v(ns)).toSeq flatMap (_ apply ns))
+}
+
+class CanBind[-T](f: T => NodeSeq => NodeSeq) extends (T => NodeSeq => NodeSeq) {
+ def apply(v: T) = f(v)
+}
+
+//TODO obviate StringPromotable
+//TODO obviate Bindable
+
+object CanBind {
+ /**
+ * Bind a string by replacing content with a Text node (or NodeSeq.empty in the case of null)
+ */
+ implicit val string = new CanBind[String](str => _ => (if (null eq str) NodeSeq.Empty else Text(str)))
+
+ /**
+ * Bind a NodeSeq by replacing content with it
+ */
+ implicit val nodeSeq: CanBind[NodeSeq] = new CanBind[NodeSeq](ns => _ => ns)
+
+ /**
+ * Bind a Seq[Node] by replacing content with it, via NodeSeq.fromSeq
+ */
+ implicit val seqNode: CanBind[Seq[Node]] = new CanBind[Seq[Node]](ns => _ => NodeSeq fromSeq ns)
+
+ /**
+ * Bind a function NodeSeq=>U where U has an implicit CanBind, by applying it
+ * to content and replacing it with the result
+ */
+ implicit def func[U](implicit canBind: CanBind[U]): CanBind[NodeSeq => U] =
+ new CanBind[NodeSeq => U](f => in => f(in) apply in)
+
+ /**
+ * Bind an object that extends Bindable, by calling its asHtml method
+ * and replacing content with its result.
+ * Mapper and Record fields implement Bindable.
+ */
+ implicit val bindable: CanBind[Bindable] = new CanBind[Bindable](bindable => _ => bindable.asHtml)
+
+ /**
+ * Bind something that has a conversion to StringPromotable, by
+ * calling the StringPromotable's toString method and replacing content with it wrapped in a Text node.
+ * StringPromotable includes Int, Long, Boolean, and Symbol
+ */
+ implicit def stringPromotable[T](implicit view: T=>StringPromotable) = new CanBind[T]({strPromo => _ =>
+ view(strPromo).toString match {
+ case null => NodeSeq.Empty
+ case s => Text(s)
+ }
+ })
+
+
+}
+
+
+
+/**
+ * An intermediate class used to promote a String or a CssSelector to
+ * something that can be associated with a value to apply to the selector
+ * @param stringSelector the unparsed css selector string
+ * @param css the parsed CssSelector object
+ */
+final class ToCssBindPromoter(stringSelector: Box[String], css: Box[CssSelector]) {
+ def #>[T](v: T)(implicit canBindN: CanBindN[T]): CssSel =
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] = canBindN.apply(v)(in)
+ }
+ def replaceWith[T: CanBindN](v: T): CssSel = #>[T](v)
+}
+
+
+/**
+ * A trait that has some helpful implicit conversions from
+ * Iterable[NodeSeq], Seq[String], Box[String], and Option[String]
+ */
+trait IterableConst {
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq]
+}
+
+import scala.collection.JavaConversions._
+
+/**
+ * The implementation for a NodeSeq Iterable Const
+ */
+final case class NodeSeqIterableConst(it: Iterable[NodeSeq]) extends IterableConst {
+ def this(it: JavaList[NodeSeq]) = this(it: Iterable[NodeSeq])
+
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.toSeq
+}
+
+/**
+ * The implementation for a NodeSeq => NodeSeq Iterable Const
+ */
+final case class NodeSeqFuncIterableConst(it: Iterable[NodeSeq => NodeSeq]) extends IterableConst {
+ def this(it: JavaList[NodeSeq => NodeSeq]) = this(it: Iterable[NodeSeq => NodeSeq])
+
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = Helpers.ensureUniqueId(it.map(_(nodeSeq)).toSeq)
+}
+
+/**
+ * The implementation for a Box[NodeSeq => Node] Iterable Const
+ */
+final case class BoxNodeSeqFuncIterableConst(it: Box[NodeSeq => NodeSeq]) extends IterableConst {
+
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.toList.map(_(nodeSeq))
+}
+
+/**
+ * The implementation for a Option[NodeSeq => Node] Iterable Const
+ */
+final case class OptionNodeSeqFuncIterableConst(it: Option[NodeSeq => NodeSeq]) extends IterableConst {
+
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.toList.map(_(nodeSeq))
+}
+
+/**
+ * Sequence of String iterable const
+ */
+final case class SeqStringIterableConst(it: Iterable[String]) extends IterableConst {
+ def this(it: JavaList[String]) = this(it: Iterable[String])
+
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.map(a => Text(a)).toSeq
+}
+
+/**
+ * Sequence of Bindable iterable const
+ */
+final case class SeqBindableIterableConst(it: Iterable[Bindable]) extends IterableConst {
+ def this(it: JavaList[Bindable]) = this(it: Iterable[Bindable])
+
+ def constList(nodeSeq: NodeSeq): Seq[NodeSeq] = it.map(_.asHtml).toSeq
+}
+
+/**
+ * The companion object that does the helpful promotion of common
+ * collection types into an IterableConst,
+ * e.g. Iterable[NodeSeq], Seq[String], Box[String], and Option[String]
+ */
+object IterableConst {
+ /**
+ * Converts anything that can be converted into an Iterable[NodeSeq]
+ * into an IterableConst. This includes Seq[NodeSeq]
+ */
+ implicit def itNodeSeq(it: Iterable[NodeSeq]): IterableConst =
+ NodeSeqIterableConst(it)
+
+ /**
+ * Converts anything that can be converted into an Box[NodeSeq]
+ * Bind a value that has a CanBindN implicit available
+ */
+ implicit def boxNodeSeq(it: Box[NodeSeq]): IterableConst =
+ NodeSeqIterableConst(it.toList)
+
+ /**
+ * Converts anything that can be converted into an Box[NodeSeq]
+ */
+ implicit def optionNodeSeq(it: Option[NodeSeq]): IterableConst =
+ NodeSeqIterableConst(it.toList)
+
+ /**
+ * Converts anything that can be converted into an Iterable[NodeSeq]
+ * into an IterableConst. This includes Seq[NodeSeq], Option[NodeSeq],
+ * and Box[NodeSeq]
+ * Bind a value that has a CanBindN implicit available
+ */
+ implicit def itNodeSeq(it: JavaList[NodeSeq]): IterableConst =
+ new NodeSeqIterableConst(it)
+
+ implicit def itNodeSeqFunc(it: Iterable[NodeSeq => NodeSeq]): IterableConst =
+ NodeSeqFuncIterableConst(it)
+
+ implicit def itNodeSeqFunc(it: JavaList[NodeSeq => NodeSeq]): IterableConst =
+ new NodeSeqFuncIterableConst(it)
+
+ implicit def boxNodeSeqFunc(it: Box[NodeSeq => NodeSeq]): IterableConst =
+ BoxNodeSeqFuncIterableConst(it)
+
+ implicit def optionNodeSeqFunc(it: Option[NodeSeq => NodeSeq]): IterableConst =
+ OptionNodeSeqFuncIterableConst(it)
+
+ implicit def itStringPromotable(it: Iterable[String]): IterableConst =
+ SeqStringIterableConst(it)
+
+ implicit def javaListStringPromotable(it: JavaList[String]): IterableConst =
+ new SeqStringIterableConst(it)
+
+ implicit def boxString(it: Box[String]): IterableConst =
+ SeqStringIterableConst(it.toList)
+
+ implicit def optionString(it: Option[String]): IterableConst =
+ SeqStringIterableConst(it.toList)
+
+ implicit def itBindable(it: Iterable[Bindable]): IterableConst =
+ SeqBindableIterableConst(it)
+
+ implicit def itBindable(it: JavaList[Bindable]): IterableConst =
+ new SeqBindableIterableConst(it)
+
+
+ implicit def boxBindablePromotable(it: Box[Bindable]): IterableConst =
+ SeqBindableIterableConst(it.toList)
+
+ implicit def optionBindablePromotable(it: Option[Bindable]): IterableConst =
+ SeqBindableIterableConst(it.toList)
+
+ implicit def optionStringPromotable[T](o: Option[T])(implicit view:T=>StringPromotable) = optionString(o.map(view(_).toString))
+}
+
+sealed trait IterableFunc extends Function1[NodeSeq, Seq[NodeSeq]] {
+ def apply(ns: NodeSeq): Seq[NodeSeq]
+}
+
+object IterableFunc {
+ implicit def itNodeSeq[C <% Iterable[NodeSeq]](it: NodeSeq => C): IterableFunc =
+ new IterableFunc {
+ def apply(in: NodeSeq): Seq[NodeSeq] = it(in).toSeq
+ }
+
+ implicit def itNodeSeqPromotable(it: NodeSeq => NodeSeq): IterableFunc =
+ new IterableFunc {
+ def apply(in: NodeSeq): Seq[NodeSeq] = List(it(in))
+ }
+
+
+ implicit def itStringFuncPromotable(it: NodeSeq => String): IterableFunc =
+ new IterableFunc {
+ def apply(in: NodeSeq): Seq[NodeSeq] = it(in) match {
+ case null => List(NodeSeq.Empty)
+ case str => List(Text(str))}
+ }
+
+
+ implicit def itStringPromotable(it: NodeSeq => Seq[String]): IterableFunc =
+ new IterableFunc {
+ def apply(in: NodeSeq): Seq[NodeSeq] = it(in).filter(_ ne null).map(a => Text(a))
+ }
+
+ implicit def boxStringPromotable(it: NodeSeq => Box[String]): IterableFunc =
+ new IterableFunc {
+ def apply(in: NodeSeq): Seq[NodeSeq] = it(in).filter(_ ne null).toList.map(a => Text(a))
+ }
+
+
+ implicit def optionStringPromotable(it: NodeSeq => Option[String]): IterableFunc =
+ new IterableFunc {
+ def apply(in: NodeSeq): Seq[NodeSeq] = it(in).filter(_ ne null).toList.map(a => Text(a))
+ }
+}
+
+
+/**
+ * This trait marks something that can be promoted into a String.
+ * The companion object has helpful conversions from Int,
+ * Symbol, Long, and Boolean
+ */
+trait StringPromotable
+
+object StringPromotable {
+ implicit def hasStringConversion[T <% String](in: T): StringPromotable =
+ new StringPromotable {
+ override val toString: String = in
+ }
+ implicit def jsCmdToStrPromo(in: ToJsCmd): StringPromotable =
+ new StringPromotable {
+ override val toString = in.toJsCmd
+ }
+
+ implicit def jsCmdToStrPromo(in: (_, ToJsCmd)): StringPromotable =
+ new StringPromotable {
+ override val toString = in._2.toJsCmd
+ }
+
+
+ implicit def intToStrPromo(in: Int): StringPromotable =
+ new StringPromotable {
+ override val toString = in.toString
+ }
+
+ implicit def symbolToStrPromo(in: Symbol): StringPromotable =
+ new StringPromotable {
+ override val toString = in.name
+ }
+
+ implicit def longToStrPromo(in: Long): StringPromotable =
+ new StringPromotable {
+ override val toString = in.toString
+ }
+
+ implicit def booleanToStrPromo(in: Boolean): StringPromotable =
+ new StringPromotable {
+ override val toString = in.toString
+ }
+}
+
+/**
+ * A passthrough function that does not change the nodes
+ *
+ * @tag CssFunction
+ */
+object PassThru extends Function1[NodeSeq, NodeSeq] {
+ def apply(in: NodeSeq): NodeSeq = in
+}
+
+/**
+ * Replaces the nodes with an Empty NodeSeq. Useful
+ * for removing unused nodes
+ *
+ * @tag CssFunction
+ */
+object ClearNodes extends Function1[NodeSeq, NodeSeq] {
+ def apply(in: NodeSeq): NodeSeq = NodeSeq.Empty
+}
+
+/**
+ * This CssBind will clear all nodes marked with the class
+ * clearable. Designers can mark extra nodes in markup with
+ * class="clearable" and this Bind will make them go away
+ */
+class ClearClearable extends CssBindImpl(Full(".clearable"), CssSelectorParser.parse(".clearable")) {
+
+ def calculate(in: NodeSeq): Seq[NodeSeq] = Nil
+}
+
+/**
+ * This CssBind will clear all nodes marked with the class
+ * clearable. Designers can mark extra nodes in markup with
+ * class="clearable" and this Bind will make them go away
+ */
+object ClearClearable extends ClearClearable
+
+
View
51 core/util/src/test/scala/net/liftweb/util/BindHelpersSpec.scala
@@ -354,7 +354,7 @@ object CssBindHelpersSpec extends Specification {
}
"substitute a String by id" in {
- ("#foo" #> "hello")(<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
+ ("#foo" #> "hello") apply (<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
}
@@ -430,11 +430,11 @@ object CssBindHelpersSpec extends Specification {
}
"substitute a String by id" in {
- ("#foo" replaceWith "hello")(<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
+ ("#foo" replaceWith "hello") apply (<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
}
"Select a node" in {
- ("#foo ^^" #> "hello")(<div><span id="foo"/></div>) must ==/ (<span id="foo"/>)
+ ("#foo ^^" #> "hello") apply (<div><span id="foo"/></div>) must ==/ (<span id="foo"/>)
}
"Another nested select" in {
@@ -559,19 +559,19 @@ object CssBindHelpersSpec extends Specification {
"option transform on *" in {
val opt: Option[String] = None
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = ("* *" #> opt.map(ignore => "Dog")) apply (<top>cat</top>)
res.head must_== <top></top>
}
"append attribute to a class with spaces" in {
val stuff = List("a", "b")
- val res = ("* [class+]" #> stuff)(<top class="q">cat</top>)
+ val res = ("* [class+]" #> stuff) apply (<top class="q">cat</top>)
(res \ "@class").text must_== "q a b"
}
"append attribute to an href" in {
val stuff = List("&a=b", "&b=d")
- val res = ("* [href+]" #> stuff)(<top href="q?z=r">cat</top>)
+ val res = ("* [href+]" #> stuff) apply (<top href="q?z=r">cat</top>)
(res \ "@href").text must_== "q?z=r&a=b&b=d"
}
@@ -614,47 +614,47 @@ object CssBindHelpersSpec extends Specification {
"option transform on *" in {
val opt: Option[Int] = Full(44)
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = "* *" #> opt.map(ignore => "Dog") apply <top>cat</top>
res must ==/ (<top>Dog</top>)
}
"option transform on *" in {
val opt: Box[String] = Empty
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = "* *" #> opt.map(ignore => "Dog") apply <top>cat</top>
res.head must_== <top></top>
}
"option transform on *" in {
val opt: Box[Int] = Some(44)
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = "* *" #> opt.map(ignore => "Dog") apply <top>cat</top>
res must ==/ (<top>Dog</top>)
}
"transform on *" in {
- val res = ("* *" #> "Dog")(<top>cat</top>)
+ val res = "* *" #> "Dog" apply <top>cat</top>
res must ==/ (<top>Dog</top>)
}
"transform child content on *+" in {
- val res = ("* *+" #> "moose")(<a>I like </a>)
+ val res = "* *+" #> "moose" apply <a>I like </a>
res.text must_== "I like moose"
}
"transform child content on -*" in {
- val res = ("* -*" #> "moose")(<a> I like</a>)
+ val res = "* -*" #> "moose" apply <a> I like</a>
res.text must_== "moose I like"
}
"transform on li" in {
- val res = ("li *" #> List("Woof", "Bark") & ClearClearable)(
- <ul><li>meow</li><li class="clearable">a</li><li class="clearable">a</li></ul>)
+ val res = "li *" #> List("Woof", "Bark") & ClearClearable apply
+ <ul><li>meow</li><li class="clearable">a</li><li class="clearable">a</li></ul>
res must ==/ (<ul><li>Woof</li><li>Bark</li></ul>)
}
"substitute multiple Strings by id" in {
- (("#foo" replaceWith "hello") &
- ("#baz" replaceWith "bye"))(<b><div id="baz">Hello</div><span id="foo"/></b>) must ==/ (<b>{Text("bye")}{Text("hello")}</b>)
+ ("#foo" replaceWith "hello") &
+ ("#baz" replaceWith "bye") apply <b><div id="baz">Hello</div><span id="foo"/></b> must ==/ (<b>{Text("bye")}{Text("hello")}</b>)
}
"substitute multiple Strings with a List by id" in {
@@ -893,7 +893,18 @@ object CssBindHelpersSpec extends Specification {
(answer \ "a" \ "@href").text must_== "Hi"
(answer \\ "li").length must_== 0
}
-
+
+ "bind something implicity convertable to a String" in {
+ class X
+ implicit def X2str(x: X): String = "This is X"
+ implicitly[X => String] apply new X must_== "This is X"
+ (implicitly[X => StringPromotable] apply new X toString) must_== "This is X"
+ val s: String = new X
+ s must_== "This is X"
+ val sp: StringPromotable = new X
+ sp.toString must_== "This is X"
+ ("foo" #> new X apply <foo/> text) must_== "This is X"
+ }
}
}
@@ -908,6 +919,12 @@ object CheckTheImplicitConversionsForToCssBindPromoter {
import BindHelpers._
+ implicitly[CanBind[NodeSeq]]
+ implicitly[CanBindN[Iterable[NodeSeq]]]
+ implicitly[CanBindN[NodeSeq => Iterable[NodeSeq]]]
+ implicitly[CanBindN[NodeSeq => Seq[Node]]]
+ implicitly[CanBind[NodeSeq => String]]
+
"foo" #> "baz"
bog #> "Hello"
View
2  web/webkit/src/main/scala/net/liftweb/http/StatefulSnippet.scala
@@ -113,7 +113,7 @@ trait StatefulSnippet extends DispatchSnippet {
if (formElem.isDefined) {
import util.Helpers._
- ("form *" #> ((kids: NodeSeq) => toMerge ++ kids))(res)
+ "form *" #> ((kids: NodeSeq) => toMerge ++ kids) apply res
} else if (isForm) {
toMerge ++ res
} else {
View
4 web/webkit/src/main/scala/net/liftweb/http/js/JsCommands.scala
@@ -615,7 +615,7 @@ trait HtmlFixer {
import scala.collection.mutable.ListBuffer
val lb = new ListBuffer[JsCmd]
- val revised = ("script" #> ((ns: NodeSeq) => {
+ val revised = "script" #> ((ns: NodeSeq) => {
ns match {
case FindScript(e) => {
lb += JE.JsRaw(ns.text).cmd
@@ -623,7 +623,7 @@ trait HtmlFixer {
}
case x => x
}
- }))(xhtml)
+ }) apply xhtml
S.htmlProperties.htmlWriter(Group(revised), w)

No commit comments for this range

Something went wrong with that request. Please try again.