Title: Programing Assignment 2 – Styling your App

The purpose of this assignment is to introduce you to styling web pages in Grails and includes introductions to:

  • Grails Plugin
  • HTML and CSS
  • Groovy
  • Twitter Bootstrap CSS framework
  •  g-tags

You are to complete this programming assignment individually. In this assignment you will make new “responsive” public views for the book store’s website using Twitter Bootstrap. In particular you will make responsive home page, and list views for books and authors.

Step 1: Learn HTML and CSS

If you do not already know HTML and CSS, read the brief tutorial at W3Schools:

http://www.w3schools.com/html/default.asp
http://www.w3schools.com/css/default.asp

You do not have to be an expert in HTML and CSS, but you should know the basics. Read through the tutorial in the above links and get an idea of the language and the material that is in these tutorials. This will take you about 60 minutes. When you need to use the language, you’ll know where to look.

Step 2: Study Twitter Bootstrap Framework

Read the Twitter Bootstrap documentation. In particular read about the CSS styling and the components documentations:

http://getbootstrap.com/css/
http://getbootstrap.com/components/

Reading this material should take you about 60 minutes. Pay particular attention to the section about the bootstrap grid system:

https://getbootstrap.com/docs/3.3/css/#grid

This is the heart of the bootstrap’s responsiveness. Realize when you read about the grid system that it is mobile first. This implies that on small devices the columns in a row will be stacked. When you set the “div class=”, you specify how it will look on larger devices. You will have to experiment with the grid system to fully understand it.

Also study the Navbar component:

https://getbootstrap.com/docs/3.3/components/#navbar

Step 3: Examine Bootstrap Files

Currently, basic Twitter Bootstrap styling and component files are already incorporated into Grails 3. Examine the files “grails-app/assets/stylesheets/bootstrap.css” and “grails-app/assets/javastripts/bootstrap.js”. These files are sufficient for the programming assignment.

For your project, if you want to use “Font Awesome” especially the “Glyhicons” or if you want to compile your style sheets using LESS then you will want to add the Bootstrap Framework plugin to your project. You can get the plugin at:

http://grails.org/plugins.html#plugin/bootstrap-framework

Step 4: Make App Home Page

I like to save the Grails generated views for the administrative backend of the web site because they do not have to look as pretty as the public views and the generated pages look well enough for administrative use. For the public pages, I like to code separately the views and style them using bootstrap.

1. Read about Grails Templates and Layout:

https://gsp.grails.org/latest/guide/index.html#viewsAndTemplates
https://gsp.grails.org/latest/guide/index.html#layouts

2. Make Site Layout GSP

You should notice that there is already a “main.gsp” layout in the “grail-app/views/layout/” directory. Your public pages will use a different layout, so create a gsp file in the views/layout/. Call it site.gsp.

Copy and paste the code below to your site.gsp

<!DOCTYPE html>
<html>
<head>
    <title><g:layoutTitle default="Book Store"/></title>
    <asset:stylesheet src="application.css"/>
    
    <g:layoutHead/>
</head>
<body>
    <g:render template="/navbar" />
    <g:layoutBody/>
    <asset:javascript src="application.js"/>
</body>
</html>

Grails uses Sitemesh to implement layouts:

http://wiki.sitemesh.org/wiki/display/sitemesh3/SiteMesh+3+Overview

You will not have to understand all of Sitemesh complexities to create a simple layout. The layout GSP specifies the general layout of the view. In essences, any view rendered with a layout will be a combination of two GSP files, the layout GSP and the specific view GSP files, called the “target page” in the documentation. Both the layout GSP and specific view GSP use special “g:layout” tags. In the above layout GSP, “site.gsp”, the special “g:layout” tags are

  • <g:layoutTitle …/> – specifies the title for the page (the text that appears in the browser tab). In this case a default title, “Book Store”, is specified. The specific view GSP can override the default title
  • <g:layoutHead /> – specifies where to put the specific view GSP “head” content
  • <g:layoutBody /> – specifies where to put the specific view GSP “body” content

