[Lift] Re: Javascript and Lift, what should go where.
Hi, Lift's abstractions on JS stuff are very useful as you can compose JS expressions very easily etc. However I would not recommend using JsExp/ JsCmd to generate large JS code because the Scala code would get quite big. But you can build you JS objects/function in your own JS file and from Ajax functions you build short expressions that calls your JS code etc. Br's, Marius On Jan 8, 9:07 am, timshawn tim.sh...@gmail.com wrote: Hi there, I'm currently playing with Lift, and one of the things that surprised me was how much Javascript code is in Scala for snippets and bind. I'm not saying this is bad, because I haven't done an app this way yet, but I'm more used to writing the JS myself using jQuery or some other library. I can certainly understand that but sometime it is so convenient to write a small Scala code using Lift's JS abstractions and have the intended result. I'm wondering if anyone has had more experience working with Lift and maintaining an app in it, to say when in their opinion is a good time to put things in JS or in Scala snippets, and the advantages and disadvantages of putting most of the JS in snippets. (would you mostly use it for Ajax callbacks and comet-related stuff, or would you do a lot more stuff like hide/unhiding elements, etc. in scala?) Actually both I'd say (depending on the situations) as long as the Scala code for generating JsExp/JsCmd is reasonably small. The one thing I can think of is Scala's type safety, but when for example, I accidentally change an HTML node's id and there is a JSCmd to trigger behaviour on that, there won't be JS errors, but the right/expected behaviour won't happen either. Well accidents are accidents and IMO this is an application specific concern and not a framework concern. I mean regardless if the JS code come from JsCmd/JsExp or plain Javascript from .js files consistency between markup and JS code should be ensured to have expected behaviors. Thanks, Tim --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: accessing the attributes of the XML node associated with a FuncBindParam in bind(...)
On Jan 8, 7:54 pm, 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. Major typo and I think this is the case. = and I think this is NOT the case.. Sorry. Thoughts? 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.cxmarc%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
[Lift] Re: Javascript and Lift, what should go where.
Tim, On Wed, Jan 7, 2009 at 11:07 PM, timshawn tim.sh...@gmail.com wrote: Hi there, I'm currently playing with Lift, and one of the things that surprised me was how much Javascript code is in Scala for snippets and bind. Hmmm... bind() doesn't generate any JavaScript and snippets are typically ways to insert server-generated code. Lift does have a lot of helper methods, mostly in SHtml, that do attach JavaScript to the HTML elements the generate. I'm not saying this is bad, because I haven't done an app this way yet, but I'm more used to writing the JS myself using jQuery or some other library. Except for Lift's Comet support (when you include a CometActor), Lift only inserts JavaScript into the elements that you explicitly ask it to. Some people I'm wondering if anyone has had more experience working with Lift and maintaining an app in it, to say when in their opinion is a good time to put things in JS or in Scala snippets, and the advantages and disadvantages of putting most of the JS in snippets. (would you mostly use it for Ajax callbacks and comet-related stuff, or would you do a lot more stuff like hide/unhiding elements, etc. in scala?) I put any business logic in my Scala code. If the JavaScript helps express the business logic, then it it belongs in the Scala or bound very tightly to the Scala code. In general, I think of JavaScript as assembly language and I try to abstract it as much as possible. The one thing I can think of is Scala's type safety, but when for example, I accidentally change an HTML node's id and there is a JSCmd to trigger behaviour on that, there won't be JS errors, but the right/expected behaviour won't happen either. That's why Lift's helpers are useful as they assign the id and tie the behavior to the generated id. A number of Lift users (Charles Munat comes to mind) have cloned the Lift libraries and modified them to suit particular coding styles. I love looking at their code (especially Charles') because it helps me find the best ideas to roll back into Lift. In this way, the community becomes involved in the whole Lift growth process. So, please learn some Lift and add your style into the mix. Thanks, David Thanks, Tim -- 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 -~--~~~~--~~--~--~---
[Lift] Re: accessing the attributes of the XML node associated with a FuncBindParam in bind(...)
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 marc%2blift...@boschma.cx marc%252blift...@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
[Lift] Re: Javascript and Lift, what should go where.
Thanks. I'll play around more. Do you guys think it'll be a good idea to have a collection of people's github repos with lift code from the mailing list if they have it public? The examples for lift-core code were very useful for my learning. On Thu, Jan 8, 2009 at 10:07 AM, David Pollak feeder.of.the.be...@gmail.com wrote: Tim, On Wed, Jan 7, 2009 at 11:07 PM, timshawn tim.sh...@gmail.com wrote: Hi there, I'm currently playing with Lift, and one of the things that surprised me was how much Javascript code is in Scala for snippets and bind. Hmmm... bind() doesn't generate any JavaScript and snippets are typically ways to insert server-generated code. Lift does have a lot of helper methods, mostly in SHtml, that do attach JavaScript to the HTML elements the generate. I'm not saying this is bad, because I haven't done an app this way yet, but I'm more used to writing the JS myself using jQuery or some other library. Except for Lift's Comet support (when you include a CometActor), Lift only inserts JavaScript into the elements that you explicitly ask it to. Some people I'm wondering if anyone has had more experience working with Lift and maintaining an app in it, to say when in their opinion is a good time to put things in JS or in Scala snippets, and the advantages and disadvantages of putting most of the JS in snippets. (would you mostly use it for Ajax callbacks and comet-related stuff, or would you do a lot more stuff like hide/unhiding elements, etc. in scala?) I put any business logic in my Scala code. If the JavaScript helps express the business logic, then it it belongs in the Scala or bound very tightly to the Scala code. In general, I think of JavaScript as assembly language and I try to abstract it as much as possible. The one thing I can think of is Scala's type safety, but when for example, I accidentally change an HTML node's id and there is a JSCmd to trigger behaviour on that, there won't be JS errors, but the right/expected behaviour won't happen either. That's why Lift's helpers are useful as they assign the id and tie the behavior to the generated id. A number of Lift users (Charles Munat comes to mind) have cloned the Lift libraries and modified them to suit particular coding styles. I love looking at their code (especially Charles') because it helps me find the best ideas to roll back into Lift. In this way, the community becomes involved in the whole Lift growth process. So, please learn some Lift and add your style into the mix. Thanks, David Thanks, Tim -- 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 -- Timothy Wee 612-889-1185 http://greystark.blogspot.com --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] What tags cannot be open/close in IE?
Folks, IE barfs on br/br (it treats them as 2 BR tags). What other tags are in this category in IE? Thanks, David -- 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 -~--~~~~--~~--~--~---
[Lift] Google syntax highlighter on the Lift site
I apologize if this is not the right place, but I noticed that you have the Google code formatter installed on the Lift site. http://liftweb.net/index.php/Lift_View_First http://code.google.com/p/syntaxhighlighter/wiki/Usage Given that it's a MediaWiki site, how did you get the pages to include the Javascript references? Did you use and extension? http://www.mediawiki.org/wiki/Extension:Javascript --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Javascript and Lift, what should go where.
David Pollak wrote: A number of Lift users (Charles Munat comes to mind) have cloned the Lift libraries and modified them to suit particular coding styles. I love looking at their code (especially Charles') because it helps me find the best ideas to roll back into Lift. And I here I thought it was just so you could laugh at my lousy grasp of functional programming... :-) Chas. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[Lift] Re: Javascript and Lift, what should go where.
On Thu, Jan 8, 2009 at 1:34 PM, Charles F. Munat c...@munat.com wrote: David Pollak wrote: A number of Lift users (Charles Munat comes to mind) have cloned the Lift libraries and modified them to suit particular coding styles. I love looking at their code (especially Charles') because it helps me find the best ideas to roll back into Lift. And I here I thought it was just so you could laugh at my lousy grasp of functional programming... :-) S... I asked you not to mention that... ;-) Chas. -- 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 -~--~~~~--~~--~--~---
Build problem. Was: Re: [Lift] Re: accessing the attributes of the XML node associated with a FuncBindParam in bind(...)
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
Re: Build problem. Was: Re: [Lift] Re: accessing the attributes of the XML node associated with a FuncBindParam in bind(...)
Marc, Sorry... dunno what to tell you. :-( David On Thu, Jan 8, 2009 at 3:47 PM, Marc Boschma marc+lift...@boschma.cxmarc%2blift...@boschma.cx wrote: 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