From fcf8c4ae5879ce47d0a0f7c692790917ce425b97 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 18 Sep 2012 09:29:31 +1000 Subject: [PATCH 1/2] Added voting to comments. --- client/templates/comment_item.js | 4 ++++ client/templates/post_item.js | 2 +- lib/vote.js | 31 ++++++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/client/templates/comment_item.js b/client/templates/comment_item.js index 6e17091de..b6a6b2edd 100644 --- a/client/templates/comment_item.js +++ b/client/templates/comment_item.js @@ -120,6 +120,10 @@ Template.comment_item.rendered=function(){ } ); // $(event.target).closest(".comment").addClass("queued"); + }, + 'click .upvote': function(e) { + e.preventDefault(); + Meteor.call('voteForComment', this._id); } }; diff --git a/client/templates/post_item.js b/client/templates/post_item.js index 741be86fa..99dd21624 100644 --- a/client/templates/post_item.js +++ b/client/templates/post_item.js @@ -8,7 +8,7 @@ Template.post_item.events = { , 'click .upvote-link': function(){ console.log('upvote', this); - Meteor.call('voteForPost', this); + Meteor.call('voteForPost', this._id); } , 'click .share-link': function(e){ diff --git a/lib/vote.js b/lib/vote.js index aeec48740..a93f96a5b 100644 --- a/lib/vote.js +++ b/lib/vote.js @@ -1,19 +1,40 @@ Meteor.methods({ - voteForPost: function(post){ - console.log('voting for ' + post._id); + voteForPost: function(postId){ + console.log('voting for ' + postId); var userId = this.userId(); if(!userId) return false; // atomically update the post's votes - var query = {_id: post._id, voters: {$ne: userId}}; + var query = {_id: postId, voters: {$ne: userId}}; var update = {$push: {voters: userId}, $inc: {votes: 1}}; Posts.update(query, update); if (!this.is_simulation) { // now update the post's score - post = Posts.findOne(post._id); + post = Posts.findOne(postId); Scoring.updateObject(post); - Posts.update(post._id, {$set: {score: post.score}}); + Posts.update(postId, {$set: {score: post.score}}); + } + + return true; + }, + + // this is like the exact same code as above. Is there a way to refactor? + voteForComment: function(commentId) { + console.log('voting for ' + commentId); + var userId = this.userId(); + if(!userId) return false; + + // atomically update the comment's votes + var query = {_id: commentId, voters: {$ne: userId}}; + var update = {$push: {voters: userId}, $inc: {votes: 1}}; + Comments.update(query, update); + + if (!this.is_simulation) { + // now update the comment's score + comment = Comments.findOne(commentId); + Scoring.updateObject(comment); + Comments.update(commentId, {$set: {score: comment.score}}); } return true; From 2ccbf64eddb0d2d370792b93ae7bc1f501d9d0c9 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 18 Sep 2012 10:04:26 +1000 Subject: [PATCH 2/2] Downvoting / cancel voting. --- client/templates/comment_item.js | 2 +- client/templates/post_item.js | 4 +- lib/vote.js | 107 ++++++++++++++++++++++--------- server/bootstrap.js | 54 ++++++++-------- 4 files changed, 106 insertions(+), 61 deletions(-) diff --git a/client/templates/comment_item.js b/client/templates/comment_item.js index b6a6b2edd..64ea11a36 100644 --- a/client/templates/comment_item.js +++ b/client/templates/comment_item.js @@ -123,7 +123,7 @@ Template.comment_item.rendered=function(){ }, 'click .upvote': function(e) { e.preventDefault(); - Meteor.call('voteForComment', this._id); + Meteor.call('up voteComment', this._id); } }; diff --git a/client/templates/post_item.js b/client/templates/post_item.js index 99dd21624..e5f3e0fb2 100644 --- a/client/templates/post_item.js +++ b/client/templates/post_item.js @@ -8,7 +8,7 @@ Template.post_item.events = { , 'click .upvote-link': function(){ console.log('upvote', this); - Meteor.call('voteForPost', this._id); + Meteor.call('upvotePost', this._id); } , 'click .share-link': function(e){ @@ -82,7 +82,7 @@ Template.post_item.voted = function(){ var user = Meteor.user(); if(!user) return false; - return _.include(this.voters, user._id); + return _.include(this.upvoters, user._id); }; var getRank = function(post){ diff --git a/lib/vote.js b/lib/vote.js index a93f96a5b..999a69783 100644 --- a/lib/vote.js +++ b/lib/vote.js @@ -1,42 +1,87 @@ -Meteor.methods({ - voteForPost: function(postId){ - console.log('voting for ' + postId); +(function() { + var prepareVote = function(collection, id, fn) { + // ensure we are logged in + console.log('voting for ' + id); var userId = this.userId(); if(!userId) return false; - // atomically update the post's votes - var query = {_id: postId, voters: {$ne: userId}}; - var update = {$push: {voters: userId}, $inc: {votes: 1}}; - Posts.update(query, update); + // now do the real work + fn(userId); + // now update scores if (!this.is_simulation) { // now update the post's score - post = Posts.findOne(postId); - Scoring.updateObject(post); - Posts.update(postId, {$set: {score: post.score}}); + var object = collection.findOne(id); + Scoring.updateObject(object); + collection.update(id, {$set: {score: object.score}}); } return true; - }, + }; - // this is like the exact same code as above. Is there a way to refactor? - voteForComment: function(commentId) { - console.log('voting for ' + commentId); - var userId = this.userId(); - if(!userId) return false; - - // atomically update the comment's votes - var query = {_id: commentId, voters: {$ne: userId}}; - var update = {$push: {voters: userId}, $inc: {votes: 1}}; - Comments.update(query, update); - - if (!this.is_simulation) { - // now update the comment's score - comment = Comments.findOne(commentId); - Scoring.updateObject(comment); - Comments.update(commentId, {$set: {score: comment.score}}); + var upvote = function(collection, id) { + return prepareVote.call(this, collection, id, function(userId) { + + var query = {_id: id, upvoters: {$ne: userId}}; + var update = {$push: {upvoters: userId}, $inc: {votes: 1}}; + collection.update(query, update); + }); + }; + + var downvote = function(collection, id) { + return prepareVote.call(this, collection, id, function(userId) { + + var query = {_id: id, downvoters: {$ne: userId}}; + var update = {$push: {downvoters: userId}, $inc: {votes: -1}}; + collection.update(query, update); + }); + }; + + var cancelUpvote = function(collection, id) { + return prepareVote.call(this, collection, id, function(userId) { + + var query = {_id: id, upvoters: userId}; + var update = {$pull: {upvoters: userId}, $inc: {votes: -1}}; + collection.update(query, update); + }); + }; + + var cancelDownvote = function(collection, id) { + return prepareVote.call(this, collection, id, function(userId) { + + var query = {_id: id, downvoters: userId}; + var update = {$pull: {downvoters: userId}, $inc: {votes: 1}}; + collection.update(query, update); + }); + }; + + Meteor.methods({ + upvotePost: function(postId){ + return upvote.call(this, Posts, postId); + }, + downvotePost: function(postId){ + return downvote.call(this, Posts, postId); + }, + cancelUpvotePost: function(postId){ + return cancelUpvote.call(this, Posts, postId); + }, + cancelDownvotePost: function(postId){ + return cancelDownvote.call(this, Posts, postId); + }, + + upvoteComment: function(commentId){ + return upvote.call(this, Comments, commentId); + }, + downvoteComment: function(commentId){ + return downvote.call(this, Comments, commentId); + }, + cancelUpvoteComment: function(commentId){ + return cancelUpvote.call(this, Comments, commentId); + }, + cancelDownvoteComment: function(commentId){ + return cancelDownvote.call(this, Comments, commentId); } - - return true; - } -}); + }); + +})(); + diff --git a/server/bootstrap.js b/server/bootstrap.js index 4dce3b05f..7ec3da94b 100644 --- a/server/bootstrap.js +++ b/server/bootstrap.js @@ -1,28 +1,28 @@ -// function prepopulateDatabase(){ -// [ -// { -// headline: 'The first post ever, a link to Hacker News' -// , url: 'http://news.ycombinator.com/' -// , submitter: 'Sacha' -// , submitted: new Date(2012, 7, 22).getTime() -// , votes: 0 -// , comments: 0 -// } -// , { -// headline: 'Another post to fill the page up a little' -// , url: 'http://sachagreif.com/' -// , submitter: 'Sacha' -// , submitted: new Date(2012, 7, 22).getTime() -// , votes: 0 -// , comments: 0 -// } -// ].forEach(function(post){ -// Posts.insert(post); -// }); -// } +function prepopulateDatabase(){ + [ + { + headline: 'The first post ever, a link to Hacker News' + , url: 'http://news.ycombinator.com/' + , submitter: 'Sacha' + , submitted: new Date(2012, 7, 22).getTime() + , votes: 0 + , comments: 0 + } + , { + headline: 'Another post to fill the page up a little' + , url: 'http://sachagreif.com/' + , submitter: 'Sacha' + , submitted: new Date(2012, 7, 22).getTime() + , votes: 0 + , comments: 0 + } + ].forEach(function(post){ + Posts.insert(post); + }); +} -// Meteor.startup(function () { -// if(Posts.find().count() === 0){ -// prepopulateDatabase(); -// } -// }); +Meteor.startup(function () { + if(Posts.find().count() === 0){ + prepopulateDatabase(); + } +});