Add commentsListController

This commit is contained in:
Sacha Greif 2015-05-08 09:20:58 +09:00
parent 3de1cf87eb
commit 11bd064039
10 changed files with 275 additions and 79 deletions

View file

@ -0,0 +1,25 @@
-<template name="comments_list_compact">
<table>
<thead>
<tr>
<td>{{_ "post"}}</td>
<td>{{_ "comment"}}</td>
<td>{{fieldLabel}}</td>
</tr>
</thead>
{{#each commentsCursor}}
<tr>
<td><a href="{{pathFor route='post_page' _id=postId}}/">{{postTitle}}</a></td>
<td>{{{htmlBody}}}</td>
<td>{{fieldValue}}</td>
</tr>
{{/each}}
{{#if hasMoreComments}}
<tr>
<td colspan="2">
<a class="more-button grid-module" href="#"><span>{{_ "load_more"}}</span></a>
</td>
</tr>
{{/if}}
</table>
</template>

View file

@ -0,0 +1,37 @@
Template.comments_list_compact.helpers({
commentsCursor: function () {
if (this.commentsCursor) { // not sure why this should ever be undefined, but it can apparently
var comments = this.commentsCursor.map(function (comment, index) {
comment.rank = index;
return comment;
});
return comments;
} else {
console.log('commentsCursor not defined');
}
},
postTitle: function () {
var post = Posts.findOne(this.postId);
return post.title;
},
fieldLabel: function () {
return this.controllerOptions.fieldLabel;
},
fieldValue: function () {
var controllerOptions = Template.parentData(3).data.controllerOptions;
return controllerOptions.fieldValue(this);
}
});
Template.comments_list_compact.events({
'click .more-button': function (event) {
event.preventDefault();
if (this.controllerInstance) {
// controller is a template
this.loadMoreHandler(this.controllerInstance);
} else {
// controller is router
this.loadMoreHandler();
}
}
});

View file

@ -0,0 +1,3 @@
<template name="commentsListController">
{{> Template.dynamic template=template data=data}}
</template>

View file

@ -0,0 +1,109 @@
// see https://www.discovermeteor.com/blog/template-level-subscriptions/
/*
This template acts as the controller that sets and manages the reactive context
for the embedded commentsList template. It receives its parameters from a "caller" template.
*/
Template.commentsListController.onCreated(function () {
// 1. Initialization (*not* reactive!)
var instance = this;
// initialize the reactive variables
instance.terms = new ReactiveVar(instance.data.terms);
instance.commentsLimit = new ReactiveVar(Settings.get('commentsPerPage', 10));
// 2. Autorun
// Autorun 1: when terms change, reset the limit
instance.autorun(function () {
// add a dependency on data context to trigger the autorun
var terms = Template.currentData().terms; // ⚡ reactive ⚡
instance.commentsLimit.set(Settings.get('commentsPerPage', 10));
});
// Autorun 2: will re-run when limit or terms are changed
instance.autorun(function () {
// get terms from data context
var terms = Template.currentData().terms; // ⚡ reactive ⚡
// get limit from local template variable
var commentsLimit = instance.commentsLimit.get(); // ⚡ reactive ⚡
// create new subscriptionTerms object using the new limit
var subscriptionTerms = _.extend(_.clone(terms), {limit: commentsLimit}); // extend terms with limit
// use this new object to subscribe
var commentsSubscription = instance.subscribe('userComments', subscriptionTerms);
var subscriptionsReady = instance.subscriptionsReady(); // ⚡ reactive ⚡
console.log('// ------ autorun running ------ //');
console.log("terms: ", terms);
console.log("limit: ", commentsLimit);
console.log("ready: ", subscriptionsReady);
// Tracker.onInvalidate(console.trace.bind(console));
// if subscriptions are ready, set terms to subscriptionsTerms
if (subscriptionsReady) {
instance.terms.set(subscriptionTerms);
}
});
});
Template.commentsListController.helpers({
template: function () {
return !!this.template? this.template: "comments_list";
},
data: function () {
var context = this;
var instance = Template.instance();
var terms = instance.terms.get(); // ⚡ reactive ⚡
var commentsReady = instance.subscriptionsReady(); // ⚡ reactive ⚡
var commentsLimit = terms.limit;
var parameters = Comments.getSubParams(terms);
var commentsCursor = Comments.find(parameters.find, parameters.options);
var data = {
// comments cursor
commentsCursor: commentsCursor,
// comments subscription readiness, used to show spinner
commentsReady: commentsReady,
// whether to show the load more button or not
hasMorecomments: commentsCursor.count() >= commentsLimit,
// what to do when user clicks "load more"
loadMoreHandler: function (instance) {
event.preventDefault();
// increase limit by 5 and update it
var limit = instance.commentsLimit.get();
limit += Settings.get('commentsPerPage', 10);
instance.commentsLimit.set(limit);
},
// the current instance
controllerInstance: instance,
controllerOptions: context.options // pass any options on to the template
};
console.log(data)
return data;
}
});

View file

@ -0,0 +1,34 @@
/**
* Gives an object containing the appropriate find
* and options arguments for the subscriptions's Comments.find()
* @param {Object} terms
*/
Comments.getSubParams = function (terms) {
var maxLimit = 200;
// console.log(terms)
// note: using jquery's extend() with "deep" parameter set to true instead of shallow _.extend()
// see: http://api.jquery.com/jQuery.extend/
// initialize parameters by extending baseParameters object, to avoid passing it by reference
var parameters = Telescope.utils.deepExtend(true, {}, Comments.views.baseParameters);
// get query parameters according to current view
if (typeof Comments.views[terms.view] !== 'undefined')
parameters = Telescope.utils.deepExtend(true, parameters, Comments.views[terms.view](terms));
// if a limit was provided with the terms, add it too (note: limit=0 means "no limit")
if (typeof terms.limit !== 'undefined')
_.extend(parameters.options, {limit: parseInt(terms.limit)});
// limit to "maxLimit" posts at most when limit is undefined, equal to 0, or superior to maxLimit
if(!parameters.options.limit || parameters.options.limit == 0 || parameters.options.limit > maxLimit) {
parameters.options.limit = maxLimit;
}
// console.log(parameters);
return parameters;
};

View file

@ -23,6 +23,22 @@ Meteor.publish('commentPost', function(commentId) {
return [];
});
// Publish a user's comments and the posts that were commented on
Meteor.publish('userComments', function(terms) {
if(Users.can.viewById(this.userId)){
var parameters = Comments.getSubParams(terms);
var comments = Comments.find(parameters.find, parameters.options);
// if there are comments, find out which posts were commented on
var commentedPostIds = comments.count() ? _.pluck(comments.fetch(), 'postId') : [];
return [
comments,
Posts.find({_id: {$in: commentedPostIds}})
];
}
});
// Publish author of the current comment, and author of the post related to the current comment
Meteor.publish('commentUsers', function(commentId) {

View file

@ -0,0 +1,33 @@
/**
* Comment views are filters used for subscribing to and viewing comments
* @namespace Comments.views
*/
Comments.views = {};
/**
* Add a module to a comment view
* @param {string} viewName - The name of the view
* @param {function} [viewFunction] - The function used to calculate query terms. Takes terms and baseParameters arguments
*/
Comments.views.register = function (viewName, viewFunction) {
Comments.views[viewName] = viewFunction;
};
// will be common to all other view unless specific properties are overwritten
Comments.views.baseParameters = {
options: {
limit: 10
}
};
Comments.views.register("postComments", function (terms) {
return {
find: {postId: terms.postId}
};
});
Comments.views.register("userComments", function (terms) {
return {
find: {userId: terms.userId}
};
});

View file

@ -1,28 +1,6 @@
<template name="user_comments">
<div class="user-profile-comments grid grid-module">
<h3>{{_ "comments_"}}</h3>
<table>
<thead>
<tr>
<td>Post</td>
<td>Comment</td>
<td>Commented At</td>
</tr>
</thead>
{{#each comments}}
<tr>
<td><a href="{{pathFor route='post_page' _id=postId}}/">{{postTitle}}</a></td>
<td>{{{htmlBody}}}</td>
<td>{{formatDate createdAt "MM/DD/YYYY, HH:mm"}}</td>
</tr>
{{/each}}
{{#if hasMoreComments}}
<tr>
<td colspan="10">
<a class="comments-more more-button grid-module" href="#"><span>{{_ "load_more"}}</span></a>
</td>
</tr>
{{/if}}
</table>
<h3>{{_ "comments"}}</h3>
{{> commentsListController arguments}}
</div>
</template>

View file

@ -1,48 +1,20 @@
Template.user_comments.created = function () {
Session.set('commentsShown', 5);
var user = this.data;
var instance = this;
instance.commentsShown = new ReactiveVar(5);
instance.comments = new ReactiveVar({});
this.autorun(function () {
// get parameters
var limit = instance.commentsShown.get();
// subscribe
instance.subscription = Meteor.subscribe('userComments', user._id, limit);
// set cursor
instance.comments.set(Comments.find({userId: user._id}, {limit: limit}));
});
};
Template.user_comments.helpers({
comments: function () {
var comments = Template.instance().comments.get();
if(!!comments){
// extend comments with each commented post
var extendedComments = comments.map(function (comment) {
var post = Posts.findOne(comment.postId);
if(post) // post might not be available anymore
comment.postTitle = post.title;
return comment;
});
return extendedComments;
arguments: function () {
var user = this;
return {
template: "comments_list_compact",
options: {
currentUser: user,
fieldLabel: i18n.t("commentedAt"),
fieldValue: function (comment) {
return moment(comment.createdAt).format("MM/DD/YYYY, HH:mm");
}
},
terms: {
view: 'userComments',
userId: user._id,
limit: 5
}
}
},
hasMoreComments: function () {
return Template.instance().comments.get().count() >= Template.instance().commentsShown.get();
}
});
Template.user_comments.events({
'click .comments-more': function (e) {
e.preventDefault();
var commentsShown = Template.instance().commentsShown.get();
Template.instance().commentsShown.set(commentsShown+5);
}
});

View file

@ -28,17 +28,6 @@ Meteor.publish('userDownvotedPosts', function(terms) {
return posts;
});
Meteor.publish('userComments', function(userId, limit) {
var comments = Comments.find({userId: userId}, {limit: limit});
// if there are comments, find out which posts were commented on
var commentedPostIds = comments.count() ? _.pluck(comments.fetch(), 'postId') : [];
return [
comments,
Posts.find({_id: {$in: commentedPostIds}})
]
});
// Publish the current user
Meteor.publish('currentUser', function() {