DC DG extract infininte scroll to a mixin

This commit is contained in:
danielgrippi 2012-04-18 12:34:09 -07:00
parent 7361b8f305
commit a307b60dd2
3 changed files with 85 additions and 62 deletions

View file

@ -21,7 +21,8 @@ app.views.Base = Backbone.View.extend({
},
defaultPresenter : function(){
var modelJson = this.model ? _.clone(this.model.attributes) : {}
var modelJson = this.model && this.model.attributes ? _.clone(this.model.attributes) : {}
return _.extend(modelJson, {
current_user : app.currentUser.attributes,
loggedIn : app.currentUser.authenticated()
@ -71,3 +72,66 @@ app.views.Base = Backbone.View.extend({
$(".tooltip").remove();
}
});
// Mixin to render a collection that fetches more via infinite scroll, for a view that has no template.
// Requires:
// a stream model, bound as this.stream
// a stream's posts, bound as this.collection
// a postClass to be declared
// a #paginate div in the layout
// a call to setupInfiniteScroll
app.views.infiniteScrollMixin = {
setupInfiniteScroll : function() {
this.postViews = this.postViews || []
this.bind("loadMore", this.fetchAndshowLoader, this)
this.stream.bind("fetched", this.hideLoader, this)
this.stream.bind("allPostsLoaded", this.unbindInfScroll, this)
this.collection.bind("add", this.addPost, this);
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
$(window).scroll(throttledScroll);
},
renderTemplate : function() {
if(this.stream.isFetching()) { this.showLoader() }
},
addPost : function(post) {
var postView = new this.postClass({ model: post })
, placeInStream = (this.collection.at(0).id == post.id) ? "prepend" : "append";
this.$el[placeInStream](postView.render().el);
this.postViews.push(postView)
},
unbindInfScroll : function() {
$(window).unbind("scroll");
},
fetchAndshowLoader : function(){
if(this.stream.isFetching()) { return false }
this.stream.fetch()
this.showLoader()
},
showLoader: function(){
$("#paginate .loader").removeClass("hidden")
},
hideLoader: function() {
$("#paginate .loader").addClass("hidden")
},
infScroll : function() {
var $window = $(window)
, distFromTop = $window.height() + $window.scrollTop()
, distFromBottom = $(document).height() - distFromTop
, bufferPx = 500;
if(distFromBottom < bufferPx) {
this.trigger("loadMore")
}
}
};

View file

@ -1,74 +1,26 @@
app.views.Stream = Backbone.View.extend({
app.views.Stream = Backbone.View.extend(_.extend({
initialize: function(options) {
this.stream = this.model
this.collection = this.model.posts
this.setupEvents()
this.setupInfiniteScroll()
this.setupLightbox()
this.postViews = []
this.setupNSFW()
this.setupLightbox()
this.setupInfiniteScroll()
},
setupEvents : function(){
this.stream.bind("fetched", this.removeLoader, this)
this.stream.bind("allPostsLoaded", this.unbindInfScroll, this)
this.collection.bind("add", this.addPost, this);
app.currentUser.bind("nsfwChanged", reRenderPostViews, this)
function reRenderPostViews() {
_.map(this.postViews, function(view){ view.render() })
}
},
addPost : function(post) {
var postView = new app.views.StreamPost({ model: post })
, placeInStream = (this.collection.at(0).id == post.id) ? "prepend" : "append";
this.$el[placeInStream](postView.render().el);
this.postViews.push(postView)
},
unbindInfScroll : function() {
$(window).unbind("scroll");
},
render : function() {
if(this.stream.isFetching()) { this.appendLoader() }
return this;
},
fetchAndAppendLoader : function(){
if(this.stream.isFetching()) { return false }
this.stream.fetch()
this.appendLoader()
},
appendLoader: function(){
$("#paginate .loader").removeClass("hidden")
},
removeLoader: function() {
$("#paginate .loader").addClass("hidden")
},
postClass : app.views.StreamPost,
setupLightbox : function(){
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
this.$el.delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked);
},
setupInfiniteScroll : function() {
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
$(window).scroll(throttledScroll);
},
setupNSFW : function(){
app.currentUser.bind("nsfwChanged", reRenderPostViews, this)
infScroll : function() {
var $window = $(window)
, distFromTop = $window.height() + $window.scrollTop()
, distFromBottom = $(document).height() - distFromTop
, bufferPx = 500;
if(distFromBottom < bufferPx) {
this.fetchAndAppendLoader()
function reRenderPostViews() {
_.map(this.postViews, function(view){ view.render() })
}
}
});
}, app.views.infiniteScrollMixin));

View file

@ -43,10 +43,17 @@ describe("app.views.Stream", function() {
it("fetches moar when the user is at the bottom of the page", function() {
spyOn($.fn, "height").andReturn(0);
spyOn($.fn, "scrollTop").andReturn(100);
spyOn(this.view, "fetchAndAppendLoader");
spyOn(this.view.model, "fetch");
this.view.infScroll();
expect(this.view.fetchAndAppendLoader).toHaveBeenCalled();
waitsFor(function(){
return this.view.model.fetch.wasCalled
}, "the infinite scroll function didn't fetch the stream")
runs(function(){
expect(this.view.model.fetch).toHaveBeenCalled()
})
});
});