Soon we will make the specific GSP view for the home page and this will make more sense.

There are three other tags  in the layout GSP

  • <assest:stylesheet src=…/> – uses asset-pipeline plugin to source the style sheets
  • <g:render template=…> – locates where to render a template, in this case the navigation bar
  • <asset:javascript src=…/> – uses asset-pipeline plugin to source the JavaScript files

The navigation bar is complex enough to have it own GSP file. Also this will let you swap out and in different navigation bars.

3. Make the Navigation Bar Template

Read about navbar in the bootstrap documentation:

https://getbootstrap.com/docs/3.3/components/#navbar

Add the “_navbar.gsp” file to the views directory. Note the leading underscore. You need it in the name of the file so that Grails can identify it as a template view.

Copy and paste the code into your _navbar.gsp template view.

<!DOCTYPE html>
<nav class="navbar navbar-default navbar-static-top" role="navigation">
   <div class="container-fluid">
 
       <!-- Brand and toggle get grouped for better mobile display -->
       <div class="navbar-header">
            <!-- This makes the button for collapsed navbar -->
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
               <span class="sr-only">Toggle navigation</span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
            </button>
            <a href="/${grails.util.Metadata.current.getApplicationName()}">
                <div class="navbar-brand title-name">Book Store</div>
            </a>
       </div><!-- /.navbar-header -->
 
       <!-- Collect the nav links, forms, and other content for toggling -->
       <div class="collapse navbar-collapse" id="navbar-collapse-1">
            <ul class="nav navbar-nav navbar-right">
                  <li><a href="#">Books</a></li>
                  <li><a href="#">Authors</a></li> 
            </ul>
       </div><!-- /.navbar-collapse --> 
    </div><!-- /.container-fluid -->
</nav>

The navbar is described by two major div classes, the “navbar-header” and the “navbar-collapse”. The “navbar-header” describes two elements, the hamburger button for expanding the menu and the branding link to the home page. The “navbar-collapse” describes the links in the collapsed menu. Notice that the navbar-collapse is linked to the navbar-header through its id, “navbar-collapse-1”. The hamburger button in the navbar-header associates the collapsed menu with the “data-target” attribute.

4. Make the Home Specific GSP

Study the Examples in the bootstrap getting started page.

https://getbootstrap.com/docs/3.3/getting-started/#examples

Decide how you want the Book Store home page to look. For example you may want to use a Jumbotron for the home page. Look at the page source for how the Jumbotron is coded. If you lack initiative you can use code below for your home page.

<!DOCTYPE html>
<html>
<head>
    <meta name="layout" content="site"/>
    <title>Book Store Home</title>
</head>

<body>
    <div class="jumbotron jumb-margin">
        <div class="container">
           <h1>Book Store</h1>
        </div>
    </div>

   <p>Under construction</p>
   <p>
       <g:link controller="controllerList">Go to ControllerList</g:link> 
   </p>

</body>
</html>

Now stop and run the app again. You should see the public home page with the navigation bar. Adjust the browser window width. Notice that when the browser window width is narrow the hamburger menu appears and when clicked the menu expands. Also notice that when the browser window is wide then the menu is expanded into the navbar area.

The branding link is on the left side of the navbar. It is barely visible because the default color is mid grey. We will fix that shortly when we style the navbar.

5. Clean Up the Control List Link

If you visited the controller list view and clicked on the Grails icon at the top left, you will notice that it points the browser to the root of server instead of the app home page.

Open the main.gsp file. In the navbar section of main.gsp layout, look at the anchor tag with the class designation “navbar-brand.” The href attributes points to the root of the server.

<div class="navbar navbar-default navbar-static-top" role="navigation">
    <div class="container">
        <div class="navbar-header">
            ...
            <a class="navbar-brand" href="/#">
                <i class="fa grails-icon">
                    <asset:image src="grails-cupsonly-logo-white.svg"/>
                </i> Grails
            </a>
        </div>
