Skip to content
Extraits de code Groupes Projets
Valider c219cee9 rédigé par danielgrippi's avatar danielgrippi
Parcourir les fichiers

fix inf scroll issues in stream view

parent 8ae9fdfd
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -10,7 +10,9 @@
#gs-shim{:title => popover_with_close_html("3. #{t('.stay_updated')}"), 'data-content' => t('.stay_updated_explanation')}
#main_stream.stream{:data => {:guids => stream.aspect_ids.join(',')}}
#main_stream.stream
#paginate
- if current_user.contacts.size < 2
= render 'aspects/no_contacts_message'
......
......@@ -7,19 +7,33 @@ app.models.Stream = Backbone.Collection.extend({
return _.any(this.posts.models) ? this.timeFilteredPath() : this.basePath()
},
_fetching : false,
fetch: function() {
var self = this
// we're fetching the collection... there is probably a better way to do this
self._fetching = true;
this.posts
.fetch({
add : true,
url : self.url()
})
.done(
function(){
function(resp){
// we're done fetching... there is probably a better way to handle this
self._fetching = false;
self.trigger("fetched", self);
// all loaded?
if(resp.posts && (resp.posts.author || resp.posts.length == 0)) {
self.trigger("allPostsLoaded", self);
}
}
)
return this;
},
basePath : function(){
......
......@@ -14,10 +14,12 @@ app.Router = Backbone.Router.extend({
stream : function() {
app.stream = new app.models.Stream()
app.page = new app.views.Stream().render();
$("#main_stream").html(app.page.el);
app.page = new app.views.Stream({model : app.stream}).render();
app.publisher = app.publisher || new app.views.Publisher({collection : app.stream.posts});
var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts}).render();
$("#main_stream").html(app.page.el);
$('#selected_aspect_contacts .content').html(streamFacesView.el);
}
});
......
......@@ -12,6 +12,9 @@ app.views.CommentStream = app.views.Base.extend({
initialize: function(options) {
this.model.comments.bind('add', this.appendComment, this);
// add autoexpanders to new comment textarea
this.$('textarea').autoResize();
},
postRenderTemplate : function() {
......
......@@ -12,7 +12,7 @@ app.views.Publisher = Backbone.View.extend({
},
initialize : function(){
this.collection = this.collection || new app.collections.Posts;
this.collection = this.collection //takes a Posts collection
return this;
},
......
......@@ -4,16 +4,20 @@ app.views.Stream = Backbone.View.extend({
},
initialize: function(options) {
this.stream = app.stream || new app.models.Stream()
this.collection = this.stream.posts
this.publisher = new app.views.Publisher({collection : this.collection});
this.stream = this.model
this.collection = this.model.posts
this.stream.bind("fetched", this.collectionFetched, this)
this.collection.bind("add", this.addPost, this);
this.setupEvents()
this.setupInfiniteScroll()
this.setupLightbox()
},
setupEvents : function(){
this.stream.bind("fetched", this.removeLoader, this)
this.stream.bind("allPostsLoaded", this.unbindInfScroll, this)
this.collection.bind("add", this.addPost, this);
},
addPost : function(post) {
var postView = new app.views.Post({ model: post });
......@@ -26,51 +30,30 @@ app.views.Stream = Backbone.View.extend({
return this;
},
isLoading : function(){
return this._loading && !this._loading.isResolved();
},
allContentLoaded : false,
collectionFetched: function(collection, response) {
this.removeLoader()
if(!collection.parse(response).length || collection.parse(response).length == 0) {
this.allContentLoaded = true;
$(window).unbind('scroll')
return
}
$(this.el).append($("<a>", {
href: this.stream.url(),
id: "paginate"
}).text('Load more posts'));
unbindInfScroll : function() {
$("window").unbind("scroll");
},
render : function(evt) {
if(evt) { evt.preventDefault(); }
this.addLoader();
this._loading = this.stream.fetch();
// fetch more posts from the stream model
if(this.stream.fetch()) {
this.appendLoader()
};
return this;
},
addLoader: function(){
if(this.$("#paginate").length == 0) {
$(this.el).append($("<div>", {
"id" : "paginate"
}));
}
this.$("#paginate").html($("<img>", {
appendLoader: function(){
$("#paginate").html($("<img>", {
src : "/images/static-loader.png",
"class" : "loader"
}));
},
removeLoader : function(){
this.$("#paginate").remove();
removeLoader: function() {
$("#paginate").empty();
},
setupLightbox : function(){
......@@ -80,13 +63,11 @@ app.views.Stream = Backbone.View.extend({
setupInfiniteScroll : function() {
var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200);
$(window).scroll(throttledScroll);
$("window").scroll(throttledScroll);
},
infScroll : function() {
if(this.allContentLoaded || this.isLoading()) { return }
var $window = $(window);
var $window = $("window");
var distFromTop = $window.height() + $window.scrollTop();
var distFromBottom = $(document).height() - distFromTop;
var bufferPx = 500;
......
......@@ -9,7 +9,7 @@ describe("app.models.Stream", function() {
beforeEach(function(){
postFetch = new $.Deferred()
spyOn(this.stream.posts, "fetch").andCallFake(function(){
spyOn(this.stream.posts, "fetch").andCallFake(function(){
return postFetch
})
})
......@@ -32,7 +32,23 @@ describe("app.models.Stream", function() {
var fetchedSpy = jasmine.createSpy()
this.stream.bind('fetched', fetchedSpy)
this.stream.fetch()
postFetch.resolve()
postFetch.resolve({posts : [1,2,3]})
expect(fetchedSpy).toHaveBeenCalled()
})
it("triggers allPostsLoaded on the stream when zero posts are returned", function(){
var fetchedSpy = jasmine.createSpy()
this.stream.bind('allPostsLoaded', fetchedSpy)
this.stream.fetch()
postFetch.resolve({posts : []})
expect(fetchedSpy).toHaveBeenCalled()
})
it("triggers allPostsLoaded on the stream when a Post is returned", function(){
var fetchedSpy = jasmine.createSpy()
this.stream.bind('allPostsLoaded', fetchedSpy)
this.stream.fetch()
postFetch.resolve({posts : factory.post().attributes})
expect(fetchedSpy).toHaveBeenCalled()
})
});
......
......@@ -4,11 +4,10 @@ describe("app.views.Stream", function(){
this.posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"];
app.stream = new app.models.Stream()
app.stream.add(this.posts);
this.stream = new app.models.Stream()
this.stream.add(this.posts);
this.collection = app.stream.posts
this.view = new app.views.Stream({collection : this.collection});
this.view = new app.views.Stream({model : this.stream});
app.stream.bind("fetched", this.collectionFetched, this) //untested
......@@ -20,16 +19,15 @@ describe("app.views.Stream", function(){
describe("initialize", function(){
it("binds an infinite scroll listener", function(){
spyOn($.fn, "scroll");
new app.views.Stream();
new app.views.Stream({model : this.stream});
expect($.fn.scroll).toHaveBeenCalled()
})
})
describe("#render", function(){
beforeEach(function(){
this.statusMessage = this.collection.models[0];
this.reshare = this.collection.models[1];
this.statusMessage = this.stream.posts.models[0];
this.reshare = this.stream.posts.models[1];
this.statusElement = $(this.view.$("#" + this.statusMessage.get("guid")));
this.reshareElement = $(this.view.$("#" + this.reshare.get("guid")));
})
......@@ -44,77 +42,31 @@ describe("app.views.Stream", function(){
describe("infScroll", function(){
// NOTE: inf scroll happens at 500px
beforeEach(function(){
spyOn(this.view.collection, "fetch").andReturn($.Deferred())
})
context("when the user is at the bottom of the page", function(){
beforeEach(function(){
spyOn($.fn, "height").andReturn(0)
spyOn($.fn, "scrollTop").andReturn(100)
})
it("calls fetch", function(){
spyOn(this.view, "isLoading").andReturn(false)
this.view.infScroll();
expect(this.view.collection.fetch).toHaveBeenCalled();
})
it("does not call fetch if the collection is loading", function(){
spyOn(this.view, "isLoading").andReturn(true)
this.view.infScroll();
expect(this.view.collection.fetch).not.toHaveBeenCalled();
})
it("does not call fetch if all content has been fetched", function(){
spyOn(this.view, "isLoading").andReturn(false)
this.view.allContentLoaded = true;
this.view.infScroll();
expect(this.view.collection.fetch).not.toHaveBeenCalled();
})
})
it("does not fetch new content when the user is not at the bottom of the page", function(){
spyOn(this.view, "isLoading").andReturn(false)
spyOn($.fn, "height").andReturn(0);
spyOn($.fn, "scrollTop").andReturn(-500);
it("calls render when the user is at the bottom of the page", function(){
spyOn($.fn, "height").andReturn(0)
spyOn($.fn, "scrollTop").andReturn(100)
spyOn(this.view, "render")
this.view.infScroll();
expect(this.view.collection.fetch).not.toHaveBeenCalled();
expect(this.view.render).toHaveBeenCalled();
})
})
describe("collectionFetched", function(){
context("unbinding scroll", function(){
beforeEach(function(){
spyOn($.fn, "unbind")
})
it("unbinds scroll if there are no more posts left to load", function(){
this.view.collectionFetched(this.collection, {posts : []})
expect($.fn.unbind).toHaveBeenCalled()
})
it("does not fetch new content when the user is fetching one post", function(){
this.view.collectionFetched(this.collection, {posts : {}})
expect($.fn.unbind).toHaveBeenCalled()
})
})
it("sets this.allContentLoaded if there are no more posts left to load", function(){
expect(this.view.allContentLoaded).toBe(false)
this.view.collectionFetched(this.collection, {posts : []})
expect(this.view.allContentLoaded).toBe(true)
describe("removeLoader", function() {
it("emptys the pagination div when the stream is fetched", function(){
$("#jasmine_content").append($('<div id="paginate">OMG</div>'))
expect($("#paginate").text()).toBe("OMG")
this.view.stream.trigger("fetched")
expect($("#paginate")).toBeEmpty()
})
})
it("does not set this.allContentLoaded if there was a non-empty response from the server", function(){
expect(this.view.allContentLoaded).toBe(false)
this.view.collectionFetched(this.collection, {posts : this.posts})
expect(this.view.allContentLoaded).toBe(false)
describe("unbindInfScroll", function(){
it("unbinds scroll", function() {
spyOn($.fn, "unbind")
this.view.unbindInfScroll()
expect($.fn.unbind.mostRecentCall.object.selector).toBe("window")
expect($.fn.unbind).toHaveBeenCalledWith("scroll")
})
})
})
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter