refactor stream page scroll spy

This commit is contained in:
Dennis Collinson 2012-05-30 16:49:50 -07:00
parent 1ac01cc156
commit a9288daf19
5 changed files with 103 additions and 133 deletions

View file

@ -1,8 +1,12 @@
//= require_self
//= require_tree ./helpers
//= require ./router
//= require ./models
//= require ./views
//= require ./views/infinite_stream_view
//= require_tree ./models
//= require_tree ./pages
//= require_tree ./collections

View file

@ -7,8 +7,6 @@ app.views.NewStream = app.views.InfScroll.extend({
}
});
/*--------------------*/
app.pages.Stream = app.views.Base.extend({
templateName : "stream",
@ -23,64 +21,48 @@ app.pages.Stream = app.views.Base.extend({
initialize : function(){
this.stream = this.model = new app.models.Stream()
this.stream.preloadOrFetch();
this.stream.preloadOrFetch()
this.streamView = new app.views.NewStream({ model : this.stream })
var interactions = this.interactionsView = new app.views.StreamInteractions()
this.setUpThrottledInteractionScroll();
this.stream.on("frame:interacted", function(post){
interactions.setInteractions(post)
})
this.streamView.on('loadMore', this.updateUrlState, this);
this.stream.on("fetched", this.refreshScrollSpy, this)
},
postRenderTemplate : function() {
this.$("#header").css("background-image", "url(" + app.currentUser.get("wallpaper") + ")")
_.defer(function(){$('body').scrollspy({target : '.stream-frame-wrapper', offset : 50})})
this.setUpHashChangeOnStreamLoad()
},
setUpThrottledInteractionScroll : function(){
this.focusedPost = undefined;
var self = this;
this.updateInteractions = _.throttle(function(){
console.log("firing for " + self.focusedPost.get('id'));
self.interactionsView.setInteractions(self.focusedPost)
}, 1000)
},
setUpHashChangeOnStreamLoad : function(){
var self = this;
this.streamView.on('loadMore', function(){
var post = this.stream.items.last();
if(post){
self.navigateToPost(post)
}
self.refreshScrollSpy()
});
updateUrlState : function(){
var post = this.stream.items.last();
if(post){
this.navigateToPost(post)
}
},
navigateToPost : function(post){
app.router.navigate(location.pathname + "?ex=true&max_time=" + post.createdAt(), {replace: true})
},
triggerInteractionLoad : function(evt){
var id = $(evt.target).data("id");
console.log("calling triggerInteractiosns for: " + id)
this.focusedPost = this.stream.items.get(id)
this.updateInteractions()
this._throttledInteractions = this._throttledInteractions || _.bind(_.throttle(this.updateInteractions, 1000), this)
this._throttledInteractions()
},
updateInteractions: function () {
this.interactionsView.setInteractions(this.focusedPost)
},
//on active guid => this guid
// fire interacted from stream collection w/guid
refreshScrollSpy : function(){
setTimeout(function(){
$('body').scrollspy('refresh')
}, 2000)
_.defer($('body').scrollspy('refresh'))
}
});

View file

@ -95,81 +95,3 @@ app.views.Base = Backbone.View.extend({
}
});
// Mixin to render a collection that fetches more via infinite scroll, for a view that has no template.
// Requires:
// a stream model, assigned to this.stream
// a stream's posts, assigned to this.collection
// a postClass to be declared
// a #paginate div in the layout
// a call to setupInfiniteScroll
app.views.InfScroll = app.views.Base.extend({
setupInfiniteScroll : function() {
this.postViews = this.postViews || []
this.bind("loadMore", this.fetchAndshowLoader, this)
this.stream.bind("fetched", this.hideLoader, this)
this.stream.bind("allItemsLoaded", this.unbindInfScroll, this)
this.collection.bind("add", this.addPostView, this);
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
$(window).scroll(throttledScroll);
},
postRenderTemplate : function() {
if(this.stream.isFetching()) { this.showLoader() }
},
createPostView : function(post){
var postView = new this.postClass({ model: post, stream: this.stream });
this.postViews.push(postView)
return postView
},
addPostView : function(post) {
var placeInStream = (this.collection.at(0).id == post.id) ? "prepend" : "append";
this.$el[placeInStream](this.createPostView(post).render().el);
},
unbindInfScroll : function() {
$(window).unbind("scroll");
},
renderTemplate : function(){
this.renderInitialPosts()
},
renderInitialPosts : function(){
this.$el.empty()
this.stream.items.each(_.bind(function(post){
this.$el.append(this.createPostView(post).render().el);
}, this))
},
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

@ -0,0 +1,77 @@
// Abstract Infinite Scroll View Super Class
// Requires:
// a stream model, assigned to this.stream
// a stream's posts, assigned to this.collection
// a postClass to be declared
// a #paginate div in the layout
// a call to setupInfiniteScroll
app.views.InfScroll = app.views.Base.extend({
setupInfiniteScroll : function() {
this.postViews = this.postViews || []
this.bind("loadMore", this.fetchAndshowLoader, this)
this.stream.bind("fetched", this.hideLoader, this)
this.stream.bind("allItemsLoaded", this.unbindInfScroll, this)
this.collection.bind("add", this.addPostView, this);
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
$(window).scroll(throttledScroll);
},
postRenderTemplate : function() {
if(this.stream.isFetching()) { this.showLoader() }
},
createPostView : function(post){
var postView = new this.postClass({ model: post, stream: this.stream });
this.postViews.push(postView)
return postView
},
addPostView : function(post) {
var placeInStream = (this.collection.at(0).id == post.id) ? "prepend" : "append";
this.$el[placeInStream](this.createPostView(post).render().el);
},
unbindInfScroll : function() {
$(window).unbind("scroll");
},
renderTemplate : function(){
this.renderInitialPosts()
},
renderInitialPosts : function(){
this.$el.empty()
this.stream.items.each(_.bind(function(post){
this.$el.append(this.createPostView(post).render().el);
}, this))
},
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

@ -6,18 +6,11 @@ describe("app.Pages.Stream", function(){
expect(this.post).toBeTruthy()
})
describe('postRenderTemplate', function(){
it("sets the background-image of #header", function(){
this.page.render()
expect(this.page.$('#header').css('background-image')).toBeTruthy()
})
it('calls setUpHashChangeOnStreamLoad', function(){
spyOn(this.page, 'setUpHashChangeOnStreamLoad')
this.page.render();
expect(this.page.setUpHashChangeOnStreamLoad).toHaveBeenCalled()
})
})
describe("rendering", function(){
@ -34,21 +27,13 @@ describe("app.Pages.Stream", function(){
})
})
describe("setUpHashChangeOnStreamLoad", function(){
it('calls navigateToPost on the loadMore event', function(){
spyOn(this.page, 'navigateToPost')
this.page.setUpHashChangeOnStreamLoad()
this.page.streamView.trigger('loadMore')
expect(this.page.navigateToPost).toHaveBeenCalled()
})
})
describe("navigateToPost", function(){
it("sets the max time of the url to the created at time of a post", function(){
context("when more posts are loaded", function(){
it("navigates to the last post in the stream's max_time", function(){
spyOn(app.router, 'navigate')
this.page.navigateToPost(this.post)
var url = location.pathname + "?ex=true&max_time=" + this.post.createdAt()
var options = {replace: true}
, options = {replace: true}
this.page.streamView.trigger('loadMore')
expect(app.router.navigate).toHaveBeenCalledWith(url, options)
})
})