h1. Building the first screen

Now that we have built a first data model, it’s time to start to create the first page of the application. This page will just show the most recent posts, as well as a list of older posts.

Here is a mock-up of what we want to achieve:

!images/guide-mock1!

h2. <a>Bootstrapping with default data</a>

In fact, before coding the first screen we need one more thing. Working on a web application without test data is not fun. You can’t even test what you’re doing. But because we haven’t developed the contribution screens yet, we can’t populate the blog with posts ourselves. 

One way to inject default data into the blog is to load a fixture file at application load time. To do that we will create a Bootstrap Job. A Play job is something that executes itself outside of any HTTP request, for example at the application start or at specific interval using a CRON job.

Let’s create the @/yabe/app/Bootstrap.java@ job that will load a set of default data using @Fixtures@:

bc. import play.*;
import play.jobs.*;
import play.test.*;
 
import models.*;
 
@OnApplicationStart
public class Bootstrap extends Job {
 
    public void doJob() {
        // Check if the database is empty
        if(User.count() == 0) {
            Fixtures.loadModels("initial-data.yml");
        }
    }
 
}

We have annotated this Job with the <code>@OnApplicationStart</code> annotation to tell Play that we want to run this job synchronously at application start-up.

p(note). In fact this job will be run differently in DEV or PROD modes. In DEV mode, Play waits for a first request to start. So this job will be executed synchronously at the first request. That way, if the job fails, you will get the error message in your browser. In PROD mode however, the job will be executed at application start-up (synchrously with the @play run@ command) and will prevent the application from starting in case of an error.

You have to create an @initial-data.yml@ in the @yabe/conf/@ directory. You can of course reuse the @data.yml@ content that we just used for tests previously.

Now run the application using @play run@ and display the page "http://localhost:9000/":http://localhost:9000/ in the browser.

h2. <a>The blog home page</a>

This time, we can really start to code the home page.

Do you remember how the first page is displayed? First the routes file specifies that the @/@ URL will invoke the @controllers.Application.index()@ action method. Then this method calls @render()@ and executes the @/yabe/app/views/Application/index.html@ template.

We will keep these components but add code to them to load the posts list and display them.

Open the @/yabe/app/controllers/Application.java@ controller and modify the @index()@ action to load the posts list, as is:

bc. package controllers;
 
import java.util.*;
 
import play.*;
import play.mvc.*;
 
import models.*;
 
public class Application extends Controller {
 
    public static void index() {
        Post frontPost = Post.find("order by postedAt desc").first();
        List<Post> olderPosts = Post.find(
            "order by postedAt desc"
        ).from(1).fetch(10);
        render(frontPost, olderPosts);
    }
 
}

Can you see how we pass objects to the @render@ method? It will allow us to access them from the template using the same name. In this case, the variables @frontPost@ and @olderPosts@ will be available in the template.

Open the @/yabe/app/views/Application/index.html@ and modify it to display these objects:

bc. #{extends 'main.html' /}
#{set title:'Home' /}
 
#{if frontPost}
    <div class="post">
        <h2 class="post-title">
            <a href="#">${frontPost.title}</a>
        </h2>
        <div class="post-metadata">
            <span class="post-author">by ${frontPost.author.fullname}</span>
            <span class="post-date">${frontPost.postedAt.format('MMM dd')}</span>
            <span class="post-comments">
                &nbsp;|&nbsp; 
                ${frontPost.comments.size() ?: 'no'} 
                comment${frontPost.comments.size().pluralize()}
                #{if frontPost.comments}
                    , latest by ${frontPost.comments[-1].author}
                #{/if}
            </span>
        </div>
        <div class="post-content">
            ${frontPost.content.nl2br()}
        </div>
    </div>
    
    #{if olderPosts}
        <div class="older-posts">    
            <h3>Older posts <span class="from">from this blog</span></h3>
        
            #{list items:olderPosts, as:'oldPost'}
                <div class="post">
                    <h2 class="post-title">
                        <a href="#">${oldPost.title}</a>
                    </h2>
                    <div class="post-metadata">
                        <span class="post-author">
                            by ${oldPost.author.fullname}
                        </span>
                        <span class="post-date">
                            ${oldPost.postedAt.format('dd MMM yy')}
                        </span>
                        <div class="post-comments">
                            ${oldPost.comments.size() ?: 'no'} 
                            comment${oldPost.comments.size().pluralize()}
                            #{if oldPost.comments}
                                - latest by ${oldPost.comments[-1].author}
                            #{/if}
                        </div>
                    </div>
                </div>
            #{/list}
        </div>
        
    #{/if}
    
#{/if}
 
#{else}
    <div class="empty">
        There is currently nothing to read here.
    </div>
#{/else}

You can read about how this template works in the "Templates chapter":templates. Basically, it allows you to access your Java objects dynamically. Under the hood we use Groovy. Most of the pretty constructs you see (like the @?:@ operator) come from Groovy. But you don’t really need to learn Groovy to write Play templates. If you’re already familiar with another template language like JSP with JSTL you won’t be lost.

OK, now refresh the blog home page.

!images/guide3-0!

Not pretty but it works!

However you can see we have already started to duplicate code. Because we will display posts in several ways (full, full with comment, teaser) we should create something like a function that we could call from several templates. This is exactly what a Play tag does!

To create a tag, just create the new @/yabe/app/views/tags/display.html@ file. A tag is just another template. It has parameters (like a function). The @#{display /}@ tag will have two parameters: the Post object to display and the display mode which will be one of @home@, @teaser@ or @full@.

