]> git.example.dev Git - binbsis50.git/commitdiff
added ability to view up to 210 results on the leaderboards
authorLuigi Pinca <luigipinca@gmail.com>
Sun, 25 Nov 2012 13:51:38 +0000 (14:51 +0100)
committerLuigi Pinca <luigipinca@gmail.com>
Sun, 25 Nov 2012 13:51:38 +0000 (14:51 +0100)
app.js
lib/utils.js
package.json
public/css/style.css
public/js/leaderboards.js [new file with mode: 0644]
routes/user.js
views/layout.jade
views/leaderboards.jade

diff --git a/app.js b/app.js
index 6ca2d835e78ed5a49a599f5441c4e1681b260bdd..9b32aa6a5315f18b5504a3118b2f0ad40ff7f569 100644 (file)
--- a/app.js
+++ b/app.js
@@ -27,7 +27,7 @@ app.use('/static', express.static(pub, {maxAge: 2419200000})); // 4 weeks = 2419
 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);
@@ -38,12 +38,13 @@ app.get('/leaderboards', user.leaderboards);
 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);
 
index 84b11274d367c3b964bb5ba0556207a57a8a02d2..b5118ec2e9a59e417728eb0a2f2493f54d5fb991 100644 (file)
@@ -1,26 +1,3 @@
-/**
- * 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.
@@ -43,3 +20,46 @@ exports.buildLeaderboards = function(pointsresults, timesresults) {
     }
     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;
+};
index dfe55b1cf0984ba70285348ceaa33b2c4222d259..6e829e172e2cfeaf455ef3c6f66f1ace17fa6f40 100644 (file)
@@ -21,5 +21,5 @@
     "start": "app.js"
   },
   "subdomain": "binb",
-  "version": "0.3.4-10"
+  "version": "0.3.5"
 }
\ No newline at end of file
index c009672209d6e2dc160818d88007e66d6e7018b7..2b622d19f6ce2ec089f90e546190b0aeb421a710 100644 (file)
@@ -218,6 +218,97 @@ form .clearfix {
 .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;
diff --git a/public/js/leaderboards.js b/public/js/leaderboards.js
new file mode 100644 (file)
index 0000000..d009716
--- /dev/null
@@ -0,0 +1,33 @@
+(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);
+                });
+            }
+        });
+    });
+})();
index 03472caf767ad4c431717f32ad073b4de4eedea8..43b66295e51e28b2529a50a2002243f986de0b6f 100644 (file)
@@ -24,19 +24,7 @@ for (var i=0; i<rooms.length; i++) {
 
 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);
@@ -44,6 +32,28 @@ exports.leaderboards = function(req, res) {
     });
 };
 
+/**
+ * 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.
  */
index 07126ddb10a83d98b47bb10dcf6f00b53bb962a3..dcf77317204bec9f4719dfe75536dbc5540eb478 100644 (file)
@@ -43,7 +43,7 @@ html
                     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 = {};
index 800a64c9be7934d967179e3ec8200e2904c3e889..2dfef063efebfa85855ec80bcf3173a77294e922 100644 (file)
@@ -15,31 +15,41 @@ block sections
                     .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, '&amp;')}
-                                td #{user.totpoints}
-            .span7
+                            - each user, i in pointsleaderboard
+                                tr
+                                    td #{i+1}
+                                    td
+                                        a(href="/user/#{encodeURIComponent(user.username)}")
+                                            | #{user.username.replace(/&/g, '&amp;')}
+                                    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, '&amp;')}
-                                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, '&amp;')}
+                                    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")