From 9b1d64bb7611ba34a0c3a6fe6a95c8476fb55993 Mon Sep 17 00:00:00 2001 From: Dennis Collinson <dennis.collective@gmail.com> Date: Wed, 18 Jan 2012 19:08:25 -0800 Subject: [PATCH] stream model has a posts collection --- .../app/collections/{stream.js => posts.js} | 12 +-- public/javascripts/app/models/stream.js | 36 +++++++ public/javascripts/app/router.js | 7 +- public/javascripts/app/views/feedback_view.js | 2 +- public/javascripts/app/views/post_view.js | 4 +- .../javascripts/app/views/publisher_view.js | 4 +- .../app/views/stream_faces_view.js | 2 +- public/javascripts/app/views/stream_view.js | 95 ++++++++++--------- .../app/collections/stream_spec.js | 19 ---- spec/javascripts/app/models/stream_spec.js | 39 ++++++++ spec/javascripts/app/views/post_view_spec.js | 2 +- .../app/views/stream_faces_view_spec.js | 13 ++- .../javascripts/app/views/stream_view_spec.js | 13 ++- 13 files changed, 152 insertions(+), 96 deletions(-) rename public/javascripts/app/collections/{stream.js => posts.js} (53%) create mode 100644 public/javascripts/app/models/stream.js delete mode 100644 spec/javascripts/app/collections/stream_spec.js create mode 100644 spec/javascripts/app/models/stream_spec.js diff --git a/public/javascripts/app/collections/stream.js b/public/javascripts/app/collections/posts.js similarity index 53% rename from public/javascripts/app/collections/stream.js rename to public/javascripts/app/collections/posts.js index b16e137e12..496d5a7545 100644 --- a/public/javascripts/app/collections/stream.js +++ b/public/javascripts/app/collections/posts.js @@ -1,13 +1,5 @@ -app.collections.Stream = Backbone.Collection.extend({ - url: function() { - var path = document.location.pathname; - - if(this.models.length) { - path += "?max_time=" + _.last(this.models).createdAt(); - } - - return path; - }, +app.collections.Posts = Backbone.Collection.extend({ + url : "/posts", model: function(attrs, options) { var modelClass = app.models[attrs.post_type] || app.models.Post diff --git a/public/javascripts/app/models/stream.js b/public/javascripts/app/models/stream.js new file mode 100644 index 0000000000..8611af3e28 --- /dev/null +++ b/public/javascripts/app/models/stream.js @@ -0,0 +1,36 @@ +app.models.Stream = Backbone.Collection.extend({ + initialize : function(){ + this.posts = new app.collections.Posts(); + }, + + url : function(){ + return _.any(this.posts.models) ? this.timeFilteredPath() : this.basePath() + }, + + fetch: function() { + var self = this + + this.posts + .fetch({ + add : true, + url : self.url() + }) + .done( + function(){ + self.trigger("fetched", self); + } + ) + }, + + basePath : function(){ + return document.location.pathname; + }, + + timeFilteredPath : function(){ + return this.basePath() + "?max_time=" + _.last(this.posts.models).createdAt(); + }, + + add : function(models){ + this.posts.add(models) + } +}) diff --git a/public/javascripts/app/router.js b/public/javascripts/app/router.js index ab7234f59f..986e2789b3 100644 --- a/public/javascripts/app/router.js +++ b/public/javascripts/app/router.js @@ -13,10 +13,11 @@ app.Router = Backbone.Router.extend({ }, stream : function() { - app.stream = new app.views.Stream().render(); - $("#main_stream").html(app.stream.el); + app.stream = new app.models.Stream() + app.page = new app.views.Stream().render(); + $("#main_stream").html(app.page.el); - var streamFacesView = new app.views.StreamFaces({collection : app.stream.collection}).render(); + var streamFacesView = new app.views.StreamFaces({collection : app.stream.posts}).render(); $('#selected_aspect_contacts .content').html(streamFacesView.el); } }); diff --git a/public/javascripts/app/views/feedback_view.js b/public/javascripts/app/views/feedback_view.js index 84c1ced120..bfa7110adf 100644 --- a/public/javascripts/app/views/feedback_view.js +++ b/public/javascripts/app/views/feedback_view.js @@ -20,7 +20,7 @@ app.views.Feedback = app.views.StreamObject.extend({ reshare.save({}, { url: this.model.createReshareUrl, success : function(){ - app.stream.collection.add(reshare); + app.stream.add(reshare); } }); } diff --git a/public/javascripts/app/views/post_view.js b/public/javascripts/app/views/post_view.js index adb46d6b8f..94011ecfc2 100644 --- a/public/javascripts/app/views/post_view.js +++ b/public/javascripts/app/views/post_view.js @@ -63,9 +63,9 @@ app.views.Post = app.views.StreamObject.extend({ success : function(){ if(!app.stream) { return } - _.each(app.stream.collection.models, function(model){ + _.each(app.stream.posts.models, function(model){ if(model.get("author").id == personId) { - app.stream.collection.remove(model); + app.stream.posts.remove(model); } }) } diff --git a/public/javascripts/app/views/publisher_view.js b/public/javascripts/app/views/publisher_view.js index 989d2ce9af..68e358ca04 100644 --- a/public/javascripts/app/views/publisher_view.js +++ b/public/javascripts/app/views/publisher_view.js @@ -12,7 +12,7 @@ app.views.Publisher = Backbone.View.extend({ }, initialize : function(){ - this.collection = this.collection || new app.collections.Stream; + this.collection = this.collection || new app.collections.Posts; return this; }, @@ -33,7 +33,7 @@ app.views.Publisher = Backbone.View.extend({ }, { url : "/status_messages", success : function() { - app.stream.collection.add(statusMessage.toJSON()); + app.stream.posts.add(statusMessage.toJSON()); } }); diff --git a/public/javascripts/app/views/stream_faces_view.js b/public/javascripts/app/views/stream_faces_view.js index d0979cd8af..ae5232fc7c 100644 --- a/public/javascripts/app/views/stream_faces_view.js +++ b/public/javascripts/app/views/stream_faces_view.js @@ -8,7 +8,7 @@ app.views.StreamFaces = app.views.Base.extend({ initialize : function(){ this.updatePeople() - this.collection.bind("add", this.updatePeople, this) + app.stream.posts.bind("add", this.updatePeople, this) }, presenter : function() { diff --git a/public/javascripts/app/views/stream_view.js b/public/javascripts/app/views/stream_view.js index d8c6546973..8f396f3921 100644 --- a/public/javascripts/app/views/stream_view.js +++ b/public/javascripts/app/views/stream_view.js @@ -3,46 +3,17 @@ app.views.Stream = Backbone.View.extend({ "click #paginate": "render" }, - initialize: function() { - this.collection = this.collection || new app.collections.Stream; - this.collection.bind("add", this.addPost, this); - + 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}); - // inf scroll - // we're using this._loading to keep track of backbone's collection - // fetching state... is there a better way to do this? - var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200); - $(window).scroll(throttledScroll); - - // lightbox delegation - this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox"); - $(this.el).delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked); - - return this; - }, - - infScroll : function() { - if(this.allContentLoaded || this.isLoading()) { return } - - var $window = $(window); - var distFromTop = $window.height() + $window.scrollTop(); - var distFromBottom = $(document).height() - distFromTop; - var bufferPx = 500; - - if(distFromBottom < bufferPx) { - this.render(); - } - - return this; - }, - - isLoading : function(){ - return this._loading && !this._loading.isResolved(); + this.stream.bind("fetched", this.collectionFetched, this) + this.collection.bind("add", this.addPost, this); + this.setupInfiniteScroll() + this.setupLightbox() }, - allContentLoaded : false, - addPost : function(post) { var postView = new app.views.Post({ model: post }); @@ -55,9 +26,15 @@ app.views.Stream = Backbone.View.extend({ return this; }, - collectionFetched: function(collection, response) { - this.$("#paginate").remove(); + 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') @@ -65,7 +42,7 @@ app.views.Stream = Backbone.View.extend({ } $(this.el).append($("<a>", { - href: this.collection.url(), + href: this.stream.url(), id: "paginate" }).text('Load more posts')); }, @@ -73,13 +50,8 @@ app.views.Stream = Backbone.View.extend({ render : function(evt) { if(evt) { evt.preventDefault(); } - var self = this; - self.addLoader(); - - this._loading = self.collection.fetch({ - add: true, - success: $.proxy(this.collectionFetched, self) - }); + this.addLoader(); + this._loading = this.stream.fetch(); return this; }, @@ -95,5 +67,34 @@ app.views.Stream = Backbone.View.extend({ src : "/images/static-loader.png", "class" : "loader" })); - } + }, + + removeLoader : function(){ + this.$("#paginate").remove(); + }, + + setupLightbox : function(){ + this.lightbox = Diaspora.BaseWidget.instantiate("Lightbox"); + $(this.el).delegate("a.stream-photo-link", "click", this.lightbox.lightboxImageClicked); + }, + + setupInfiniteScroll : function() { + var throttledScroll = _.throttle($.proxy(this.infScroll, this), 200); + $(window).scroll(throttledScroll); + }, + + infScroll : function() { + if(this.allContentLoaded || this.isLoading()) { return } + + var $window = $(window); + var distFromTop = $window.height() + $window.scrollTop(); + var distFromBottom = $(document).height() - distFromTop; + var bufferPx = 500; + + if(distFromBottom < bufferPx) { + this.render(); + } + + return this; + }, }); diff --git a/spec/javascripts/app/collections/stream_spec.js b/spec/javascripts/app/collections/stream_spec.js deleted file mode 100644 index 145c09c57c..0000000000 --- a/spec/javascripts/app/collections/stream_spec.js +++ /dev/null @@ -1,19 +0,0 @@ -describe("app.collections.Stream", function() { - describe("url", function() { - var stream = new app.collections.Stream(), - expectedPath = document.location.pathname; - - it("returns the correct path", function() { - expect(stream.url()).toEqual(expectedPath); - }); - - it("returns the json path with max_time if the collection has models", function() { - var post = new app.models.Post(); - spyOn(post, "createdAt").andReturn(1234); - - stream.add(post); - - expect(stream.url()).toEqual(expectedPath + "?max_time=1234"); - }); - }); -}); diff --git a/spec/javascripts/app/models/stream_spec.js b/spec/javascripts/app/models/stream_spec.js new file mode 100644 index 0000000000..064b8d8ddb --- /dev/null +++ b/spec/javascripts/app/models/stream_spec.js @@ -0,0 +1,39 @@ +describe("app.models.Stream", function() { + beforeEach(function(){ + this.stream = new app.models.Stream(), + this.expectedPath = document.location.pathname; + }) + + describe(".fetch", function() { + var postFetch + beforeEach(function(){ + postFetch = new $.Deferred() + + spyOn(this.stream.posts, "fetch").andCallFake(function(){ + return postFetch + }) + }) + + it("it fetches posts from the window's url, and ads them to tthe collection", function() { + this.stream.fetch() + expect(this.stream.posts.fetch).toHaveBeenCalledWith({ add : true, url : this.expectedPath}); + }); + + it("returns the json path with max_time if the collection has models", function() { + var post = new app.models.Post(); + spyOn(post, "createdAt").andReturn(1234); + this.stream.add(post); + + this.stream.fetch() + expect(this.stream.posts.fetch).toHaveBeenCalledWith({ add : true, url : this.expectedPath + "?max_time=1234"}); + }); + + it("triggers fetched on the stream when it is fetched", function(){ + var fetchedSpy = jasmine.createSpy() + this.stream.bind('fetched', fetchedSpy) + this.stream.fetch() + postFetch.resolve() + expect(fetchedSpy).toHaveBeenCalled() + }) + }); +}); diff --git a/spec/javascripts/app/views/post_view_spec.js b/spec/javascripts/app/views/post_view_spec.js index 790913afd9..aedea51280 100644 --- a/spec/javascripts/app/views/post_view_spec.js +++ b/spec/javascripts/app/views/post_view_spec.js @@ -13,7 +13,7 @@ describe("app.views.Post", function(){ var posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"]; - this.collection = new app.collections.Stream(posts); + this.collection = new app.collections.Posts(posts); this.statusMessage = this.collection.models[0]; this.reshare = this.collection.models[1]; }) diff --git a/spec/javascripts/app/views/stream_faces_view_spec.js b/spec/javascripts/app/views/stream_faces_view_spec.js index d94a8bc993..8cdf4eb6cb 100644 --- a/spec/javascripts/app/views/stream_faces_view_spec.js +++ b/spec/javascripts/app/views/stream_faces_view_spec.js @@ -9,8 +9,11 @@ describe("app.views.StreamFaces", function(){ this.post6 = factory.post({author : rebeccaBlack}) this.post7 = factory.post({author : rebeccaBlack}) - this.stream = new app.collections.Stream([this.post1, this.post2, this.post3, this.post4, this.post5, this.post6, this.post7]); - this.view = new app.views.StreamFaces({collection : this.stream}) + app.stream = new app.models.Stream() + app.stream.add([this.post1, this.post2, this.post3, this.post4, this.post5, this.post6, this.post7]); + this.posts = app.stream.posts + + this.view = new app.views.StreamFaces({collection : this.posts}) }) it("should take them unique", function(){ @@ -19,7 +22,7 @@ describe("app.views.StreamFaces", function(){ }) it("findsPeople when the collection changes", function(){ - this.stream.add(factory.post({author : factory.author({name : "Harriet Tubman"})})) + this.posts.add(factory.post({author : factory.author({name : "Harriet Tubman"})})) expect(this.view.people.length).toBe(6) }) @@ -39,8 +42,8 @@ describe("app.views.StreamFaces", function(){ it("rerenders when people are added, but caps to 15 people", function(){ var posts = _.map(_.range(20), function(){ return factory.post()}) - this.stream.reset(posts) //add 20 posts silently to the collection - this.stream.add(factory.post) //trigger an update + this.posts.reset(posts) //add 20 posts silently to the collection + this.posts.add(factory.post) //trigger an update expect(this.view.$("img").length).toBe(15) }) }) diff --git a/spec/javascripts/app/views/stream_view_spec.js b/spec/javascripts/app/views/stream_view_spec.js index 0ef2cdd8b4..38160b033c 100644 --- a/spec/javascripts/app/views/stream_view_spec.js +++ b/spec/javascripts/app/views/stream_view_spec.js @@ -4,14 +4,17 @@ describe("app.views.Stream", function(){ this.posts = $.parseJSON(spec.readFixture("multi_stream_json"))["posts"]; - this.collection = new app.collections.Stream(this.posts); + app.stream = new app.models.Stream() + app.stream.add(this.posts); + + this.collection = app.stream.posts this.view = new app.views.Stream({collection : this.collection}); + app.stream.bind("fetched", this.collectionFetched, this) //untested + // do this manually because we've moved loadMore into render?? this.view.render(); - _.each(this.view.collection.models, function(post){ - this.view.addPost(post); - }, this); + _.each(this.view.collection.models, function(post){ this.view.addPost(post); }, this); }) describe("initialize", function(){ @@ -42,7 +45,7 @@ describe("app.views.Stream", function(){ // NOTE: inf scroll happens at 500px beforeEach(function(){ - spyOn(this.view.collection, "fetch") + spyOn(this.view.collection, "fetch").andReturn($.Deferred()) }) context("when the user is at the bottom of the page", function(){ -- GitLab