app.use(express.favicon(pub + '/img/favicon.ico', {maxAge: 2419200000}));
app.use(express.bodyParser());
app.use(express.cookieParser(process.env.SITE_SECRET));
-app.use(express.session({store: sessionstore}));
+app.use(express.session({store: sessionstore, cookie: {maxAge: 14400000}})); // 4 h = 14400000 ms
// Routes
app.get('/', site.home);
app.get('/login', site.validationErrors, site.login);
app.post('/login', user.validateLogin, user.checkUser, user.authenticate);
app.get('/logout', user.logout);
-app.get('/signup', site.validationErrors, site.signup);
-app.post('/signup', user.validateSignUp, user.userExists, user.emailExists, user.createAccount);
app.get('/recoverpasswd', site.validationErrors, site.recoverPasswd);
app.post('/recoverpasswd', user.validateRecoverPasswd, user.sendEmail);
app.get('/resetpasswd', site.validationErrors, site.resetPasswd);
app.post('/resetpasswd', user.resetPasswd);
+app.get('/sliceleaderboard', user.sliceLeaderboard);
+app.get('/signup', site.validationErrors, site.signup);
+app.post('/signup', user.validateSignUp, user.userExists, user.emailExists, user.createAccount);
app.get('/:room', site.room);
app.get('/user/*', user.profile);
-/**
- * Get a random slogan.
- */
-
-exports.randomSlogan = function() {
- var slogans = [
- 'guess the song.'
- , 'name that tune.'
- , 'i know this track.'
- ];
- return slogans[Math.floor(Math.random() * slogans.length)];
-};
-
-/**
- * Check if the provided string is a valid email address.
- */
-
-exports.isEmail = function(str) {
- // Simple filter, but it covers most of the use cases.
- var filter = /^[+a-zA-Z0-9_.\-]+@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]{2,6}$/;
- return filter.test(str);
-};
-
/**
* Helper function used to build leaderboards.
* Rearrange database results in an object.
}
return obj;
};
+
+/**
+ * Check if the provided string is a valid email address.
+ */
+
+exports.isEmail = function(str) {
+ // Simple filter, but it covers most of the use cases.
+ var filter = /^[+a-zA-Z0-9_.\-]+@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]{2,6}$/;
+ return filter.test(str);
+};
+
+/**
+ * Get a random slogan.
+ */
+
+exports.randomSlogan = function() {
+ var slogans = [
+ 'guess the song.'
+ , 'name that tune.'
+ , 'i know this track.'
+ ];
+ return slogans[Math.floor(Math.random() * slogans.length)];
+};
+
+/**
+ * Return the sorting parameters used to get users ordered by best guess time.
+ */
+
+exports.sortParams = function(offset) {
+ var params = [
+ 'users'
+ , 'by'
+ , 'user:*->bestguesstime'
+ , 'get'
+ , '#'
+ , 'get'
+ , 'user:*->bestguesstime'
+ , 'limit'
+ , offset
+ , '30'
+ ];
+ return params;
+};
"start": "app.js"
},
"subdomain": "binb",
- "version": "0.3.4-10"
+ "version": "0.3.5"
}
\ No newline at end of file
.leaderboard tbody tr:hover td, .stats tbody tr:hover td {
background-color: #dadada;
}
+.loading {
+ 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);
+}
+.loading-block:first-child {
+ -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;
+}
+.loading-block:last-child {
+ -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;
+ }
+}
+@-moz-keyframes bounce {
+ 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;
+ }
+}
+@keyframes bounce {
+ 0% {
+ transform: scale(1);
+ opacity: 1;
+ }
+ 100% {
+ transform:s cale(0.7);
+ opacity: 0.1;
+ }
+}
.room {
height: 25px;
line-height: 25px;
--- /dev/null
+(function() {
+ var appendResults = function(data, leaderboard, offset, type) {
+ for (var i=0; i<data.length; i+=2) {
+ var link = $('<a href="/user/'+encodeURIComponent(data[i])+'"></a>').text(data[i])
+ , col1 = '<td>'+(++offset)+'</td>'
+ , col2 = $('<td></td>').append(link)
+ , col3 = (type === 'points')
+ ? '<td>'+data[i+1]+'</td>'
+ : '<td><i class="icon-time"></i> '+(data[i+1] / 1000).toFixed(2)+' sec</td>';
+ var row = $('<tr></tr>').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';
+
+ $(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);
+ });
+ }
+ });
+ });
+})();
exports.leaderboards = function(req, res) {
db.zrevrange('users', 0, 29, 'withscores', function(err, pointsresults) {
- var sortparams = [
- 'users'
- , 'by'
- , 'user:*->bestguesstime'
- , 'get'
- , '#'
- , 'get'
- , 'user:*->bestguesstime'
- , 'limit'
- , '0'
- , '30'
- ];
- db.sort(sortparams, function (e, timesresults) {
+ db.sort(utils.sortParams(0), function(e, timesresults) {
var leaderboards = utils.buildLeaderboards(pointsresults, timesresults);
res.locals.slogan = utils.randomSlogan();
res.render('leaderboards', leaderboards);
});
};
+/**
+ * Get 30 users from the ranking, starting at index `begin`.
+ */
+
+exports.sliceLeaderboard = function(req, res) {
+ 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);
+ });
+};
+
/**
* Change password middlewares.
*/
span.footer-info Powered by
block media
block scripts
- script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js")
+ script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
script(src="/static/js/bootstrap.min.js")
script
var uvOptions = {};
.icons.img
section
.row
- .span7.offset1
+ .span7.offset1.relative
h4 Points
- div.leaderboard-wrapper
+ .leaderboard-wrapper
table.table.table-striped.table-bordered.leaderboard
tbody
- - each user, i in pointsleaderboard
- tr
- td #{i+1}
- td
- a(href="/user/#{encodeURIComponent(user.username)}")
- | #{user.username.replace(/&/g, '&')}
- td #{user.totpoints}
- .span7
+ - each user, i in pointsleaderboard
+ tr
+ td #{i+1}
+ td
+ a(href="/user/#{encodeURIComponent(user.username)}")
+ | #{user.username.replace(/&/g, '&')}
+ td #{user.totpoints}
+ .loading
+ .loading-block
+ .loading-block
+ .loading-block
+ .span7.relative
h4 Times
- div.leaderboard-wrapper
+ .leaderboard-wrapper
table.table.table-striped.table-bordered.leaderboard
tbody
- - each user, i in timesleaderboard
- tr
- td #{i+1}
- td
- a(href="/user/#{encodeURIComponent(user.username)}")
- | #{user.username.replace(/&/g, '&')}
- td
- i.icon-time
- | #{user.bestguesstime} sec
+ - each user, i in timesleaderboard
+ tr
+ td #{i+1}
+ td
+ a(href="/user/#{encodeURIComponent(user.username)}")
+ | #{user.username.replace(/&/g, '&')}
+ td
+ i.icon-time
+ | #{user.bestguesstime} sec
+ .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")