DC DG extract infininte scroll to a mixin
This commit is contained in:
parent
7361b8f305
commit
a307b60dd2
3 changed files with 85 additions and 62 deletions
|
|
@ -21,7 +21,8 @@ app.views.Base = Backbone.View.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
defaultPresenter : function(){
|
defaultPresenter : function(){
|
||||||
var modelJson = this.model ? _.clone(this.model.attributes) : {}
|
var modelJson = this.model && this.model.attributes ? _.clone(this.model.attributes) : {}
|
||||||
|
|
||||||
return _.extend(modelJson, {
|
return _.extend(modelJson, {
|
||||||
current_user : app.currentUser.attributes,
|
current_user : app.currentUser.attributes,
|
||||||
loggedIn : app.currentUser.authenticated()
|
loggedIn : app.currentUser.authenticated()
|
||||||
|
|
@ -71,3 +72,66 @@ app.views.Base = Backbone.View.extend({
|
||||||
$(".tooltip").remove();
|
$(".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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,74 +1,26 @@
|
||||||
app.views.Stream = Backbone.View.extend({
|
app.views.Stream = Backbone.View.extend(_.extend({
|
||||||
initialize: function(options) {
|
initialize: function(options) {
|
||||||
this.stream = this.model
|
this.stream = this.model
|
||||||
this.collection = this.model.posts
|
this.collection = this.model.posts
|
||||||
|
|
||||||
this.setupEvents()
|
|
||||||
this.setupInfiniteScroll()
|
|
||||||
this.setupLightbox()
|
|
||||||
this.postViews = []
|
this.postViews = []
|
||||||
|
|
||||||
|
this.setupNSFW()
|
||||||
|
this.setupLightbox()
|
||||||
|
this.setupInfiniteScroll()
|
||||||
},
|
},
|
||||||
|
|
||||||
setupEvents : function(){
|
postClass : app.views.StreamPost,
|
||||||
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")
|
|
||||||
},
|
|
||||||
|
|
||||||
setupLightbox : function(){
|
setupLightbox : function(){
|
||||||
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
|
this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox");
|
||||||
this.$el.delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked);
|
this.$el.delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked);
|
||||||
},
|
},
|
||||||
|
|
||||||
setupInfiniteScroll : function() {
|
setupNSFW : function(){
|
||||||
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
|
app.currentUser.bind("nsfwChanged", reRenderPostViews, this)
|
||||||
$(window).scroll(throttledScroll);
|
|
||||||
},
|
|
||||||
|
|
||||||
infScroll : function() {
|
function reRenderPostViews() {
|
||||||
var $window = $(window)
|
_.map(this.postViews, function(view){ view.render() })
|
||||||
, distFromTop = $window.height() + $window.scrollTop()
|
|
||||||
, distFromBottom = $(document).height() - distFromTop
|
|
||||||
, bufferPx = 500;
|
|
||||||
|
|
||||||
if(distFromBottom < bufferPx) {
|
|
||||||
this.fetchAndAppendLoader()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}, app.views.infiniteScrollMixin));
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,17 @@ describe("app.views.Stream", function() {
|
||||||
it("fetches moar when the user is at the bottom of the page", function() {
|
it("fetches moar when the user is at the bottom of the page", function() {
|
||||||
spyOn($.fn, "height").andReturn(0);
|
spyOn($.fn, "height").andReturn(0);
|
||||||
spyOn($.fn, "scrollTop").andReturn(100);
|
spyOn($.fn, "scrollTop").andReturn(100);
|
||||||
spyOn(this.view, "fetchAndAppendLoader");
|
spyOn(this.view.model, "fetch");
|
||||||
|
|
||||||
this.view.infScroll();
|
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()
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue