Massively simplified all the posts_lists using the paginatedSub.

This commit is contained in:
Tom Coleman 2012-12-13 17:06:13 +11:00
commit 0be912db24
14 changed files with 160 additions and 257 deletions

View file

@ -56,101 +56,40 @@ STATUS_PENDING=1;
STATUS_APPROVED=2;
STATUS_REJECTED=3;
FIND_APPROVED={$or: [{status: {$exists : false}}, {status: STATUS_APPROVED}]};
TOP_PAGE_PER_PAGE = 10;
NEW_PAGE_PER_PAGE = 10;
BEST_PAGE_PER_PAGE = 10;
PENDING_PAGE_PER_PAGE = 10;
DIGEST_PAGE_PER_PAGE = 5;
// name <- the name of various session vars that will be set:
// - 'nameReady' <- is the subscription loading or ready?
// - 'nameLimit' <- how many of this type are we currently displaying?
// options:
// - find <- how to find the items
// - sort <- how to sort them
// - perPage <- how many to display per-page
// -
postsForSub = {};
setupPostSubscription = function(name, options) {
var readyName = name + 'Ready';
var limitName = name + 'Limit';
if (options.perPage && ! Session.get(limitName))
Session.set(limitName, options.perPage);
// setup the subscription
Meteor.autosubscribe(function() {
Session.set(readyName, false);
var findOptions = {
sort: options.sort,
limit: options.perPage && Session.get(limitName)
};
var find = _.isFunction(options.find) ? options.find() : options.find;
Meteor.subscribe('posts', find || {}, findOptions, name, function() {
Session.set('initialLoad', false);
Session.set(readyName, true);
});
});
// setup a function to find the relevant posts (+deal with mm's lack of limit)
postsForSub[name] = function() {
var find = _.isFunction(options.find) ? options.find() : options.find;
var orderedPosts = Posts.find(find || {}, {sort: options.sort});
if (options.perPage) {
return limitDocuments(orderedPosts, Session.get(limitName));
} else {
return orderedPosts;
}
};
var postListSubscription = function(find, options, per_page) {
var handle = paginatedSubscription(per_page, 'paginatedPosts', find, options);
handle.fetch = function() {
return limitDocuments(Posts.find(find, options), handle.loaded());
}
return handle;
}
// if(Session.get('selectedPostId')){
setupPostSubscription('singlePost', {
find: function() { return Session.get('selectedPostId'); }
});
// }
var topPostsHandle = postListSubscription(FIND_APPROVED, {sort: {score: -1}}, 10);
var newPostsHandle = postListSubscription(FIND_APPROVED, {sort: {submitted: -1}}, 10);
var bestPostsHandle = postListSubscription(FIND_APPROVED, {sort: {baseScore: -1}}, 10);
var pendingPostsHandle = postListSubscription(
{$or: [{status: STATUS_PENDING}, {status: STATUS_REJECTED}]},
{sort: {score: -1}},
10
);
setupPostSubscription('topPosts', {
find: FIND_APPROVED,
sort: {score: -1},
perPage: TOP_PAGE_PER_PAGE
});
setupPostSubscription('newPosts', {
find: FIND_APPROVED,
sort: {submitted: -1},
perPage: NEW_PAGE_PER_PAGE
});
setupPostSubscription('bestPosts', {
find: FIND_APPROVED,
sort: {baseScore: -1},
perPage: NEW_PAGE_PER_PAGE
});
setupPostSubscription('pendingPosts', {
find: {$or: [{status: STATUS_PENDING}, {status: STATUS_REJECTED}]},
sort: {score: -1},
perPage: PENDING_PAGE_PER_PAGE
});
setupPostSubscription('digestPosts', {
find: function() {
var mDate = moment(Session.get('currentDate'));
var find = {
submitted: {
$gte: mDate.startOf('day').valueOf(),
$lt: mDate.endOf('day').valueOf()
}
};
find=_.extend(find, FIND_APPROVED);
return find;
},
sort: {score: -1}
,perPage: DIGEST_PAGE_PER_PAGE
});
// setupPostSubscription('digestPosts', {
// find: function() {
// var mDate = moment(Session.get('currentDate'));
// var find = {
// submitted: {
// $gte: mDate.startOf('day').valueOf(),
// $lt: mDate.endOf('day').valueOf()
// }
// };
// find=_.extend(find, FIND_APPROVED);
// return find;
// },
// sort: {score: -1}
// ,perPage: DIGEST_PAGE_PER_PAGE
// });
// ** Categories **

View file

@ -0,0 +1,48 @@
PaginatedSubscriptionHandle = function(perPage) {
this.perPage = perPage;
this._limit = perPage;
this._limitListeners = new Meteor.deps._ContextSet();
this._loaded = 0;
this._loadedListeners = new Meteor.deps._ContextSet();
}
PaginatedSubscriptionHandle.prototype.loaded = function() {
this._loadedListeners.addCurrentContext();
return this._loaded;
}
PaginatedSubscriptionHandle.prototype.limit = function() {
this._limitListeners.addCurrentContext();
return this._limit;
}
PaginatedSubscriptionHandle.prototype.loading = function() {
return this.loaded() < this.limit();
}
PaginatedSubscriptionHandle.prototype.loadNextPage = function() {
this._limit += this.perPage;
this._limitListeners.invalidateAll();
}
PaginatedSubscriptionHandle.prototype.done = function() {
// XXX: check if subs that are canceled before they are ready ever fire ready?
// if they do we need to increase loaded by perPage, not set it to limit
this._loaded = this._limit;
this._loadedListeners.invalidateAll();
}
paginatedSubscription = function (perPage/*, name, arguments */) {
var handle = new PaginatedSubscriptionHandle(perPage);
var args = Array.prototype.slice.call(arguments, 1);
Meteor.autosubscribe(function() {
var subHandle = Meteor.subscribe.apply(this, args.concat([
handle.limit(), function() { handle.done(); }
]));
handle.stop = subHandle.stop;
});
return handle;
}

View file

@ -1,20 +1,4 @@
(function() {
// XXX: could we just work this out programmatically based on the name?
// -- fix this along with the general problem of subscription mess
PAGE_SUBS = {
'posts_top': 'topPostsReady',
'posts_new': 'newPostsReady',
'posts_best': 'bestPostsReady',
'posts_pending': 'pendingPostsReady',
'posts_digest': 'digestPostsReady',
'post_page': 'singlePostReady',
'post_edit': 'singlePostReady',
'comment_page': 'commentReady',
'comment_reply': 'commentReady',
'comment_edit': 'commentReady'
}
// specific router functions
digest = function(year, month, day, view){
var destination = (typeof view === 'undefined') ? 'posts_digest' : 'posts_digest_'+view
@ -191,10 +175,6 @@
return isAdmin(Meteor.user()) ? page : "no_rights";
},
awaitSubscription: function(page) {
return Session.equals(PAGE_SUBS[page], true) ? page : 'loading';
},
// if the user is logged in but their profile isn't filled out enough
requireProfile: function(page) {
var user = Meteor.user();
@ -220,7 +200,6 @@
});
//
Meteor.Router.filter('requireProfile');
Meteor.Router.filter('awaitSubscription', {only: ['posts_top', 'posts_new', 'posts_pending', 'posts_best']});
Meteor.Router.filter('requireLogin', {only: ['comment_reply','post_submit']});
Meteor.Router.filter('canView', {only: ['posts_top', 'posts_new', 'posts_digest', 'posts_best']});
Meteor.Router.filter('isLoggedOut', {only: ['user_signin', 'user_signup']});

View file

@ -1,10 +0,0 @@
<template name="posts_best">
<div class="posts grid list">
{{#each posts}}
{{> post_item}}
{{/each}}
</div>
<div class="grid more-button {{#if allPostsLoaded}} hidden {{/if}}">
<a class="more-link" href="#">Load more</a>
</div>
</template>

View file

@ -1,27 +0,0 @@
Template.posts_best.posts = function() {
return postsForSub.bestPosts();
};
Template.posts_best.helpers({
allPostsLoaded: function(){
return postsForSub.bestPosts().length < Session.get('bestPostsLimit');
}
});
Template.posts_best.rendered = function(){
var distanceFromTop = 0;
$('.post').each(function(){
distanceFromTop += $(this).height();
});
$('body').css('min-height',distanceFromTop+160);
$('.more-button').css('top', distanceFromTop+"px");
}
Template.posts_best.events({
'click .more-link': function(e) {
e.preventDefault();
Session.set('currentScroll',$('body').scrollTop());
Session.set('bestPostsLimit', Session.get('bestPostsLimit') + BEST_PAGE_PER_PAGE);
}
});

View file

@ -0,0 +1,32 @@
<template name="posts_list">
<div class="posts grid list">
{{#each posts}}
{{> post_item}}
{{/each}}
</div>
{{#if postsReady}}
<div class="grid more-button {{#if allPostsLoaded}} hidden {{/if}}">
<a class="more-link" href="#">Load more</a>
</div>
{{else}}
<div>SPINNER...</div>
{{/if}}
</template>
<!-- and the various pages that use the above template -->
<!-- XXX: makes me want to be able to set a context from the router... -->
<template name="posts_top">
{{> posts_list topPostsHandle}}
</template>
<template name="posts_new">
{{> posts_list newPostsHandle}}
</template>
<template name="posts_best">
{{> posts_list bestPostsHandle}}
</template>
<template name="posts_pending">
{{> posts_list pendingPostsHandle}}
</template>

View file

@ -0,0 +1,42 @@
Template.posts_top.topPostsHandle = function() {
return topPostsHandle;
}
Template.posts_new.newPostsHandle = function() {
return newPostsHandle;
}
Template.posts_best.bestPostsHandle = function() {
return bestPostsHandle;
}
Template.posts_best.pendingPostsHandle = function() {
return pendingPostsHandle;
}
Template.posts_list.helpers({
posts: function() {
return this.fetch();
},
postsReady: function() {
return ! this.loading();
},
allPostsLoaded: function(){
return this.fetch().length < this.loaded()
}
});
Template.posts_top.rendered = function(){
var distanceFromTop = 0;
$('.post').each(function(){
distanceFromTop += $(this).height();
});
$('body').css('min-height',distanceFromTop+160);
$('.more-button').css('top', distanceFromTop+"px");
}
Template.posts_top.events({
'click .more-link': function(e) {
e.preventDefault();
Session.set('currentScroll',$('body').scrollTop());
this.loadNextPage();
}
});

View file

@ -1,10 +0,0 @@
<template name="posts_new">
<div class="posts grid list">
{{#each posts}}
{{> post_item}}
{{/each}}
</div>
<div class="grid more-button {{#if allPostsLoaded}} hidden {{/if}}">
<a class="more-link" href="#">Load more</a>
</div>
</template>

View file

@ -1,26 +0,0 @@
Template.posts_new.posts = function() {
return postsForSub.newPosts();
};
Template.posts_new.helpers({
allPostsLoaded: function(){
return postsForSub.newPosts().length < Session.get('newPostsLimit');
}
});
Template.posts_new.rendered = function(){
var distanceFromTop = 0;
$('.post').each(function(){
distanceFromTop += $(this).height();
});
$('body').css('min-height',distanceFromTop+160);
$('.more-button').css('top', distanceFromTop+"px");
}
Template.posts_new.events({
'click .more-link': function(e) {
e.preventDefault();
Session.set('currentScroll',$('body').scrollTop());
Session.set('newPostsLimit', Session.get('newPostsLimit') + NEW_PAGE_PER_PAGE)
}
});

View file

@ -1,10 +0,0 @@
<template name="posts_pending">
<div class="posts grid list">
{{#each posts}}
{{> post_item}}
{{/each}}
</div>
<div class="grid more-button {{#if allPostsLoaded}} hidden {{/if}}">
<a class="more-link" href="#">Load more</a>
</div>
</template>

View file

@ -1,25 +0,0 @@
Template.posts_pending.posts = function() {
return postsForSub.pendingPosts();
};
Template.posts_pending.helpers({
allPostsLoaded: function(){
return postsForSub.pendingPosts().length < Session.get('pendingPostsLimit');
}
});
Template.posts_pending.rendered = function(){
var distanceFromTop = 0;
$('.post').each(function(){
distanceFromTop += $(this).height();
});
$('.more-button').css('top', distanceFromTop+"px");
}
Template.posts_pending.events({
'click .more-link': function(e) {
e.preventDefault();
Session.set('currentScroll',$('body').scrollTop());
Session.set('pendingPostsLimit', Session.get('pendingPostsLimit') + NEW_PAGE_PER_PAGE)
}
});

View file

@ -1,10 +0,0 @@
<template name="posts_top">
<div class="posts grid list">
{{#each posts}}
{{> post_item}}
{{/each}}
</div>
<div class="grid more-button {{#if allPostsLoaded}} hidden {{/if}}">
<a class="more-link" href="#">Load more</a>
</div>
</template>

View file

@ -1,27 +0,0 @@
Template.posts_top.posts = function() {
return postsForSub.topPosts();
};
Template.posts_top.helpers({
allPostsLoaded: function(){
return postsForSub.topPosts().length < Session.get('topPostsLimit');
}
});
Template.posts_top.rendered = function(){
var distanceFromTop = 0;
$('.post').each(function(){
distanceFromTop += $(this).height();
});
$('body').css('min-height',distanceFromTop+160);
$('.more-button').css('top', distanceFromTop+"px");
}
Template.posts_top.events({
'click .more-link': function(e) {
e.preventDefault();
Session.set('currentScroll',$('body').scrollTop());
Session.set('topPostsLimit', Session.get('topPostsLimit') + TOP_PAGE_PER_PAGE);
}
});

View file

@ -54,6 +54,14 @@ Posts = new Meteor.Collection('posts');
// return Posts.find({}, {sort: {score: -1}});
// });
Meteor.publish('paginatedPosts', function(find, options, limit) {
options = options || {};
options.limit = limit;
return Posts.find(find || {}, options);
});
Meteor.publish('posts', function(find, options, subName) {
var collection=Posts.find(find, options);
var collectionArray=collection.fetch();