From: Luigi Pinca Date: Sat, 23 Feb 2013 11:48:16 +0000 (+0100) Subject: reformatted files to have 2 space indentations X-Git-Url: https://git.saalbach.dev/?a=commitdiff_plain;h=a72b08a17ebc7c8b1d76c4d8126e1f907585e9b6;p=binbsis50.git reformatted files to have 2 space indentations --- diff --git a/app.js b/app.js index 9c3cc6c..129416a 100644 --- a/app.js +++ b/app.js @@ -3,22 +3,22 @@ */ var config = require('./config') - , express = require('express') - , http = require('http') - , parseCookie = require('express/node_modules/cookie').parse - , parseSignedCookies = require('express/node_modules/connect').utils.parseSignedCookies - , redisstore = require('connect-redis')(express) - , site = require('./routes/site') - , user = require('./routes/user') - , usersdb = require('./lib/redis-clients').users; + , express = require('express') + , http = require('http') + , parseCookie = require('express/node_modules/cookie').parse + , parseSignedCookies = require('express/node_modules/connect').utils.parseSignedCookies + , redisstore = require('connect-redis')(express) + , site = require('./routes/site') + , user = require('./routes/user') + , usersdb = require('./lib/redis-clients').users; /** * Setting up Express. */ var app = express() - , pub = __dirname + '/public' // Path to public directory - , sessionstore = new redisstore({client: usersdb}); + , pub = __dirname + '/public' // Path to public directory + , sessionstore = new redisstore({client: usersdb}); // Configuration app.set('view engine', 'jade'); @@ -55,7 +55,7 @@ var server = http.createServer(app); */ var io = require('socket.io').listen(server) - , sockets = Object.create(null); // Sockets of all rooms + , sockets = Object.create(null); // Sockets of all rooms // Configuration io.enable('browser client minification'); @@ -63,106 +63,106 @@ io.enable('browser client etag'); io.enable('browser client gzip'); io.set('log level', 1); io.set('transports', [ - 'websocket' - , 'htmlfile' - , 'xhr-polling' - , 'jsonp-polling' + 'websocket' + , 'htmlfile' + , 'xhr-polling' + , 'jsonp-polling' ]); // Authorization io.set('authorization', function(data, accept) { - if(!data.headers.cookie) { - return accept('no cookie transmitted', false); + if(!data.headers.cookie) { + return accept('no cookie transmitted', false); + } + var signedcookie = parseCookie(data.headers.cookie); + var cookie = parseSignedCookies(signedcookie, process.env.SITE_SECRET); + sessionstore.get(cookie['connect.sid'], function(err, session) { + if (err) { + return accept(err.message, false); } - var signedcookie = parseCookie(data.headers.cookie); - var cookie = parseSignedCookies(signedcookie, process.env.SITE_SECRET); - sessionstore.get(cookie['connect.sid'], function(err, session) { - if (err) { - return accept(err.message, false); - } - else if (!session) { - var debuginfos = { - address: data.headers['x-forwarded-for'], - ua: data.headers['user-agent'], - cookie: data.headers.cookie - }; - console.log(debuginfos); - return accept('session not found', false); - } - data.session = session; - accept(null, true); - }); + else if (!session) { + var debuginfos = { + address: data.headers['x-forwarded-for'], + ua: data.headers['user-agent'], + cookie: data.headers.cookie + }; + console.log(debuginfos); + return accept('session not found', false); + } + data.session = session; + accept(null, true); + }); }); io.sockets.on('connection', function(socket) { - var session = socket.handshake.session; - socket.on('disconnect', function() { - if (socket.roomname) { - rooms[socket.roomname].removeUser(socket.nickname); - } - }); - socket.on('getoverview', function(callback) { - if (typeof callback !== 'function') { - return; - } - var data = Object.create(null); - for (var prop in rooms) { - data[prop] = rooms[prop].getPopulation(); - } - callback(data); - }); - socket.on('getstatus', function(callback) { - if (socket.roomname && typeof callback === 'function') { - rooms[socket.roomname].sendStatus(callback); - } - }); - socket.on('guess', function(guess) { - if (socket.roomname && typeof guess === 'string') { - rooms[socket.roomname].guess(socket, guess); - } - }); - socket.on('ignore', function(who, callback) { - if (socket.roomname && typeof who === 'string' && typeof callback === 'function') { - rooms[socket.roomname].ignore(who, socket.nickname, callback); - } - }); - socket.on('joinanonymously', function(nickname, roomname) { - if (!socket.nickname && typeof nickname === 'string' && ~config.rooms.indexOf(roomname)) { - rooms[roomname].setNickName(socket, nickname); - } - }); - socket.on('joinroom', function(room) { - if (session.user && ~config.rooms.indexOf(room)) { - if (sockets[session.user]) { // User already in a room - socket.emit('alreadyinaroom'); - return; - } - socket.nickname = session.user; - rooms[room].joinRoom(socket); - } - }); - socket.on('kick', function(who, why, callback) { - if (socket.roomname && typeof who === 'string' && typeof why === 'string' && - typeof callback === 'function') { - rooms[socket.roomname].kick(who, why, socket.nickname, callback); - } - }); - socket.on('loggedin', function(callback) { - if (typeof callback !== 'function') { - return; - } - return (session.user) ? callback(session.user) : callback(false); - }); - socket.on('sendchatmsg', function(msg, to) { - if (socket.roomname && typeof msg === 'string') { - rooms[socket.roomname].sendChatMessage(msg, socket, to); - } - }); - socket.on('unignore', function(who) { - if (socket.roomname && typeof who === 'string') { - rooms[socket.roomname].unignore(who, socket.nickname); - } - }); + var session = socket.handshake.session; + socket.on('disconnect', function() { + if (socket.roomname) { + rooms[socket.roomname].removeUser(socket.nickname); + } + }); + socket.on('getoverview', function(callback) { + if (typeof callback !== 'function') { + return; + } + var data = Object.create(null); + for (var prop in rooms) { + data[prop] = rooms[prop].getPopulation(); + } + callback(data); + }); + socket.on('getstatus', function(callback) { + if (socket.roomname && typeof callback === 'function') { + rooms[socket.roomname].sendStatus(callback); + } + }); + socket.on('guess', function(guess) { + if (socket.roomname && typeof guess === 'string') { + rooms[socket.roomname].guess(socket, guess); + } + }); + socket.on('ignore', function(who, callback) { + if (socket.roomname && typeof who === 'string' && typeof callback === 'function') { + rooms[socket.roomname].ignore(who, socket.nickname, callback); + } + }); + socket.on('joinanonymously', function(nickname, roomname) { + if (!socket.nickname && typeof nickname === 'string' && ~config.rooms.indexOf(roomname)) { + rooms[roomname].setNickName(socket, nickname); + } + }); + socket.on('joinroom', function(room) { + if (session.user && ~config.rooms.indexOf(room)) { + if (sockets[session.user]) { // User already in a room + socket.emit('alreadyinaroom'); + return; + } + socket.nickname = session.user; + rooms[room].joinRoom(socket); + } + }); + socket.on('kick', function(who, why, callback) { + if (socket.roomname && typeof who === 'string' && typeof why === 'string' && + typeof callback === 'function') { + rooms[socket.roomname].kick(who, why, socket.nickname, callback); + } + }); + socket.on('loggedin', function(callback) { + if (typeof callback !== 'function') { + return; + } + return (session.user) ? callback(session.user) : callback(false); + }); + socket.on('sendchatmsg', function(msg, to) { + if (socket.roomname && typeof msg === 'string') { + rooms[socket.roomname].sendChatMessage(msg, socket, to); + } + }); + socket.on('unignore', function(who) { + if (socket.roomname && typeof who === 'string') { + rooms[socket.roomname].unignore(who, socket.nickname); + } + }); }); /** @@ -170,14 +170,14 @@ io.sockets.on('connection', function(socket) { */ var Room = require('./lib/room')({io: io, sockets: sockets}) - , rooms = Object.create(null); // The Object that contains all the room instances + , rooms = Object.create(null); // The Object that contains all the room instances for (var i=0; i/, token); + return texttemplate.replace(//, token); }; /** @@ -27,11 +27,11 @@ var plaintextMessage = function(token) { */ var transport = nodemailer.createTransport('SMTP', { - service: 'SendGrid', - auth: { - user: process.env.SENDGRID_USER, - pass: process.env.SENDGRID_PASS - } + service: 'SendGrid', + auth: { + user: process.env.SENDGRID_USER, + pass: process.env.SENDGRID_PASS + } }); /** @@ -39,16 +39,16 @@ var transport = nodemailer.createTransport('SMTP', { */ exports.sendEmail = function(to, token, callback) { - transport.sendMail({ - from: 'binb ', - to: to, - subject: 'binb password recovery', - html: HTMLMessage({token:token}), - text: plaintextMessage(token) - }, function(err, response) { - if(err) { - return callback(err); - } - callback(null, response); - }); + transport.sendMail({ + from: 'binb ', + to: to, + subject: 'binb password recovery', + html: HTMLMessage({token:token}), + text: plaintextMessage(token) + }, function(err, response) { + if(err) { + return callback(err); + } + callback(null, response); + }); }; diff --git a/lib/email/template.jade b/lib/email/template.jade index 99041e0..624bee0 100644 --- a/lib/email/template.jade +++ b/lib/email/template.jade @@ -1,22 +1,22 @@ doctype html html - head - meta(charset="UTF-8") - title binb password recovery - body(style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;") - div(style="width:600px;margin:0 auto;border:3px solid #CCC;border-radius:5px;background-color:#F0F0F0;") - div(style="padding:16px 16px 0;font-size:15px;color:#505050;") - img(alt="logo",src="https://dl.dropbox.com/u/58444696/binb-logo.png") - h2 Password recovery - p To initiate the password reset process for your binb account, - | click the link below: - a(style="color:#0088CC;text-decoration:none;", - href="http://binb.nodejitsu.com/resetpasswd?token=#{token}") - | http://bind.nodejitsu.com/resetpasswd?token=#{token} - p If you can't click it, please copy and paste the URL in a new tab/window. - p If you haven't requested a password reset, you can disregard this message, - | because it's likely that another user entered your email address - | by mistake while trying to reset a password. - p.note(style="font-size:13px;") - b Note: - | This email cannot accept replies. + head + meta(charset="UTF-8") + title binb password recovery + body(style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;") + div(style="width:600px;margin:0 auto;border:3px solid #CCC;border-radius:5px;background-color:#F0F0F0;") + div(style="padding:16px 16px 0;font-size:15px;color:#505050;") + img(alt="logo",src="https://dl.dropbox.com/u/58444696/binb-logo.png") + h2 Password recovery + p To initiate the password reset process for your binb account, + | click the link below: + a(style="color:#0088CC;text-decoration:none;", + href="http://binb.nodejitsu.com/resetpasswd?token=#{token}") + | http://bind.nodejitsu.com/resetpasswd?token=#{token} + p If you can't click it, please copy and paste the URL in a new tab/window. + p If you haven't requested a password reset, you can disregard this message, + | because it's likely that another user entered your email address + | by mistake while trying to reset a password. + p.note(style="font-size:13px;") + b Note: + | This email cannot accept replies. diff --git a/lib/match.js b/lib/match.js index 8fef54a..36c1776 100644 --- a/lib/match.js +++ b/lib/match.js @@ -14,41 +14,41 @@ var threshold = require('../config').allowederrors; */ var checkDistance = function(s1, s2, k) { - if (k === 0) { - return s1 === s2; - } - if (Math.abs(s1.length - s2.length) > k) { - return false; - } - var d = []; - for (var i=0; i <= s1.length; i++) { - d[i] = []; // Now d is a matrix with s1.length + 1 rows - d[i][0] = i; - } - for (var j=1; j <= s2.length; j++) { - d[0][j] = j; - } - for (i=1; i <= s1.length; i++) { - var l = ((i-k) < 1) ? 1 : i-k; - var m = ((i+k) > s2.length) ? s2.length : i+k; - for (j=l; j<=m; j++) { - if (s1.charAt(i-1) === s2.charAt(j-1)) { - d[i][j] = d[i-1][j-1]; - } - else { - if ((j === l) && (d[i][j-1] === undefined)) { - d[i][j] = Math.min(d[i-1][j-1]+1, d[i-1][j]+1); - } - else if ((j === m) && (d[i-1][j] === undefined)) { - d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1); - } - else { - d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1, d[i-1][j]+1); - } - } + if (k === 0) { + return s1 === s2; + } + if (Math.abs(s1.length - s2.length) > k) { + return false; + } + var d = []; + for (var i=0; i <= s1.length; i++) { + d[i] = []; // Now d is a matrix with s1.length + 1 rows + d[i][0] = i; + } + for (var j=1; j <= s2.length; j++) { + d[0][j] = j; + } + for (i=1; i <= s1.length; i++) { + var l = ((i-k) < 1) ? 1 : i-k; + var m = ((i+k) > s2.length) ? s2.length : i+k; + for (j=l; j<=m; j++) { + if (s1.charAt(i-1) === s2.charAt(j-1)) { + d[i][j] = d[i-1][j-1]; + } + else { + if ((j === l) && (d[i][j-1] === undefined)) { + d[i][j] = Math.min(d[i-1][j-1]+1, d[i-1][j]+1); + } + else if ((j === m) && (d[i-1][j] === undefined)) { + d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1); } + else { + d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1, d[i-1][j]+1); + } + } } - return d[s1.length][s2.length] <= k; + } + return d[s1.length][s2.length] <= k; }; /** @@ -56,79 +56,79 @@ var checkDistance = function(s1, s2, k) { */ module.exports = function(subject, guess, enableartistrules) { - if (checkDistance(subject, guess, threshold)) { - return true; - } + if (checkDistance(subject, guess, threshold)) { + return true; + } - // Ignore dots - if (/\./.test(subject) && - checkDistance(subject.replace(/\./g, ''), guess, threshold)) { - return true; - } - // Ignore dashes - if (/\-/.test(subject) && - checkDistance(subject.replace(/\-/g, ''), guess, threshold)) { - return true; - } - // Allow to write "and" in place of "+" - if (/\+/.test(subject) && - checkDistance(subject.replace(/\+/, 'and'), guess, threshold)) { + // Ignore dots + if (/\./.test(subject) && + checkDistance(subject.replace(/\./g, ''), guess, threshold)) { + return true; + } + // Ignore dashes + if (/\-/.test(subject) && + checkDistance(subject.replace(/\-/g, ''), guess, threshold)) { + return true; + } + // Allow to write "and" in place of "+" + if (/\+/.test(subject) && + checkDistance(subject.replace(/\+/, 'and'), guess, threshold)) { + return true; + } + // Allow to write "and" in place of " & " + if (/ & /.test(subject) && !/\(/.test(subject) && + checkDistance(subject.replace(/ & /, ' and '), guess, threshold)) { + return true; + } + + if (enableartistrules) { + // Ignore "the" at the beginning of artist name + if (/^the /.test(subject)) { + var nothe = subject.replace(/^the /, ''); + if (checkDistance(nothe, guess, threshold)) { return true; - } - // Allow to write "and" in place of " & " - if (/ & /.test(subject) && !/\(/.test(subject) && - checkDistance(subject.replace(/ & /, ' and '), guess, threshold)) { + } + if (/jimi hendrix experience/.test(nothe) && + checkDistance(nothe.replace(/ experience/, ''), guess, threshold)) { return true; + } } - - if (enableartistrules) { - // Ignore "the" at the beginning of artist name - if (/^the /.test(subject)) { - var nothe = subject.replace(/^the /, ''); - if (checkDistance(nothe, guess, threshold)) { - return true; - } - if (/jimi hendrix experience/.test(nothe) && - checkDistance(nothe.replace(/ experience/, ''), guess, threshold)) { - return true; - } + // Split artist name on " & " and ", " (artist name can be composed by more names) + var splitted = subject.split(/ & |, /); + if (splitted.length !== 1) { + for (var i=0; i 0) { // Check role - if (usersData[who]) { - if (why) { - why = ' ('+why+')'; - } - var notice = 'you have been kicked by '+executor+why+'.'; - var recipient = sockets[who]; - recipient.emit('chatmsg', notice, 'binb', who); - recipient.disconnect(); - } - 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; + else { + usersData[nickname].points += 2; + stats.points = 2; } + } + usersData[nickname].matched = 'both'; + usersData[nickname].guessed++; + usersData[nickname].totguesstime += usersData[nickname].guesstime; + + if (usersData[nickname].registered) { + stats.userscore = usersData[nickname].points; + stats.guesstime = usersData[nickname].guesstime; + collectStats(nickname, stats); + } + }; + + // Add a new user in the room + var addUser = function(socket, loggedin) { + sockets[socket.nickname] = socket; + usersData[socket.nickname] = { + nickname: socket.nickname, + registered: loggedin, + points: 0, + roundpoints: 0, + matched: null, + guessed: 0, + guesstime: null, + totguesstime: 0, + golds: 0, + silvers: 0, + bronzes: 0 }; - - // 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; + totusers++; + // Broadcast new user event + io.sockets.emit('updateoverview', roomname, totusers); + socket.emit('ready', usersData, trackscount, loggedin); + socket.broadcast.to(roomname).emit('newuser', socket.nickname, usersData); + }; + + var gameOver = function() { + status = 3; // Game over + + // Build podium + var users = []; + for (var key in usersData) { + users.push(usersData[key]); + } + users.sort(function(a, b) {return b.points - a.points;}); + var podium = users.slice(0,3); + io.sockets.in(roomname).emit('gameover', podium); + + // Collect podium stats + if (podium[0] && podium[0].registered) { + collectStats(podium[0].nickname, {firstplace:true}); + } + if (podium[1] && podium[1].registered) { + collectStats(podium[1].nickname, {secondplace:true}); + } + if (podium[2] && podium[2].registered) { + collectStats(podium[2].nickname, {thirdplace:true}); + } + + resetPoints(false); + songcounter = 0; + // Check if FIFO is full + if (playedtracks.length === fifolength) { + playedtracks.splice(0, config.songsinarun); + } + + // Start a new game + setTimeout(sendLoadTrack, 5000); + }; + + // Return the number of users in the room + this.getPopulation = function() { + return totusers; + }; + + // A user is sending a guess + this.guess = function(socket, guess) { + if (allowedguess) { + if (!usersData[socket.nickname].matched) { // No track no artist + if ((artist === title) && amatch(title, guess, true)) { + addPointsAndStats(socket.nickname, true); + socket.emit('bothmatched'); + io.sockets.in(roomname).emit('updateusers', usersData); } - // 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 if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) { + usersData[socket.nickname].roundpoints++; + usersData[socket.nickname].points++; + usersData[socket.nickname].matched = 'artist'; + socket.emit('artistmatched'); + io.sockets.in(roomname).emit('updateusers', usersData); + if (usersData[socket.nickname].registered) { + var stats = {points:1,userscore:usersData[socket.nickname].points}; + collectStats(socket.nickname, stats); + } } - 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(); - } - playedtracks.push(res); - var args = [ - 'song:'+res - , 'artistName' - , 'trackName' - , 'previewUrl' - , 'artworkUrl60' - , 'trackViewUrl' - ]; - songsdb.hmget(args, function(e, replies) { - artistName = replies[0]; - artist = artistName.toLowerCase(); - trackName = replies[1]; - title = trackName.toLowerCase(); - feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null; - previewUrl = replies[2]; - artworkUrl = replies[3]; - trackViewUrl = replies[4]; - 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 - }; - 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, - }; - io.sockets.in(roomname).emit('trackinfo', trackinfo); - finishline = 1; - allowedguess = false; - - if (songcounter < config.songsinarun) { - resetPoints(true); - sendLoadTrack(); - return; + else if (amatch(title, guess)) { + usersData[socket.nickname].roundpoints++; + usersData[socket.nickname].points++; + usersData[socket.nickname].matched = 'title'; + socket.emit('titlematched'); + io.sockets.in(roomname).emit('updateusers', usersData); + if (usersData[socket.nickname].registered) { + var stats = {points:1,userscore:usersData[socket.nickname].points}; + collectStats(socket.nickname, stats); + } } - - 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 === 'binb') { - feedback = 'That name is reserved.'; - } - else if (!isUsername(nickname)) { - feedback = 'Name must contain only '; - feedback += 'alphanumeric characters.'; + else { + socket.emit('nomatch'); } - else if (sockets[nickname]) { - feedback = 'Name already taken.'; + } + else if (usersData[socket.nickname].matched !== 'both') { // Track or artist + if (usersData[socket.nickname].matched === 'artist') { + if (amatch(title, guess)) { + addPointsAndStats(socket.nickname, false); + socket.emit('bothmatched'); + io.sockets.in(roomname).emit('updateusers', usersData); + } + else { + socket.emit('nomatch'); + } } - - if (feedback) { - return socket.emit('invalidnickname', feedback); + else { + if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) { + addPointsAndStats(socket.nickname, false); + socket.emit('bothmatched'); + io.sockets.in(roomname).emit('updateusers', usersData); + } + else { + socket.emit('nomatch'); + } } - - // 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); - }); - }; - - // Timer for the playing song - var songTimeLeft = function(end, delay) { - songtimeleft = end - Date.now(); - if (songtimeleft < delay) { - return; + } + else { // The user has guessed both track and artist + socket.emit('stoptrying'); + } + } + else { + socket.emit('noguesstime'); + } + }; + + this.ignore = function(who, executor, callback) { + // Check if the player to be ignored is in the room + if (usersData[who]) { + // Inform the bad player that he/she is being ignored + var recipient = sockets[who]; + recipient.emit('chatmsg', executor+' is ignoring you.', 'binb', who); + return callback(who); + } + callback(false); + }; + + this.joinRoom = function(socket) { + socket.roomname = roomname; + socket.join(roomname); + addUser(socket, true); + }; + + // Kick a user + this.kick = function(who, why, executor, callback) { + usersdb.hget('user:'+executor, 'role', function (err, role) { + if (role > 0) { // Check role + if (usersData[who]) { + if (why) { + why = ' ('+why+')'; + } + var notice = 'you have been kicked by '+executor+why+'.'; + var recipient = sockets[who]; + recipient.emit('chatmsg', notice, 'binb', who); + recipient.disconnect(); } - setTimeout(songTimeLeft, delay, end, delay); + 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; + } + 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(); + } + playedtracks.push(res); + var args = [ + 'song:'+res + , 'artistName' + , 'trackName' + , 'previewUrl' + , 'artworkUrl60' + , 'trackViewUrl' + ]; + songsdb.hmget(args, function(e, replies) { + artistName = replies[0]; + artist = artistName.toLowerCase(); + trackName = replies[1]; + title = trackName.toLowerCase(); + feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null; + previewUrl = replies[2]; + artworkUrl = replies[3]; + trackViewUrl = replies[4]; + 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 }; - - // Start the room - this.start = function() { - songsdb.scard(roomname, function(err, res) { - trackscount = res; - }); - sendLoadTrack(); + 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 }; - - this.unignore = function(who, executor) { - if (usersData[who]) { - // Inform the bad player that he/she is no longer ignored - var notice = executor+' has stopped ignoring you.'; - var recipient = sockets[who]; - recipient.emit('chatmsg', notice, 'binb', who); - } + callback(data); + }; + + var sendTrackInfo = function() { + var trackinfo = { + artworkUrl: artworkUrl, + artistName: artistName, + trackName: trackName, + trackViewUrl: trackViewUrl, }; + io.sockets.in(roomname).emit('trackinfo', trackinfo); + finishline = 1; + allowedguess = false; + + 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 === 'binb') { + feedback = 'That name is reserved.'; + } + else if (!isUsername(nickname)) { + feedback = 'Name must contain only '; + feedback += 'alphanumeric characters.'; + } + 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); + } + 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(who, executor) { + if (usersData[who]) { + // Inform the bad player that he/she is no longer ignored + var notice = executor+' has stopped ignoring you.'; + var recipient = sockets[who]; + recipient.emit('chatmsg', notice, 'binb', who); + } + }; } diff --git a/lib/stats.js b/lib/stats.js index b4c4ee8..7e30939 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -9,57 +9,57 @@ var db = require('./redis-clients').users; */ 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); - } + 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 675c76e..0f79218 100644 --- a/lib/user.js +++ b/lib/user.js @@ -3,21 +3,21 @@ */ module.exports = function(username, email, salt, hash, joindate) { - this.username = username; - this.email = email; - this.salt = salt; - this.password = hash; - this.joindate = joindate; - this.totpoints = 0; - this.bestscore = 0; - this.golds = 0; - this.silvers = 0; - this.bronzes = 0; - this.bestguesstime = 30000; - this.worstguesstime = 0; - this.totguesstime = 0; - this.guessed = 0; - this.victories = 0; - this.secondplaces = 0; - this.thirdplaces = 0; + this.username = username; + this.email = email; + this.salt = salt; + this.password = hash; + this.joindate = joindate; + this.totpoints = 0; + this.bestscore = 0; + this.golds = 0; + this.silvers = 0; + this.bronzes = 0; + this.bestguesstime = 30000; + this.worstguesstime = 0; + this.totguesstime = 0; + this.guessed = 0; + this.victories = 0; + this.secondplaces = 0; + this.thirdplaces = 0; }; diff --git a/lib/utils.js b/lib/utils.js index d5b81ca..2c74f35 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -4,21 +4,21 @@ */ exports.buildLeaderboards = function(pointsresults, timesresults) { - var obj = { - pointsleaderboard: [], - timesleaderboard: [] - }; - for (var i=0; ibestguesstime' - , 'get' - , '#' - , 'get' - , 'user:*->bestguesstime' - , 'limit' - , offset - , '30' - ]; - return params; + var params = [ + 'users' + , 'by' + , 'user:*->bestguesstime' + , 'get' + , '#' + , 'get' + , 'user:*->bestguesstime' + , 'limit' + , offset + , '30' + ]; + return params; }; diff --git a/public/css/style.css b/public/css/style.css index 1200e10..1453f58 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1,817 +1,817 @@ @font-face { - font-family: 'ChristopherhandRegular'; - 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; + font-family: 'ChristopherhandRegular'; + 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/img/bg.jpg') repeat-x scroll 0 0 #F5F6F7; - padding-top: 45px; + background: url('/static/img/bg.jpg') repeat-x scroll 0 0 #F5F6F7; + padding-top: 45px; } section { - margin-top: 30px; + margin-top: 30px; } h1, h2, h3, h4, h5, h6 { - margin: 0; + margin: 0; } h1 { - font-size: 30px; - line-height: 36px; + font-size: 30px; + line-height: 36px; } h2 { - font-size: 24px; - line-height: 36px; + font-size: 24px; + line-height: 36px; } h3 { - font-size: 18px; - line-height: 27px; + font-size: 18px; + line-height: 27px; } h4, h5, h6 { - line-height: 18px; + line-height: 18px; } h4 { - font-size: 14px; + font-size: 14px; } h5 { - font-size: 12px; + font-size: 12px; } h6 { - font-size: 11px; - color: #999999; - text-transform: uppercase; + font-size: 11px; + color: #999999; + text-transform: uppercase; } .icons { - background: url('/static/img/sprites.png') no-repeat; + background: url('/static/img/sprites.png') no-repeat; } .align-left { - text-align: left; + text-align: left; } .navbar .brand { - padding: 2px 20px 4px; + padding: 2px 20px 4px; } .logo { - font-family: 'ChristopherhandRegular'; + font-family: 'ChristopherhandRegular'; } .navbar .brand .logo { - height: 34px; - padding-left: 68px; - line-height: 40px; - background-position: -36px -174px; - font-size: 25px; + height: 34px; + padding-left: 68px; + line-height: 40px; + background-position: -36px -174px; + font-size: 25px; } .navbar .nav > li > a { - padding: 11px 10px; + padding: 11px 10px; } .navbar .nav.pull-right { - margin-left: 10px; - margin-right: 0; + margin-left: 10px; + margin-right: 0; } .page-header .logo { - display: inline-block; - height: 54px; - padding-left: 109px; - line-height: 68px; - background-position: 0 -120px; - font-size: 34px; - color: #0088CC; + display: inline-block; + height: 54px; + padding-left: 109px; + line-height: 68px; + background-position: 0 -120px; + font-size: 34px; + color: #0088CC; } .form-horizontal .control-group { - margin-bottom: 10px; + margin-bottom: 10px; } .form-horizontal .control-label { - width: 100px; + width: 100px; } .form-horizontal .controls { - margin-left: 120px; + margin-left: 120px; } form .clearfix { - margin-bottom: 10px; + margin-bottom: 10px; } .well { - background-color: #DDDDDD; - margin-bottom: 18px; + background-color: #DDDDDD; + margin-bottom: 18px; } .alert { - margin-bottom: 9px; + margin-bottom: 9px; } .submit-button { - margin-left: 120px; - margin-top: 9px; + margin-left: 120px; + margin-top: 9px; } .forgot-passwd { - display: inline-block; - vertical-align: top; - margin: 14px 0 0 15px; + display: inline-block; + vertical-align: top; + margin: 14px 0 0 15px; } #captcha-input { - width: 122px; + width: 122px; } #captcha { - margin-right: 20px; + margin-right: 20px; } .page-header { - padding: 0; - margin: 0 0 17px 0; - border-bottom: 1px solid #ddd; - -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + padding: 0; + margin: 0 0 17px 0; + border-bottom: 1px solid #ddd; + -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } #login, #guess, #message { - margin-bottom: 0; + margin-bottom: 0; } #login { - float: left; + float: left; } #join { - margin-right: 45px; + margin-right: 45px; } .modal-footer .divider, .modal-footer .divider span { - position: absolute; + position: absolute; } .modal-footer .divider { - border-left: 1px solid #ddd; - height: 38px; - top: 9px; - left: 442px; + border-left: 1px solid #ddd; + height: 38px; + top: 9px; + left: 442px; } .modal-footer .divider span { - color: #aaa; - background-color: #F5F5F5; - top: 10px; - left: -6px; + color: #aaa; + background-color: #F5F5F5; + top: 10px; + left: -6px; } .users-counter, #total-tracks, #tracks a, #nodejitsu-logo, .footer-info { - float: right; + float: right; } .thumbnails { - margin-bottom: 0; + margin-bottom: 0; } .thumbnails > li { - margin: 0 0 18px 80px; + margin: 0 0 18px 80px; } .thumbnail { - border: 1px solid #ccc; - height: 140px; - opacity: 0.7; + border: 1px solid #ccc; + height: 140px; + opacity: 0.7; } .thumbnail:hover { - opacity: 1; + opacity: 1; } .thumbnail img { - float: left; - width: 70px; - height: 70px; + float: left; + width: 70px; + height: 70px; } .highscores, .profile { - font-weight: bold; - font-size: 22px; - line-height: 32px; + font-weight: bold; + font-size: 22px; + line-height: 32px; } .highscores .img, .profile .img, .medals { - width: 32px; - height: 32px; + width: 32px; + height: 32px; } .profile .img { - margin-right: 5px; - background-position: 0 -56px; + margin-right: 5px; + background-position: 0 -56px; } .highscores .img { - margin-right: 7px; - background-position: -64px 0; + margin-right: 7px; + background-position: -64px 0; } .leaderboard-wrapper, .stats { - border: 1px solid #ccc; - border-left: 0; - margin-top: 8px; + border: 1px solid #ccc; + border-left: 0; + margin-top: 8px; } .leaderboard-wrapper { - height: 349px; - overflow: auto; - margin-bottom: 18px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + height: 349px; + overflow: auto; + margin-bottom: 18px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } .leaderboard { - margin: 0; - border: 0; + margin: 0; + border: 0; } .leaderboard td, .stats td { - border-left: 1px solid #ccc; - border-top: 1px solid #ccc; - vertical-align: middle; + border-left: 1px solid #ccc; + border-top: 1px solid #ccc; + vertical-align: middle; } .leaderboard td [class^="icon-"] { - vertical-align: top; - margin-top: 2px; + vertical-align: top; + margin-top: 2px; } .leaderboard tr:first-child td { - border-top: 0; + border-top: 0; } .leaderboard tbody tr:nth-child(odd) td, .stats tbody tr:nth-child(odd) td { - background-color: #ddd; + background-color: #ddd; } .leaderboard tbody tr:hover td, .stats tbody tr:hover td { - background-color: #dadada; + background-color: #dadada; } .loading { - width: 18px; - position: absolute; - top: 360px; - left: 191px; - display: none; + width: 18px; + position: absolute; + top: 360px; + left: 191px; + display: none; } .loading-block { - background-color: #6184B7; - border: 1px solid #466085; - float: left; - height: 12px; - margin-left: 1px; - width: 3px; - opacity: 0.1; - -o-animation-name: bounce; - -o-animation-duration: 1s; - -o-animation-iteration-count: infinite; - -o-transform: scale(0.7); - -moz-animation-name: bounce; - -moz-animation-duration: 1s; - -moz-animation-iteration-count: infinite; - -moz-transform: scale(0.7); - -ms-transform: scale(0.7); - -webkit-animation-name: bounce; - -webkit-animation-duration: 1s; - -webkit-animation-iteration-count: infinite; - -webkit-transform: scale(0.7); - animation-name: bounce; - animation-duration: 1s; - animation-iteration-count: infinite; - transform: scale(0.7); + background-color: #6184B7; + border: 1px solid #466085; + float: left; + height: 12px; + margin-left: 1px; + width: 3px; + opacity: 0.1; + -o-animation-name: bounce; + -o-animation-duration: 1s; + -o-animation-iteration-count: infinite; + -o-transform: scale(0.7); + -moz-animation-name: bounce; + -moz-animation-duration: 1s; + -moz-animation-iteration-count: infinite; + -moz-transform: scale(0.7); + -ms-transform: scale(0.7); + -webkit-animation-name: bounce; + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -webkit-transform: scale(0.7); + animation-name: bounce; + animation-duration: 1s; + animation-iteration-count: infinite; + transform: scale(0.7); } .loading-block:first-child { - -o-animation-delay: 0.4s; - -moz-animation-delay: 0.4s; - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; + -o-animation-delay: 0.4s; + -moz-animation-delay: 0.4s; + -webkit-animation-delay: 0.4s; + animation-delay: 0.4s; } .loading-block:nth-child(2) { - -o-animation-delay: 0.5s; - -moz-animation-delay: 0.5s; - -webkit-animation-delay: 0.5s; - animation-delay: 0.5s; + -o-animation-delay: 0.5s; + -moz-animation-delay: 0.5s; + -webkit-animation-delay: 0.5s; + animation-delay: 0.5s; } .loading-block:last-child { - -o-animation-delay: 0.6s; - -moz-animation-delay: 0.6s; - -webkit-animation-delay: 0.6s; - animation-delay: 0.6s; + -o-animation-delay: 0.6s; + -moz-animation-delay: 0.6s; + -webkit-animation-delay: 0.6s; + animation-delay: 0.6s; } @-o-keyframes bounce { - 0% { - -o-transform: scale(1); - opacity: 1; - } - 100% { - -o-transform: scale(0.7); - opacity: 0.1; - } + 0% { + -o-transform: scale(1); + opacity: 1; + } + 100% { + -o-transform: scale(0.7); + opacity: 0.1; + } } @-moz-keyframes bounce { - 0% { - -moz-transform: scale(1); - opacity: 1; - } - 100% { - -moz-transform: scale(0.7); - opacity: 0.1; - } + 0% { + -moz-transform: scale(1); + opacity: 1; + } + 100% { + -moz-transform: scale(0.7); + opacity: 0.1; + } } @-webkit-keyframes bounce { - 0% { - -webkit-transform: scale(1); - opacity: 1; - } - 100% { - -webkit-transform: scale(0.7); - opacity: 0.1; - } + 0% { + -webkit-transform: scale(1); + opacity: 1; + } + 100% { + -webkit-transform: scale(0.7); + opacity: 0.1; + } } @keyframes bounce { - 0% { - transform: scale(1); - opacity: 1; - } - 100% { - transform:s cale(0.7); - opacity: 0.1; - } + 0% { + transform: scale(1); + opacity: 1; + } + 100% { + transform:s cale(0.7); + opacity: 0.1; + } } .room { - height: 25px; - line-height: 25px; - position: absolute; - top: 61px; - background-color: rgba(51,51,51, 0.7); - color: white; - font-weight: bold; - font-size: 14px; - width: 210px; - text-align: center; - text-transform: capitalize; + height: 25px; + line-height: 25px; + position: absolute; + top: 61px; + background-color: rgba(51,51,51, 0.7); + color: white; + font-weight: bold; + font-size: 14px; + width: 210px; + text-align: center; + text-transform: capitalize; } .dropdown-menu li > a { - padding: 2px 10px; - white-space: normal; + padding: 2px 10px; + white-space: normal; } .users-counter { - font-size: 12px; - margin-right: 4px; + font-size: 12px; + margin-right: 4px; } .matched { - color: #f3a22f; + color: #f3a22f; } .cups, .medals { - margin-left: auto; - margin-right: auto; + margin-left: auto; + margin-right: auto; } .cups { - width: 16px; - height: 16px; + width: 16px; + height: 16px; } .rank1 { - background-position: -32px -16px; + background-position: -32px -16px; } .rank2 { - background-position: -32px -48px; + background-position: -32px -48px; } .rank3 { - background-position: -32px -80px; + background-position: -32px -80px; } .scoreboard th, .scoreboard td { - vertical-align: middle; - text-align: center; + vertical-align: middle; + text-align: center; } .scoreboard .name { - font-weight: bold; + font-weight: bold; } .relative { - position: relative; + position: relative; } #app-name { - display: inline-block; + display: inline-block; } #total-tracks { - color: #BFBFBF; - margin-top: 34px; + color: #BFBFBF; + margin-top: 34px; } #cassette { - margin-top: 22px; - height: 137px; - background: url('/static/img/cassette.png') no-repeat 0 0; + margin-top: 22px; + height: 137px; + background: url('/static/img/cassette.png') no-repeat 0 0; } #countdown { - position: absolute; - width: 26px; - text-align: center; - top: 80px; - left: 175px; + position: absolute; + width: 26px; + text-align: center; + top: 80px; + left: 175px; } #wheel-left, #wheel-right { - position: absolute; - width: 24px; - height: 24px; - top: 49px; - background-position: 0 -32px; + position: absolute; + width: 24px; + height: 24px; + top: 49px; + background-position: 0 -32px; } #wheel-left { - left: 51px; + left: 51px; } #wheel-right { - left: 145px; + left: 145px; } #tape-left, #tape-right { - height: 70px; - width: 70px; - position: absolute; - top: 25px; - background-color: black; - -webkit-border-radius: 70px; - -moz-border-radius: 70px; - border-radius: 70px; - z-index: -1; + height: 70px; + width: 70px; + position: absolute; + top: 25px; + background-color: black; + -webkit-border-radius: 70px; + -moz-border-radius: 70px; + border-radius: 70px; + z-index: -1; } #tape-left { - left: 20px; + left: 20px; } #tape-right { - left: 106px; + left: 106px; } #progress-bar, #progress { - height: 7px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px 0 #333; - -moz-box-shadow: inset 0 1px 2px 0 #333; - box-shadow: inset 0 1px 2px 0 #333; + height: 7px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px 0 #333; + -moz-box-shadow: inset 0 1px 2px 0 #333; + box-shadow: inset 0 1px 2px 0 #333; } #progress-bar { - position: absolute; - width: 148px; - top: 85px; - left: 20px; - border: 1px solid #404040; - border: 1px solid rgba(0, 0, 0, 0.5); + position: absolute; + width: 148px; + top: 85px; + left: 20px; + border: 1px solid #404040; + border: 1px solid rgba(0, 0, 0, 0.5); } #progress { - background-color: #6184b7; - width: 0; + background-color: #6184b7; + width: 0; } #touch-backdrop { - height: 137px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - background: rgba(50,50,50,0.8); + height: 137px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + background: rgba(50,50,50,0.8); } #touch-play { - position: absolute; - top: 54px; - left: 73px; + position: absolute; + top: 54px; + left: 73px; } #volume { - height: 159px; + height: 159px; } #volume-button, #volume-slider, #volume-total, #volume-current, #volume-handle { - position: absolute; + position: absolute; } #volume-button { - bottom: 0; - height: 20px; - width: 20px; + bottom: 0; + height: 20px; + width: 20px; } #volume-button .button { - display: block; - height: 18px; - width: 18px; - border: 1px solid; - border-color: #CCCCCC #CCCCCC #AAAAAA; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - cursor: pointer; - filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#ffffffff,EndColorStr=#ffe0e0e0); - background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%); - background-image: -ms-linear-gradient(top,#fff 0,#e0e0e0 100%); - background-image: -o-linear-gradient(top,#fff 0,#e0e0e0 100%); - background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e0e0e0)); - background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%); - background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%); + display: block; + height: 18px; + width: 18px; + border: 1px solid; + border-color: #CCCCCC #CCCCCC #AAAAAA; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; + filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#ffffffff,EndColorStr=#ffe0e0e0); + background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%); + background-image: -ms-linear-gradient(top,#fff 0,#e0e0e0 100%); + background-image: -o-linear-gradient(top,#fff 0,#e0e0e0 100%); + background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e0e0e0)); + background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%); + background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%); } #volume-button .button:hover { - border-color: #999999; - -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); - -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); + border-color: #999999; + -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); } #volume-button .button:active { - border-color: #999999 #AAAAAA #CCCCCC; - -webkit-box-shadow: 0 1px 2px 0 #aaa inset; - -moz-box-shadow: 0 1px 2px 0 #aaa inset; - box-shadow: 0 1px 2px 0 #aaa inset; - filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#e6e6e6,EndColorStr=#dcdcdc); - background-image: -moz-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); - background-image: -ms-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); - background-image: -o-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); - background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#e6e6e6),color-stop(100%,#dcdcdc)); - background-image: -webkit-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); - background-image: linear-gradient(to bottom,#e6e6e6 0,#dcdcdc 100%); + border-color: #999999 #AAAAAA #CCCCCC; + -webkit-box-shadow: 0 1px 2px 0 #aaa inset; + -moz-box-shadow: 0 1px 2px 0 #aaa inset; + box-shadow: 0 1px 2px 0 #aaa inset; + filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#e6e6e6,EndColorStr=#dcdcdc); + background-image: -moz-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); + background-image: -ms-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); + background-image: -o-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); + background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#e6e6e6),color-stop(100%,#dcdcdc)); + background-image: -webkit-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%); + background-image: linear-gradient(to bottom,#e6e6e6 0,#dcdcdc 100%); } #volume-button .button #icon { - margin: 1px; - width: 16px; - height: 16px; + margin: 1px; + width: 16px; + height: 16px; } #volume-button .button .volume-none { - background-position: 0 -88px; + background-position: 0 -88px; } #volume-button .button .volume-low { - background-position: -16px -88px; + background-position: -16px -88px; } #volume-button .button .volume-medium { - background-position: 0 -104px; + background-position: 0 -104px; } #volume-button .button .volume-high { - background-position: -16px -104px; + background-position: -16px -104px; } #volume-slider { - display: none; - height: 116px; - width: 20px; - top: -116px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - background: rgba(50, 50, 50, 0.1); - z-index: 1; + display: none; + height: 116px; + width: 20px; + top: -116px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background: rgba(50, 50, 50, 0.1); + z-index: 1; } #volume-total, #volume-current { - left: 8px; - top: 8px; - width: 4px; - height: 100px; + left: 8px; + top: 8px; + width: 4px; + height: 100px; } #volume-total, #volume-current, #volume-handle { - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; } #volume-total { - -webkit-box-shadow: inset 0 0 3px 0 #333; - -moz-box-shadow: inset 0 0 3px 0 #333; - box-shadow: inset 0 0 3px 0 #333; + -webkit-box-shadow: inset 0 0 3px 0 #333; + -moz-box-shadow: inset 0 0 3px 0 #333; + box-shadow: inset 0 0 3px 0 #333; } #volume-current { - -webkit-box-shadow: inset 0 0 1px 0 #000; - -moz-box-shadow: inset 0 0 1px 0 #000; - box-shadow: inset 0 0 1px 0 #000; - background-color: #6184b7; + -webkit-box-shadow: inset 0 0 1px 0 #000; + -moz-box-shadow: inset 0 0 1px 0 #000; + box-shadow: inset 0 0 1px 0 #000; + background-color: #6184b7; } #volume-handle { - left: 1px; - width: 16px; - height: 4px; - background: #ddd; - background: rgba(255, 255, 255, 0.9); - cursor: N-resize; - border: 1px solid #999; + left: 1px; + width: 16px; + height: 4px; + background: #ddd; + background: rgba(255, 255, 255, 0.9); + cursor: N-resize; + border: 1px solid #999; } #summary { - text-align: center; - margin-bottom: 18px; + text-align: center; + margin-bottom: 18px; } #users-wrapper { - margin-left: 120px; - width: 300px; + margin-left: 120px; + width: 300px; } #users { - padding-left: 20px; - margin-bottom: 72px; - max-height: 398px; - overflow: auto; + padding-left: 20px; + margin-bottom: 72px; + max-height: 398px; + overflow: auto; } #users .name, #tracks .artist { - font-weight: bold; + font-weight: bold; } #message-wrapper { - text-align: right; + text-align: right; } #users li, #tracks li, #chat li { - color: #404040; + color: #404040; } #users li { - height: 18px; - position: relative; + height: 18px; + position: relative; } #users .private { - display: none; - font-size: 9.75px; - padding: 2px 4px; - position: absolute; - left: -19px; + display: none; + font-size: 9.75px; + padding: 2px 4px; + position: absolute; + left: -19px; } .registered, .round-rank { - height: 16px; - width: 16px; - margin: 1px 2px 0 0; + height: 16px; + width: 16px; + margin: 1px 2px 0 0; } .registered { - background-position: 0 -16px; + background-position: 0 -16px; } .registered:hover { - background-position: -16px -16px; + background-position: -16px -16px; } #users .name { - margin-right: 4px; + margin-right: 4px; } #users .name, .registered { - cursor: pointer; + cursor: pointer; } #users .you { - cursor: auto; + cursor: auto; } #users .points, #users .round-points { - margin-right: 10px; + margin-right: 10px; } .stand1 { - background-position: 0 0; + background-position: 0 0; } .stand2 { - background-position: -16px 0; + background-position: -16px 0; } .stand3 { - background-position: -32px 0; + background-position: -32px 0; } #users .guess-time { - font-size: 11px; - line-height: 18px; + font-size: 11px; + line-height: 18px; } #toggle-chat { - position: absolute; - top: -17px; - left: 805px; - color: #BFBFBF; - height: 16px; - line-height: 16px; - font-size: 11px; - border: 1px solid #DDDDDD; - -moz-border-radius: 4px 4px 0 0; - -webkit-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; - cursor: pointer; - padding: 0 10px; - text-decoration: none; + position: absolute; + top: -17px; + left: 805px; + color: #BFBFBF; + height: 16px; + line-height: 16px; + font-size: 11px; + border: 1px solid #DDDDDD; + -moz-border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; + cursor: pointer; + padding: 0 10px; + text-decoration: none; } #toggle-chat:hover { - border-color: #CCCCCC; - background-color: #f5f5f5; - color: #333333; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(top, #ffffff, #e6e6e6); - filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); + border-color: #CCCCCC; + background-color: #f5f5f5; + color: #333333; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); } #toggle-chat:active { - background-image: none; - -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); - background-color: #e6e6e6; - background-color: #d9d9d9 \9; - outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + outline: 0; } #chat-wrapper { - margin-bottom: 4px; - height: 160px; - background-color: white; + margin-bottom: 4px; + height: 160px; + background-color: white; } #chat { - height: 152px; - width: 446px; - margin: 4px 6px; - overflow: auto; + height: 152px; + width: 446px; + margin: 4px 6px; + overflow: auto; } .bordered { - border: 1px solid #ccc; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075); - -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075); - box-shadow: 0 1px 2px rgba(0,0,0,.075); + border: 1px solid #ccc; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075); + -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075); + box-shadow: 0 1px 2px rgba(0,0,0,.075); } #chat .join, #chat .left { - font-style: italic; + font-style: italic; } #chat .private { - color: #a65fc3; + color: #a65fc3; } #feedback { - text-align: center; + text-align: center; } #feedback .correct, #users .correct{ - color: #46A546; + color: #46A546; } #feedback .wrong, #chat .error { - color: #C43C35; + color: #C43C35; } #guess.correct { - border-color: #46A546; + border-color: #46A546; } #guess.correct:focus { - -webkit-box-shadow: 0 0 6px #7aba7b; - -moz-box-shadow: 0 0 6px #7aba7b; - box-shadow: 0 0 6px #7aba7b; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; } #guess.wrong { - border-color: #C43C35; + border-color: #C43C35; } #guess.wrong:focus { - -webkit-box-shadow: 0 0 6px #d59392; - -moz-box-shadow: 0 0 6px #d59392; - box-shadow: 0 0 6px #d59392; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; } #tracks { - margin: 18px 0; - max-height: 240px; - overflow: auto; + margin: 18px 0; + max-height: 240px; + overflow: auto; } #tracks li { - margin: 0 2px 2px 0; - padding: 8px; - min-height: 40px; - background: -moz-linear-gradient(center top , #FBFBFB, #F5F5F5); - background: -webkit-gradient(linear, center top, center bottom, from(#FBFBFB), to(#F5F5F5)); - background: -webkit-linear-gradient(center top , #FBFBFB, #F5F5F5); - background: -o-linear-gradient(center top , #FBFBFB, #F5F5F5); - background: -ms-linear-gradient(center top , #FBFBFB, #F5F5F5); - background: linear-gradient(center top , #FBFBFB, #F5F5F5); + margin: 0 2px 2px 0; + padding: 8px; + min-height: 40px; + background: -moz-linear-gradient(center top , #FBFBFB, #F5F5F5); + background: -webkit-gradient(linear, center top, center bottom, from(#FBFBFB), to(#F5F5F5)); + background: -webkit-linear-gradient(center top , #FBFBFB, #F5F5F5); + background: -o-linear-gradient(center top , #FBFBFB, #F5F5F5); + background: -ms-linear-gradient(center top , #FBFBFB, #F5F5F5); + background: linear-gradient(center top , #FBFBFB, #F5F5F5); } .registered, #users .name, #users .points, .round-rank, .round-points, #users .guess-time, #tracks img.artwork, #tracks .info, .highscores .img, .profile .img, #copy, #facebook-button, #twitter-button, #github-button { - float: left; + float: left; } #tracks img.artwork { - width: 40px; - height: 40px; - margin-right: 10px; + width: 40px; + height: 40px; + margin-right: 10px; } #tracks .info { - margin-right: 15px; + margin-right: 15px; } #tracks .artist, #tracks .title { - white-space: nowrap; - max-width: 270px; - overflow: hidden; - -o-text-overflow: ellipsis; - -ms-text-overflow: ellipsis; - text-overflow: ellipsis; + white-space: nowrap; + max-width: 270px; + overflow: hidden; + -o-text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; } #tracks .artist { - margin-top: 1px; - font-size: 14px; + margin-top: 1px; + font-size: 14px; } #tracks .round-rank { - margin-top: 12px; + margin-top: 12px; } #tracks .round-points { - margin-top: 11px; + margin-top: 11px; } #tracks a { - display: block; - width: 44px; - height: 15px; - margin-top: 13px; - background-position: 0 -248px; + display: block; + width: 44px; + height: 15px; + margin-top: 13px; + background-position: 0 -248px; } #tracks a:hover { - background-position: -44px -248px; + background-position: -44px -248px; } #tracks a:active { - background-position: 0 -263px; + background-position: 0 -263px; } #disclaimer { - position: absolute; - left: 60px; - bottom: 18px; - color: #BFBFBF; - width: 340px; + position: absolute; + left: 60px; + bottom: 18px; + color: #BFBFBF; + width: 340px; } footer { - padding: 0; - margin-top: 17px; - border-top: 1px solid #DDDDDD; - color: #BFBFBF; - text-shadow: 0 1px 0 #FFFFFF; + padding: 0; + margin-top: 17px; + border-top: 1px solid #DDDDDD; + color: #BFBFBF; + text-shadow: 0 1px 0 #FFFFFF; } #footer-inner, #twitter-button, #github-button { - height: 20px; + height: 20px; } #footer-inner { - border-top: 1px solid white; - padding: 5px 20px 0 20px; - margin-bottom: 30px; + border-top: 1px solid white; + padding: 5px 20px 0 20px; + margin-bottom: 30px; } #copy { - margin-right: 20px; + margin-right: 20px; } #facebook-button { - width: 90px; - height: 21px + width: 90px; + height: 21px } #twitter-button, #github-button { - width: 100px; + width: 100px; } #copy, .footer-info { - line-height: 20px; + line-height: 20px; } .footer-info { - white-space: pre-wrap; + white-space: pre-wrap; } #nodejitsu-logo { - display: block; - width: 84px; - height: 20px; - background-position: 0 -208px; + display: block; + width: 84px; + height: 20px; + background-position: 0 -208px; } #nodejitsu-logo:hover { - background-position: 0 -228px; + background-position: 0 -228px; } diff --git a/public/js/app.js b/public/js/app.js index e899f83..9fb8fe5 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -1,985 +1,985 @@ (function() { - var elapsedtime = 0 - , DOM = {} - , historycursor = 0 - , historyvalues = [] - , ignoredplayers = {} - , jplayer - , nickname - , pvtmsgto - , subscriber = false - , roundpoints = 0 - , roomname = window.location.pathname.replace('/', '') - , socket - , stopanimation = false - , touchplay - , 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?' - , 'Exactly, now tell me the title!' - , 'Do you also know the title?' - ]; - - var bmstrings = [ - 'Yeah true! do you like this track?' - , 'Good job!' - , 'Great!' - , 'Very well done!' - , 'Exactly!' - , 'Excellent!' - , 'Woohoo!' - ]; - - var nmstrings = [ - 'Nope, sorry!' - , 'No way!' - , 'Fail' - , 'Nope' - , 'No' - , 'That\'s wrong' - , 'What?!' - , 'Wrong', 'Haha, what?!' - , 'You kidding?' - , 'Don\'t make me laugh' - , 'You mad?' - , 'Try again' - ]; - - var states = [ - 'A song is already playing, please wait for the next one...' - , 'Game is about to start...' - , 'Game is over' - , 'New game will start soon...' - ]; - - var tmstrings = [ - 'Yes, you guessed the title. Who is the artist?' - , 'Now tell me the artist!' - , 'Correct, do you also know the artist?' - ]; - - String.prototype.encodeEntities = function() { - return this.replace(/&/g, '&').replace(//g, '>'); - }; - - // Add a chat entry, whether message, notification, etc. - var addChatEntry = function(childNode) { - var li = $('
  • '); - li.append(childNode); - DOM.chat.append(li); - DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight; - }; - - var addFeedback = function(txt, style) { - if (typeof style === 'string') { - var fbspan = $(''); - fbspan.text(txt); - DOM.feedback.html(fbspan); - DOM.guessbox.addClass(style); - setTimeout(function() {DOM.guessbox.removeClass(style);}, 350); - return; - } - DOM.feedback.text(txt); - }; - - var addPrivate = function(usrname) { - if (pvtmsgto) { - clearPrivate(); - } - if (nickname === usrname) { - return; - } - DOM.recipient.css('margin-right', '4px'); - DOM.recipient.text('To '+usrname+':'); - var width = DOM.recipient.outerWidth(true) + 1; - DOM.recipient.hide(); - DOM.messagebox.animate({'width':'-='+width+'px'}, 'fast', function() { - DOM.recipient.show(); - }); - var el = $('.name').filter(function(index) { - return $(this).text() === usrname; - }); - el.prevAll('.private').show(); - el.unbind('click'); - el.click(clearPrivate); - pvtmsgto = usrname; - DOM.messagebox.focus(); - }; - - // Add track info - var addTrackInfo = function(data) { - if (touchplay) { - touchplay.removeClass('btn-success').addClass('btn-danger disabled'); - touchplay.html(' Wait'); - } - cassetteAnimation(Date.now()+5000, false); - - var artistName = data.artistName.replace(/"/g, '"') - , trackName = data.trackName.replace(/"/g, '"') - , attrs = '' - , rp = ''; - - var html = '
  • '; - html += '
    '+artistName+'
    '; - html += '
    '+trackName+'
    '; - - if (roundpoints > 0) { - rp = '+'+roundpoints; - if (roundpoints > 3) { - var stand = 7 - roundpoints; - attrs += 'class="icons round-rank stand'+stand+'"'; - } - } - html += '
    '+rp+'
    '; - html += '
  • '; - - DOM.tracks.prepend($(html)); - }; - - var addVolumeControl = function() { - var volumebutton = $('
    '+ - '
    '+ - '
    '+ // Outer background - '
    '+ // Rail - '
    '+ // Current volume - '
    '+ // Handle - '
    ').appendTo('#volume'); - - var clicked = false - , icon = volumebutton.find('#icon') - , mouseisdown = false - , mouseisover = false - , oldvalue = 1 - , volumecurrent = volumebutton.find('#volume-current') - , volumehandle = volumebutton.find('#volume-handle') - , volumeslider = volumebutton.find('#volume-slider') - , volumetotal = volumebutton.find('#volume-total'); - - var handleIcon = function (volume) { - if (volume === 0) { - icon.removeClass().addClass('icons volume-none'); - } - else if (volume <= 0.33) { - icon.removeClass().addClass('icons volume-low'); - } - else if (volume <= 0.66) { - icon.removeClass().addClass('icons volume-medium'); - } - else { - icon.removeClass().addClass('icons volume-high'); - } - }; - - var handleVolumeMove = function(e) { - var railheight = volumetotal.height() - , totaloffset = volumetotal.offset() - , totalTop = parseInt(volumetotal.css('top').replace(/px/, ''), 10) - , newy = e.pageY - totaloffset.top - , volume = (railheight - newy) / railheight; - - clicked = false; - - if (newy < 0) { - newy = 0; - } - else if (newy > railheight) { - newy = railheight; - } - - volumecurrent.height(railheight - newy); - volumecurrent.css('top', newy + totalTop); - volumehandle.css('top', totalTop + newy - (volumehandle.height() / 2)); - - volume = Math.max(0, volume); - volume = Math.min(volume, 1); - - setVolume(volume); - }; - - var loadFromCookie = function() { - if (/volume\s*\=/.test(document.cookie)) { - var value = document.cookie.replace(/.*volume\s*\=\s*([^;]*);?.*/, '$1'); - value = parseFloat(value); - positionVolumeHandle(value); - setVolume(value); - return; - } - positionVolumeHandle(1); - }; - - var positionVolumeHandle = function(volume) { - if (!volumeslider.is(':visible')) { - volumeslider.show(); - positionVolumeHandle(volume); - volumeslider.hide(); - return; - } - var totalheight = volumetotal.height(); - var totalposition = volumetotal.position(); - var newtop = totalheight - (totalheight * volume); - volumecurrent.height(totalheight - newtop ); - volumecurrent.css('top', totalposition.top + newtop); - volumehandle.css('top', totalposition.top + newtop - (volumehandle.height() / 2)); - }; - - var setCookie = function(volume) { - var d = new Date(); - d.setTime(d.getTime() + 31536000000); // One year in milliseconds - document.cookie = 'volume='+volume+';path=/;expires='+d.toGMTString()+';'; - }; - - var setVolume = function(volume) { - handleIcon(volume); - jplayer.jPlayer('volume', volume); - oldvalue = volume; - setCookie(volume); - }; - - volumebutton.find('.button').click(function() { - if (!clicked) { - clicked = true; - if (oldvalue !== 0) { - handleIcon(0); - jplayer.jPlayer('volume', 0); - positionVolumeHandle(0); - } - } - else { - clicked = false; - if (oldvalue !== 0) { - handleIcon(oldvalue); - jplayer.jPlayer('volume', oldvalue); - positionVolumeHandle(oldvalue); - } - } - }); - - volumebutton.hover(function() { - mouseisover = true; - volumeslider.show(); - }, function() { - mouseisover = false; - if (!mouseisdown) { - volumeslider.hide(); - } - }); - - volumeslider.on('mouseover', function() { - mouseisover = true; - }).on('mousedown', function(e) { - handleVolumeMove(e); - mouseisdown = true; - return false; - }); - - $(document).on('mouseup', function(e) { - mouseisdown = false; - if (!mouseisover) { - volumeslider.hide(); - } - }).on('mousemove', function(e) { - if (mouseisdown) { - handleVolumeMove(e); - } - }); - - loadFromCookie(); - }; - - // Called when a registered user already in a room, tries to enter in another room - var alreadyInARoom = function() { - var html = ''; - html += ''; - $(html).appendTo(DOM.modal); - DOM.modal.modal('show'); - }; - - // Start cassette animation - var cassetteAnimation = function(endtime, forward) { - var millisleft = endtime - Date.now() - , secleft = millisleft / 1000 - , width - , deg - , offsetleft - , offsetright - , css; - - if (forward) { - width = 148 - (148*secleft/30); - deg = 360 - (360*secleft/30); - offsetleft = 44 - 24*secleft/30; - offsetright = 130 - 24*secleft/30; - DOM.progress.width(width); - DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)'); - DOM.tapeleft.css('left', offsetleft+'px'); - DOM.taperight.css('left', offsetright+'px'); - } - else { - width = 148*secleft/5; - deg = 360*secleft/5; - offsetleft = 20 + 24*secleft/5; - offsetright = 106 + 24*secleft/5; - DOM.progress.width(width); - DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)'); - DOM.tapeleft.css('left', offsetleft+'px'); - DOM.taperight.css('left', offsetright+'px'); - } - - if (forward) { - DOM.countdown.text(secleft.toFixed(1)); - if (touchplay) {elapsedtime = 30 - Math.round(secleft);} - } - else { - DOM.countdown.text(Math.round(secleft)); - } - - if (stopanimation || millisleft < 50) { - return; - } - - setTimeout(function() {cassetteAnimation(endtime, forward);}, 50); - }; - - var clearPrivate = function() { - var width = DOM.recipient.outerWidth(true) + 1; - DOM.recipient.css('margin-right', '0'); - DOM.recipient.text(''); - DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast'); - var el = $('.name').filter(function(index) { - return $(this).text() === pvtmsgto; - }); - el.prevAll('.private').hide(); - el.unbind('click'); - el.click(function() { - addPrivate($(this).text()); - }); - pvtmsgto = null; - DOM.messagebox.focus(); - }; - - // Game over countdown - var countDown = function(endtime) { - var millisleft = endtime - Date.now(); - var secleft = millisleft / 1000; - $('.modal-footer span').text(Math.round(secleft)); - if (millisleft < 200) { - return; - } - setTimeout(function() {countDown(endtime);}, 200); - }; - - // Let the user know when he/she has disconnected - var disconnect = function() { - stopanimation = true; - jplayer.jPlayer('stop'); - var errorspan = $('ERROR: You have disconnected.'); - addChatEntry(errorspan); - addFeedback('Something wrong happened'); - DOM.users.empty(); - }; + var elapsedtime = 0 + , DOM = {} + , historycursor = 0 + , historyvalues = [] + , ignoredplayers = {} + , jplayer + , nickname + , pvtmsgto + , subscriber = false + , roundpoints = 0 + , roomname = window.location.pathname.replace('/', '') + , socket + , stopanimation = false + , touchplay + , 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?' + , 'Exactly, now tell me the title!' + , 'Do you also know the title?' + ]; + + var bmstrings = [ + 'Yeah true! do you like this track?' + , 'Good job!' + , 'Great!' + , 'Very well done!' + , 'Exactly!' + , 'Excellent!' + , 'Woohoo!' + ]; + + var nmstrings = [ + 'Nope, sorry!' + , 'No way!' + , 'Fail' + , 'Nope' + , 'No' + , 'That\'s wrong' + , 'What?!' + , 'Wrong', 'Haha, what?!' + , 'You kidding?' + , 'Don\'t make me laugh' + , 'You mad?' + , 'Try again' + ]; + + var states = [ + 'A song is already playing, please wait for the next one...' + , 'Game is about to start...' + , 'Game is over' + , 'New game will start soon...' + ]; + + var tmstrings = [ + 'Yes, you guessed the title. Who is the artist?' + , 'Now tell me the artist!' + , 'Correct, do you also know the artist?' + ]; + + String.prototype.encodeEntities = function() { + return this.replace(/&/g, '&').replace(//g, '>'); + }; + + // Add a chat entry, whether message, notification, etc. + var addChatEntry = function(childNode) { + var li = $('
  • '); + li.append(childNode); + DOM.chat.append(li); + DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight; + }; + + var addFeedback = function(txt, style) { + if (typeof style === 'string') { + var fbspan = $(''); + fbspan.text(txt); + DOM.feedback.html(fbspan); + DOM.guessbox.addClass(style); + setTimeout(function() {DOM.guessbox.removeClass(style);}, 350); + return; + } + DOM.feedback.text(txt); + }; - var gameOver = function(podium) { - var html = ''; - html += ''; - html += ''; - DOM.modal.append($(html)); - DOM.modal.modal('show'); - countDown(Date.now()+10000); - }; + volumebutton.hover(function() { + mouseisover = true; + volumeslider.show(); + }, function() { + mouseisover = false; + if (!mouseisdown) { + volumeslider.hide(); + } + }); - // Receive a chat message - var getChatMessage = function(chatmsg, from, to) { - if (ignoredplayers[from]) { - return; - } - var prefix = from; - var msgspan = $(''); - if (to) { - // Private Message - prefix = (nickname === from) ? '(To '+to+')' : '(From '+prefix+')'; - msgspan.addClass('private'); - } - var msg = prefix+': '+chatmsg; - msgspan.html(urlize(msg)); - addChatEntry(msgspan); - }; + volumeslider.on('mouseover', function() { + mouseisover = true; + }).on('mousedown', function(e) { + handleVolumeMove(e); + mouseisdown = true; + return false; + }); - var hideChat = function() { - DOM.togglechat.text('Show chat').unbind('click'); - DOM.chatwrapper.toggle(300); - DOM.tracks.animate({maxHeight:'434px'}, 300); - DOM.togglechat.click(showChat); - }; + $(document).on('mouseup', function(e) { + mouseisdown = false; + if (!mouseisover) { + volumeslider.hide(); + } + }).on('mousemove', function(e) { + if (mouseisdown) { + handleVolumeMove(e); + } + }); - // Put a player in the ignore list - var ignorePlayer = function(args, outcome) { - if (ignoredplayers[args[0]]) { - outcome.text('(From binb): '+args[0]+' is already ignored.'); - return addChatEntry(outcome); - } - socket.emit('ignore', args[0], function(player) { - if (player) { - ignoredplayers[player] = true; - outcome.text('(From binb): '+player+' is now ignored.'); - return addChatEntry(outcome); - } - outcome.append('player not found.'); - addChatEntry(outcome); - }); - }; + loadFromCookie(); + }; + + // Called when a registered user already in a room, tries to enter in another room + var alreadyInARoom = function() { + var html = ''; + html += ''; + $(html).appendTo(DOM.modal); + DOM.modal.modal('show'); + }; + + // Start cassette animation + var cassetteAnimation = function(endtime, forward) { + var millisleft = endtime - Date.now() + , secleft = millisleft / 1000 + , width + , deg + , offsetleft + , offsetright + , css; + + if (forward) { + width = 148 - (148*secleft/30); + deg = 360 - (360*secleft/30); + offsetleft = 44 - 24*secleft/30; + offsetright = 130 - 24*secleft/30; + DOM.progress.width(width); + DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)'); + DOM.tapeleft.css('left', offsetleft+'px'); + DOM.taperight.css('left', offsetright+'px'); + } + else { + width = 148*secleft/5; + deg = 360*secleft/5; + offsetleft = 20 + 24*secleft/5; + offsetright = 106 + 24*secleft/5; + DOM.progress.width(width); + DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)'); + DOM.tapeleft.css('left', offsetleft+'px'); + DOM.taperight.css('left', offsetright+'px'); + } - // Submitted name was invalid - var invalidNickName = function(feedback) { - joinAnonymously(feedback+'
    Try with another one:'); - }; + if (forward) { + DOM.countdown.text(secleft.toFixed(1)); + if (touchplay) {elapsedtime = 30 - Math.round(secleft);} + } + else { + DOM.countdown.text(Math.round(secleft)); + } - // Prompt for name and send it - var joinAnonymously = function(msg) { - if (/nickname\s*\=/.test(document.cookie) && !msg) { - var nickname = document.cookie.replace(/.*nickname\s*\=\s*([^;]*);?.*/, '$1'); - return socket.emit('joinanonymously', nickname, roomname); - } + if (stopanimation || millisleft < 50) { + return; + } - if (DOM.modal.hasClass('in')) { - $('.modal-body p').html(msg); - return $('#login').focus(); - } + setTimeout(function() {cassetteAnimation(endtime, forward);}, 50); + }; - var html = ''; - html += ''; - html += ''; - - $(html).appendTo(DOM.modal); - var login = $('#login'); - var button = $('#join'); - - button.click(function() { - if ($.trim(login.val()) !== '') { - nickname = login.val(); - socket.emit('joinanonymously', nickname, roomname); - } - else { - var txt = 'Nickname can\'t be empty.'; - invalidNickName(''+txt+''); - } - login.val(''); - }); + var clearPrivate = function() { + var width = DOM.recipient.outerWidth(true) + 1; + DOM.recipient.css('margin-right', '0'); + DOM.recipient.text(''); + DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast'); + var el = $('.name').filter(function(index) { + return $(this).text() === pvtmsgto; + }); + el.prevAll('.private').hide(); + el.unbind('click'); + el.click(function() { + addPrivate($(this).text()); + }); + pvtmsgto = null; + DOM.messagebox.focus(); + }; + + // Game over countdown + var countDown = function(endtime) { + var millisleft = endtime - Date.now(); + var secleft = millisleft / 1000; + $('.modal-footer span').text(Math.round(secleft)); + if (millisleft < 200) { + return; + } + setTimeout(function() {countDown(endtime);}, 200); + }; + + // Let the user know when he/she has disconnected + var disconnect = function() { + stopanimation = true; + jplayer.jPlayer('stop'); + var errorspan = $('ERROR: You have disconnected.'); + addChatEntry(errorspan); + addFeedback('Something wrong happened'); + DOM.users.empty(); + }; + + var gameOver = function(podium) { + var html = ''; + html += ''; + html += ''; + DOM.modal.append($(html)); + DOM.modal.modal('show'); + countDown(Date.now()+10000); + }; + + // Receive a chat message + var getChatMessage = function(chatmsg, from, to) { + if (ignoredplayers[from]) { + return; + } + var prefix = from; + var msgspan = $(''); + if (to) { + // Private Message + prefix = (nickname === from) ? '(To '+to+')' : '(From '+prefix+')'; + msgspan.addClass('private'); + } + var msg = prefix+': '+chatmsg; + msgspan.html(urlize(msg)); + addChatEntry(msgspan); + }; + + var hideChat = function() { + DOM.togglechat.text('Show chat').unbind('click'); + DOM.chatwrapper.toggle(300); + DOM.tracks.animate({maxHeight:'434px'}, 300); + DOM.togglechat.click(showChat); + }; + + // Put a player in the ignore list + var ignorePlayer = function(args, outcome) { + if (ignoredplayers[args[0]]) { + outcome.text('(From binb): '+args[0]+' is already ignored.'); + return addChatEntry(outcome); + } + socket.emit('ignore', args[0], function(player) { + if (player) { + ignoredplayers[player] = true; + outcome.text('(From binb): '+player+' is now ignored.'); + return addChatEntry(outcome); + } + outcome.append('player not found.'); + addChatEntry(outcome); + }); + }; + + // Submitted name was invalid + var invalidNickName = function(feedback) { + joinAnonymously(feedback+'
    Try with another one:'); + }; + + // Prompt for name and send it + var joinAnonymously = function(msg) { + if (/nickname\s*\=/.test(document.cookie) && !msg) { + nickname = document.cookie.replace(/.*nickname\s*\=\s*([^;]*);?.*/, '$1'); + return socket.emit('joinanonymously', nickname, roomname); + } - DOM.modal.modal('show'); - DOM.modal.on('shown', function() { - login.focus(); - }); - }; + if (DOM.modal.hasClass('in')) { + $('.modal-body p').html(msg); + return $('#login').focus(); + } - var jplayerReady = function() { - socket.emit('loggedin', function(data) { - if (data) { - nickname = data; - subscriber = true; - return socket.emit('joinroom', roomname); - } - joinAnonymously(); - }); - if (!$.jPlayer.platform.mobile && !$.jPlayer.platform.tablet) { - return addVolumeControl(); - } - var touchbackdrop = $('
    '+ - '
    ').appendTo('#cassette'); - touchplay = $('#touch-play'); - touchplay.click(function() { - if (!$(this).hasClass('btn-danger')) { - touchplay = null; - jplayer.jPlayer('play', elapsedtime); - touchbackdrop.remove(); - } - }); - }; + var html = ''; + html += ''; + html += ''; + + $(html).appendTo(DOM.modal); + var login = $('#login'); + var button = $('#join'); + + button.click(function() { + if ($.trim(login.val()) !== '') { + nickname = login.val(); + socket.emit('joinanonymously', nickname, roomname); + } + else { + var txt = 'Nickname can\'t be empty.'; + invalidNickName(''+txt+''); + } + login.val(''); + }); - // Kick a player - var kickPlayer = function(args, outcome) { - outcome.append('you are not allowed to kick a player.'); - if (!subscriber) { - return addChatEntry(outcome); - } - var why = args[1] || ''; - socket.emit('kick', args[0], why, function() { - addChatEntry(outcome); - }); - }; + login.keyup(function(event) { + if (event.keyCode === 13) { + button.click(); + } + }); - var loadTrack = function(previewUrl) { - jplayer.jPlayer('mute'); - jplayer.jPlayer('setMedia', {m4a: previewUrl}); - }; + DOM.modal.modal('show'); + DOM.modal.on('shown', function() { + login.focus(); + }); + }; + + var jplayerReady = function() { + socket.emit('loggedin', function(data) { + if (data) { + nickname = data; + subscriber = true; + return socket.emit('joinroom', roomname); + } + joinAnonymously(); + }); + if (!$.jPlayer.platform.mobile && !$.jPlayer.platform.tablet) { + return addVolumeControl(); + } + var touchbackdrop = $('
    '+ + '
    ').appendTo('#cassette'); + touchplay = $('#touch-play'); + touchplay.click(function() { + if (!$(this).hasClass('btn-danger')) { + touchplay = null; + jplayer.jPlayer('play', elapsedtime); + touchbackdrop.remove(); + } + }); + }; - /** - * Given a string, parse the string extracting fields separated by whitespace - * and optionally enclosed within double quotes (which are stripped off), and - * build an array of copies of the string for each field. - */ - - var parseCommand = function(input) { - var inquotes = false - , token = '' - , tokens = []; - for (var i = 0; i < input.length; i++) { - if (input[i] === '\\') { - if (++i === input.length) { - throw new Error('SyntaxError: Unexpected end of input'); - } - if (input[i] === '\\' || input[i] === '"' || !inquotes) { - token += input[i]; - continue; - } - token += '\\'+input[i]; - continue; - } - if (input[i] === '"') { - inquotes = !inquotes; - var j = i + 1; - if (!inquotes && (input[j] === ' ' || j === input.length)) { - tokens.push(token); - token = ''; - i = j; - } - continue; - } - if (input[i] === ' ') { - if (inquotes) { - token += ' '; - } - else if (token.length) { - tokens.push(token); - token = ''; - } - continue; - } - token += input[i]; - } + // Kick a player + var kickPlayer = function(args, outcome) { + outcome.append('you are not allowed to kick a player.'); + if (!subscriber) { + return addChatEntry(outcome); + } + var why = args[1] || ''; + socket.emit('kick', args[0], why, function() { + addChatEntry(outcome); + }); + }; + + var loadTrack = function(previewUrl) { + jplayer.jPlayer('mute'); + jplayer.jPlayer('setMedia', {m4a: previewUrl}); + }; + + /** + * Given a string, parse the string extracting fields separated by whitespace + * and optionally enclosed within double quotes (which are stripped off), and + * build an array of copies of the string for each field. + */ + + var parseCommand = function(input) { + var inquotes = false + , token = '' + , tokens = []; + for (var i = 0; i < input.length; i++) { + if (input[i] === '\\') { + if (++i === input.length) { + throw new Error('SyntaxError: Unexpected end of input'); + } + if (input[i] === '\\' || input[i] === '"' || !inquotes) { + token += input[i]; + continue; + } + token += '\\'+input[i]; + continue; + } + if (input[i] === '"') { + inquotes = !inquotes; + var j = i + 1; + if (!inquotes && (input[j] === ' ' || j === input.length)) { + tokens.push(token); + token = ''; + i = j; + } + continue; + } + if (input[i] === ' ') { if (inquotes) { - throw new Error('SyntaxError: Unexpected end of input'); - } - if (token.length) { - tokens.push(token); - } - return tokens; - }; - - // Play a track - var playTrack = function(data) { - if (touchplay) { - touchplay.removeClass('btn-danger disabled').addClass('btn-success'); - touchplay.html(' Play'); - } - jplayer.jPlayer('unmute'); - jplayer.jPlayer('play'); - updateUsers(data.users); - cassetteAnimation(Date.now()+30000, true); - if (data.counter === 1) { - DOM.modal.modal('hide').empty(); - DOM.tracks.empty(); - } - DOM.track.text(data.counter+'/'+data.tot); - addFeedback('What is this song?'); - }; - - // Successfully joined the room - var ready = function(usersData, trackscount, loggedin) { - if (!loggedin && !/nickname\s*\=/.test(document.cookie)) { - document.cookie = 'nickname='+nickname+';path=/;'; - } - - DOM.modal.modal('hide').empty(); - $('#total-tracks span').text(trackscount); - var msg = nickname+' joined the game'; - var joinspan = $(''); - joinspan.text(msg); - addChatEntry(joinspan); - updateUsers(usersData); - - DOM.messagebox.keydown(function(event) { - if (event.keyCode === 13) { - var val = $.trim(DOM.messagebox.val()); - if (val !== '') { - if (pvtmsgto) { - socket.emit('sendchatmsg', val, pvtmsgto); - } - else if (/^\/[^ ]/.test(val)) { - slashCommandHandler(val); - } - else { - socket.emit('sendchatmsg', val); - } - } - DOM.messagebox.val(''); - } - }); - - DOM.guessbox.keydown(function(event) { - switch (event.keyCode) { - case 13: // return - var guess = $.trim(DOM.guessbox.val()); - if (guess !== '') { - socket.emit('guess', guess.toLowerCase()); - historyvalues.push(guess); - if (historyvalues.length > 20) { - historyvalues.splice(0, 1); - } - historycursor = historyvalues.length; - } - DOM.guessbox.val(''); - break; - case 38: // up-arrow - if (historycursor > 0) { - DOM.guessbox.val(historyvalues[--historycursor]); - } - break; - case 40: // down-arrow - if (historycursor < historyvalues.length - 1) { - DOM.guessbox.val(historyvalues[++historycursor]); - } - else { - historycursor = historyvalues.length; - DOM.guessbox.val(''); - } - } - }); - - DOM.guessbox.focus(); - - socket.on('artistmatched', function() { - addFeedback(amstrings[Math.floor(Math.random()*amstrings.length)], 'correct'); - }); - socket.on('bothmatched', function() { - addFeedback(bmstrings[Math.floor(Math.random()*bmstrings.length)], 'correct'); - }); - socket.on('chatmsg', getChatMessage); - socket.on('gameover', gameOver); - socket.on('loadtrack', loadTrack); - socket.on('newuser', userJoin); - socket.on('noguesstime', function() { - addFeedback('You have to wait the next song...'); - }); - socket.on('nomatch', function() { - addFeedback(nmstrings[Math.floor(Math.random()*nmstrings.length)], 'wrong'); - }); - socket.on('playtrack', playTrack); - socket.on('stoptrying', function() { - addFeedback('You guessed both artist and title. Please wait...'); - }); - socket.on('titlematched', function() { - addFeedback(tmstrings[Math.floor(Math.random()*tmstrings.length)], 'correct'); - }); - socket.on('trackinfo', addTrackInfo); - socket.on('updateusers', updateUsers); - socket.on('userleft', userLeft); - socket.emit('getstatus', setStatus); - }; - - // Show the number of players inside each room - var roomsOverview = function(data) { - for (var prop in data) { - if (prop !== roomname) { - DOM.userscounters[prop].text(data[prop]); - } - } - }; - - var setStatus = function(data) { - if (data.status === 0) { - cassetteAnimation(Date.now()+data.timeleft, true); + token += ' '; } - else if (data.status === 1) { - loadTrack(data.previewUrl); + else if (token.length) { + tokens.push(token); + token = ''; } - addFeedback(states[data.status]); - }; - - var setVariables = function() { - DOM.cassettewheels = $('#cassette .wheel'); - DOM.chat = $('#chat'); - DOM.chatwrapper = $('#chat-outer-wrapper'); - DOM.countdown = $('#countdown'); - DOM.feedback = $('#feedback'); - DOM.guessbox = $('#guess'); - DOM.messagebox = $('#message'); - DOM.modal = $('#modal'); - DOM.points = $('#summary .points'); - DOM.progress = $('#progress'); - DOM.rank = $('#summary .rank'); - DOM.recipient = $('#recipient'); - DOM.tapeleft = $('#tape-left'); - DOM.taperight = $('#tape-right'); - DOM.togglechat = $('#toggle-chat'); - DOM.track = $('#summary .track'); - DOM.tracks = $('#tracks'); - DOM.users = $('#users'); - DOM.userscounters = {}; - $('.users-counter').each(function() { - DOM.userscounters[$(this).prevAll('.room-name').text()] = $(this); - }); - }; - - var showChat = function() { - DOM.togglechat.text('Hide chat').unbind('click'); - DOM.chatwrapper.toggle(300); - DOM.tracks.animate({maxHeight:'240px'}, 300, function() { - DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight; - }); - DOM.togglechat.click(hideChat); - }; - - var slashCommandHandler = function(line) { - var args; - var outcome = $('(From binb): '); + continue; + } + token += input[i]; + } + if (inquotes) { + throw new Error('SyntaxError: Unexpected end of input'); + } + if (token.length) { + tokens.push(token); + } + return tokens; + }; + + // Play a track + var playTrack = function(data) { + if (touchplay) { + touchplay.removeClass('btn-danger disabled').addClass('btn-success'); + touchplay.html(' Play'); + } + jplayer.jPlayer('unmute'); + jplayer.jPlayer('play'); + updateUsers(data.users); + cassetteAnimation(Date.now()+30000, true); + if (data.counter === 1) { + DOM.modal.modal('hide').empty(); + DOM.tracks.empty(); + } + DOM.track.text(data.counter+'/'+data.tot); + addFeedback('What is this song?'); + }; + + // Successfully joined the room + var ready = function(usersData, trackscount, loggedin) { + if (!loggedin && !/nickname\s*\=/.test(document.cookie)) { + document.cookie = 'nickname='+nickname+';path=/;'; + } - try { - args = parseCommand(line); - } - catch (err) { - outcome.append(err.message); - return addChatEntry(outcome); - } + DOM.modal.modal('hide').empty(); + $('#total-tracks span').text(trackscount); + var msg = nickname+' joined the game'; + var joinspan = $(''); + joinspan.text(msg); + addChatEntry(joinspan); + updateUsers(usersData); + + DOM.messagebox.keydown(function(event) { + if (event.keyCode === 13) { + var val = $.trim(DOM.messagebox.val()); + if (val !== '') { + if (pvtmsgto) { + socket.emit('sendchatmsg', val, pvtmsgto); + } + else if (/^\/[^ ]/.test(val)) { + slashCommandHandler(val); + } + else { + socket.emit('sendchatmsg', val); + } + } + DOM.messagebox.val(''); + } + }); - var cmdname = args.shift(); - var command = slashcommands[cmdname.substr(1)]; + DOM.guessbox.keydown(function(event) { + switch (event.keyCode) { + case 13: // return + var guess = $.trim(DOM.guessbox.val()); + if (guess !== '') { + socket.emit('guess', guess.toLowerCase()); + historyvalues.push(guess); + if (historyvalues.length > 20) { + historyvalues.splice(0, 1); + } + historycursor = historyvalues.length; + } + DOM.guessbox.val(''); + break; + case 38: // up-arrow + if (historycursor > 0) { + DOM.guessbox.val(historyvalues[--historycursor]); + } + break; + case 40: // down-arrow + if (historycursor < historyvalues.length - 1) { + DOM.guessbox.val(historyvalues[++historycursor]); + } + else { + historycursor = historyvalues.length; + DOM.guessbox.val(''); + } + } + }); - if (command) { - if (args.length < command.minargs) { - outcome.append(command.usage); - return addChatEntry(outcome); - } - if (command.checkrecipient && (!args[0] || args[0] === nickname)) { - outcome.append('invalid argument.'); - return addChatEntry(outcome); - } - return command.fn(args, outcome); - } + DOM.guessbox.focus(); - outcome.text('(From binb): unknown command '+cmdname+'.'); - addChatEntry(outcome); - }; + socket.on('artistmatched', function() { + addFeedback(amstrings[Math.floor(Math.random()*amstrings.length)], 'correct'); + }); + socket.on('bothmatched', function() { + addFeedback(bmstrings[Math.floor(Math.random()*bmstrings.length)], 'correct'); + }); + socket.on('chatmsg', getChatMessage); + socket.on('gameover', gameOver); + socket.on('loadtrack', loadTrack); + socket.on('newuser', userJoin); + socket.on('noguesstime', function() { + addFeedback('You have to wait the next song...'); + }); + socket.on('nomatch', function() { + addFeedback(nmstrings[Math.floor(Math.random()*nmstrings.length)], 'wrong'); + }); + socket.on('playtrack', playTrack); + socket.on('stoptrying', function() { + addFeedback('You guessed both artist and title. Please wait...'); + }); + socket.on('titlematched', function() { + addFeedback(tmstrings[Math.floor(Math.random()*tmstrings.length)], 'correct'); + }); + socket.on('trackinfo', addTrackInfo); + socket.on('updateusers', updateUsers); + socket.on('userleft', userLeft); + socket.emit('getstatus', setStatus); + }; + + // Show the number of players inside each room + var roomsOverview = function(data) { + for (var prop in data) { + if (prop !== roomname) { + DOM.userscounters[prop].text(data[prop]); + } + } + }; - // Remove a player from the ignore list - var unignorePlayer = function(args, outcome) { - if (!ignoredplayers[args[0]]) { - outcome.text('(From binb): you have not ignored '+args[0]+'.'); - return addChatEntry(outcome); - } - delete ignoredplayers[args[0]]; - socket.emit('unignore', args[0]); - outcome.text('(From binb): '+args[0]+' is no longer ignored.'); - addChatEntry(outcome); - }; + var setStatus = function(data) { + if (data.status === 0) { + cassetteAnimation(Date.now()+data.timeleft, true); + } + else if (data.status === 1) { + loadTrack(data.previewUrl); + } + addFeedback(states[data.status]); + }; + + var setVariables = function() { + DOM.cassettewheels = $('#cassette .wheel'); + DOM.chat = $('#chat'); + DOM.chatwrapper = $('#chat-outer-wrapper'); + DOM.countdown = $('#countdown'); + DOM.feedback = $('#feedback'); + DOM.guessbox = $('#guess'); + DOM.messagebox = $('#message'); + DOM.modal = $('#modal'); + DOM.points = $('#summary .points'); + DOM.progress = $('#progress'); + DOM.rank = $('#summary .rank'); + DOM.recipient = $('#recipient'); + DOM.tapeleft = $('#tape-left'); + DOM.taperight = $('#tape-right'); + DOM.togglechat = $('#toggle-chat'); + DOM.track = $('#summary .track'); + DOM.tracks = $('#tracks'); + DOM.users = $('#users'); + DOM.userscounters = {}; + $('.users-counter').each(function() { + DOM.userscounters[$(this).prevAll('.room-name').text()] = $(this); + }); + }; - // Update the list of players - var updateUsers = function(usersData) { - DOM.users.empty(); + var showChat = function() { + DOM.togglechat.text('Hide chat').unbind('click'); + DOM.chatwrapper.toggle(300); + DOM.tracks.animate({maxHeight:'240px'}, 300, function() { + DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight; + }); + DOM.togglechat.click(hideChat); + }; - var users = []; - for (var key in usersData) { - users.push(usersData[key]); - } - users.sort(function(a, b) {return b.points - a.points;}); - - // Flag to test if our private recipient is in the list of active users - var found = false; - for (var i=0; i') - , pvt = $('P') - , username = $('').text(user.nickname) - , points = $('('+user.points+')') - , roundrank = $('') - , roundpointsel = $('') - , guesstime = $(''); - - li.append(pvt, username, points, roundrank, roundpointsel, guesstime); - if (user.registered) { - var href = 'href="/user/'+user.nickname+'"'; - pvt.after(''); - } - DOM.users.append(li); + var slashCommandHandler = function(line) { + var args; + var outcome = $('(From binb): '); - if (pvtmsgto === user.nickname) { - pvt.show(); - username.click(clearPrivate); - found = true; - } - else { - username.click(function() { - addPrivate($(this).text()); - }); - } + try { + args = parseCommand(line); + } + catch (err) { + outcome.append(err.message); + return addChatEntry(outcome); + } - if (nickname === user.nickname) { - username.addClass('you'); - roundpoints = user.roundpoints; - DOM.rank.text(i+1); - DOM.points.text(user.points); - } + var cmdname = args.shift(); + var command = slashcommands[cmdname.substr(1)]; + + if (command) { + if (args.length < command.minargs) { + outcome.append(command.usage); + return addChatEntry(outcome); + } + if (command.checkrecipient && (!args[0] || args[0] === nickname)) { + outcome.append('invalid argument.'); + return addChatEntry(outcome); + } + return command.fn(args, outcome); + } - if (user.roundpoints > 0) { - roundpointsel.text('+'+user.roundpoints); - if (user.roundpoints === 1) { - username.addClass('matched'); - } - else { - if (user.roundpoints > 3) { - var stand = 7 - user.roundpoints; - roundrank.addClass('icons round-rank stand'+stand); - var gtime = (user.guesstime / 1000).toFixed(1); - guesstime.text(gtime+' s'); - } - username.addClass('correct'); - } - } - } + outcome.text('(From binb): unknown command '+cmdname+'.'); + addChatEntry(outcome); + }; - if (!found && pvtmsgto) { - var width = DOM.recipient.outerWidth(true) + 1; - DOM.recipient.css('margin-right', '0'); - DOM.recipient.text(''); - DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast'); - pvtmsgto = null; - DOM.messagebox.focus(); - } - }; + // Remove a player from the ignore list + var unignorePlayer = function(args, outcome) { + if (!ignoredplayers[args[0]]) { + outcome.text('(From binb): you have not ignored '+args[0]+'.'); + return addChatEntry(outcome); + } + delete ignoredplayers[args[0]]; + socket.emit('unignore', args[0]); + outcome.text('(From binb): '+args[0]+' is no longer ignored.'); + addChatEntry(outcome); + }; + + // Update the list of players + var updateUsers = function(usersData) { + DOM.users.empty(); + + var users = []; + for (var key in usersData) { + users.push(usersData[key]); + } + users.sort(function(a, b) {return b.points - a.points;}); + + // Flag to test if our private recipient is in the list of active users + var found = false; + for (var i=0; i') + , pvt = $('P') + , username = $('').text(user.nickname) + , points = $('('+user.points+')') + , roundrank = $('') + , roundpointsel = $('') + , guesstime = $(''); + + li.append(pvt, username, points, roundrank, roundpointsel, guesstime); + if (user.registered) { + var href = 'href="/user/'+user.nickname+'"'; + pvt.after(''); + } + DOM.users.append(li); + + if (pvtmsgto === user.nickname) { + pvt.show(); + username.click(clearPrivate); + found = true; + } + else { + username.click(function() { + addPrivate($(this).text()); + }); + } - var updateRoomsOverview = function(room, players) { - if (room !== roomname) { - DOM.userscounters[room].text(players); - } - }; + if (nickname === user.nickname) { + username.addClass('you'); + roundpoints = user.roundpoints; + DOM.rank.text(i+1); + DOM.points.text(user.points); + } - // Convert any URLs in text into clickable links - var urlize = function(text) { - if (urlregex.test(text)) { - var html = ''; - var splits = text.split(urlregex); - for (var i=0; i'+escapedsplit+''; - continue; - } - html += escapedsplit; - } - return html; + if (user.roundpoints > 0) { + roundpointsel.text('+'+user.roundpoints); + if (user.roundpoints === 1) { + username.addClass('matched'); } - return text.encodeEntities(); - }; - - // A new player has joined the game - var userJoin = function(username, usersData) { - var joinmsg = username+' joined the game'; - var joinspan = $(''); - joinspan.text(joinmsg); - addChatEntry(joinspan); - updateUsers(usersData); - }; - - // A player has left the game - var userLeft = function(username, usersData) { - var leftmsg = username+' left the game'; - var leftspan = $(''); - leftspan.text(leftmsg); - addChatEntry(leftspan); - updateUsers(usersData); - }; + else { + if (user.roundpoints > 3) { + var stand = 7 - user.roundpoints; + roundrank.addClass('icons round-rank stand'+stand); + var gtime = (user.guesstime / 1000).toFixed(1); + guesstime.text(gtime+' s'); + } + username.addClass('correct'); + } + } + } - var slashcommands = { - ignore: { - checkrecipient: true, // Assume that the first argument (argv[0]) is the recipient - fn: ignorePlayer, - minargs: 1, - usage: 'usage: /ignore <player name>' - }, - kick: { - checkrecipient: true, - fn: kickPlayer, - minargs: 1, - usage: 'usage: /kick <player name> [message]' - }, - unignore: { - checkrecipient: true, - fn: unignorePlayer, - minargs: 1, - usage: 'usage: /unignore <player name>' - } - }; + if (!found && pvtmsgto) { + var width = DOM.recipient.outerWidth(true) + 1; + DOM.recipient.css('margin-right', '0'); + DOM.recipient.text(''); + DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast'); + pvtmsgto = null; + DOM.messagebox.focus(); + } + }; - // 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; - } - }); + var updateRoomsOverview = function(room, players) { + if (room !== roomname) { + DOM.userscounters[room].text(players); } - 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); + }; + + // Convert any URLs in text into clickable links + var urlize = function(text) { + if (urlregex.test(text)) { + var html = ''; + var splits = text.split(urlregex); + for (var i=0; i'+escapedsplit+''; + continue; + } + html += escapedsplit; + } + return html; + } + return text.encodeEntities(); + }; + + // A new player has joined the game + var userJoin = function(username, usersData) { + var joinmsg = username+' joined the game'; + var joinspan = $(''); + joinspan.text(joinmsg); + addChatEntry(joinspan); + updateUsers(usersData); + }; + + // A player has left the game + var userLeft = function(username, usersData) { + var leftmsg = username+' left the game'; + var leftspan = $(''); + leftspan.text(leftmsg); + addChatEntry(leftspan); + updateUsers(usersData); + }; + + var slashcommands = { + ignore: { + checkrecipient: true, // Assume that the first argument (argv[0]) is the recipient + fn: ignorePlayer, + minargs: 1, + usage: 'usage: /ignore <player name>' + }, + kick: { + checkrecipient: true, + fn: kickPlayer, + minargs: 1, + usage: 'usage: /kick <player name> [message]' + }, + unignore: { + checkrecipient: true, + fn: unignorePlayer, + minargs: 1, + usage: 'usage: /unignore <player name>' + } + }; + + // 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/js/home.js b/public/js/home.js index 5c0ec62..e1c9083 100644 --- a/public/js/home.js +++ b/public/js/home.js @@ -1,31 +1,31 @@ (function() { - if ($.browser.mozilla) { - // Block ESC button in firefox (breaks socket connections). - $(document).keypress(function(event) { - if(event.keyCode === 27) { - return false; - } - }); - } - $.get('/artworks', function(data) { - $('.thumbnail').each(function(index) { - var i = index * 6; - var j = i + 6; - for(i; i < j; i++) { - $('').appendTo($(this)); - } - }); + 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; - var socket = io.connect(uri, {'reconnect':false}); - socket.on('connect', function() { - socket.emit('getoverview', function(data) { - for (var prop in data) { - $('#'+prop).text(data[prop]); - } - }); - socket.on('updateoverview', function(room, players) { - $('#'+room).text(players); - }); + } + $.get('/artworks', function(data) { + $('.thumbnail').each(function(index) { + var i = index * 6; + var j = i + 6; + for(i; i < j; i++) { + $('').appendTo($(this)); + } }); + }); + var uri = window.location.protocol+'//'+window.location.host; + var socket = io.connect(uri, {'reconnect':false}); + socket.on('connect', function() { + socket.emit('getoverview', function(data) { + for (var prop in data) { + $('#'+prop).text(data[prop]); + } + }); + socket.on('updateoverview', function(room, players) { + $('#'+room).text(players); + }); + }); })(); diff --git a/public/js/leaderboards.js b/public/js/leaderboards.js index 81d84b6..eb4e9c2 100644 --- a/public/js/leaderboards.js +++ b/public/js/leaderboards.js @@ -1,33 +1,33 @@ (function() { - var appendResults = function(data, leaderboard, offset, type) { - for (var i=0; i').text(data[i]) - , col1 = ''+(++offset)+'' - , col2 = $('').append(link) - , col3 = (type === 'points') - ? ''+data[i+1]+'' - : ' '+(data[i+1] / 1000).toFixed(2)+' sec'; - var row = $('').append(col1, col2, col3); - leaderboard.append(row); - } - }; + var appendResults = function(data, leaderboard, offset, type) { + for (var i=0; i').text(data[i]) + , col1 = ''+(++offset)+'' + , col2 = $('').append(link) + , col3 = (type === 'points') + ? ''+data[i+1]+'' + : ' '+(data[i+1] / 1000).toFixed(2)+' sec'; + var row = $('').append(col1, col2, col3); + leaderboard.append(row); + } + }; - $('.leaderboard-wrapper').each(function(index) { - var leaderboard = $(this).find('tbody') - , loading = $(this).find('.loading') - , offset = 0 - , type = (index === 0) ? 'points' : 'times'; + $('.leaderboard-wrapper').each(function(index) { + var leaderboard = $(this).find('tbody') + , loading = $(this).find('.loading') + , offset = 0 + , type = (index === 0) ? 'points' : 'times'; - $(this).scroll(function() { - var diff = $(this).prop('scrollHeight') - $(this).scrollTop(); - if (diff === $(this).height() && offset < 180) { - offset += 30; - loading.show(); - $.get('/sliceleaderboard', {begin: offset, by: type}, function(data) { - loading.hide(); - appendResults(data, leaderboard, offset, type); - }); - } + $(this).scroll(function() { + var diff = $(this).prop('scrollHeight') - $(this).scrollTop(); + if (diff === $(this).height() && offset < 180) { + offset += 30; + loading.show(); + $.get('/sliceleaderboard', {begin: offset, by: type}, function(data) { + loading.hide(); + appendResults(data, leaderboard, offset, type); }); + } }); + }); })(); diff --git a/routes/site.js b/routes/site.js index d690964..6e91359 100644 --- a/routes/site.js +++ b/routes/site.js @@ -3,21 +3,21 @@ */ var async = require('async') - , Captcha = require('../lib/captcha') - , db = require('../lib/redis-clients').songs - , randomSlogan = require('../lib/utils').randomSlogan - , rooms = require('../config').rooms; + , Captcha = require('../lib/captcha') + , db = require('../lib/redis-clients').songs + , randomSlogan = require('../lib/utils').randomSlogan + , rooms = require('../config').rooms; /** * Generate a task. */ var task = function(genre) { - return function(callback) { - db.srandmember(genre, function(err, res) { - db.hget('song:'+res, 'artworkUrl100', callback); - }); - }; + return function(callback) { + db.srandmember(genre, function(err, res) { + db.hget('song:'+res, 'artworkUrl100', callback); + }); + }; }; /** @@ -25,84 +25,84 @@ var task = function(genre) { */ exports.artworks = function(req, res) { - var tasks = []; - for (var i=0; i 180 || (by !== 'points' && by !== 'times')) { - return res.send(412); - } - var end = begin + 29; - if (by === 'points') { - db.zrevrange('users', begin, end, 'withscores', function(err, results) { - res.json(results); - }); - return; - } - db.sort(utils.sortParams(begin), function(err, results) { - res.json(results); + var begin = parseInt(req.query.begin, 10) + , by = req.query.by; + if (isNaN(begin) || begin > 180 || (by !== 'points' && by !== 'times')) { + return res.send(412); + } + var end = begin + 29; + if (by === 'points') { + db.zrevrange('users', begin, end, 'withscores', function(err, results) { + res.json(results); }); + return; + } + db.sort(utils.sortParams(begin), function(err, results) { + res.json(results); + }); }; /** @@ -59,57 +59,57 @@ exports.sliceLeaderboard = function(req, res) { */ exports.validateChangePasswd = function(req, res, next) { - if (!req.session.user || req.body.oldpassword === undefined || - req.body.newpassword === undefined) { - return res.send(412); - } - - var errors = {}; - - if (req.body.oldpassword.trim() === '') { - errors.oldpassword = "can't be empty"; - } - if (req.body.newpassword.length < 6) { - errors.newpassword = 'must be at least 6 characters long'; - } - else if(req.body.newpassword === req.body.oldpassword) { - errors.newpassword = "can't be changed to the old one"; - } - - if (errors.oldpassword || errors.newpassword) { - req.session.errors = errors; - return res.redirect(req.url); - } - - next(); + if (!req.session.user || req.body.oldpassword === undefined || + req.body.newpassword === undefined) { + return res.send(412); + } + + var errors = {}; + + if (req.body.oldpassword.trim() === '') { + errors.oldpassword = "can't be empty"; + } + if (req.body.newpassword.length < 6) { + errors.newpassword = 'must be at least 6 characters long'; + } + else if(req.body.newpassword === req.body.oldpassword) { + errors.newpassword = "can't be changed to the old one"; + } + + if (errors.oldpassword || errors.newpassword) { + req.session.errors = errors; + return res.redirect(req.url); + } + + next(); }; exports.checkOldPasswd = function(req, res, next) { - var key = 'user:'+req.session.user; - db.hmget(key, 'salt', 'password', function(err, data) { - var hash = crypto.createHash('sha256').update(data[0]+req.body.oldpassword).digest('hex'); - if (hash !== data[1]) { - req.session.errors = {oldpassword: 'is incorrect'}; - return res.redirect(req.url); - } - next(); - }); + var key = 'user:'+req.session.user; + db.hmget(key, 'salt', 'password', function(err, data) { + var hash = crypto.createHash('sha256').update(data[0]+req.body.oldpassword).digest('hex'); + if (hash !== data[1]) { + req.session.errors = {oldpassword: 'is incorrect'}; + return res.redirect(req.url); + } + next(); + }); }; exports.changePasswd = function(req, res) { - var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/' - , user = req.session.user - , key = 'user:'+user - , salt = crypto.randomBytes(6).toString('base64') - , password = crypto.createHash('sha256').update(salt+req.body.newpassword).digest('hex'); - db.hmset(key, 'salt', salt, 'password', password, function(err, data) { - // Regenerate the session - req.session.regenerate(function() { - req.session.cookie.maxAge = 604800000; // One week - req.session.user = user; - res.redirect(followup); - }); + var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/' + , user = req.session.user + , key = 'user:'+user + , salt = crypto.randomBytes(6).toString('base64') + , password = crypto.createHash('sha256').update(salt+req.body.newpassword).digest('hex'); + db.hmset(key, 'salt', salt, 'password', password, function(err, data) { + // Regenerate the session + req.session.regenerate(function() { + req.session.cookie.maxAge = 604800000; // One week + req.session.user = user; + res.redirect(followup); }); + }); }; /** @@ -117,56 +117,56 @@ exports.changePasswd = function(req, res) { */ exports.validateLogin = function(req, res, next) { - if (req.body.username === undefined || req.body.password === undefined) { - return res.send(412); - } - - var errors = {}; - - if (req.body.username.trim() === '') { - errors.username = "can't be empty"; - } - if (req.body.password.trim() === '') { - errors.password = "can't be empty"; - } - - req.session.oldvalues = {username: req.body.username}; - if (errors.username || errors.password) { - req.session.errors = errors; - return res.redirect(req.url); - } - next(); + if (req.body.username === undefined || req.body.password === undefined) { + return res.send(412); + } + + var errors = {}; + + if (req.body.username.trim() === '') { + errors.username = "can't be empty"; + } + if (req.body.password.trim() === '') { + errors.password = "can't be empty"; + } + + req.session.oldvalues = {username: req.body.username}; + if (errors.username || errors.password) { + req.session.errors = errors; + return res.redirect(req.url); + } + next(); }; exports.checkUser = function(req, res, next) { - var key = 'user:'+req.body.username; - db.exists(key, function(err, data) { - if (data === 1) { - // User exists, proceed with authentication - return next(); - } - req.session.errors = {alert: 'The username you specified does not exists.'}; - res.redirect(req.url); - }); + var key = 'user:'+req.body.username; + db.exists(key, function(err, data) { + if (data === 1) { + // User exists, proceed with authentication + return next(); + } + req.session.errors = {alert: 'The username you specified does not exists.'}; + res.redirect(req.url); + }); }; exports.authenticate = function(req, res) { - var key = 'user:'+req.body.username; - 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 = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/'; - // Authentication succeeded, regenerate the session - req.session.regenerate(function() { - req.session.cookie.maxAge = 604800000; // One week - req.session.user = req.body.username; - res.redirect(followup); - }); - return; - } - req.session.errors = {alert: 'The password you specified is not correct.'}; - res.redirect(req.url); - }); + var key = 'user:'+req.body.username; + 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 = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/'; + // Authentication succeeded, regenerate the session + req.session.regenerate(function() { + req.session.cookie.maxAge = 604800000; // One week + req.session.user = req.body.username; + res.redirect(followup); + }); + return; + } + req.session.errors = {alert: 'The password you specified is not correct.'}; + res.redirect(req.url); + }); }; /** @@ -174,10 +174,10 @@ exports.authenticate = function(req, res) { */ exports.logout = function(req, res) { - // Destroy the session - req.session.destroy(function() { - res.redirect('/'); - }); + // Destroy the session + req.session.destroy(function() { + res.redirect('/'); + }); }; /** @@ -185,97 +185,97 @@ exports.logout = function(req, res) { */ exports.validateSignUp = function(req, res, next) { - if (req.body.username === undefined || req.body.email === undefined || - req.body.password === undefined || req.body.captcha === undefined) { - return res.send(412); - } - - var errors = {}; - - if (req.body.username === 'binb') { - errors.username = 'is reserved'; - } - else if (!utils.isUsername(req.body.username)) { - errors.username = 'must contain only alphanumeric characters'; - } - if (!utils.isEmail(req.body.email)) { - errors.email = 'is not an email address'; - } - if (req.body.password.length < 6) { - errors.password = 'must be at least 6 characters long'; - } - if (req.body.captcha !== req.session.captchacode) { - errors.captcha = 'no match'; - } - - // Save old values to repopulate the fields in case of future errors - req.session.oldvalues = { - username: req.body.username, - email: req.body.email - }; - - if (errors.username || errors.email || errors.password || errors.captcha) { - req.session.errors = errors; - return res.redirect(req.url); - } - - next(); + if (req.body.username === undefined || req.body.email === undefined || + req.body.password === undefined || req.body.captcha === undefined) { + return res.send(412); + } + + var errors = {}; + + if (req.body.username === 'binb') { + errors.username = 'is reserved'; + } + else if (!utils.isUsername(req.body.username)) { + errors.username = 'must contain only alphanumeric characters'; + } + if (!utils.isEmail(req.body.email)) { + errors.email = 'is not an email address'; + } + if (req.body.password.length < 6) { + errors.password = 'must be at least 6 characters long'; + } + if (req.body.captcha !== req.session.captchacode) { + errors.captcha = 'no match'; + } + + // Save old values to repopulate the fields in case of future errors + req.session.oldvalues = { + username: req.body.username, + email: req.body.email + }; + + if (errors.username || errors.email || errors.password || errors.captcha) { + req.session.errors = errors; + return res.redirect(req.url); + } + + next(); }; exports.userExists = function(req, res, next) { - var key = 'user:'+req.body.username; - db.exists(key, function(err, data) { - if (data === 1) { - // User already exists - req.session.errors = {alert: 'A user with that name already exists.'}; - return res.redirect(req.url); - } - next(); - }); + var key = 'user:'+req.body.username; + db.exists(key, function(err, data) { + if (data === 1) { + // User already exists + req.session.errors = {alert: 'A user with that name already exists.'}; + return res.redirect(req.url); + } + next(); + }); }; exports.emailExists = function(req, res, next) { - var key = 'email:'+req.body.email; - db.exists(key, function(err, data) { - if (data === 1) { - // Email already exists - req.session.errors = {alert: 'A user with that email already exists.'}; - return res.redirect(req.url); - } - next(); - }); + var key = 'email:'+req.body.email; + db.exists(key, function(err, data) { + if (data === 1) { + // Email already exists + req.session.errors = {alert: 'A user with that email already exists.'}; + return res.redirect(req.url); + } + next(); + }); }; exports.createAccount = function(req, res) { - var userkey = 'user:'+req.body.username - , mailkey = 'email:'+req.body.email - , salt = crypto.randomBytes(6).toString('base64') - , hash = crypto.createHash('sha256').update(salt+req.body.password).digest('hex') - , date = new Date() - , day = date.getDate() - , month = date.getMonth() + 1 - , year = date.getFullYear(); - - if (day < 10) { - day = '0' + day; - } - if (month < 10) { - month = '0' + month; - } - var joindate = day+'/'+month+'/'+year; - var user = new User(req.body.username, req.body.email, salt, hash, joindate); - // Add new user in the db - db.hmset(userkey, user); - db.set(mailkey, userkey); - db.zadd('users', 0, req.body.username); - db.sadd('emails', req.body.email); - // Delete old fields values - delete req.session.oldvalues; - res.render('login', { - followup: req.query.followup || '/', - slogan: utils.randomSlogan(), - success: 'You successfully created your account. You are now ready to login.' - }); + var userkey = 'user:'+req.body.username + , mailkey = 'email:'+req.body.email + , salt = crypto.randomBytes(6).toString('base64') + , hash = crypto.createHash('sha256').update(salt+req.body.password).digest('hex') + , date = new Date() + , day = date.getDate() + , month = date.getMonth() + 1 + , year = date.getFullYear(); + + if (day < 10) { + day = '0' + day; + } + if (month < 10) { + month = '0' + month; + } + var joindate = day+'/'+month+'/'+year; + var user = new User(req.body.username, req.body.email, salt, hash, joindate); + // Add new user in the db + db.hmset(userkey, user); + db.set(mailkey, userkey); + db.zadd('users', 0, req.body.username); + db.sadd('emails', req.body.email); + // Delete old fields values + delete req.session.oldvalues; + res.render('login', { + followup: req.query.followup || '/', + slogan: utils.randomSlogan(), + success: 'You successfully created your account. You are now ready to login.' + }); }; /** @@ -283,54 +283,54 @@ exports.createAccount = function(req, res) { */ exports.validateRecoverPasswd = function(req, res, next) { - if (req.body.email === undefined || req.body.captcha === undefined) { - return res.send(412); - } - - var errors = {}; - - if (!utils.isEmail(req.body.email)) { - errors.email = 'is not an email address'; - } - if (req.body.captcha !== req.session.captchacode) { - errors.captcha = 'no match'; - } - - req.session.oldvalues = {email: req.body.email}; - - if (errors.email || errors.captcha) { - req.session.errors = errors; - return res.redirect(req.url); - } - - next(); + if (req.body.email === undefined || req.body.captcha === undefined) { + return res.send(412); + } + + var errors = {}; + + if (!utils.isEmail(req.body.email)) { + errors.email = 'is not an email address'; + } + if (req.body.captcha !== req.session.captchacode) { + errors.captcha = 'no match'; + } + + req.session.oldvalues = {email: req.body.email}; + + if (errors.email || errors.captcha) { + req.session.errors = errors; + return res.redirect(req.url); + } + + next(); }; exports.sendEmail = function(req, res) { - var key = 'email:'+req.body.email; - db.get(key, function(err, data) { - if (data !== null) { - // Email exists, generate a secure random token - delete req.session.captchacode; - var token = crypto.randomBytes(48).toString('hex'); - // Token expires after 4 hours - db.setex('token:'+token, 14400, data, function(err, reply) { - mailer.sendEmail(req.body.email, token, function(err, response) { - if (err) { - console.log('error sending email: '+err.message); - } - }); - }); - delete req.session.oldvalues; - 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); - }); + var key = 'email:'+req.body.email; + db.get(key, function(err, data) { + if (data !== null) { + // Email exists, generate a secure random token + delete req.session.captchacode; + var token = crypto.randomBytes(48).toString('hex'); + // Token expires after 4 hours + db.setex('token:'+token, 14400, data, function(err, reply) { + mailer.sendEmail(req.body.email, token, function(err, response) { + if (err) { + console.log('error sending email: '+err.message); + } + }); + }); + delete req.session.oldvalues; + 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); + }); }; /** @@ -338,46 +338,46 @@ exports.sendEmail = function(req, res) { */ exports.resetPasswd = function(req, res) { - if (req.body.password === undefined) { - return res.send(412); - } - - var errors = {}; - - // Validate new password - if (req.body.password.length < 6) { - errors.password = 'must be at least 6 characters long'; - } - // Check token availability - if (!req.query.token) { - errors.alert = 'Missing token.'; - } - - if (errors.password || errors.alert) { - req.session.errors = errors; - return res.redirect(req.url); + if (req.body.password === undefined) { + return res.send(412); + } + + var errors = {}; + + // Validate new password + if (req.body.password.length < 6) { + errors.password = 'must be at least 6 characters long'; + } + // Check token availability + if (!req.query.token) { + errors.alert = 'Missing token.'; + } + + if (errors.password || errors.alert) { + req.session.errors = errors; + return res.redirect(req.url); + } + + var key = 'token:'+req.query.token; + db.get(key, function(err, user) { + if (user !== null) { + // Delete the token + db.del(key); + // Update password + 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', { + followup: '/', + slogan: utils.randomSlogan(), + success: 'You can now login with your new password.' + }); + }); + return; } - - var key = 'token:'+req.query.token; - db.get(key, function(err, user) { - if (user !== null) { - // Delete the token - db.del(key); - // Update password - 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', { - followup: '/', - slogan: utils.randomSlogan(), - success: 'You can now login with your new password.' - }); - }); - return; - } - req.session.errors = {alert: 'Invalid or expired token.'}; - res.redirect(req.url); - }); + req.session.errors = {alert: 'Invalid or expired token.'}; + res.redirect(req.url); + }); }; /** @@ -385,24 +385,24 @@ exports.resetPasswd = function(req, res) { */ exports.profile = function(req, res) { - var key = 'user:'+req.params[0]; - db.exists(key, function(err, data) { - if (data === 1) { - db.hgetall(key, function(e, obj) { - obj.bestguesstime = (obj.bestguesstime/1000).toFixed(1); - obj.worstguesstime = (obj.worstguesstime/1000).toFixed(1); - if (obj.guessed !== '0') { - obj.meanguesstime = ((obj.totguesstime/obj.guessed)/1000).toFixed(1); - } - delete obj.email; - delete obj.password; - delete obj.salt; - delete obj.totguesstime; - res.locals.slogan = utils.randomSlogan(); - res.render('user', obj); - }); - return; + var key = 'user:'+req.params[0]; + db.exists(key, function(err, data) { + if (data === 1) { + db.hgetall(key, function(e, obj) { + obj.bestguesstime = (obj.bestguesstime/1000).toFixed(1); + obj.worstguesstime = (obj.worstguesstime/1000).toFixed(1); + if (obj.guessed !== '0') { + obj.meanguesstime = ((obj.totguesstime/obj.guessed)/1000).toFixed(1); } - res.send(404); - }); + delete obj.email; + delete obj.password; + delete obj.salt; + delete obj.totguesstime; + res.locals.slogan = utils.randomSlogan(); + res.render('user', obj); + }); + return; + } + res.send(404); + }); }; diff --git a/views/changepasswd.jade b/views/changepasswd.jade index 01c714c..5af4d7d 100644 --- a/views/changepasswd.jade +++ b/views/changepasswd.jade @@ -1,65 +1,64 @@ extends layout block title - title binb :: Change password + title binb :: Change password block nav - ul.nav.pull-right + ul.nav.pull-right + li + a(href="/") Home + li.dropdown + a.dropdown-toggle(data-toggle="dropdown", href="#") Logged in as #{loggedin} + span.caret + ul.dropdown-menu li - a(href="/") Home - li.dropdown - a.dropdown-toggle(data-toggle="dropdown", href="#") - | Logged in as #{loggedin} - span.caret - ul.dropdown-menu - li - a(href="/user/#{loggedin}", target="_blank") Profile - li - a(href="/logout") Logout + a(href="/user/#{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#oldpassword(type="password", name="oldpassword", - placeholder="enter your current password...") - - if (errors.newpassword) - .control-group.error - label.control-label(for="newpassword") New password - .controls - input#newpassword(type="password", name="newpassword") - span.help-inline #{errors.newpassword} - - else - .control-group - label.control-label(for="newpassword") New password - .controls - input#newpassword(type="password", name="newpassword", - placeholder="enter your new password...") - - else - .control-group - label.control-label(for="oldpassword") Old password - .controls - input#oldpassword(type="password", name="oldpassword", - placeholder="enter your current password...") - .control-group - label.control-label(for="password") New password - .controls - input#newpassword(type="password", name="newpassword", - placeholder="enter your new password...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-edit.icon-white - | Update + 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#oldpassword(type="password", name="oldpassword", + placeholder="enter your current password...") + - if (errors.newpassword) + .control-group.error + label.control-label(for="newpassword") New password + .controls + input#newpassword(type="password", name="newpassword") + span.help-inline #{errors.newpassword} + - else + .control-group + label.control-label(for="newpassword") New password + .controls + input#newpassword(type="password", name="newpassword", + placeholder="enter your new password...") + - else + .control-group + label.control-label(for="oldpassword") Old password + .controls + input#oldpassword(type="password", name="oldpassword", + placeholder="enter your current password...") + .control-group + label.control-label(for="password") New password + .controls + input#newpassword(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/home.jade b/views/home.jade index cbbf765..5bc0cc3 100644 --- a/views/home.jade +++ b/views/home.jade @@ -1,61 +1,60 @@ extends layout block title - title binb + 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} - span.caret - ul.dropdown-menu - li - a(href="/user/#{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 + 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} + span.caret + ul.dropdown-menu + li + a(href="/user/#{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 + 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") + script(src="/socket.io/socket.io.js") + script(src="/static/js/home.js") diff --git a/views/layout.jade b/views/layout.jade index 967d81c..e1edb60 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -1,62 +1,62 @@ 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!") - meta(property="og:description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!") - meta(property="og:image", content="https://dl.dropbox.com/u/58444696/binb-logo-200.png") - meta(property="og:title", content="binb") - meta(property="og:type", content="game") - meta(property="og:url", content="http://binb.nodejitsu.com/") - 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 + 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!") + meta(property="og:description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!") + meta(property="og:image", content="https://dl.dropbox.com/u/58444696/binb-logo-200.png") + meta(property="og:title", content="binb") + meta(property="og:type", content="game") + meta(property="og:url", content="http://binb.nodejitsu.com/") + 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 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.3/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); - })(); + 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.3/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 d8e24d8..53b7899 100644 --- a/views/leaderboards.jade +++ b/views/leaderboards.jade @@ -1,53 +1,53 @@ extends layout block title - title binb :: Leaderboards + title binb :: Leaderboards block brand - a.brand(href="#") - .icons.logo #{slogan} + a.brand(href="#") + .icons.logo #{slogan} block sections - section - .row - .span7.offset1 - .highscores High Scores - .icons.img - section - .row - .span7.offset1.relative - h4 Points - .leaderboard-wrapper - table.table.table-striped.table-bordered.leaderboard - tbody - - each user, i in pointsleaderboard - tr - td #{i+1} - td - a(href="/user/#{user.username}") #{user.username} - td #{user.totpoints} - .loading - .loading-block - .loading-block - .loading-block - .span7.relative - h4 Times - .leaderboard-wrapper - table.table.table-striped.table-bordered.leaderboard - tbody - - each user, i in timesleaderboard - tr - td #{i+1} - td - a(href="/user/#{user.username}") #{user.username} - td - i.icon-time - | #{user.bestguesstime} sec - .loading - .loading-block - .loading-block - .loading-block + section + .row + .span7.offset1 + .highscores High Scores + .icons.img + section + .row + .span7.offset1.relative + h4 Points + .leaderboard-wrapper + table.table.table-striped.table-bordered.leaderboard + tbody + - each user, i in pointsleaderboard + tr + td #{i+1} + td + a(href="/user/#{user.username}") #{user.username} + td #{user.totpoints} + .loading + .loading-block + .loading-block + .loading-block + .span7.relative + h4 Times + .leaderboard-wrapper + table.table.table-striped.table-bordered.leaderboard + tbody + - each user, i in timesleaderboard + tr + td #{i+1} + td + a(href="/user/#{user.username}") #{user.username} + td + i.icon-time + | #{user.bestguesstime} sec + .loading + .loading-block + .loading-block + .loading-block block scripts - script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js") - script(src="/static/js/leaderboards.js") + script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js") + script(src="/static/js/leaderboards.js") diff --git a/views/login.jade b/views/login.jade index 382df57..dfe1d12 100644 --- a/views/login.jade +++ b/views/login.jade @@ -1,75 +1,75 @@ extends layout block title - title binb :: login - + 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 + 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", - maxlength="15", value=oldvalues.username) - span.help-inline #{errors.username} - - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text", name="username", - maxlength="15", 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", - maxlength="15", 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? + 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", + maxlength="15", value=oldvalues.username) + span.help-inline #{errors.username} + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + maxlength="15", 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", + maxlength="15", 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 c83ab09..f9d577e 100644 --- a/views/recoverpasswd.jade +++ b/views/recoverpasswd.jade @@ -1,78 +1,78 @@ extends layout block title - title binb :: Recover password + 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 + 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. + 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#email(type="text", name="email", + value=oldvalues.email) + span.help-inline #{errors.email} - 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#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.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", - maxlength="4") - 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", - maxlength="4", 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", - maxlength="4", placeholder="type what you see...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-envelope.icon-white - | Send password reset link + .control-group + label.control-label(for="email") Email + .controls + input#email(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", + maxlength="4") + 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", + maxlength="4", 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", + maxlength="4", 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 cee041e..c4f96df 100644 --- a/views/resetpasswd.jade +++ b/views/resetpasswd.jade @@ -1,35 +1,35 @@ extends layout block title - title binb :: Reset password + title binb :: Reset password block brand - a.brand(href="#") - .icons.logo #{slogan} + 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 && errors.password) - .control-group.error - label.control-label(for="password") New password - .controls - input#password(type="password", name="password") - span.help-inline #{errors.password} - - else - .control-group - label.control-label(for="password") New password - .controls - input#password(type="password", name="password", - placeholder="enter your new password...") - button.submit-button.btn.btn-primary(type="submit") - i.icon-edit.icon-white - | Update + 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 && errors.password) + .control-group.error + label.control-label(for="password") New password + .controls + input#password(type="password", name="password") + span.help-inline #{errors.password} + - else + .control-group + label.control-label(for="password") New password + .controls + input#password(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 7a558d6..94ab232 100644 --- a/views/room.jade +++ b/views/room.jade @@ -1,102 +1,101 @@ extends layout block title - title binb :: #{roomname} + title binb :: #{roomname} block brand 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=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} - span.caret - ul.dropdown-menu - li - a(href="/user/#{loggedin}", target="_blank") Profile - li - a(href="/changepasswd?followup=/#{roomname}") Change password - li - a(href="/logout") Logout - - else + 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="/signup?followup=/#{roomname}") Sign up - li - a(href="/login?followup=/#{roomname}") Login + 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} + span.caret + ul.dropdown-menu + li + a(href="/user/#{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 - .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. + 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 + .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. block media - #modal.modal.fade - #player + #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") + 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 ee10d0c..8e0c262 100644 --- a/views/signup.jade +++ b/views/signup.jade @@ -1,114 +1,114 @@ extends layout block title - title binb :: sign up + 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 + 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", - maxlength="15", value=oldvalues.username) - span.help-inline #{errors.username} - - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text", name="username", - maxlength="15", 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", - maxlength="4") - 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", - maxlength="4", placeholder="type what you see...") - - else - .control-group - label.control-label(for="username") Name - .controls - input#username(type="text", name="username", - maxlength="15", 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", - maxlength="4", placeholder="type what you see...") - button.submit-button.btn.btn-success(type="submit") - i.icon-user.icon-white - | Sign up! + 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", + maxlength="15", value=oldvalues.username) + span.help-inline #{errors.username} + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + maxlength="15", 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", + maxlength="4") + 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", + maxlength="4", placeholder="type what you see...") + - else + .control-group + label.control-label(for="username") Name + .controls + input#username(type="text", name="username", + maxlength="15", 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", + maxlength="4", 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 01cb36f..e5a3f96 100644 --- a/views/user.jade +++ b/views/user.jade @@ -1,88 +1,88 @@ extends layout block title - title binb :: #{username} info - + title binb :: #{username} info + block brand - a.brand(href="#") - .icons.logo #{slogan} + a.brand(href="#") + .icons.logo #{slogan} block sections - section - .row - .span7.offset1 - .profile #{username} - .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} + section + .row + .span7.offset1 + .profile #{username} + .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