Very cool indeed, except... I now get: [WARNING] /Users/marc/src/todo/src/main/scala/com/liftworkshop/snippet/ TD.scala:99: error: value attr is not a member of object net.liftweb.util.BindHelpers [WARNING] val singular = BindHelpers.attr("singular", {s: String => s.toLowerCase match { [WARNING] ^ [WARNING] one error found
I've cleaned out my .m2/repository and I always mvn -U clean install... No proxies in place. Usually works a charm. Frustrating as hell - I feel for those that actually make a living in the Java/Maven world (must make a mental note to not quibble so much on what those who do want to get paid :) Thoughts? Marc The full context of the code for those interested (David's todo app modified thus): (The top of the file has import net.liftweb._ and import util._) private def doList(reDraw: () => JsCmd)(html: NodeSeq): NodeSeq = { val singular = BindHelpers.attr("singular", {s: String => s.toLowerCase match { case "" => true case "true" => true case "t" => true case "yes" => true case "y" => true case _ => false}}, false) val l = toShow if (singular) l.flatMap(td => bind("todo", html, "check" -> ajaxCheckbox(td.done, v => {td.done(v).save; reDraw()}), "priority" -> ajaxSelect(ToDo.priorityList, Full(td.priority.toString), v => {td.priority(v.toInt).save; reDraw()}), "desc" -> desc(td, reDraw) )) else { val xhtmls = template(html, l.length) l.zip(xhtmls).flatMap(n => { val (td , xhtml) = n bind("todo", xhtml, "check" -> ajaxCheckbox(td.done, v => {td.done(v).save; reDraw()}), "priority" -> ajaxSelect(ToDo.priorityList, Full(td.priority.toString), v => {td.priority(v.toInt).save; reDraw()}), "desc" -> desc(td, reDraw) )}) } } private def template(html: NodeSeq, i: Int): List[NodeSeq] = expand(nodeSeq2List(html), i) private def nodeSeq2List(html: NodeSeq): List[NodeSeq] = { val es = html.elements.toList.filter(_ match { case Text(s) if (s.trim.length == 0) => false // remove whitespace text case _ => true }) es match { // it was just white space, return it case Nil => List(html) // are all the nodes the same (prefix == lift)? // this allows the use of different snippets as the different templates... case x :: xs if (x.prefix == "lift" && xs.foldLeft(true)( (t, n) => (t && n.prefix == x.prefix) )) => es // are all the nodes the same (prefix, label)? case x :: xs => { if (xs.foldLeft(true)( (t, n) => (t && n.prefix == x.prefix && n.label == x.label) )) es else List(html) // nope, return origional sequence... } } } // duplicate a list until it is at least as long as *i* private def expand(xhtmls: List[NodeSeq], i: Int): List[NodeSeq] = if (i > 0) expand(xhtmls ::: xhtmls, i - xhtmls.length) else xhtmls On 09/01/2009, at 5:08 AM, David Pollak wrote: > > > On Thu, Jan 8, 2009 at 9:54 AM, Marius <marius.dan...@gmail.com> > wrote: > > Ok, I just committed the updates. Now both BindHelpers.attr and S.attr > implement AttrHelpers trait where we have a bunch of overloaded apply, > > I would have liked to use Option[NodeSeq] for S.attr as well but this > would be a breaking change and breaking changes are frozen now. So > S.attr("someparam") still returns a Box[String]. However I added 2 > helper function ~ that would return Option[NodeSeq], so you can call > S.attr ~("someparam") and get back an Option[NodeSeq]. > > I know we could have used implicits to convert from Box[String] to > Option[NodeSeq] but I feel that this would be an abuse of implicits as > the use of implicits IMHO should be motivated byt strong design > rationales and I think this is the case. > > Thoughts? > > Very cool! > > > > Br's, > Marius > > On Jan 7, 7:40 pm, Marius <marius.dan...@gmail.com> wrote: > > I'll look into it. > > > > On Jan 7, 7:38 pm, "David Pollak" <feeder.of.the.be...@gmail.com> > > wrote: > > > > > Marc, > > > > > Good suggestion. Marius -- do you want to do this... maybe even > turn the > > > pattern into a trait that we can apply over and over? > > > > > Thanks, > > > > > David > > > > > On Tue, Jan 6, 2009 at 9:57 PM, Marc Boschma > > > <marc+lift...@boschma.cx<marc%2blift...@boschma.cx> > > > > > > wrote: > > > > Cool code! Works nicely... > > > > Would it make sense to also add something similar to this from > S.attr ? > > > > > > def apply[T](what: String, f: String => T, default: => T): T > > > > = apply(what).map(f) openOr default > > > > > > ie maybe: > > > > > > def apply[T](prefix: String, key: String, f: String => T): > Option[T] > > > > = apply(prefix, key).map(f) > > > > def apply[T](key: String, f: String => T): Option[T] = > apply(key).map(f) > > > > > > to BindHelpers.attr ? > > > > > > Thinking about it should the applys of the two attr objects be > aligned > > > > (Option verses Box, etc) ? It would make the crafting of > snippets and bind > > > > functions in terms of access to attributes the same, dropping > a potential > > > > barrier to learning lift... > > > > > > ie Maybe BindHelpers.attr should have applys with the following > > > > signatures... > > > > > > def apply(key: String): Box[String] > > > > def apply(prefix: String, key: String): Box[String] > > > > > > def apply(key: String, default: => String): String > > > > def apply(prefix: String, key: String, default: => > String): String > > > > > > def apply[T](key: String, f: String => T, default: => T): T > > > > def apply[T](prefix: String, key: String, f: String => T, > default: => > > > > T): T > > > > > > Lastly, and maybe I am missing something here, but I take it > for a snippet > > > > a prefixed attribute isn't accessible via S.attr ??? > > > > > > Regards, > > > > > > Marc > > > > > > On 07/01/2009, at 6:54 AM, David Pollak wrote: > > > > > > On Tue, Jan 6, 2009 at 11:16 AM, Marius > <marius.dan...@gmail.com> wrote: > > > > > >> Ok ... i just committed some changes: > > > > > >> 1. Renamed curAttr to attr > > > >> 2. The BindHelpers vals are now private but we expose two > functions > > > >> currentNode and bindNodes > > > > > > Cool beans! > > > > > >> Br's, > > > >> Marius > > > > > >> On Jan 6, 8:37 pm, "David Pollak" > <feeder.of.the.be...@gmail.com> > > > >> wrote: > > > >> > On Tue, Jan 6, 2009 at 10:28 AM, Marius > <marius.dan...@gmail.com> > > > >> wrote: > > > > > >> > > On Jan 6, 7:15 pm, "David Pollak" > <feeder.of.the.be...@gmail.com> > > > >> > > wrote: > > > >> > > > I also added > > > >> > > > BindHelpers.attr("tag"): Option[NodeSeq] > > > >> > > > so you can do something like: > > > > > >> > > > <span class={BindHelpers.attr("class")>...</span> > > > > > >> > > > and: > > > >> > > > BindHelpers.attr("prefix", "tag") > > > > > >> > > I think it is committed to curAttr which personally I'm > not a fan ... > > > >> > > Doyou mind if I change it to attr or nodeAttr ? > > > > > >> > Go for it. > > > > > >> > > > Thanks, > > > > > >> > > > David > > > > > >> > > > On Tue, Jan 6, 2009 at 9:13 AM, Marius > <marius.dan...@gmail.com> > > > >> wrote: > > > > > >> > > > > Very cool Dave ! > > > > > >> > > > > thx, > > > >> > > > > Marius > > > > > >> > > > > On Jan 6, 4:36 pm, "David Pollak" > <feeder.of.the.be...@gmail.com> > > > >> > > > > wrote: > > > >> > > > > > Folks, > > > > > >> > > > > > I'm about to commit up a non-breaking solution. > > > > > >> > > > > > In bind, you can call: > > > >> > > > > > BindHelpers.bindNodes.value: List[NodeSeq] > > > >> > > > > > BindHelpers.currentNode.value: Elem > > > > > >> > > > > > bindNodes is a list of the nodes that were passed > into bind with > > > >> the > > > >> > > more > > > >> > > > > > current node at the head of the list. If you're > doing > > > >> hierarchical > > > >> > > > > binding, > > > >> > > > > > you can see all the nodes that were passed into > bind this was. > > > > > >> > > > > > currentNode is available to the BindParam and it > contains the > > > >> parent > > > >> > > Elem > > > >> > > > > to > > > >> > > > > > the NodeSeq that was passed into your BindParam. > You can > > > >> inspect > > > >> > > > > attributes > > > >> > > > > > to your heart's content. > > > > > >> > > > > > Give it an hour or two for these changes to make > their way > > > >> through > > > >> > > > > Hudson. > > > > > >> > > > > > Thanks, > > > > > >> > > > > > David > > > > > >> > > > > > On Tue, Jan 6, 2009 at 4:50 AM, Marc Boschma > > > >> > > > > > <marc+lift...@boschma.cx <marc > %2blift...@boschma.cx> < > > > >> marc%2blift...@boschma.cx <marc%252blift...@boschma.cx>> < > > > >> > > marc%2blift...@boschma.cx <marc%252blift...@boschma.cx> < > > > >> marc%252blift...@boschma.cx <marc%25252blift...@boschma.cx>>>< > > > >> > > > > marc%2blift...@boschma.cx <marc > %252blift...@boschma.cx> < > > > >> marc%252blift...@boschma.cx <marc%25252blift...@boschma.cx>> < > > > >> > > marc%252blift...@boschma.cx <marc > %25252blift...@boschma.cx> < > > > >> marc%25252blift...@boschma.cx <marc > %2525252blift...@boschma.cx>>>> > > > > > >> > > > > > > wrote: > > > > > >> > > > > > > I've just had a thought as to how to make it not > a breaking > > > >> change. > > > > > >> > > > > > > Leave your change "calcValue(s.child) I just call > > > >> calcValue(s)" > > > > > >> > > > > > > change: > > > >> > > > > > > case class FuncBindParam(name: String, value: > NodeSeq => > > > >> NodeSeq) > > > >> > > > > > > extends Tuple2(name, value) with BindParam { > > > >> > > > > > > def calcValue(in: NodeSeq): NodeSeq = value(in) > > > >> > > > > > > } > > > > > >> > > > > > > to: > > > >> > > > > > > case class FuncBindParam(name: String, value: > NodeSeq => > > > >> NodeSeq) > > > >> > > > > > > extends Tuple2(name, value) with BindParam { > > > >> > > > > > > def calcValue(in: NodeSeq): NodeSeq = > value(in.child) > > > >> > > > > > > } > > > > > >> > > > > > > That should prevent old code breaking... which > would be a good > > > >> > > > > > > thing(tm) given the amount of code that uses > bind(...) > > > > > >> > > > > > > then create something like: > > > > > >> > > > > > > case class FuncMetaDataBindParam(name: String, > value: > > > >> (MetaData, > > > >> > > > > > > NodeSeq) => NodeSeq) extends Tuple2(name, value) > with > > > >> BindParam { > > > >> > > > > > > def calcValue(in: NodeSeq): NodeSeq = > value(in.attributes, > > > >> > > > > > > in.child) > > > >> > > > > > > } > > > > > >> > > > > > > along with adding to class SuperArrowAssoc... > > > >> > > > > > > def ->(in: (MetaData, NodeSeq) => NodeSeq) = > > > >> > > > > > > FuncMetaDataBindParam(name, in) > > > > > >> > > > > > > That would be fairly clean... > > > > > >> > > > > > > ----- > > > > > >> > > > > > > Maybe for those that actually want the full node > add: > > > > > >> > > > > > > case class FuncBoxBindParam(name: String, value: > > > >> Box(NodeSeq) => > > > >> > > > > > > NodeSeq) extends Tuple2(name, value) with > BindParam { > > > >> > > > > > > def calcValue(in: NodeSeq): NodeSeq = > value(Full(in)) > > > >> > > > > > > } > > > > > >> > > > > > > and you could go nuts and: > > > > > >> > > > > > > case class FuncPrefixAndLabelBindParam(name: > String, value: > > > >> > > > > > > (String, String, NodeSeq) => NodeSeq) extends > Tuple2(name, > > > >> value) > > > >> > > with > > > >> > > > > > > BindParam { > > > >> > > > > > > def calcValue(in: NodeSeq): NodeSeq = > value(in.prefix, > > > >> > > in.label, > > > >> > > > > > > in.child) > > > >> > > > > > > } > > > > > >> > > > > > > etc... > > > > > >> > > > > > > On 06/01/2009, at 10:51 PM, Marc Boschma wrote: > > > > > >> > > > > > > > (you can tel I'm sleeping well :/ - too hot) > > > > > >> > > > > > > > The toList function is one of David's (todo > example app). I > > > >> do > > > >> > > love > > > >> > > > > > > > the ability to curry :) > > > > > >> > > > > > > > Marc > > > >> > > > > > > > On 06/01/2009, at 9:51 PM, Marius wrote: > > > > > >> > > > > > > >> On Jan 6, 12:47 pm, Marc Boschma <marc > +lift...@boschma.cx<marc%2blift...@boschma.cx> > > > >> <marc%2blift...@boschma.cx <marc%252blift...@boschma.cx>> > > > >> > > <marc%2blift...@boschma.cx <marc%252blift...@boschma.cx> < > > > >> marc%252blift...@boschma.cx <marc%25252blift...@boschma.cx>>> > > > >> > > > > <marc%2blift...@boschma.cx <marc > %252blift...@boschma.cx> < > > > >> marc%252blift...@boschma.cx <marc%25252blift...@boschma.cx>> < > > > >> > > marc%252blift...@boschma.cx <marc > %25252blift...@boschma.cx> < > > > >> marc%25252blift...@boschma.cx <marc > %2525252blift...@boschma.cx>>>>> > > > >> > > > > > > wrote: > > > >> > > > > > > >>> A quick just before going to bed reaction is > that your > > > >> change > > > >> > > would > > > >> > > > > > > >>> solve the issue. > > > > > >> > > > > > > >> Yeah it would ... (I mean it worked fine in my > tests) > > > > > >> > > > > > > >>> It is interesting you focused on the > "exclude" and not the > > > >> > > > > > > >>> "list" (which is what I have been playing > with). I > > > >> actually > > > >> > > missed > > > >> > > > > > > >>> it > > > >> > > > > > > >>> was a similar case... > > > > > >> > > > > > > >> I just picked it randomly :) ... I've seen > that you're > > > >> using a > > > >> > > > > > > >> partially applied function doList ... (which I > assume it is > > > >> a > > > >> > > > > curried > > > >> > > > > > > >> function):) > > > > > >> > > > > > > >>> Regards, > > > > > >> > > > > > > >>> Marc > > > > > >> > > > > > > >>> On 06/01/2009, at 9:24 PM, Marius wrote: > > > > > >> > > > > > > >>>> I just did a minor modification to the lift > code so the > > > >> actual > > > >> > > > > > > >>>> node it > > > >> > > > > > > >>>> is passed to the BindParam and not its > child. Now having: > > > > > >> > > > > > > >>>> bind("todo", html, > > > >> > > > > > > >>>> "exclude" -> {node:NodeSeq > > > >> =>ajaxCheckbox > > > >> > > > > > > >>>> (QueryNotDone, v => {QueryNotDone(v); > reDraw})} > > > >> > > > > > > >>>> ... ) > > > > > >> > > > > > > >>>> and the markup <todo:exclude param="Dumb"/> > > > > > >> > > > > > > >>>> The node parameter to the anonymous function > will be the > > > >> > > > > > > >>>> <todo:exclude> node and not its children. So > now you can > > > >> > > access > > > >> > > > > the > > > >> > > > > > > >>>> "param" attribute from node. The change was > in in_bind > > > >> > > function so > > > >> > > > > > > >>>> instead of calling calcValue(s.child) I just > call > > > >> calcValue(s) > > > > > >> > > > > > > >>>> Looking at the existent BindParams this > change does not > > > > ... > > > > read more ยป > > > > > -- > Lift, the simply functional web framework http://liftweb.net > Collaborative Task Management http://much4.us > Follow me: http://twitter.com/dpp > Git some: http://github.com/dpp > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Lift" group. To post to this group, send email to liftweb@googlegroups.com To unsubscribe from this group, send email to liftweb+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/liftweb?hl=en -~----------~----~----~----~------~----~------~--~---