...
    </div>
</div>

We should change the URL for the navbar-brand. Also, we probably do not want the Grials icon if the link is to point to our app home page. Replace the entire anchor tag with

<a class="navbar-brand" href="/${grails.util.Metadata.current.getApplicationName()}/">
    <div class="navbar-brand title-name">Book Store</div>
</a>

Now someone using the admin pages has an easy link back to the public pages.

Step 5: Styling the Home Page

The public home page probably does not look as good as you like. You should add some styling.

1. Add Style Sheet

Add the file “myStyles.css” to the directory grails-app/assets/stylesheet/, and then cut and paste the content below into the myStyles.css:

/* Change nav bar background color */
 .navbar {
     background-color: blue;
 }
 .navbar-default .navbar-brand{
     color: white;
 }

Now you must source your style sheet to the site.gsp file. There are two ways to source the style sheet into the view. If you want the syles to appear only on the public pages then in the head of the site.gsp file just below the asset:stylesheet tag for application.css add the link to your style sheet so that your styles will over write bootstrap styles:

<asset:stylesheet src="application.css"/>
<asset:stylesheet src="myStyles.css"/>

If you should reverse the order then bootstrap styles will overwrite your styles and your styles will have no effect.

If you’d like your styles to effect all views including the admin pages then you will need to edit the “asset/stylesheets/application.css” file. The asset-pipeline documentation is at

http://bertramdev.github.io/grails-asset-pipeline/

In particular you need to read the usage section

http://bertramdev.github.io/grails-asset-pipeline/guide/usage.html#directives

In short, we need to add to the list of “require” style files to application.css

/*
...

*= require bootstrap
*= require grails
*= require main
*= require mobile
*= require myStyles
*= require_self
*/

I added the “*= require myStyles” at the bottom but above “*= require_self”. In this location myStyles will over write any styles in sheets listed above, but any styles defined in application.css will over write the styles in myStyles.

You need to re-run the application for the styles to appear so that asset-pipeline can source them into the app’s views.

2. Styling the Jumbotron

In the views/index.gsp add the center class to the h1 tag:

<h1 class="text-center">Book Store</h1>

You do not need to re-run Grails to view the changes. You only need to refresh the page in your browser.

3. Experiment with More Styling

Use the Chrome browser to inspect element styles. Open the Chrome browser, and cut and paste the URL into the browser’s address bar. Right click on the page and select “inspect element.” This will open the Developer’s Tools. The tool allows you examine styling inheritance and temporally add new styles to elements.

Note that you do not have to stop and stop the app to view your style changes, but the effects may not show for a while. Generally, the app only needs restarting when you change the domain class or controller.

Step 6: Make the Public Books Page

Currently, I like to make separate controllers for the public pages. This keeps the admin pages completely separate from the public pages.

1. Make the Books Controller

Naming the public controllers can be tricky because the controller name will appear in the URL. Consequently we want the name to be short and memorible. In the case of a public page showing a list of books, we might like to call it “Book”, but that name is already being used by the admin controllers. We could call it “Books”, especially since its index view will show a list of books. This is not always the best choice for the name because it differs from the admin controller by a single letter, “s”. Nevertheless, we will name our public controller “Books”, and we’ll have to be careful to discriminate it from the admin controller.

Use the grail command to make a new controller. Call it “Books”. The editor should show the BooksController.grooy file with an empty index method or action.

2. Write the Index Action for Books

We will want the cs4760progassign/books/ page to show the list of books sorted by the title of the book and showing the author of the book.

Cut and paste the code below for the Book controller methods.

static final boolean debugIndex = true
 def index(){
 
     // Book.list() gets all Book instances from the database and puts them in a list.
     def bks = Book.listOrderByTitle()
 
     // println outputs to console
     if(debugIndex){
          println ""
          bks.each{ println it.title+" by "+Author.get(it.authorId).name}
     }
 
    // Make a list of all books title and authors
    def bkList = []
    for(int i=0; i<bks.size; i++){
         def bkAuthor = [:]
         bkAuthor.put('title', bks[i].title)
         bkAuthor.put('author', Author.get(bks[i].authorId).name)
         bkList << bkAuthor
    }
    if(debugIndex){
        println " "
        println bkList
     }
 
     // The view expects a Map
     // This a Map to the list of title-author maps 
     [bkList: bkList]
 }

3. Study the Groovy Code

The programming language in the Books controller is groovy. Groovy is a scripting language built on top of Java. You can almost always write Java instead of groovy in a groovy file.

Because the BooksController is in the same package as the domain classes, it has access to the domain classes. The call “Book.listOrderByTitle() gets a list of books in the Book table and sort them by the title. You can read the about GORM Querying at

http://gorm.grails.org/6.0.x/hibernate/manual/#querying

The “list” call can work very much like dynamic finders

http://gorm.grails.org/6.0.x/hibernate/manual/#finders

The particular documentation for “listOrderBy” can be found in the “Quick Reference” listed on the right of the documentation. Look in “Domain Classes”:

http://docs.grails.org/latest/ref/Domain%20Classes/listOrderBy.html

After getting the list of all the books, the code constructs a sub Map, “bkAuthor” which will contain the title of the book under the key, “title”, and the author of the book under the key, “author”. Finally this sub map is added to the “bkList” List. The action returns a Map with key “bkList” to the List “bkList.”

You can read about groovy at

http://groovy-lang.org/documentation.html

In particular you will want to study the syntax of the language

http://groovy-lang.org/syntax.html

This code uses List and Map syntax built into groovy

http://groovy-lang.org/syntax.html#_lists

http://groovy-lang.org/syntax.html#_maps

4. Make the Books Index View

Add an “index.gsp” file to the /views/books/ directory.

Cut and paste the code below into the views/books/index.gsp.

<!DOCTYPE html>
<html>
 <head>
    <meta name="layout" content="site"/>
    <title>Book Store Books</title>
 </head>
 
 <body>
     <h1> BOOKS </h1>
     <ul>
        <g:each in="${bkList}">
            <li> ${it.title} by ${it.author} </li>
        </g:each> 
     </ul> 
 </body>
</html>

5. Study the HTML Code

The index view makes use of Grails tags, g-tags. Documentation for g-tags are also found in the “Quick Reference” at the bottom under “Tags” in the Groovy Server Pages documentation. In particular the “each” tag is at:

https://gsp.grails.org/latest/ref/Tags/each.html

6. Edit the Navbar

We need a link to the Books index view. This can be in the navbar menu. Open the _navbar.gsp file in the editor. Replace the anchor tag for the Books link:

<li><a href="#">Books</a></li>

with a g:link tag in the navbar-collapse section of the navbar:

<li><g:link controller="Books">Books</g:link></li>

7. Test the Code

After stop and starting the app you should be able to view the new public books controller by clicking on the books link in the navbar. Note that the outputs from println appear in the run console at the bottom of IntelliJ IDEA. You can modify the either code and refresh page in the browser without “stopping and running” the app. As long as no new classes are made the browser will pick up the changes.

Step 7: Make the Authors Public Page.

You are on your own making the new Authors controller, coding the index method/action and making the new view. Use what you have learned from the steps above.

We want the page to look a little different than the Books view. The Authors public view should be hierarchical list. The top most list should be an alphabetical list of authors and below each author should be an indented alphabetical list of book titles for the author. In other words, we want the view to appear similar to:

Authors

Mark Twain
    Huckleberry Finn
    Tom Sawyer
Stephen King
    The Shining
    The Stand

Also do not forget to change the link for the Authors menu item in the navbar.

Step 9: Make the Screen Shot and Email Me

After creating the public Authors index view, make a screen shoot of the public Authors page. The URL is

http://localhost:8080/cs4760progassign/authors/index

Email me (pastel at mtu.edu) the screen shot. The subject of the email should be

“cs4760 Programming Assignment 2 Proof”