Teaching Guide

Elvenware Logo

TOC

Overview

In the Express Pages and Mixins assignment you will learn about Jade, bootstrap and mixins. I'd like you to build a single page app (SPA) that switches between showing the main page and the about page.

References:

Steps

Main Page

The main page might look something like this:

The front page

When the user clicks the Help button, the user is shown the text that begins "Select some controls...".

About Page

The about page might look a bit like this:

The front page

When the user clicks the About Charlie button, the user is shown the text that begins with the words "This is a note...".

Create page

The details are in the slides listed above, in a slide from noderoutes called Add About Page. It's about the third slide in the deck. Two key lines are:

var about = require('./routes/about');
// Code omitted here
app.use('/about', about);

BootStrap

bower install bootstrap --save

Your layout.pug/jade should look like this:

doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
    link(rel='stylesheet', href='/bower_components/bootstrap/dist/css/bootstrap.css')
    script(src="/bower_components/requirejs/require.js", data-main="/javascripts/main")
  body
    block content

And here is views/index.pug:

extends layout

block content

    .header
        +nav("Prog272 Midterm", "navigationbar", "navbar-default navbar-fixed-top")
            +nav_item( "/", "home", "active" ) Home
            +nav_item( "json-ajax", "json-ajax") JsonAjax
            +nav_item( "about", "about" ) About
            +nav_item_dropdown( "#" )( label="Dropdown" )
                +nav_item( "#" ) Action
                +nav_item( "#" ) Another action
                +nav_item( "#" ) Something else here
                +nav_divider
                +nav_header Nav header
                +nav_item( "#" ) Separated link
                +nav_item( "#" ) One more separated link

Bootstrap Active Selection

Set the active menu with this code:

$('nav li').hover(function(event) {
    setActiveMenuItem(event.currentTarget.id);
});


function setActiveMenuItem() {

    $(".nav li").removeClass("active");

    // var menuItem = $('a[href=".' + this.location.pathname + '"]');
    var name = this.location.pathname;
    var name = name.slice(1, name.length).trim();
    if (name.length === 0) { name = 'home'; }
    var selector = '#' + name;
    try {
        var menuItem1 = $(selector);
        menuItem1.addClass('active');
    } catch(e) {
       // console.log('Could not find selector. This is expected when testing.', e);
    }
}

After we covered this method in class, I realized that it could throw an exception in a unit tests because it may not be able to find the menus, which at least for now, may not be part of your tests. So I have added a try catch statement to suppress the exception if it occurs.

I should add that in some cases, you may not need this code. It's purpose is to help you clear and set the highlight over a menu item when the mouse hovers over it. In some cases, Bootstrap will do that for you automatically. But if it is not doing that properly, try inserting this code. Note that the selector nav li may not properly select the mouse hover events in some cases, depending on how you crafted your HTML. If necessary, compose another selector.

Bootswatch

Bootswatch is a tool for adding themes to bootstrap. When working with our mixins, try using it like this:

+bootswatch('cerulean')

For instance:

extends menu-mixin

block append content
  h1= title
  p Welcome to #{title}

  +attribution

  +bio

  +bootswatch('cerulean')

Here bcerulean** is one of the bootswatch themes. Don't, as a number of you did, try using it like this, as it just throws an error:

+bootswatch

You have to pass in the name of the theme you want to use, as described above.

The JavaScript

Create two files in public/javascripts:

NOTE: You can use either jade or pug.

When the user clicks on the home button, the code in control.js should be in effect. When the user clicks on the about button, the code in about.js should be in effect.

Put a button on each page.

When the user clicks on a button, place text on the appropriate page in an HTML paragraph element. For instance, if the user clicks on the About button, then text should appear on the About page.

Put the button handler for the help button in Control.js.

Put the button handler for the about in About.js

Details are on Elvenware.

If you want to put a button in a form and not have it act like a submit button, then give it a type of button:

button.btn.btn-default#help(type="button") Help

About Button

Radio Mixins

From the root of your project, copy in the radio and checkbox mixins:

cp -v $ELF_TEMPLATES/JadeMixins/mixin-radios.jade views/mixin-radios.pug

In the above, I still have jade as the extension in JsObjects, but I'm copying to a pug file. If you are still using jade:

cp -v $ELF_TEMPLATES/JadeMixins/mixin-radios.jade views/.

Mixins

Place the following code in /views/mixins.jade

mixin bootswatch(theme)
    link(href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.0/" + theme + "/bootstrap.min.css", rel="stylesheet")

//- Navbar mixins
mixin nav(name, id, style)
    - var style = (typeof style === 'undefined') ? "navbar-default" : style
    nav(class=["navbar", style], role="navigation")
        .container-fluid#navfluid
            .navbar-header
                button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navigationbar')
                    span.sr-only Toggle navigation
                    span.icon-bar
                    span.icon-bar
                    span.icon-bar
                a.navbar-brand(href='./index.html') Project name
            .collapse.navbar-collapse( id=id )
                ul.nav.navbar-nav
                    block

mixin nav_item(href, idName, active)
    li(class=active, id=idName): a( href=href )
        block

mixin nav_item_dropdown(href, active)
    li.dropdown
        a.dropdown-toggle(href=href, data-toggle='dropdown', role='button', aria-expanded='false')
            | Dropdown
            span.caret
        ul.dropdown-menu(role='menu')
            block

mixin nav_item_dropdowna(href, active)
    li(class=["dropdown", active])
        a.dropdown-toggle( href=href, data-toggle="dropdown", role="button", aria-expanded="false" )= attributes.label
        span.caret
        ul.dropdown-menu( role="menu" )
            block

mixin nav_divider
    li.divider

mixin nav_header
    li.dropdown-header
        block
//- End navbar mixins

//- Panel mixin
mixin panel(heading, style)
    - var style = (typeof style === 'undefined') ? "default" : style
    div( class=["panel", "panel-" + style] )
        .panel-heading= heading
        .panel-body
            block

//- Button mixin
mixin button(style, href, size)
    - var style = (typeof style === 'undefined') ? "default" : style
    - var href = (typeof href === 'undefined') ? "#" : href
    case size
        when "large"
            - size = "btn-lg"
        when "small"
            - size = "btn-sm"
        when "mini"
            - size = "btn-xs"
    a( class=["btn", "btn-" + style, size], href=href )
        block

  //- List group mixins

mixin listGroup(type, id)
    - var groupType
    - groupType = type
    case groupType
        when 'list'
            ul.list-group(id=id)
                block
        default
            .list-group(id=id)
                block

mixin listItem(arg1, arg2)
    case groupType
        when 'list'
            li( class=["list-group-item", arg1] )
                block
        when 'links'
            a( href=arg1, class=["list-group-item", arg2] )
                block
        default
            .list-group-item( class=["list-group-item", arg1] )
                block

mixin listHeading
    h4.list-group-item-heading
        block

mixin listText
    .list-group-item-text
        block

Load Jade/Pug

When the user requests to load a Jade file, you will need a route on the server side to handle the request. Here is one simple way to set one up:

router.get('/:id', function(request, response) {
    'use strict';
    response.render(request.params.id, {
        id: request.params.id
    });
});

An explanation is in the [node discussion on Elvenware][node-js-parmas].

Turn it in

Make sure the folder is named correctly. Push your work and submit your assignment.

Gravatar

You can use use gravatar for the image on your home page. At the command prompt calculate the md5 hash of your email for the gravatar you want to use. For instance, at the bash prompt type this:

echo -n 'charlie@elvenware.com'| md5sum
b7b423c6d8d9d877ababb3f91b74b4a8  -