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

Merge branch 'stream-js-cleanup'

Conflicts:
	public/javascripts/app/models/stream.js
parents b583a7a4 c219cee9
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 @@ ...@@ -10,7 +10,9 @@
#gs-shim{:title => popover_with_close_html("3. #{t('.stay_updated')}"), 'data-content' => t('.stay_updated_explanation')} #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 - if current_user.contacts.size < 2
= render 'aspects/no_contacts_message' = render 'aspects/no_contacts_message'
......
...@@ -7,19 +7,33 @@ app.models.Stream = Backbone.Collection.extend({ ...@@ -7,19 +7,33 @@ app.models.Stream = Backbone.Collection.extend({
return _.any(this.posts.models) ? this.timeFilteredPath() : this.basePath() return _.any(this.posts.models) ? this.timeFilteredPath() : this.basePath()
}, },
_fetching : false,
fetch: function() { fetch: function() {
var self = this var self = this
// we're fetching the collection... there is probably a better way to do this
self._fetching = true;
this.posts this.posts
.fetch({ .fetch({
add : true, add : true,
url : self.url() url : self.url()
}) })
.done( .done(
function(response){ function(resp){
self.trigger("fetched", self, response); // 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(){ basePath : function(){
......
...@@ -14,10 +14,12 @@ app.Router = Backbone.Router.extend({ ...@@ -14,10 +14,12 @@ app.Router = Backbone.Router.extend({
stream : function() { stream : function() {
app.stream = new app.models.Stream() app.stream = new app.models.Stream()
app.page = new app.views.Stream().render(); app.page = new app.views.Stream({model : app.stream}).render();
$("#main_stream").html(app.page.el); app.publisher = app.publisher || new app.views.Publisher({collection : app.stream.posts});
var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts}).render(); var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts}).render();
$("#main_stream").html(app.page.el);
$('#selected_aspect_contacts .content').html(streamFacesView.el); $('#selected_aspect_contacts .content').html(streamFacesView.el);
} }
}); });
......
...@@ -12,6 +12,9 @@ app.views.CommentStream = app.views.Base.extend({ ...@@ -12,6 +12,9 @@ app.views.CommentStream = app.views.Base.extend({
initialize: function(options) { initialize: function(options) {
this.model.comments.bind('add', this.appendComment, this); this.model.comments.bind('add', this.appendComment, this);
// add autoexpanders to new comment textarea
this.$('textarea').autoResize();
}, },
postRenderTemplate : function() { postRenderTemplate : function() {
......
...@@ -12,7 +12,7 @@ app.views.Publisher = Backbone.View.extend({ ...@@ -12,7 +12,7 @@ app.views.Publisher = Backbone.View.extend({
}, },
initialize : function(){ initialize : function(){
this.collection = this.collection || new app.collections.Posts; this.collection = this.collection //takes a Posts collection
return this; return this;
}, },
......
...@@ -4,16 +4,20 @@ app.views.Stream = Backbone.View.extend({ ...@@ -4,16 +4,20 @@ app.views.Stream = Backbone.View.extend({
}, },
initialize: function(options) { initialize: function(options) {
this.stream = app.stream || new app.models.Stream() this.stream = this.model
this.collection = this.stream.posts this.collection = this.model.posts
this.publisher = new app.views.Publisher({collection : this.collection});
this.stream.bind("fetched", this.collectionFetched, this) this.setupEvents()
this.collection.bind("add", this.addPost, this);
this.setupInfiniteScroll() this.setupInfiniteScroll()
this.setupLightbox() 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) { addPost : function(post) {
var postView = new app.views.Post({ model: post }); var postView = new app.views.Post({ model: post });
...@@ -26,51 +30,30 @@ app.views.Stream = Backbone.View.extend({ ...@@ -26,51 +30,30 @@ app.views.Stream = Backbone.View.extend({
return this; return this;
}, },
isLoading : function(){ unbindInfScroll : function() {
return this._loading && !this._loading.isResolved(); $("window").unbind("scroll");
},
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'));
}, },
render : function(evt) { render : function(evt) {
if(evt) { evt.preventDefault(); } if(evt) { evt.preventDefault(); }
this.addLoader(); // fetch more posts from the stream model
this._loading = this.stream.fetch(); if(this.stream.fetch()) {
this.appendLoader()
};
return this; return this;
}, },
addLoader: function(){ appendLoader: function(){
if(this.$("#paginate").length == 0) { $("#paginate").html($("<img>", {
$(this.el).append($("<div>", {
"id" : "paginate"
}));
}
this.$("#paginate").html($("<img>", {
src : "/images/static-loader.png", src : "/images/static-loader.png",
"class" : "loader" "class" : "loader"
})); }));
}, },
removeLoader : function(){ removeLoader: function() {
this.$("#paginate").remove(); $("#paginate").empty();
}, },
setupLightbox : function(){ setupLightbox : function(){
...@@ -80,13 +63,11 @@ app.views.Stream = Backbone.View.extend({ ...@@ -80,13 +63,11 @@ app.views.Stream = Backbone.View.extend({
setupInfiniteScroll : function() { setupInfiniteScroll : function() {
var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200); var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200);
$(window).scroll(throttledScroll); $("window").scroll(throttledScroll);
}, },
infScroll : function() { infScroll : function() {
if(this.allContentLoaded || this.isLoading()) { return } var $window = $("window");
var $window = $(window);
var distFromTop = $window.height() + $window.scrollTop(); var distFromTop = $window.height() + $window.scrollTop();
var distFromBottom = $(document).height() - distFromTop; var distFromBottom = $(document).height() - distFromTop;
var bufferPx = 500; var bufferPx = 500;
......
...@@ -9,7 +9,7 @@ describe("app.models.Stream", function() { ...@@ -9,7 +9,7 @@ describe("app.models.Stream", function() {
beforeEach(function(){ beforeEach(function(){
postFetch = new $.Deferred() postFetch = new $.Deferred()
spyOn(this.stream.posts, "fetch").andCallFake(function(){ spyOn(this.stream.posts, "fetch").andCallFake(function(){
return postFetch return postFetch
}) })
}) })
...@@ -32,7 +32,23 @@ describe("app.models.Stream", function() { ...@@ -32,7 +32,23 @@ describe("app.models.Stream", function() {
var fetchedSpy = jasmine.createSpy() var fetchedSpy = jasmine.createSpy()
this.stream.bind('fetched', fetchedSpy) this.stream.bind('fetched', fetchedSpy)
this.stream.fetch() 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() expect(fetchedSpy).toHaveBeenCalled()
}) })
}); });
......
...@@ -4,11 +4,10 @@ describe("app.views.Stream", function(){ ...@@ -4,11 +4,10 @@ describe("app.views.Stream", function(){
this.posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"]; this.posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"];
app.stream = new app.models.Stream() this.stream = new app.models.Stream()
app.stream.add(this.posts); this.stream.add(this.posts);
this.collection = app.stream.posts this.view = new app.views.Stream({model : this.stream});
this.view = new app.views.Stream({collection : this.collection});
app.stream.bind("fetched", this.collectionFetched, this) //untested app.stream.bind("fetched", this.collectionFetched, this) //untested
...@@ -20,16 +19,15 @@ describe("app.views.Stream", function(){ ...@@ -20,16 +19,15 @@ describe("app.views.Stream", function(){
describe("initialize", function(){ describe("initialize", function(){
it("binds an infinite scroll listener", function(){ it("binds an infinite scroll listener", function(){
spyOn($.fn, "scroll"); spyOn($.fn, "scroll");
new app.views.Stream({model : this.stream});
new app.views.Stream();
expect($.fn.scroll).toHaveBeenCalled() expect($.fn.scroll).toHaveBeenCalled()
}) })
}) })
describe("#render", function(){ describe("#render", function(){
beforeEach(function(){ beforeEach(function(){
this.statusMessage = this.collection.models[0]; this.statusMessage = this.stream.posts.models[0];
this.reshare = this.collection.models[1]; this.reshare = this.stream.posts.models[1];
this.statusElement = $(this.view.$("#" + this.statusMessage.get("guid"))); this.statusElement = $(this.view.$("#" + this.statusMessage.get("guid")));
this.reshareElement = $(this.view.$("#" + this.reshare.get("guid"))); this.reshareElement = $(this.view.$("#" + this.reshare.get("guid")));
}) })
...@@ -44,77 +42,31 @@ describe("app.views.Stream", function(){ ...@@ -44,77 +42,31 @@ describe("app.views.Stream", function(){
describe("infScroll", function(){ describe("infScroll", function(){
// NOTE: inf scroll happens at 500px // NOTE: inf scroll happens at 500px
beforeEach(function(){ it("calls render when the user is at the bottom of the page", function(){
spyOn(this.view.collection, "fetch").andReturn($.Deferred()) spyOn($.fn, "height").andReturn(0)
}) spyOn($.fn, "scrollTop").andReturn(100)
spyOn(this.view, "render")
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);
this.view.infScroll(); this.view.infScroll();
expect(this.view.collection.fetch).not.toHaveBeenCalled(); expect(this.view.render).toHaveBeenCalled();
}) })
}) })
describe("collectionFetched", function(){ describe("removeLoader", function() {
context("unbinding scroll", function(){ it("emptys the pagination div when the stream is fetched", function(){
beforeEach(function(){ $("#jasmine_content").append($('<div id="paginate">OMG</div>'))
spyOn($.fn, "unbind") expect($("#paginate").text()).toBe("OMG")
}) this.view.stream.trigger("fetched")
expect($("#paginate")).toBeEmpty()
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)
}) })
})
it("does not set this.allContentLoaded if there was a non-empty response from the server", function(){ describe("unbindInfScroll", function(){
expect(this.view.allContentLoaded).toBe(false) it("unbinds scroll", function() {
this.view.collectionFetched(this.collection, {posts : this.posts}) spyOn($.fn, "unbind")
expect(this.view.allContentLoaded).toBe(false) 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