From: Luigi Pinca Date: Sat, 3 Nov 2012 14:29:50 +0000 (+0100) Subject: refactoring X-Git-Url: https://git.saalbach.dev/?a=commitdiff_plain;h=14935226a818bbcef7e146bf54656e18b5e8fd4b;p=binbsis50.git refactoring --- diff --git a/app.js b/app.js index 271c0aa..6ca2d83 100644 --- a/app.js +++ b/app.js @@ -8,70 +8,41 @@ var config = require('./config') , parseCookie = require('express/node_modules/cookie').parse , parseSignedCookies = require('express/node_modules/connect').utils.parseSignedCookies , redisstore = require('connect-redis')(express) - , redisurl = require('redis-url') , site = require('./routes/site') - , user = require('./routes/user'); - -/** - * Setting up redis. - */ - -var songsdb = redisurl.createClient(process.env.SONGS_DB_URL) - , usersdb = redisurl.createClient(process.env.USERS_DB_URL); - -songsdb.on('error', function(err) { - console.log(err.message); -}); - -usersdb.on('error', function(err) { - console.log(err.message); -}); + , user = require('./routes/user') + , usersdb = require('./lib/redis-clients').users; /** * Setting up Express. */ var app = express() - , sessionstore = new redisstore({client:usersdb}); + , pub = __dirname + '/public' // Path to public directory + , sessionstore = new redisstore({client: usersdb}); // Configuration -app.use(express.static(__dirname + '/public'), {maxAge: 2592000000}); -app.use(express.favicon(__dirname + '/public/static/images/favicon.ico', {maxAge: 2592000000})); +app.set('view engine', 'jade'); +app.use(express.compress()); +app.use('/static', express.static(pub, {maxAge: 2419200000})); // 4 weeks = 2419200000 ms +app.use(express.favicon(pub + '/img/favicon.ico', {maxAge: 2419200000})); app.use(express.bodyParser()); app.use(express.cookieParser(process.env.SITE_SECRET)); -app.use(express.session({store:sessionstore})); -app.set('view engine', 'jade'); - -// Middleware to report errors during form submission -app.use(function(req, res, next) { - if (req.session.errors) { - res.locals.errors = req.session.errors; - delete req.session.errors; - } - if (req.session.oldvalues) { - res.locals.oldvalues = req.session.oldvalues; - delete req.session.oldvalues; - } - next(); -}); +app.use(express.session({store: sessionstore})); // Routes -site.use({db:songsdb,rooms:config.rooms}); -user.use({db:usersdb,rooms:config.rooms}); - -app.get('/', site.index); +app.get('/', site.home); app.get('/artworks', site.artworks); -app.get('/changepasswd', site.changePasswd); +app.get('/changepasswd', site.validationErrors, site.changePasswd); app.post('/changepasswd', user.validateChangePasswd, user.checkOldPasswd, user.changePasswd); app.get('/leaderboards', user.leaderboards); -app.get('/login', site.login); +app.get('/login', site.validationErrors, site.login); app.post('/login', user.validateLogin, user.checkUser, user.authenticate); app.get('/logout', user.logout); -app.get('/signup', site.signup); +app.get('/signup', site.validationErrors, site.signup); app.post('/signup', user.validateSignUp, user.userExists, user.emailExists, user.createAccount); -app.get('/recoverpasswd', site.recoverPasswd); +app.get('/recoverpasswd', site.validationErrors, site.recoverPasswd); app.post('/recoverpasswd', user.validateRecoverPasswd, user.sendEmail); -app.get('/resetpasswd', site.resetPasswd); +app.get('/resetpasswd', site.validationErrors, site.resetPasswd); app.post('/resetpasswd', user.resetPasswd); app.get('/:room', site.room); app.get('/user/*', user.profile); @@ -103,7 +74,7 @@ io.set('authorization', function(data, accept) { if(!data.headers.cookie) { return accept('no cookie transmitted', false); } - var signedcookie = parseCookie(decodeURIComponent(data.headers.cookie)); + var signedcookie = parseCookie(data.headers.cookie); var cookie = parseSignedCookies(signedcookie, process.env.SITE_SECRET); sessionstore.get(cookie['connect.sid'], function(err, session) { if (err) { @@ -157,12 +128,12 @@ io.sockets.on('connection', function(socket) { }); socket.on('joinanonymously', function(nickname, roomname) { if (!socket.nickname && typeof nickname === 'string' && nickname !== '' && - config.rooms.indexOf(roomname) !== -1) { + ~config.rooms.indexOf(roomname)) { rooms[roomname].setNickName(socket, nickname); } }); socket.on('joinroom', function(room) { - if (session.user && config.rooms.indexOf(room) !== -1) { + if (session.user && ~config.rooms.indexOf(room)) { if (sockets[session.user]) { // User already in a room socket.emit('alreadyinaroom'); return; @@ -198,17 +169,7 @@ io.sockets.on('connection', function(socket) { * Setting up the rooms. */ -var roomoptions = { - songsdb: songsdb, - usersdb: usersdb, - io: io, - sockets: sockets, - songsinarun: config.songsinarun, - fifolength: config.songsinarun * config.gameswithnorepeats, - threshold: config.allowederrors -}; - -var Room = require('./lib/room')(roomoptions) +var Room = require('./lib/room')({io: io, sockets: sockets}) , rooms = Object.create(null); // The Object that contains all the room instances for (var i=0; i 0) { // Check role - if (usersData[baduser]) { - var notice = 'you have been kicked by '+executor+'.'; - var recipient = sockets[baduser]; - recipient.emit('chatmsg', notice, 'binb', baduser); - recipient.disconnect(); + socket.emit('nomatch'); } - return; - } - callback(); - }); - }; - - // A user has left (DCed, etc.) - this.removeUser = function(nickname) { - // Delete the references - delete sockets[nickname]; - delete usersData[nickname]; - totusers--; - // Broadcast the event - io.sockets.emit('updateoverview', roomname, totusers); - io.sockets.in(roomname).emit('userleft', nickname, usersData); - }; - - var resetPoints = function(roundonly) { - for (var key in usersData) { - if (!roundonly) { - usersData[key].points = 0; - usersData[key].guessed = 0; - usersData[key].totguesstime = 0; - usersData[key].golds = 0; - usersData[key].silvers = 0; - usersData[key].bronzes = 0; - } - usersData[key].roundpoints = 0; - usersData[key].matched = null; - usersData[key].guesstime = null; - } - }; - - // A user is sending a chat message - this.sendChatMessage = function(msg, socket, to) { - if (typeof to === 'string') { - // Check if the recipient is in the room - if (usersData[to]) { - socket.emit('chatmsg', msg, socket.nickname, to); - var recipient = sockets[to]; - recipient.emit('chatmsg', msg, socket.nickname, to); } - return; } - // Censor answers from chat - var msglcase = msg.toLowerCase(); - if (allowedguess && (amatch(artist, msglcase, true) || - (feat && amatch(feat, msglcase, true)) || amatch(title, msglcase))) { - var notice = 'You are probably right, but you have to use the box above.'; - socket.emit('chatmsg', notice, 'binb', socket.nickname); - return; + else { // The user has guessed both track and artist + socket.emit('stoptrying'); } - io.sockets.in(roomname).emit('chatmsg', msg, socket.nickname); - }; - - // Extract a random track from the database and send the load event - var sendLoadTrack = function() { - songsdb.srandmember(roomname, function(err, res) { - // Check if extracted track is in the list of already played tracks - if (playedtracks.indexOf(res) !== -1) { - return sendLoadTrack(); + } + else { + socket.emit('noguesstime'); + } + }; + + this.ignore = function(baduser, executor, callback) { + // Check if the player to be ignored is in the room + if (usersData[baduser]) { + // Inform the bad player that he/she is being ignored + var recipient = sockets[baduser]; + recipient.emit('chatmsg', executor+' is ignoring you.', 'binb', baduser); + return callback(baduser); + } + callback(false); + }; + + this.joinRoom = function(socket) { + socket.roomname = roomname; + socket.join(roomname); + addUser(socket, true); + }; + + // Kick a user + this.kick = function(baduser, executor, callback) { + usersdb.hget('user:'+executor, 'role', function (err, role) { + if (role > 0) { // Check role + if (usersData[baduser]) { + var notice = 'you have been kicked by '+executor+'.'; + var recipient = sockets[baduser]; + recipient.emit('chatmsg', notice, 'binb', baduser); + recipient.disconnect(); } - playedtracks.push(res); - songsdb.hmget('song:'+res, 'artistName', 'trackName', 'collectionName', - 'previewUrl', 'artworkUrl60', 'trackViewUrl', function(e, replies) { - artistName = replies[0]; - artist = artistName.toLowerCase(); - trackName = replies[1]; - title = trackName.toLowerCase(); - feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null; - collectionName = replies[2]; - previewUrl = replies[3]; - artworkUrl = replies[4]; - trackViewUrl = replies[5]; - io.sockets.in(roomname).emit('loadtrack', previewUrl); - setTimeout(sendPlayTrack, 5000); - }); - }); - status = 1; // Loading next song - }; - - var sendPlayTrack = function() { - songcounter++; - status = 0; // Playing track - var data = { - counter: songcounter, - tot: songsinarun, - users: usersData - }; - io.sockets.in(roomname).emit('playtrack', data); - songTimeLeft(Date.now() + 30000, 50); - allowedguess = true; - setTimeout(sendTrackInfo, 30000); - }; - - // Send the room status - this.sendStatus = function(callback) { - var data = { - status: status, - timeleft: songtimeleft, - previewUrl: previewUrl - }; - callback(data); - }; - - var sendTrackInfo = function() { - var trackinfo = { - artworkUrl: artworkUrl, - artistName: artistName, - trackName: trackName, - trackViewUrl: trackViewUrl, - collectionName: collectionName - }; - io.sockets.in(roomname).emit('trackinfo', trackinfo); - finishline = 1; - allowedguess = false; - - if (songcounter < songsinarun) { - resetPoints(true); - sendLoadTrack(); return; } - - status = 2; // Sending last track info - setTimeout(gameOver, 5000); - }; - - // A user is submitting a name - this.setNickName = function(socket, nickname) { - var feedback = null; - - if (nickname.length > 15) { - feedback = 'That name is too long.'; - } - else if (nickname === 'binb') { - feedback = 'That name is reserved.'; + callback(); + }); + }; + + // A user has left (DCed, etc.) + this.removeUser = function(nickname) { + // Delete the references + delete sockets[nickname]; + delete usersData[nickname]; + totusers--; + // Broadcast the event + io.sockets.emit('updateoverview', roomname, totusers); + io.sockets.in(roomname).emit('userleft', nickname, usersData); + }; + + var resetPoints = function(roundonly) { + for (var key in usersData) { + if (!roundonly) { + usersData[key].points = 0; + usersData[key].guessed = 0; + usersData[key].totguesstime = 0; + usersData[key].golds = 0; + usersData[key].silvers = 0; + usersData[key].bronzes = 0; } - else if (sockets[nickname]) { - feedback = 'Name already taken.'; + usersData[key].roundpoints = 0; + usersData[key].matched = null; + usersData[key].guesstime = null; + } + }; + + // A user is sending a chat message + this.sendChatMessage = function(msg, socket, to) { + if (typeof to === 'string') { + // Check if the recipient is in the room + if (usersData[to]) { + socket.emit('chatmsg', msg, socket.nickname, to); + var recipient = sockets[to]; + recipient.emit('chatmsg', msg, socket.nickname, to); } - - if (feedback) { - return socket.emit('invalidnickname', feedback); + return; + } + // Censor answers from chat + var msglcase = msg.toLowerCase(); + if (allowedguess && (amatch(artist, msglcase, true) || + (feat && amatch(feat, msglcase, true)) || amatch(title, msglcase))) { + var notice = 'You are probably right, but you have to use the box above.'; + socket.emit('chatmsg', notice, 'binb', socket.nickname); + return; + } + io.sockets.in(roomname).emit('chatmsg', msg, socket.nickname); + }; + + // Extract a random track from the database and send the load event + var sendLoadTrack = function() { + songsdb.srandmember(roomname, function(err, res) { + // Check if extracted track is in the list of already played tracks + if (~playedtracks.indexOf(res)) { + return sendLoadTrack(); } - - // Check if requested nickname belong to a registered user - var key = 'user:'+nickname; - usersdb.exists(key, function(err, resp) { - if (resp === 1) { - feedback = 'That name belongs '; - feedback += 'to a registered user.'; - return socket.emit('invalidnickname', feedback); - } - socket.nickname = nickname; - socket.roomname = roomname; - socket.join(roomname); - addUser(socket, false); + playedtracks.push(res); + songsdb.hmget('song:'+res, 'artistName', 'trackName', 'collectionName', + 'previewUrl', 'artworkUrl60', 'trackViewUrl', function(e, replies) { + artistName = replies[0]; + artist = artistName.toLowerCase(); + trackName = replies[1]; + title = trackName.toLowerCase(); + feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null; + collectionName = replies[2]; + previewUrl = replies[3]; + artworkUrl = replies[4]; + trackViewUrl = replies[5]; + io.sockets.in(roomname).emit('loadtrack', previewUrl); + setTimeout(sendPlayTrack, 5000); }); + }); + status = 1; // Loading next song + }; + + var sendPlayTrack = function() { + songcounter++; + status = 0; // Playing track + var data = { + counter: songcounter, + tot: config.songsinarun, + users: usersData }; - - // Timer for the playing song - var songTimeLeft = function(end, delay) { - songtimeleft = end - Date.now(); - if (songtimeleft < delay) { - return; - } - setTimeout(songTimeLeft, delay, end, delay); + io.sockets.in(roomname).emit('playtrack', data); + songTimeLeft(Date.now() + 30000, 50); + allowedguess = true; + setTimeout(sendTrackInfo, 30000); + }; + + // Send the room status + this.sendStatus = function(callback) { + var data = { + status: status, + timeleft: songtimeleft, + previewUrl: previewUrl }; - - // Start the room - this.start = function() { - songsdb.scard(roomname, function(err, res) { - trackscount = res; - }); - sendLoadTrack(); + callback(data); + }; + + var sendTrackInfo = function() { + var trackinfo = { + artworkUrl: artworkUrl, + artistName: artistName, + trackName: trackName, + trackViewUrl: trackViewUrl, + collectionName: collectionName }; + io.sockets.in(roomname).emit('trackinfo', trackinfo); + finishline = 1; + allowedguess = false; - this.unignore = function(baduser, executor) { - if (usersData[baduser]) { - // Inform the bad player that he/she is no longer ignored - var notice = executor+' has stopped ignoring you.'; - var recipient = sockets[baduser]; - recipient.emit('chatmsg', notice, 'binb', baduser); + if (songcounter < config.songsinarun) { + resetPoints(true); + sendLoadTrack(); + return; + } + + status = 2; // Sending last track info + setTimeout(gameOver, 5000); + }; + + // A user is submitting a name + this.setNickName = function(socket, nickname) { + var feedback = null; + + if (nickname.length > 15) { + feedback = 'That name is too long.'; + } + else if (nickname === 'binb') { + feedback = 'That name is reserved.'; + } + else if (sockets[nickname]) { + feedback = 'Name already taken.'; + } + + if (feedback) { + return socket.emit('invalidnickname', feedback); + } + + // Check if requested nickname belong to a registered user + var key = 'user:'+nickname; + usersdb.exists(key, function(err, resp) { + if (resp === 1) { + feedback = 'That name belongs '; + feedback += 'to a registered user.'; + return socket.emit('invalidnickname', feedback); } - }; - } - - return Room; -}; + socket.nickname = nickname; + socket.roomname = roomname; + socket.join(roomname); + addUser(socket, false); + }); + }; + + // Timer for the playing song + var songTimeLeft = function(end, delay) { + songtimeleft = end - Date.now(); + if (songtimeleft < delay) { + return; + } + setTimeout(songTimeLeft, delay, end, delay); + }; + + // Start the room + this.start = function() { + songsdb.scard(roomname, function(err, res) { + trackscount = res; + }); + sendLoadTrack(); + }; + + this.unignore = function(baduser, executor) { + if (usersData[baduser]) { + // Inform the bad player that he/she is no longer ignored + var notice = executor+' has stopped ignoring you.'; + var recipient = sockets[baduser]; + recipient.emit('chatmsg', notice, 'binb', baduser); + } + }; +} diff --git a/lib/stats.js b/lib/stats.js index a402005..b4c4ee8 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -1,64 +1,65 @@ /** - * Return `collectStats` function. + * Module dependencies. */ -module.exports = function(db) { +var db = require('./redis-clients').users; - var collectStats = function(username, stats) { - var key = 'user:'+username; - if (stats.points) { - // Update total points - db.hincrby(key, 'totpoints', stats.points); - // Update the score of the member in the sorted set - db.zincrby('users', stats.points, username); - } - if (stats.userscore) { - // Set personal best - db.hget(key, 'bestscore', function(err, res) { - if (res < stats.userscore) { - db.hset(key, 'bestscore', stats.userscore); - } - }); - } - if (stats.gold) { - // Update the number of golds - db.hincrby(key, 'golds', 1); - } - if (stats.silver) { - db.hincrby(key, 'silvers', 1); - } - if (stats.bronze) { - db.hincrby(key, 'bronzes', 1); - } - if (stats.guesstime) { - // Update the number of guessed tracks - db.hincrby(key, 'guessed', 1); - // Update total guess time - db.hincrby(key, 'totguesstime', stats.guesstime); - // Set best answer time - db.hget(key, 'bestguesstime', function(err, res) { - if (stats.guesstime < res) { - db.hset(key, 'bestguesstime', stats.guesstime); - } - }); - // Set worst answer time - db.hget(key, 'worstguesstime', function(err, res) { - if (stats.guesstime > res) { - db.hset(key, 'worstguesstime', stats.guesstime); - } - }); - } - if (stats.firstplace) { - // Update the number of first places - db.hincrby(key, 'victories', 1); - } - if (stats.secondplace) { - db.hincrby(key, 'secondplaces', 1); - } - if (stats.thirdplace) { - db.hincrby(key, 'thirdplaces', 1); - } - }; +/** + * Expose a function to collect user statistics. + */ - return collectStats; +module.exports = function(username, stats) { + var key = 'user:'+username; + if (stats.points) { + // Update total points + db.hincrby(key, 'totpoints', stats.points); + // Update the score of the member in the sorted set + db.zincrby('users', stats.points, username); + } + if (stats.userscore) { + // Set personal best + db.hget(key, 'bestscore', function(err, res) { + if (res < stats.userscore) { + db.hset(key, 'bestscore', stats.userscore); + } + }); + } + if (stats.gold) { + // Update the number of golds + db.hincrby(key, 'golds', 1); + } + if (stats.silver) { + db.hincrby(key, 'silvers', 1); + } + if (stats.bronze) { + db.hincrby(key, 'bronzes', 1); + } + if (stats.guesstime) { + // Update the number of guessed tracks + db.hincrby(key, 'guessed', 1); + // Update total guess time + db.hincrby(key, 'totguesstime', stats.guesstime); + // Set best answer time + db.hget(key, 'bestguesstime', function(err, res) { + if (stats.guesstime < res) { + db.hset(key, 'bestguesstime', stats.guesstime); + } + }); + // Set worst answer time + db.hget(key, 'worstguesstime', function(err, res) { + if (stats.guesstime > res) { + db.hset(key, 'worstguesstime', stats.guesstime); + } + }); + } + if (stats.firstplace) { + // Update the number of first places + db.hincrby(key, 'victories', 1); + } + if (stats.secondplace) { + db.hincrby(key, 'secondplaces', 1); + } + if (stats.thirdplace) { + db.hincrby(key, 'thirdplaces', 1); + } }; diff --git a/lib/user.js b/lib/user.js index 3b88b5f..675c76e 100644 --- a/lib/user.js +++ b/lib/user.js @@ -1,5 +1,5 @@ /** - * Export the class. + * Expose the constructor. */ module.exports = function(username, email, salt, hash, joindate) { diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..84b1127 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,45 @@ +/** + * Get a random slogan. + */ + +exports.randomSlogan = function() { + var slogans = [ + 'guess the song.' + , 'name that tune.' + , 'i know this track.' + ]; + return slogans[Math.floor(Math.random() * slogans.length)]; +}; + +/** + * Check if the provided string is a valid email address. + */ + +exports.isEmail = function(str) { + // Simple filter, but it covers most of the use cases. + var filter = /^[+a-zA-Z0-9_.\-]+@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]{2,6}$/; + return filter.test(str); +}; + +/** + * Helper function used to build leaderboards. + * Rearrange database results in an object. + */ + +exports.buildLeaderboards = function(pointsresults, timesresults) { + var obj = { + pointsleaderboard: [], + timesleaderboard: [] + }; + for (var i=0; i.active>a>[class^="icon-"],.nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../images/glyphicons-halflings-white.png");} +[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px;} +.icon-white,.nav>.active>a>[class^="icon-"],.nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png");} .icon-glass{background-position:0 0;} .icon-music{background-position:-24px 0;} .icon-search{background-position:-48px 0;} diff --git a/public/static/css/style.css b/public/css/style.css similarity index 97% rename from public/static/css/style.css rename to public/css/style.css index ac8e655..be5ead8 100644 --- a/public/static/css/style.css +++ b/public/css/style.css @@ -1,14 +1,14 @@ @font-face { font-family: 'ChristopherhandRegular'; - src: url('comesinhandy-webfont.eot'); - src: url('comesinhandy-webfont.eot?#iefix') format('embedded-opentype'), - url('comesinhandy-webfont.woff') format('woff'), - url('comesinhandy-webfont.ttf') format('truetype'); + src: url('/static/fonts/comesinhandy-webfont.eot'); + src: url('/static/fonts/comesinhandy-webfont.eot?#iefix') format('embedded-opentype'), + url('/static/fonts/comesinhandy-webfont.woff') format('woff'), + url('/static/fonts/comesinhandy-webfont.ttf') format('truetype'); font-weight: normal; font-style: normal; } body { - background: url('/static/images/bg.jpg') repeat-x scroll 0 0 #F5F6F7; + background: url('/static/img/bg.jpg') repeat-x scroll 0 0 #F5F6F7; padding-top: 45px; } section { @@ -44,7 +44,7 @@ h6 { text-transform: uppercase; } .icons { - background: url('/static/images/sprites.png') no-repeat; + background: url('/static/img/sprites.png') no-repeat; } .align-left { text-align: left; @@ -279,7 +279,7 @@ form .clearfix { #cassette { margin-top: 22px; height: 137px; - background: url('/static/images/cassette.png') no-repeat 0 0; + background: url('/static/img/cassette.png') no-repeat 0 0; } #countdown { position: absolute; diff --git a/public/static/css/comesinhandy-webfont.eot b/public/fonts/comesinhandy-webfont.eot similarity index 100% rename from public/static/css/comesinhandy-webfont.eot rename to public/fonts/comesinhandy-webfont.eot diff --git a/public/static/css/comesinhandy-webfont.ttf b/public/fonts/comesinhandy-webfont.ttf similarity index 100% rename from public/static/css/comesinhandy-webfont.ttf rename to public/fonts/comesinhandy-webfont.ttf diff --git a/public/static/css/comesinhandy-webfont.woff b/public/fonts/comesinhandy-webfont.woff similarity index 100% rename from public/static/css/comesinhandy-webfont.woff rename to public/fonts/comesinhandy-webfont.woff diff --git a/public/static/images/bg.jpg b/public/img/bg.jpg similarity index 100% rename from public/static/images/bg.jpg rename to public/img/bg.jpg diff --git a/public/static/images/cassette.png b/public/img/cassette.png similarity index 100% rename from public/static/images/cassette.png rename to public/img/cassette.png diff --git a/public/static/images/favicon.ico b/public/img/favicon.ico similarity index 100% rename from public/static/images/favicon.ico rename to public/img/favicon.ico diff --git a/public/static/images/glyphicons-halflings-white.png b/public/img/glyphicons-halflings-white.png similarity index 100% rename from public/static/images/glyphicons-halflings-white.png rename to public/img/glyphicons-halflings-white.png diff --git a/public/static/images/glyphicons-halflings.png b/public/img/glyphicons-halflings.png similarity index 100% rename from public/static/images/glyphicons-halflings.png rename to public/img/glyphicons-halflings.png diff --git a/public/static/images/sprites.png b/public/img/sprites.png similarity index 100% rename from public/static/images/sprites.png rename to public/img/sprites.png diff --git a/public/static/js/room.js b/public/js/app.js similarity index 96% rename from public/static/js/room.js rename to public/js/app.js index e18b6bc..526814a 100644 --- a/public/static/js/room.js +++ b/public/js/app.js @@ -1,5 +1,5 @@ (function() { - + var elapsedtime = 0 , DOM = {} , historycursor = 0 @@ -10,10 +10,12 @@ , pvtmsgto , subscriber = false , roundpoints = 0 + , roomname = window.location.pathname.replace('/', '') , socket , stopanimation = false , touchplay - , urlregex = /(https?:\/\/[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])/; + , urlregex = /(https?:\/\/[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])/ + , uri = window.location.protocol+'//'+window.location.host; // Socket.IO server URI var amstrings = [ 'Yes, that\'s the artist. What about the title?' @@ -877,36 +879,33 @@ updateUsers(usersData); }; - // Set up the room. - $(function() { - setVariables(); - DOM.modal.modal({keyboard:false, show:false, backdrop:'static'}); - DOM.togglechat.click(hideChat); - if ($.browser.mozilla) { - // Block ESC button in firefox (breaks socket connections). - $(document).keypress(function(event) { - if(event.keyCode === 27) { - return false; - } - }); - } - var uri = window.location.protocol+'//'+window.location.host; - socket = io.connect(uri, {'reconnect':false}); - socket.on('connect', function() { - jplayer = $('#player').jPlayer({ - ready: jplayerReady, - swfPath: '/static/swf/', - supplied: 'm4a', - preload: 'auto', - volume: 1 - }); - socket.on('alreadyinaroom', alreadyInARoom); - socket.on('disconnect', disconnect); - socket.on('invalidnickname', invalidNickName); - socket.on('ready', ready); - socket.on('updateoverview', updateRoomsOverview); - socket.emit('getoverview', roomsOverview); + // Set up the app. + setVariables(); + DOM.modal.modal({keyboard:false, show:false, backdrop:'static'}); + DOM.togglechat.click(hideChat); + if ($.browser.mozilla) { + // Block ESC button in firefox (breaks socket connections). + $(document).keypress(function(event) { + if(event.keyCode === 27) { + return false; + } + }); + } + socket = io.connect(uri, {'reconnect':false}); + socket.on('connect', function() { + jplayer = $('#player').jPlayer({ + ready: jplayerReady, + swfPath: '/static/swf/', + supplied: 'm4a', + preload: 'auto', + volume: 1 }); + socket.on('alreadyinaroom', alreadyInARoom); + socket.on('disconnect', disconnect); + socket.on('invalidnickname', invalidNickName); + socket.on('ready', ready); + socket.on('updateoverview', updateRoomsOverview); + socket.emit('getoverview', roomsOverview); }); })(); diff --git a/public/static/js/bootstrap.min.js b/public/js/bootstrap.min.js similarity index 100% rename from public/static/js/bootstrap.min.js rename to public/js/bootstrap.min.js diff --git a/public/static/js/home.js b/public/js/home.js similarity index 97% rename from public/static/js/home.js rename to public/js/home.js index f23c620..5c0ec62 100644 --- a/public/static/js/home.js +++ b/public/js/home.js @@ -1,4 +1,4 @@ -$(function() { +(function() { if ($.browser.mozilla) { // Block ESC button in firefox (breaks socket connections). $(document).keypress(function(event) { @@ -28,4 +28,4 @@ $(function() { $('#'+room).text(players); }); }); -}); +})(); diff --git a/public/static/js/jquery.jplayer.min.js b/public/js/jquery.jplayer.min.js similarity index 100% rename from public/static/js/jquery.jplayer.min.js rename to public/js/jquery.jplayer.min.js diff --git a/public/static/swf/Jplayer.swf b/public/swf/Jplayer.swf similarity index 100% rename from public/static/swf/Jplayer.swf rename to public/swf/Jplayer.swf diff --git a/routes/site.js b/routes/site.js index 19abf3d..d690964 100644 --- a/routes/site.js +++ b/routes/site.js @@ -4,11 +4,12 @@ var async = require('async') , Captcha = require('../lib/captcha') - , db - , rooms; + , db = require('../lib/redis-clients').songs + , randomSlogan = require('../lib/utils').randomSlogan + , rooms = require('../config').rooms; /** - * Generate a task for async. + * Generate a task. */ var task = function(genre) { @@ -19,15 +20,6 @@ var task = function(genre) { }; }; -/** - * Initialize dependencies. - */ - -exports.use = function(options) { - db = options.db; - rooms = options.rooms; -}; - /** * Extract at random in each room, some album covers and return the result as a JSON. */ @@ -52,38 +44,75 @@ exports.changePasswd = function(req, res) { if (!req.session.user) { return res.redirect('/login?followup=/changepasswd'); } - res.render('changepasswd', {followup:req.query.followup,loggedin:req.session.user}); + res.render('changepasswd', { + followup: req.query.followup || '/', + loggedin: req.session.user, + slogan: randomSlogan() + }); }; -exports.index = function(req, res) { - res.render('index', {loggedin:req.session.user,rooms:rooms}); +exports.home = function(req, res) { + res.render('home', { + loggedin: req.session.user, + rooms: rooms, + slogan: randomSlogan() + }); }; exports.login = function(req, res) { - res.render('login', {followup:req.query.followup}); + res.render('login', { + followup: req.query.followup || '/', + slogan: randomSlogan() + }); }; exports.recoverPasswd = function(req, res) { var captcha = new Captcha(); req.session.captchacode = captcha.getCode(); - res.render('recoverpasswd', {captchaurl:captcha.toDataURL(),followup:req.query.followup}); + res.render('recoverpasswd', { + captchaurl: captcha.toDataURL(), + followup: req.query.followup || '/', + slogan: randomSlogan() + }); }; exports.resetPasswd = function(req, res) { - res.render('resetpasswd', {token:req.query.token}); + res.render('resetpasswd', { + slogan: randomSlogan(), + token: req.query.token || '' + }); }; exports.room = function(req, res) { - if (rooms.indexOf(req.params.room) !== -1) { - res.render('room', {loggedin:req.session.user,roomname:req.params.room,rooms:rooms}); - } - else { - res.send(404); + if (~rooms.indexOf(req.params.room)) { + return res.render('room', { + loggedin: req.session.user, + roomname: req.params.room, + rooms: rooms, + slogan: randomSlogan() + }); } + res.send(404); }; exports.signup = function(req, res) { var captcha = new Captcha(); req.session.captchacode = captcha.getCode(); - res.render('signup', {captchaurl:captcha.toDataURL(),followup:req.query.followup}); + res.render('signup', { + captchaurl: captcha.toDataURL(), + followup: req.query.followup || '/', + slogan: randomSlogan() + }); +}; + +/** + * Report errors during form submission. + */ + +exports.validationErrors = function(req, res, next) { + res.locals.errors = req.session.errors; + res.locals.oldvalues = req.session.oldvalues; + delete req.session.errors; + delete req.session.oldvalues; + next(); }; diff --git a/routes/user.js b/routes/user.js index 2ec5df6..38bf82a 100644 --- a/routes/user.js +++ b/routes/user.js @@ -3,88 +3,20 @@ */ var crypto = require('crypto') - , db - , followupurls = [] + , db = require('../lib/redis-clients').users , mailer = require('../lib/email/mailer') - , User = require('../lib/user'); - -/** - * Extend String with custom methods for input validation. - */ - -String.prototype.trim = function() { - return this.replace(/^[\r\n\t\s]+|[\r\n\t\s]+$/g, ''); -}; - -String.prototype.isEmail = function() { - return this.match(/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/); -}; - -/** - * Check if a URL is in the whitelist of follow-up URLs. - */ - -var safeFollowup = function(url) { - if (followupurls.indexOf(url) !== -1) { - return true; - } - return false; -}; + , rooms = require('../config').rooms + , User = require('../lib/user') + , utils = require('../lib/utils'); /** - * Parameters to get users ordered by best guess time. + * Populate the whitelist of follow-up URLs. */ -var sortparams = [ - 'users' - , 'by' - , 'user:*->bestguesstime' - , 'get' - , '#' - , 'get' - , 'user:*->bestguesstime' - , 'limit' - , '0' - , '30' -]; - -/** - * Helper function used to build leaderboards. - * Rearrange database results in an object. - */ - -var buildLeaderboards = function(pointsresults, timesresults) { - var obj = { - pointsleaderboard: [], - timesleaderboard: [] - }; - for (var i=0; ibestguesstime' + , 'get' + , '#' + , 'get' + , 'user:*->bestguesstime' + , 'limit' + , '0' + , '30' + ]; db.sort(sortparams, function (e, timesresults) { - var leaderboards = buildLeaderboards(pointsresults, timesresults); + var leaderboards = utils.buildLeaderboards(pointsresults, timesresults); + res.locals.slogan = utils.randomSlogan(); res.render('leaderboards', leaderboards); }); }); @@ -143,7 +88,7 @@ exports.checkOldPasswd = function(req, res, next) { }; exports.changePasswd = function(req, res) { - var followup = (safeFollowup(req.query.followup)) ? req.query.followup : '/' + var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/' , user = req.session.user , key = 'user:'+user , salt = crypto.randomBytes(6).toString('base64') @@ -203,7 +148,7 @@ exports.authenticate = function(req, res) { db.hmget(key, 'salt', 'password', function(err, data) { var hash = crypto.createHash('sha256').update(data[0]+req.body.password).digest('hex'); if (hash === data[1]) { - var followup = (safeFollowup(req.query.followup)) ? req.query.followup : '/'; + var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/'; // Authentication succeeded, regenerate the session req.session.regenerate(function() { req.session.cookie.maxAge = 604800000; // One week @@ -247,7 +192,7 @@ exports.validateSignUp = function(req, res, next) { else if (!req.body.username.match(/^[^\x00-\x1F\x7F]{1,15}$/)) { errors.username = '1 to 15 characters required'; } - if (!req.body.email.isEmail()) { + if (!utils.isEmail(req.body.email)) { errors.email = 'is not an email address'; } if (!req.body.password.match(/^[A-Za-z0-9]{6,15}$/)) { @@ -320,8 +265,11 @@ exports.createAccount = function(req, res) { db.sadd('emails', req.body.email); // Delete old fields values delete req.session.oldvalues; - var msg = 'You successfully created your account. You are now ready to login.'; - res.render('login', {followup:req.query.followup,success:msg}); + res.render('login', { + followup: req.query.followup || '/', + slogan: utils.randomSlogan(), + success: 'You successfully created your account. You are now ready to login.' + }); }; /** @@ -335,7 +283,7 @@ exports.validateRecoverPasswd = function(req, res, next) { var errors = {}; - if (!req.body.email.isEmail()) { + if (!utils.isEmail(req.body.email)) { errors.email = 'is not an email address'; } if (req.body.captcha !== req.session.captchacode) { @@ -363,12 +311,16 @@ exports.sendEmail = function(req, res) { db.setex('token:'+token, 14400, data, function(err, reply) { mailer.sendEmail(req.body.email, token, function(err, response) { if (err) { - console.log('reset password error: '+err.message); + console.log('error sending email: '+err.message); } }); }); delete req.session.oldvalues; - return res.render('recoverpasswd', {followup:req.query.followup,success:true}); + return res.render('recoverpasswd', { + followup: req.query.followup || '/', + slogan: utils.randomSlogan(), + success: true + }); } req.session.errors = {alert: 'The email address you specified could not be found'}; res.redirect(req.url); @@ -409,7 +361,11 @@ exports.resetPasswd = function(req, res) { var salt = crypto.randomBytes(6).toString('base64'); var password = crypto.createHash('sha256').update(salt+req.body.password).digest('hex'); db.hmset(user, 'salt', salt, 'password', password, function(err, data) { - res.render('login', {success:'You can now login with your new password.'}); + res.render('login', { + followup: '/', + slogan: utils.randomSlogan(), + success: 'You can now login with your new password.' + }); }); return; } @@ -436,6 +392,7 @@ exports.profile = function(req, res) { delete obj.password; delete obj.salt; delete obj.totguesstime; + res.locals.slogan = utils.randomSlogan(); res.render('user', obj); }); return; diff --git a/views/changepasswd.jade b/views/changepasswd.jade index 8f60a5c..fac6e99 100644 --- a/views/changepasswd.jade +++ b/views/changepasswd.jade @@ -1,72 +1,65 @@ -followup = (typeof(followup) !== "undefined") ? '?followup='+followup : '?followup=/' -doctype html -html - include header - title binb :: Change password - script(src="/static/js/bootstrap.min.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="/") - .icons.logo #{motto} - ul.nav.pull-right - li - a(href="/") Home - li.dropdown - a.dropdown-toggle(data-toggle="dropdown", - href="#") Logged in as #{loggedin.replace(/&/g, '&')} - span.caret - ul.dropdown-menu - li - a(href="/user/#{encodeURIComponent(loggedin)}", - target="_blank") Profile - li - a(href="/logout") Logout - .container - section - .row - .span12.offset2 - form.form-horizontal.well(method="post",action="/changepasswd#{followup}") - fieldset - if (typeof(errors) !== "undefined") - if (typeof(errors.oldpassword) !== "undefined") - .control-group.error - label.control-label(for="oldpassword") Old password - .controls - input#oldpassword(type="password",name="oldpassword") - span.help-inline #{errors.oldpassword} - else - .control-group - label.control-label(for="oldpassword") Old password - .controls - input#username(type="password",name="oldpassword", - placeholder="enter your current password...") - if (typeof(errors.newpassword) !== 'undefined') - .control-group.error - label.control-label(for="newpassword") New password - .controls - input#password(type="password",name="newpassword") - span.help-inline #{errors.newpassword} - else - .control-group - label.control-label(for="newpassword") New password - .controls - input#password(type="password",name="newpassword", - placeholder="enter your new password...") - else - .control-group - label.control-label(for="oldpassword") Old password - .controls - input#username(type="password",name="oldpassword", - placeholder="enter your current password...") - .control-group - label.control-label(for="password") New password - .controls - input#password(type="password",name="newpassword", - placeholder="enter your new password...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-edit.icon-white - | Update - include footer +extends layout + +block title + title binb :: Change password + +block nav + ul.nav.pull-right + li + a(href="/") Home + li.dropdown + a.dropdown-toggle(data-toggle="dropdown", href="#") + | Logged in as #{loggedin.replace(/&/g, '&')} + span.caret + ul.dropdown-menu + li + a(href="/user/#{encodeURIComponent(loggedin)}", target="_blank") Profile + li + a(href="/logout") Logout + +block sections + section + .row + .span12.offset2 + form.form-horizontal.well(method="post", + action="/changepasswd?followup=#{followup}") + fieldset + - if (locals.errors) + - if (errors.oldpassword) + .control-group.error + label.control-label(for="oldpassword") Old password + .controls + input#oldpassword(type="password", name="oldpassword") + span.help-inline #{errors.oldpassword} + - else + .control-group + label.control-label(for="oldpassword") Old password + .controls + input#username(type="password", name="oldpassword", + placeholder="enter your current password...") + - if (errors.newpassword) + .control-group.error + label.control-label(for="newpassword") New password + .controls + input#password(type="password", name="newpassword") + span.help-inline #{errors.newpassword} + - else + .control-group + label.control-label(for="newpassword") New password + .controls + input#password(type="password", name="newpassword", + placeholder="enter your new password...") + - else + .control-group + label.control-label(for="oldpassword") Old password + .controls + input#username(type="password", name="oldpassword", + placeholder="enter your current password...") + .control-group + label.control-label(for="password") New password + .controls + input#password(type="password", name="newpassword", + placeholder="enter your new password...") + button.submit-button.btn.btn-primary(type="submit") + i.icon-edit.icon-white + | Update diff --git a/views/footer.jade b/views/footer.jade deleted file mode 100644 index b49d4c2..0000000 --- a/views/footer.jade +++ /dev/null @@ -1,12 +0,0 @@ -footer - #footer-inner - #copy © 2012 Luigi Pinca - iframe#facebook-button(allowTransparency="true", frameborder="0", - scrolling="no", src="//www.facebook.com/plugins/like.php?href=http%3A%2F%2Fbinb.nodejitsu.com&send=false&layout=button_count&show_faces=false&action=like&colorscheme=light&locale=en_US") - iframe#twitter-button(allowtransparency="true", frameborder="0", - scrolling="no", src="//platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fbinb.nodejitsu.com") - iframe#github-button(allowtransparency="true", frameborder="0", scrolling="0", - src="http://ghbtns.com/github-btn.html?user=lpinca&repo=binb&type=watch&count=true") - span.footer-info . Optimized for Google Chrome. - a#nodejitsu-logo.icons(target="_blank", href="http://nodejitsu.com/") - span.footer-info Powered by diff --git a/views/header.jade b/views/header.jade deleted file mode 100644 index 75762e3..0000000 --- a/views/header.jade +++ /dev/null @@ -1,21 +0,0 @@ -mottos = ['guess the song.', 'name that tune.', 'i know this track.'] -motto = mottos[Math.floor(Math.random()*mottos.length)] -head - link(href="/static/css/bootstrap.min.css", rel="stylesheet") - link(href="/static/css/style.css", rel="stylesheet") - meta(charset="UTF-8") - meta(name="keywords", content="iTunes, music, quiz, binb, beatquest, realtime, multiplayer, listening, game") - meta(name="description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!") - meta(name="author", content="Luigi Pinca") - script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js") - script - var _gaq = _gaq || []; - _gaq.push(['_setAccount', 'UA-29865853-1']); - _gaq.push(['_trackPageview']); - (function() { - var ga = document.createElement('script'); - ga.type = 'text/javascript'; ga.async = true; - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + - '.google-analytics.com/ga.js'; - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); - })(); diff --git a/views/home.jade b/views/home.jade new file mode 100644 index 0000000..1a061fd --- /dev/null +++ b/views/home.jade @@ -0,0 +1,61 @@ +extends layout + +block title + title binb + +block nav + ul.nav.pull-right + li.active + a(href="/") Home + li + a(target="_blank", href="/leaderboards") + i.icon-list-alt.icon-white + | Leaderboards + - if (locals.loggedin) + li.dropdown + a.dropdown-toggle(data-toggle="dropdown", href="#") + | Logged in as #{loggedin.replace(/&/g, '&')} + span.caret + ul.dropdown-menu + li + a(href="/user/#{encodeURIComponent(loggedin)}", target="_blank") Profile + li + a(href="/changepasswd") Change password + li + a(href="/logout") Logout + - else + li + a(href="/signup") Sign up + li + a(href="/login") Login + +block sections + section + .row + .span7 + h3 What's this? + p binb is a realtime, multiplayer, competitive music listening game. + .span9 + h3 How to play? + p All you have to do is to guess the song that is playing. A fixed number + | of songs will run and for each one correctly guessed you will earn an + | amount of points. That amount depends on the number of correct guesses + | (artist and/or title of the song) and on how fast you will be on + | answering compared to other players. At the end a scoreboard will + | report the best three players of the match. If you have read this + | far, what are you waiting? Click on a room below and prove your + | music knowledge! + section + .row + .span16 + ul.thumbnails + - each item in rooms + li.span4 + a.thumbnail.relative(href=item) + .room #{item} - + span(id=item) + | Players + +append scripts + script(src="/socket.io/socket.io.js") + script(src="/static/js/home.js") diff --git a/views/index.jade b/views/index.jade deleted file mode 100644 index fe16563..0000000 --- a/views/index.jade +++ /dev/null @@ -1,66 +0,0 @@ -doctype html -html - include header - title binb - script(src="/socket.io/socket.io.js") - script(src="/static/js/bootstrap.min.js") - script(src="/static/js/home.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="/") - .icons.logo #{motto} - ul.nav.pull-right - li.active - a(href="/") Home - li - a(target="_blank", href="/leaderboards") - i.icon-list-alt.icon-white - | Leaderboards - if (typeof(loggedin) !== "undefined") - li.dropdown - a.dropdown-toggle(data-toggle="dropdown", - href="#") Logged in as #{loggedin.replace(/&/g, '&')} - span.caret - ul.dropdown-menu - li - a(href="/user/#{encodeURIComponent(loggedin)}", - target="_blank") Profile - li - a(href="/changepasswd") Change password - li - a(href="/logout") Logout - else - li - a(href="/signup") Sign up - li - a(href="/login") Login - .container - section - .row - .span7 - h3 What's this? - p binb is a realtime, multiplayer, competitive music listening game. - .span9 - h3 How to play? - p All you have to do is to guess the song that is playing. A fixed number - | of songs will run and for each one correctly guessed you will earn an - | amount of points. That amount depends on the number of correct guesses - | (artist and/or title of the song) and on how fast you will be on - | answering compared to other players. At the end a scoreboard will - | report the best three players of the match. If you have read this - | far, what are you waiting? Click on a room below and prove your - | music knowledge! - section - .row - .span16 - ul.thumbnails - each item in rooms - li.span4 - a.thumbnail.relative(href=item) - .room #{item} - - span(id=item) - | Players - include footer diff --git a/views/layout.jade b/views/layout.jade new file mode 100644 index 0000000..07126dd --- /dev/null +++ b/views/layout.jade @@ -0,0 +1,57 @@ +doctype html +html + head + meta(charset="utf-8") + block title + meta(name="author", content="Luigi Pinca") + meta(name="description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!") + link(href="/static/css/bootstrap.min.css", rel="stylesheet") + link(href="/static/css/style.css", rel="stylesheet") + script + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-29865853-1']); + _gaq.push(['_trackPageview']); + (function() { + var ga = document.createElement('script'); + ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(ga, s); + })(); + body + .navbar.navbar-inverse.navbar-fixed-top + .navbar-inner + .container + block brand + a.brand(href="/") + .icons.logo #{slogan} + block nav + .container + block sections + footer + #footer-inner + #copy © 2012 Luigi Pinca + iframe#facebook-button(allowTransparency="true", frameborder="0", scrolling="no", + src="//www.facebook.com/plugins/like.php?href=http%3A%2F%2Fbinb.nodejitsu.com&send=false&layout=button_count&show_faces=false&action=like&colorscheme=light&locale=en_US") + iframe#twitter-button(allowtransparency="true", frameborder="0", scrolling="no", + src="//platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fbinb.nodejitsu.com") + iframe#github-button(allowtransparency="true", frameborder="0", scrolling="0", + src="http://ghbtns.com/github-btn.html?user=lpinca&repo=binb&type=watch&count=true") + span.footer-info . Optimized for Google Chrome. + a#nodejitsu-logo.icons(target="_blank", href="http://nodejitsu.com/") + span.footer-info Powered by + block media + block scripts + script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js") + script(src="/static/js/bootstrap.min.js") + script + var uvOptions = {}; + (function() { + var uv = document.createElement('script'); + uv.type = 'text/javascript'; uv.async = true; + uv.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + + 'widget.uservoice.com/LSMjFAQRifhD6BjOG2KWw.js'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(uv, s); + })(); diff --git a/views/leaderboards.jade b/views/leaderboards.jade index b4a6a6d..800a64c 100644 --- a/views/leaderboards.jade +++ b/views/leaderboards.jade @@ -1,46 +1,45 @@ -doctype html -html - include header - title binb :: Leaderboards - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="#") - .icons.logo #{motto} - .container - section - .row - .span7.offset1 - .highscores High Scores - .icons.img - section - .row - .span7.offset1 - h4 Points - div.leaderboard-wrapper - table.table.table-striped.table-bordered.leaderboard - tbody - each user, i in pointsleaderboard - tr - td #{i+1} - td - a(href="/user/#{encodeURIComponent(user.username)}") - | #{user.username.replace(/&/g, '&')} - td #{user.totpoints} - .span7 - h4 Times - div.leaderboard-wrapper - table.table.table-striped.table-bordered.leaderboard - tbody - each user, i in timesleaderboard - tr - td #{i+1} - td - a(href="/user/#{encodeURIComponent(user.username)}") - | #{user.username.replace(/&/g, '&')} - td - i.icon-time - | #{user.bestguesstime} sec - include footer +extends layout + +block title + title binb :: Leaderboards + +block brand + a.brand(href="#") + .icons.logo #{slogan} + +block sections + section + .row + .span7.offset1 + .highscores High Scores + .icons.img + section + .row + .span7.offset1 + h4 Points + div.leaderboard-wrapper + table.table.table-striped.table-bordered.leaderboard + tbody + - each user, i in pointsleaderboard + tr + td #{i+1} + td + a(href="/user/#{encodeURIComponent(user.username)}") + | #{user.username.replace(/&/g, '&')} + td #{user.totpoints} + .span7 + h4 Times + div.leaderboard-wrapper + table.table.table-striped.table-bordered.leaderboard + tbody + - each user, i in timesleaderboard + tr + td #{i+1} + td + a(href="/user/#{encodeURIComponent(user.username)}") + | #{user.username.replace(/&/g, '&')} + td + i.icon-time + | #{user.bestguesstime} sec + +block scripts diff --git a/views/login.jade b/views/login.jade index 23e52da..ea3184f 100644 --- a/views/login.jade +++ b/views/login.jade @@ -1,82 +1,75 @@ -followup = (typeof(followup) !== "undefined") ? '?followup='+followup : '?followup=/' -doctype html -html - include header - title binb :: login - script(src="/static/js/bootstrap.min.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="/") - .icons.logo #{motto} - ul.nav.pull-right - li - a(href="/") Home - li - a(href="/signup#{followup}") Sign up - li.active - a(href="/login#{followup}") Login - .container - section - .row - .span3 - h3 New user? - a(href="/signup#{followup}") Click here to create an account. - .span13 - if ((typeof(errors) !== "undefined") && (typeof(errors.alert) !== "undefined")) - .alert.alert-error - a.close(data-dismiss="alert") × - strong Oh snap! - | #{errors.alert} - else if (typeof(success) !== "undefined") - .alert.alert-success - a.close(data-dismiss="alert") × - strong Well done! - | #{success} - form.form-horizontal.well(method="post",action="/login#{followup}") - fieldset - if (typeof(errors) !== "undefined") - if (typeof(errors.username) !== "undefined") - .control-group.error - label.control-label(for="username") Name - .controls - input#username(type="text",name="username", - value=oldvalues.username) - span.help-inline #{errors.username} - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text",name="username", - value=oldvalues.username) - if (typeof(errors.password) !== 'undefined') - .control-group.error - label.control-label(for="password") Password - .controls - input#password(type="password",name="password") - span.help-inline #{errors.password} - else - .control-group - label.control-label(for="password") Password - .controls - input#password(type="password",name="password", - placeholder="enter your password...") - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text",name="username", - placeholder="enter your nickname...") - .control-group - label.control-label(for="password") Password - .controls - input#password(type="password",name="password", - placeholder="enter your password...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-lock.icon-white - | Login - a.forgot-passwd(href="/recoverpasswd#{followup}") - | Forgot your password? - include footer +extends layout + +block title + title binb :: login + +block nav + ul.nav.pull-right + li + a(href="/") Home + li + a(href="/signup?followup=#{followup}") Sign up + li.active + a(href="/login?followup=#{followup}") Login + +block sections + section + .row + .span3 + h3 New user? + a(href="/signup?followup=#{followup}") Click here to create an account. + .span13 + - if (locals.errors && errors.alert) + .alert.alert-error + a.close(data-dismiss="alert") × + strong Oh snap! + | #{errors.alert} + - else if (locals.success) + .alert.alert-success + a.close(data-dismiss="alert") × + strong Well done! + | #{success} + form.form-horizontal.well(method="post", action="/login?followup=#{followup}") + fieldset + - if (locals.errors) + - if (errors.username) + .control-group.error + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + value=oldvalues.username) + span.help-inline #{errors.username} + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + value=oldvalues.username) + - if (errors.password) + .control-group.error + label.control-label(for="password") Password + .controls + input#password(type="password", name="password") + span.help-inline #{errors.password} + - else + .control-group + label.control-label(for="password") Password + .controls + input#password(type="password", name="password", + placeholder="enter your password...") + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + placeholder="enter your nickname...") + .control-group + label.control-label(for="password") Password + .controls + input#password(type="password", name="password", + placeholder="enter your password...") + button.submit-button.btn.btn-primary(type="submit") + i.icon-lock.icon-white + | Login + a.forgot-passwd(href="/recoverpasswd?followup=#{followup}") + | Forgot your password? diff --git a/views/recoverpasswd.jade b/views/recoverpasswd.jade index 829dfe3..d52343b 100644 --- a/views/recoverpasswd.jade +++ b/views/recoverpasswd.jade @@ -1,86 +1,77 @@ -followup = (typeof(followup) !== "undefined") ? '?followup='+followup : '?followup=/' -doctype html -html - include header - title binb :: Recover password - script(src="/static/js/bootstrap.min.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="/") - .icons.logo #{motto} - ul.nav.pull-right - li - a(href="/") Home - li - a(href="/signup#{followup}") Sign up - li - a(href="/login#{followup}") Login - .container - section - .row - .span12.offset2 - if (typeof(success) !== "undefined") - .alert.alert-block.alert-success - h4.alert-heading Success! - | An email has been sent to you.
To start the password reset - | process, open this email and follow the given instructions.
- | If you don't receive it in a reasonable amount of time, please - | use the support form on the left. - else - if ((typeof(errors) !== "undefined") && (typeof(errors.alert) !== "undefined")) - .alert.alert-error - a.close(data-dismiss="alert") × - strong Oh snap! - | #{errors.alert} - form.form-horizontal.well(method="post", - action="/recoverpasswd#{followup}") - fieldset - if (typeof(errors) !== "undefined") - if (typeof(errors.email) !== "undefined") - .control-group.error - label.control-label(for="email") Email - .controls - input#oldpassword(type="text",name="email", - value=oldvalues.email) - span.help-inline #{errors.email} - else - .control-group - label.control-label(for="email") Email - .controls - input#username(type="text",name="email", - value=oldvalues.email) - if (typeof(errors.captcha) !== 'undefined') - .control-group.error - label.control-label(for="captcha-input") - | Are you human? - .controls - img#captcha(src=captchaurl) - input#captcha-input(type="text",name="captcha") - span.help-inline #{errors.captcha} - else - .control-group - label.control-label(for="captcha-input") - | Are you human? - .controls - img#captcha(src=captchaurl) - input#captcha-input(type="text",name="captcha", - placeholder="type what you see...") - else - .control-group - label.control-label(for="email") Email - .controls - input#email(type="text",name="email", - placeholder="type the email you used to sign up...") - .control-group - label.control-label(for="captcha-input") Are you human? - .controls - img#captcha(src=captchaurl) - input#captcha-input(type="text",name="captcha", - placeholder="type what you see...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-envelope.icon-white - | Send password reset link - include footer +extends layout + +block title + title binb :: Recover password + +block nav + ul.nav.pull-right + li + a(href="/") Home + li + a(href="/signup?followup=#{followup}") Sign up + li + a(href="/login?followup=#{followup}") Login + +block sections + section + .row + .span12.offset2 + - if (locals.success) + .alert.alert-block.alert-success + h4.alert-heading Success! + | An email has been sent to you.
To start the password reset + | process, open this email and follow the given instructions.
+ | If you don't receive it in a reasonable amount of time, please + | use the support form on the left. + - else + - if (locals.errors && errors.alert) + .alert.alert-error + a.close(data-dismiss="alert") × + strong Oh snap! + | #{errors.alert} + form.form-horizontal.well(method="post", + action="/recoverpasswd?followup=#{followup}") + fieldset + - if (locals.errors) + - if (errors.email) + .control-group.error + label.control-label(for="email") Email + .controls + input#oldpassword(type="text", name="email", + value=oldvalues.email) + span.help-inline #{errors.email} + - else + .control-group + label.control-label(for="email") Email + .controls + input#username(type="text", name="email", + value=oldvalues.email) + - if (errors.captcha) + .control-group.error + label.control-label(for="captcha-input") Are you human? + .controls + img#captcha(src=captchaurl) + input#captcha-input(type="text", name="captcha") + span.help-inline #{errors.captcha} + - else + .control-group + label.control-label(for="captcha-input") Are you human? + .controls + img#captcha(src=captchaurl) + input#captcha-input(type="text", name="captcha", + placeholder="type what you see...") + - else + .control-group + label.control-label(for="email") Email + .controls + input#email(type="text", name="email", + placeholder="type the email you used to sign up...") + .control-group + label.control-label(for="captcha-input") Are you human? + .controls + img#captcha(src=captchaurl) + input#captcha-input(type="text", name="captcha", + placeholder="type what you see...") + button.submit-button.btn.btn-primary(type="submit") + i.icon-envelope.icon-white + | Send password reset link diff --git a/views/resetpasswd.jade b/views/resetpasswd.jade index f289aa1..2aec806 100644 --- a/views/resetpasswd.jade +++ b/views/resetpasswd.jade @@ -1,47 +1,42 @@ -token = (typeof(token) !== "undefined") ? '?token='+token : '' -doctype html -html - include header - title binb :: Reset password - script(src="/static/js/bootstrap.min.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="#") - .icons.logo #{motto} - .container - section - .row - .span12.offset2 - if ((typeof(errors) !== "undefined") && (typeof(errors.alert) !== "undefined")) - .alert.alert-error - a.close(data-dismiss="alert") × - strong Oh snap! - | #{errors.alert} - form.form-horizontal.well(method="post",action="/resetpasswd#{token}") - fieldset - if (typeof(errors) !== "undefined") - if (typeof(errors.password) !== "undefined") - .control-group.error - label.control-label(for="password") New password - .controls - input#oldpassword(type="password",name="password") - span.help-inline #{errors.password} - else - .control-group - label.control-label(for="password") New password - .controls - input#username(type="password",name="password", - placeholder="enter your new password...") - else - .control-group - label.control-label(for="oldpassword") New password - .controls - input#username(type="password",name="password", - placeholder="enter your new password...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-edit.icon-white - | Update - include footer +extends layout + +block title + title binb :: Reset password + +block brand + a.brand(href="#") + .icons.logo #{slogan} + +block sections + section + .row + .span12.offset2 + - if (locals.errors && errors.alert) + .alert.alert-error + a.close(data-dismiss="alert") × + strong Oh snap! + | #{errors.alert} + form.form-horizontal.well(method="post", action="/resetpasswd?token=#{token}") + fieldset + - if (locals.errors) + - if (errors.password) + .control-group.error + label.control-label(for="password") New password + .controls + input#oldpassword(type="password", name="password") + span.help-inline #{errors.password} + - else + .control-group + label.control-label(for="password") New password + .controls + input#username(type="password", name="password", + placeholder="enter your new password...") + - else + .control-group + label.control-label(for="oldpassword") New password + .controls + input#username(type="password", name="password", + placeholder="enter your new password...") + button.submit-button.btn.btn-primary(type="submit") + i.icon-edit.icon-white + | Update diff --git a/views/room.jade b/views/room.jade index ea35a6d..6b27c1c 100644 --- a/views/room.jade +++ b/views/room.jade @@ -1,105 +1,103 @@ -doctype html -html - include header - title binb :: #{roomname} - script(src="/socket.io/socket.io.js") - script(src="/static/js/bootstrap.min.js") - script(src="/static/js/jquery.jplayer.min.js") - script(type='text/javascript') - var roomname = "#{roomname}"; - script(src="/static/js/room.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - ul.nav.pull-right +extends layout + +block title + title binb :: #{roomname} + +block nav + ul.nav.pull-right + li + a(href="/") Home + li + a(target="_blank", href="/leaderboards") + i.icon-list-alt.icon-white + | Leaderboards + li.active.dropdown + a.dropdown-toggle(data-toggle="dropdown",href="#") #{roomname} + b.caret + ul.dropdown-menu + - each item in rooms + - if (item !== roomname) li - a(href="/") Home - li - a(target="_blank", href="/leaderboards") - i.icon-list-alt.icon-white - | Leaderboards - li.active.dropdown - a.dropdown-toggle(data-toggle="dropdown",href="#") #{roomname} - b.caret - ul.dropdown-menu - each item in rooms - if item != roomname - li - a(href=item) - span.room-name #{item} - i.icon-user.pull-right - span.users-counter - if (typeof(loggedin) !== "undefined") - li.dropdown - a.dropdown-toggle(data-toggle="dropdown", - href="#") Logged in as #{loggedin.replace(/&/g, '&')} - span.caret - ul.dropdown-menu - li - a(href="/user/#{encodeURIComponent(loggedin)}", - target="_blank") Profile - li - a(href="/changepasswd?followup=/#{roomname}") - | Change password - li - a(href="/logout") Logout - else - li - a(href="/signup?followup=/#{roomname}") Sign up - li - a(href="/login?followup=/#{roomname}") Login - #player - #modal.modal.fade - .container - section - .row - .span4.offset1 - #cassette.relative - #wheel-left.icons.wheel - #tape-left - #tape-right - #wheel-right.icons.wheel - #progress-bar - #progress - #countdown + a(href=item) + span.room-name #{item} + i.icon-user.pull-right + span.users-counter + - if (locals.loggedin) + li.dropdown + a.dropdown-toggle(data-toggle="dropdown", href="#") + | Logged in as #{loggedin.replace(/&/g, '&')} + span.caret + ul.dropdown-menu + li + a(href="/user/#{encodeURIComponent(loggedin)}", target="_blank") Profile + li + a(href="/changepasswd?followup=/#{roomname}") Change password + li + a(href="/logout") Logout + - else + li + a(href="/signup?followup=/#{roomname}") Sign up + li + a(href="/login?followup=/#{roomname}") Login + +block sections + section + .row + .span4.offset1 + #cassette.relative + #wheel-left.icons.wheel + #tape-left + #tape-right + #wheel-right.icons.wheel + #progress-bar + #progress + #countdown + .span2 + #volume.relative + .span8 + .page-header + .icons.logo #{slogan} + #total-tracks + span + | tracks. + #summary.row + .span2 + .title Rank + .rank + .span4 + .title Points + .points .span2 - #volume.relative - .span8 - .page-header - .icons.logo #{motto} - #total-tracks tracks. - #summary.row - .span2 - .title Rank - .rank - .span4 - .title Points - .points - .span2 - .title Track - .track - p#feedback Waiting for connection... - input#guess.span8(type="text",tabindex="1", - placeholder="guess the artist and/or title here") - section.relative - .row - #users-wrapper.span5.offset2 - ul#users.unstyled - .span8 - a#toggle-chat Hide chat - #chat-outer-wrapper - #chat-wrapper.bordered - ul#chat.unstyled - #message-wrapper - span#recipient - input#message.span8(type="text",tabindex="2") - ul#tracks.unstyled - #disclaimer - div I do not own any right on the songs that are played here. - div Tracks are played using iTunes api preview. - div Original idea from - a(target="_blank", href="http://beatquest.fm/") beatquest.fm - |. - include footer + .title Track + .track + p#feedback Waiting for connection... + input#guess.span8(type="text", tabindex="1", + placeholder="guess the artist and/or title here") + section.relative + .row + #users-wrapper.span5.offset2 + ul#users.unstyled + .span8 + a#toggle-chat Hide chat + #chat-outer-wrapper + #chat-wrapper.bordered + ul#chat.unstyled + #message-wrapper + span#recipient + input#message.span8(type="text", tabindex="2") + ul#tracks.unstyled + #disclaimer + div I do not own any right on the songs that are played here. + div Tracks are played using iTunes api preview. + div Original idea from + a(target="_blank", href="http://beatquest.fm/") beatquest.fm + | . + +block media + #modal.modal.fade + #player + +append scripts + script(src="/static/js/jquery.jplayer.min.js") + script(src="/socket.io/socket.io.js") + script(src="/static/js/app.js") diff --git a/views/signup.jade b/views/signup.jade index 2419d83..1e58dce 100644 --- a/views/signup.jade +++ b/views/signup.jade @@ -1,120 +1,113 @@ -followup = (typeof(followup) !== "undefined") ? '?followup='+followup : '?followup=/' -doctype html -html - include header - title binb :: sign up - script(src="/static/js/bootstrap.min.js") - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="/") - .icons.logo #{motto} - ul.nav.pull-right - li - a(href="/") Home - li.active - a(href="/signup#{followup}") Sign up - li - a(href="/login#{followup}") Login - .container - section - .row - .span3 - h3 Not a new user? - a(href="/login#{followup}") Click here to log in. - .span13 - h3 Why sign up? - p Registration is optional, but if you are a regular user consider creating - | an account. This will provide the following advantages: - ul - li You will be the one and only owner of your nickname (no one can use - | your nickname in your place). - li Some simple stats related to your account will be collected. - if ((typeof(errors) !== "undefined") && (typeof(errors.alert) !== "undefined")) - .alert.alert-error - a.close(data-dismiss="alert") × - strong Oh snap! - | #{errors.alert} - form.form-horizontal.well(method="post",action="/signup#{followup}") - fieldset - if (typeof(errors) !== "undefined") - if (typeof(errors.username) !== "undefined") - .control-group.error - label.control-label(for="username") Name - .controls - input#username(type="text",name="username", - value=oldvalues.username) - span.help-inline #{errors.username} - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text",name="username", - value=oldvalues.username) - if (typeof(errors.email) !== 'undefined') - .control-group.error - label.control-label(for="email") Email - .controls - input#email(type="text",name="email", - value=oldvalues.email) - span.help-inline #{errors.email} - else - .control-group - label.control-label(for="email") Email - .controls - input#email(type="text",name="email", - value=oldvalues.email) - if (typeof(errors.password) !== 'undefined') - .control-group.error - label.control-label(for="password") Password - .controls - input#password(type="password",name="password") - span.help-inline #{errors.password} - else - .control-group - label.control-label(for="password") Password - .controls - input#password(type="password",name="password", - placeholder="enter a password...") - if (typeof(errors.captcha) !== 'undefined') - .control-group.error - label.control-label(for="captcha-input") Are you human? - .controls - img#captcha(src=captchaurl) - input#captcha-input(type="text",name="captcha") - span.help-inline #{errors.captcha} - else - .control-group - label.control-label(for="captcha-input") Are you human? - .controls - img#captcha(src=captchaurl) - input#captcha-input(type="text",name="captcha", - placeholder="type what you see...") - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text",name="username", - placeholder="enter a nickname...") - .control-group - label.control-label(for="email") Email - .controls - input#email(type="text",name="email", - placeholder="enter a valid email...") - .control-group - label.control-label(for="password") Password - .controls - input#password(type="password",name="password", - placeholder="enter a password...") - .control-group - label.control-label(for="captcha-input") Are you human? - .controls - img#captcha(src=captchaurl) - input#captcha-input(type="text",name="captcha", - placeholder="type what you see...") - button.submit-button.btn.btn-success(type="submit") - i.icon-user.icon-white - | Sign up! - include footer +extends layout + +block title + title binb :: sign up + +block nav + ul.nav.pull-right + li + a(href="/") Home + li.active + a(href="/signup?followup=#{followup}") Sign up + li + a(href="/login?followup=#{followup}") Login + +block sections + section + .row + .span3 + h3 Not a new user? + a(href="/login?followup=#{followup}") Click here to log in. + .span13 + h3 Why sign up? + p Registration is optional, but if you are a regular user consider creating + | an account. This will provide the following advantages: + ul + li You will be the one and only owner of your nickname (no one can use + | your nickname in your place). + li Some simple stats related to your account will be collected. + - if (locals.errors && errors.alert) + .alert.alert-error + a.close(data-dismiss="alert") × + strong Oh snap! + | #{errors.alert} + form.form-horizontal.well(method="post",action="/signup?followup=#{followup}") + fieldset + - if (locals.errors) + - if (errors.username) + .control-group.error + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + value=oldvalues.username) + span.help-inline #{errors.username} + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + value=oldvalues.username) + - if (errors.email) + .control-group.error + label.control-label(for="email") Email + .controls + input#email(type="text", name="email", + value=oldvalues.email) + span.help-inline #{errors.email} + - else + .control-group + label.control-label(for="email") Email + .controls + input#email(type="text", name="email", + value=oldvalues.email) + - if (errors.password) + .control-group.error + label.control-label(for="password") Password + .controls + input#password(type="password", name="password") + span.help-inline #{errors.password} + - else + .control-group + label.control-label(for="password") Password + .controls + input#password(type="password", name="password", + placeholder="enter a password...") + - if (errors.captcha) + .control-group.error + label.control-label(for="captcha-input") Are you human? + .controls + img#captcha(src=captchaurl) + input#captcha-input(type="text", name="captcha") + span.help-inline #{errors.captcha} + - else + .control-group + label.control-label(for="captcha-input") Are you human? + .controls + img#captcha(src=captchaurl) + input#captcha-input(type="text", name="captcha", + placeholder="type what you see...") + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + placeholder="enter a nickname...") + .control-group + label.control-label(for="email") Email + .controls + input#email(type="text", name="email", + placeholder="enter a valid email...") + .control-group + label.control-label(for="password") Password + .controls + input#password(type="password", name="password", + placeholder="enter a password...") + .control-group + label.control-label(for="captcha-input") Are you human? + .controls + img#captcha(src=captchaurl) + input#captcha-input(type="text", name="captcha", + placeholder="type what you see...") + button.submit-button.btn.btn-success(type="submit") + i.icon-user.icon-white + | Sign up! diff --git a/views/user.jade b/views/user.jade index 8b7a679..38b2b6d 100644 --- a/views/user.jade +++ b/views/user.jade @@ -1,89 +1,88 @@ -doctype html -html - include header - title binb :: #{username.replace(/&/g, '&')} info - body - include uv.jade - .navbar.navbar-inverse.navbar-fixed-top - .navbar-inner - .container - a.brand(href="#") - .icons.logo #{motto} - .container - section - .row - .span7.offset1 - .profile #{username.replace(/&/g, '&')} - .icons.img - div member since #{joindate} - section - .row - .span7.offset1 - h4 Points - table.table.table-striped.table-bordered.stats - tbody - tr - td Total - td #{totpoints} - tr - td Best score - td #{bestscore} - tr - td Guessed songs - td #{guessed} - h4 Times - table.table.table-striped.table-bordered.stats - tbody - tr - td Best guess time - if (bestguesstime !== "30.0") - td #{bestguesstime} sec - else - td N/A - tr - td Worst guess time - if (worstguesstime !== "0.0") - td #{worstguesstime} sec - else - td N/A - tr - td Mean guess time - if (typeof meanguesstime !== "undefined") - td #{meanguesstime} sec - else - td N/A - .span7 - h4 Awards - table.table.table-striped.table-bordered.stats - tbody - tr - td Gold cups - td - .icons.cups.stand1 - td #{golds} - tr - td Silver cups - td - .icons.cups.stand2 - td #{silvers} - tr - td Bronze cups - td - .icons.cups.stand3 - td #{bronzes} - tr - td Victories - td - .icons.medals.rank1 - td #{victories} - tr - td Second places - td - .icons.medals.rank2 - td #{secondplaces} - tr - td Third places - td - .icons.medals.rank3 - td #{thirdplaces} - include footer +extends layout + +block title + title binb :: #{username.replace(/&/g, '&')} info + +block brand + a.brand(href="#") + .icons.logo #{slogan} + +block sections + section + .row + .span7.offset1 + .profile #{username.replace(/&/g, '&')} + .icons.img + div member since #{joindate} + section + .row + .span7.offset1 + h4 Points + table.table.table-striped.table-bordered.stats + tbody + tr + td Total + td #{totpoints} + tr + td Best score + td #{bestscore} + tr + td Guessed songs + td #{guessed} + h4 Times + table.table.table-striped.table-bordered.stats + tbody + tr + td Best guess time + - if (bestguesstime !== "30.0") + td #{bestguesstime} sec + - else + td N/A + tr + td Worst guess time + - if (worstguesstime !== "0.0") + td #{worstguesstime} sec + - else + td N/A + tr + td Mean guess time + - if (typeof meanguesstime !== 'undefined') + td #{meanguesstime} sec + - else + td N/A + .span7 + h4 Awards + table.table.table-striped.table-bordered.stats + tbody + tr + td Gold cups + td + .icons.cups.stand1 + td #{golds} + tr + td Silver cups + td + .icons.cups.stand2 + td #{silvers} + tr + td Bronze cups + td + .icons.cups.stand3 + td #{bronzes} + tr + td Victories + td + .icons.medals.rank1 + td #{victories} + tr + td Second places + td + .icons.medals.rank2 + td #{secondplaces} + tr + td Third places + td + .icons.medals.rank3 + td #{thirdplaces} + +block scripts diff --git a/views/uv.jade b/views/uv.jade deleted file mode 100644 index 4b29b34..0000000 --- a/views/uv.jade +++ /dev/null @@ -1,11 +0,0 @@ -script - var uvOptions = {}; - (function() { - var uv = document.createElement('script'); - uv.type = 'text/javascript'; - uv.async = true; - uv.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + - 'widget.uservoice.com/LSMjFAQRifhD6BjOG2KWw.js'; - var s = document.getElementsByTagName('script')[0]; - s.parentNode.insertBefore(uv, s); - })();