Level
Level
Level
Or, check out the scoreboard Let's style the elements a little bit You know where this goes—in the style.css file: h1 { font-weight:300; font-size:39px; } Now, we need to use this view in the router Open the router.js file in the public directory and add the index route: '': 'index' Then, we'll add the index function: index: function () { this.main.html(new HomeView().render().el); }, Now, you should be able to go to the root route and see this: [ 231 ] www.it-ebooks.info Building a Game Building a scoreboard We've already built the primary view for this application However, every complete web application will have several views that aren't specific to the main purpose of the application, but help round out its usefulness In our application, this will be a scoreboard view; a place where players can see each other's best time and score Let's start on the server side this time, in the server.js file Add this route before the catch-all route: app.get('/scoreboard', function (req, res) { users.find(function (err, userRecords) { userRecords.forEach(function (user) { user.totalScore = 0; user.games.forEach(function (game) { user.totalScore += game.score; }); }); userRecords.sort(function (a,b) { return b.score - a.score }); res.render("scoreboard.ejs", { users: userRecords }); }); }); We start by getting all the users in the database Then, we loop over each user, adding a totalScore property to each one We loop over the games array for each user and sum up the score for each game, creating the totalScore property Note that we don't actually change anything in the database; we just create a temporary property here Then, we sort the userRecords array; by default, the array's sort method will sort alphabetically, so we pass a function here that sorts the users from highest- to lowest-scoring Then, we'll render the scoreboard.ejs template in the views directory, passing it the userRecords object Here is the code of the scoreboard.ejs template: Scoreboard Name Total Score Best Game [ 232 ] www.it-ebooks.info Chapter Best Time As with our other full-page templates, we'll open and close with the header and footer includes Then, we'll create the main element This element has a table element inside it We start with a element, with four column headers: the player's name, total score, best game score, and best time Then, inside the element, we loop over the user array and add a row for each user We use one of the EJS's features here: filters For example, we print the user.username property, but we filter it through the capitalize filter so that the first letter will be, you guessed it, capitalized Then, the user.time property is a seconds count, so we filter it through the time filter to display it as a human-friendly string However, this isn't a built-in filter, so we'll have to write it ourselves Back in the server.js file, we first require the ejs library that Express uses behind the scenes: var ejs = require('ejs'); Then, we have to write the filter function We can actually just copy and adjust the time method from the Game class: ejs.filters.time = function(seconds) { var hrs = parseInt(seconds / 3600), = parseInt((seconds % 3600) / 60), sec = (seconds % 3600) % 60; if (min < 10) = "0" + min; if (sec < 10) sec = "0" + sec; var time = + ":" + sec; [ 233 ] www.it-ebooks.info Building a Game if (hrs === 0) return time; if (hrs < 10) hrs = "0" + hrs; return hrs + ":" + time; }; The last step for the scoreboard is to add some styling to the user's table Once again, turn to the style.css file in the public directory: table.users { border-collapse: collapse; } users tbody tr { background: #4E5D6C; } users tbody tr td { padding: 10px; } users th, users td { width: 25%; text-align:center; } It's nothing too fancy, but it will the job We'll add some padding and color the background, and we're done! Here's the final product: [ 234 ] www.it-ebooks.info Chapter Writing the navigation The next part of our application will pull things together; it is the navigation bar In previous applications, the navigation has been its own Backbone view, but this is not the case this time Instead, we'll create a new server-side template just for navigation We'll be able to use this as an include, as we did with the header and footer templates So, create the nav.ejs file in the views directory and put the following code in it:- Tokenr
- Play
- Scoreboard
Word:
Definition:
[ 236 ] www.it-ebooks.info ChapterLevel:
Add
We will post to the /new route when the form is submitted We have an input element for the word and its definition (we could use a text area here, but an input element will encourage a short definition) Then, we have a set of radio buttons for choosing the level Since this will post to the same route, we need a POST route on the server side to catch the new word: app.post('/new', function (req, res) { if (req.user && req.user.admin) { var w = { word: req.body.word.toLowerCase(), definition: req.body.definition, level: parseInt(req.body.level, 10) }; words.find({ word: w.word }, function (err, ws) { if (ws.length === 0) { words.insert(w); } }); res.redirect('/new'); } else { res.redirect('/'); } }); If there's an admin user logged in, we'll create a word object, w Then, we'll check the word's database to see if the word already exists; if it doesn't, we'll insert it Finally, we'll return to the form so that the administrator can insert another word if they want to Finally, let's add this path to the navigation, but only when an administrator is logged in In the nav.ejs file of the views directory, add this as the last list item: