Designer Friendly Templates

Lift 2.2-M1 introduces designer-friendly HTML templates.All Lift templates can be fully valid XHTML or HTML5 with no extra namespaces, yet retain all of Lift’s features.The enhancements to Lift include:

Before 2.2-M1, a typical Lift template looked like:

<lift:surround with="default" at="content"> 
  <h2>Welcome to your project!</h2> 
  <p> 
    <lift:HelloWorld.howdy> 
      <span class="my_class">Welcome to app at<b:time/></span> 
    </lift:HelloWorld.howdy> 
  </p> 
</lift:surround>

The <lift:surround> tag invoked the “surround” snippet which surrounds the content of the template with the template page chrome.The <lift:surround> and <lift:HelloWorld.howdy> tags invoke snippets, but these tags are not valid XHTML or HTML5 without declaring the separate “lift” namespace.

Instead, we can invoke snippets via the class attribute on nodes.For example:

<div class="lift:surround?with=default;at=content"> 
  <h2>Welcome to your project!</h2> 
  <p> 
    <span class="my_class lift:HelloWorld.howdy"> 
      <span>Welcome to app at<b:time/></span> 
    </span> 
  </p> 
</div>

We’re almost to the point where we’ve removed new namespaces from the template . Here’s the Scala code for HelloWorld:

class HelloWorld { 
  def howdy(in: NodeSeq): NodeSeq = 
    Helpers.bind("b", in, "time" ->Helpers.formattedTimeNow) 
} 

Using CSS Selector Transforms, HelloWorld becomes:

class HelloWorld { 
  def howdy = ".time" #>Helpers.formattedTimeNow 
} 

And the template becomes:

<div class="lift:surround?with=default;at=content"> 
  <h2>Welcome to your project!</h2> 
  <p> 
    <span class="my_class lift:HelloWorld.howdy"> 
      <span>Welcome to app at<span class="time">no time like the present</span></span> 
    </span> 
  </p> 
</div>

Thus, we’ve eliminated the extra namespaces.We’re well on our way to having a single file in the source repository that can be opened in a browser, opened and edited by designers and coders alike.

We still can’t load the page into our browser because it doesn’t have an <html> or <body> tag… so, we have to find a way to put this chrome around the page, but have Lift dynamically replace the chrome using the surround mechanism.

So, we want our template file to look like:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
	<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
	<title>Home</title>
  </head>
  <body>
    <div class="lift:surround?with=default;at=content">
      <h2>Welcome to your project!</h2>
      <p>
        <span class="lift:helloWorld.howdy">
          Welcome to your Lift app at<span id="time">Time goes here</span>
        </span>
      </p>
    </div>
  </body>
</html>

But how do we get the surround functionality and do away with the boilerplate chrome… mark the actual root element with an id, for example “real_content” and put the following class in the body tag:lift:content_id=real_content , so the template looks like:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
  <head>
	<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
	<title>Home</title>
  </head> 
  <body class="lift:content_id=real_content"> 
    <div class="lift:surround?with=default;at=content" id="real_content"> 
      <h2>Welcome to your project!</h2> 
      <p> 
        <span class="lift:helloWorld.howdy"> 
          Welcome to your Lift app at<span id="time">Time goes here</span> 
        </span> 
      </p> 
    </div> 
  </body> 
</html>

And now we’ve got a template that’s completely valid and contains all the Lift logic, but is designer friendly.