Accessing bind-at values from a snippet in Lift - scala

I have a template that looks like this:
<lift:surround name="default" at="page-content">
<lift:bind-at name="page-title">Home</lift:bind-at>
...
</lift:surround>
The default template looks like this:
<html>
<head>
<title>Title Prefix | </title>
</head>
<body>
<h1><lift:bind name="page-title" /></h1>
<div id="page-content">
<lift:bind name="page-content" />
</div>
</body>
</html>
I want to use a snippet to replace the <title> content with a string that combines "Title Prefix" and the value of <lift:bind-at name="page-title"> (ie: "Home"). I want to contine to use that same value inside the <h1> in the <body>
How can I access a bind-at value from within a snippet that's used in the surrounding template?

I don't believe you can do what you are looking to do with bind-at directives, or at least, I haven't found a way. You should be able to use a snippet to accomplish something similar though.
For example, if you are using SiteMap, the following should be roughly equivalent.
class TitleSnippet {
//Store the value in a requestVar
private var titleVar:String = ""
def first = {
//Retrieve the title for the current Loc as defined in the Sitemap
val locTitle = for (request <- S.request;
loc <- request.location) yield loc.title
//Retrieve the text portion of the tag, and append it to the sitemap title.
//If no sitemap title exists, just display the text
"* *" #> { ns =>
val myTitle = locTitle.map{ t =>
"%s | %s".format(ns.text, t)
} openOr ns.text
titleVar = myTitle
Text(myTitle)
}
}
def title = {
"* *" #> titleVar
}
}
Then, in your template, all you'd have to do is say:
<title data-lift="TitleSnippet.first">Home</title>
So, if we had a page defined like this in the sitemap:
Menu("Sub Page 1") / "subpage"
If everything worked, you should see a title like: <title>Home | Sub Page 1</title> and if you need it elsewhere on the page, all you would have to do is: <h1 data-lift="TitleSnippet.title"></h1>.
If you need access from other snippets, you can also break out titleVar into a companion object and use a RequestVar.

Related

Replace line break

In Fluid Template and tx_news, I need to replace line breaks with "\n" for passing into JavaScript function.
If a JavaScript string contains line break, console will print "Unexpected token."
<a onclick="doSomething('{newsItem.bodytext}');">Click me</a>
How can you replace line breaks with "\n" in this example?
AS urbantrout already wrote: you can write an own viewhelper in PHP.
But you also can use a TypoScript-Viewhelper:
<a onclick="doSomething('{newsItem.bodytext -> f:cObject(typoscriptObjectPath: \'lib.nlReplace\')}');">Click me</a>
(as you are in a string you need to escape the inner ')
and some TypoScript like
lib.nlReplace = TEXT
lib.nlReplace {
current = 1
stdWrap.replacement {
1 {
search = #\n#
replace = \\n
useRegExp = 1
}
}
}
You could write your own ViewHelper and use it like this:
{namespace ns=Vendor\ExtensionName\ViewHelpers}
<a onclick="doSomething('{newsItem.bodytext -> ns:viewhelperName()}');">Click me</a>
More infos here: Developing a custom ViewHelper

Why doesn't this pass multiple HTML parameters to template

I know about this and this, but the answers are very strange, and in any case, I am looking to understand why this particular approach does not work:
#myPackage.views.html.ol(
{
Hello
}, {
World
}
)
myPackage.views.html.ol.scala.html
#(ol:Html*)
<ol>
#for(li <- ol) {
<li>
(hi)
<span class="li-body">#li</span>
</li>
}
</ol>
Error:
not found: value Hello
I must lack fundamental understanding about the rules of the template engine, because this seems intuitively correct to me.
The # character marks the beginning of a dynamic statement, so you are no longer in template syntax. It's trying to interpret the arguments to the ol() function as straight Scala/Java code, not the template syntax.
It depends on what exactly you're trying to do, but here are two ways to do it. You could probably also use the #defining helper.
#myPackage.views.html.ol(Html("Hello"), Html("World"))
Another way is to define the Html blocks at the beginning of your view.
#html1 = { Hello }
#html2 = { <strong>World</strong> }
#main(){
#myPackage.views.html.ol(html1, html2)
}
estimatic's answer was correct.
Of what he presented, I would probably have used the #html1 = ... solution, but I found something else, which I hope will benefit some future reader.
HtmlVarArgs.scala
import play.api.templates.Html
import scala.collection.mutable.ListBuffer
class HtmlVarArgs(html: Html) {
private val templates = ListBuffer(html)
def apply(html: Html) = {
templates += html
this
}
def passTo(f: Seq[Html] => Html) = f(templates)
}
object HtmlVarArgs {
def apply(html: Html) = new HtmlVarArgs(html)
}
ol.scala.html
myPackage.views.html.ol.scala.html
#(ol:Html*)
<ol>
#for(li <- ol) {
<li>
(hi)
<span class="li-body">#li</span>
</li>
}
</ol>
And then I can use it in a template as follows:
#HtmlVarArgs {
Hello
} {
World
}.passTo(myPackage.views.html.ol.apply)