bc. *{ Display a post in one of these modes: 'full', 'home' or 'teaser' }*
 
<div class="post ${_as == 'teaser' ? 'teaser' : ''}">
    <h2 class="post-title">
        <a href="#">${_post.title}</a>
    </h2>
    <div class="post-metadata">
        <span class="post-author">by ${_post.author.fullname}</span>,
        <span class="post-date">${_post.postedAt.format('dd MMM yy')}</span>
        #{if _as != 'full'}
            <span class="post-comments">
                &nbsp;|&nbsp; ${_post.comments.size() ?: 'no'} 
                comment${_post.comments.size().pluralize()}
                #{if _post.comments}
                    , latest by ${_post.comments[-1].author}
                #{/if}
            </span>
        #{/if}
    </div>
    #{if _as != 'teaser'}
        <div class="post-content">
            <div class="about">Detail: </div>
            ${_post.content.nl2br()}
        </div>
    #{/if}
</div>
 
#{if _as == 'full'}
    <div class="comments">
        <h3>
            ${_post.comments.size() ?: 'no'} 
            comment${_post.comments.size().pluralize()}
        </h3>
        
        #{list items:_post.comments, as:'comment'}
            <div class="comment">
                <div class="comment-metadata">
                    <span class="comment-author">by ${comment.author},</span>
                    <span class="comment-date">
                        ${comment.postedAt.format('dd MMM yy')}
                    </span>
                </div>
                <div class="comment-content">
                    <div class="about">Detail: </div>
                    ${comment.content.escape().nl2br()}
                </div>
            </div>
        #{/list}
        
    </div>
#{/if}

Now using this tag we can rewrite the home page without code duplication:

bc. #{extends 'main.html' /}
#{set title:'Home' /}
 
#{if frontPost}
    
    #{display post:frontPost, as:'home' /}
    
    #{if olderPosts.size()}
    
        <div class="older-posts">
            <h3>Older posts <span class="from">from this blog</span></h3>
        
            #{list items:olderPosts, as:'oldPost'}
                #{display post:oldPost, as:'teaser' /}
            #{/list}
        </div>
        
    #{/if}
    
#{/if}
 
#{else}
    <div class="empty">
        There is currently nothing to read here.
    </div>
#{/else}

Reload the page and check that all is fine.

h2. <a>Improving the layout</a>

As you can see, the @index.html@ template extends @main.html@. Because we want to provide a common layout for all blog pages, with the blog title and authentication links, we need to modify this file.

Edit the @/yabe/app/views/main.html@ file:

bc. <!DOCTYPE html >
<html>
    <head>
        <title>#{get 'title' /}</title>		
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <link rel="stylesheet" type="text/css" media="screen" 
            href="@{'/public/stylesheets/main.css'}" />
        <link rel="shortcut icon" type="image/png" 
            href="@{'/public/images/favicon.png'}" />
    </head>
    <body>
        
        <div id="header">
            <div id="logo">
                yabe.
            </div>
            <ul id="tools">
                <li>
                    <a href="#">Log in to write something</a>
                </li>
            </ul>
            <div id="title">
                <span class="about">About this blog</span>
                <h1><a href="#">${blogTitle}</a></h1>
                <h2>${blogBaseline}</h2>
            </div>
        </div>
        
        <div id="main">
            #{doLayout /} 
        </div>
        
        <p id="footer">
            Yabe is a (not that) powerful blog engine built with the 
            <a href="https://www.playframework.com">Play framework</a>
            as a tutorial application.
        </p>
        
    </body>
</html>

Refresh and check the result. It seems to work, except that the @blogTitle@ and the @blogBaseLine@ variables are not displayed. This is because we didn’t pass them to the @render(…)@ call. Of course we could add them to the @render()@ call in the @index@ action. But because the @main.html@ file will be used as main template for all application actions, we don’t want to add them every time.

One way to execute the same code for each action of a controller (or a hierarchy of controllers) is to define a <code>@Before</code> interceptor. 

Let’s add the @addDefaults()@ method to the Application controller:

bc. @Before
static void addDefaults() {
    renderArgs.put("blogTitle", Play.configuration.getProperty("blog.title"));
    renderArgs.put("blogBaseline", Play.configuration.getProperty("blog.baseline"));
}

p(note). You will need to import @play.Play@ in the @Application.java@ file.

All variables added to the @renderArgs@ scope will be available from the templates. And you can see that the method reads the variable’s values from the @Play.configuration@ object. This object contains all configuration keys from the @/yabe/conf/application.conf@ file.

Add these two keys to the configuration file:

bc. # Blog engine configuration
# ~~~~~
blog.title=Yet another blog
blog.baseline=We will write about nothing

Reload the home page and check that it works!

!images/guide3-1!

h2. <a>Adding some style</a>

Now the blog home page is almost done, but it’s not very pretty. We’ll add some style to make it shinier. As you have seen, the main template file main.html includes the @/public/stylesheets/main.css@ stylesheet. We’ll keep it but add more style rules to it.

You can "download it here":files/main.css, and copy it to the @/public/stylesheets/main.css@ file.

Refresh the home page and you should now see a styled page.

!images/guide3-2!

h2. <a>Commit your work</a>

The blog home page is now finished. As usual we can commit this blog version to bazaar:

bc. $ bzr st
$ bzr add
$ bzr commit -m "Home page"

p(note). Next: %(next)"The comments page":guide4%. 