How Do I Access A Snippet Option In Lift?

If I have a template like this:
<div class="lift:ThisIsMySnippet?option1=a_value;option2=another_value">
<div class="morestuff">
{embed}
</div>
</div>
and then a snippet like this:
class ThisIsMySnippet {
// I want option1's value!
}
How do I get those values?
I believe you can get the param values of a snippet via the S object like this:
val x = S.attr("option1")
In this case, x will be a Box[String], so if you want to get the value in a safe way you could do this:
val x = S.attr("option1") openOr "defaultValue"

How can I set dynamically the parameter of a lift snippet?

Is there a way I can modify dynamically the param of a snippet?
E.g. If I call this URL
host:port/a_page?name=myname
I would like that my page look like this:
<div class="lift:surround?with=default;at=content">
<div class="lift:comet?type=MySnippet;name=myname" >
...
</div>
</div>
Is that even possible? I tried using some javascript in order to extract the param from the url and putting it in the class attribute of the div but in my understanding that won't work becase the scripts will always execute after lift framework does it's magic.
Thanks in advance! Any help is really appreciated.
I used both tips provided to make it work, like ajantis mentioned reading the param directly from snippet is the easiest way but doesnt work in a comet call. Rogach solution works.
So the solution is:
<div class="lift:Ex.wrap">
<div id="myid"></div>
</div>
def wrap = {
val name = "lift:comet?type=MySnippet;name=" + S.param("name").openOr("...")
"#myid" #> <div id="myid" class={name} ></div>
}
Why not just extract http parameter inside snippet processing? i.e.
def render = {
val name = S.param("name").openOr("...")
....
}
You can try wrapping that comet snippet in other snippet, which would transform xml and add that name=myname to class. Like:
<div class="lift:Ex.wrap">
<div class="lift:comet?type=MySnippet"></div>
</div>
class Ex {
def wrap = { (n: NodeSeq) =>
// example transformation
// AntiXML syntax
import com.codecommit.antixml._;
val comet = n \ "div" head;
val comet2 =
comet.copy(attrs = comet.attrs +
("class" -> (comet.attrs("class") + ";name=myname")))
n \ "div" updated (0, comet2) unselect
}
}

Scala NodeSeq reduce/foldLeft with newlines

Assume this is pretty easy but having a hard time printing out NodeSeq of html tags with newlines (so when I view source in web browser, I can scan top-to-bottom)
As is, the NodeSeq is printed as one long line.
example code:
listOfPaths map ( jsNode(_) ) reduce (_++_)
def jsNode(path: String): NodeSeq =
<script type="text/javascript" src={"/static/js/"+path}></script>
So, how to get a \n at end of each node?
Thanks
This is really a job for whatever you're using to render the HTML. For example, if you're using scala.xml.PrettyPrinter, you could do something like this:
val printer = new xml.PrettyPrinter(80, 2)
val paths = List("script-1.js", "script-2.js")
val header = <head>{paths map ( jsNode(_) ) reduce (_++_)}</head>
Now when you call printer.format(header), you'll get the following:
<head>
<script type="text/javascript" src="/static/js/script-1.js"></script>
<script type="text/javascript" src="/static/js/script-2.js"></script>
</head>
Note that the first argument to the PrettyPrinter constructor specifies the page width, and the second the number of spaces to indent.
If you just want something quick and dirty, you could drop a text node between (or after) the elements:
paths map ( jsNode(_) ) reduce (_++ Text("\n") ++ _)
But the other solution is almost always preferable.