diff --git a/app/assets/javascripts/app/views/single-post-viewer/single_post_interaction_counts.js b/app/assets/javascripts/app/views/single-post-viewer/single_post_interaction_counts.js index 42348627c..abc4f5d9e 100644 --- a/app/assets/javascripts/app/views/single-post-viewer/single_post_interaction_counts.js +++ b/app/assets/javascripts/app/views/single-post-viewer/single_post_interaction_counts.js @@ -4,8 +4,15 @@ app.views.SinglePostInteractionCounts = app.views.Base.extend({ templateName: "single-post-viewer/single-post-interaction-counts", tooltipSelector: ".avatar.micro", + events: { + "click #show-all-likes": "showAllLikes", + "click #show-all-reshares": "showAllReshares" + }, + initialize: function() { this.model.interactions.on("change", this.render, this); + this.model.interactions.likes.on("change", this.render, this); + this.model.interactions.reshares.on("change", this.render, this); }, presenter: function() { @@ -15,8 +22,28 @@ app.views.SinglePostInteractionCounts = app.views.Base.extend({ reshares: interactions.reshares.toJSON(), commentsCount: interactions.commentsCount(), likesCount: interactions.likesCount(), - resharesCount: interactions.resharesCount() + resharesCount: interactions.resharesCount(), + showMoreLikes: interactions.likes.length < interactions.likesCount(), + showMoreReshares: interactions.reshares.length < interactions.resharesCount() }; + }, + + _showAll: function(interactionType, models) { + this.$("#show-all-" + interactionType).addClass("hidden"); + this.$("#" + interactionType + " .loader").removeClass("hidden"); + models.fetch({success: function() { + models.trigger("change"); + }}); + }, + + showAllLikes: function(evt) { + evt.preventDefault(); + this._showAll("likes", this.model.interactions.likes); + }, + + showAllReshares: function(evt) { + evt.preventDefault(); + this._showAll("reshares", this.model.interactions.reshares); } }); // @license-end diff --git a/app/assets/stylesheets/single-post-view.scss b/app/assets/stylesheets/single-post-view.scss index 0593436d3..ceaabc4fa 100644 --- a/app/assets/stylesheets/single-post-view.scss +++ b/app/assets/stylesheets/single-post-view.scss @@ -157,5 +157,11 @@ .author-name:hover { text-decoration: none; } + + .loader { + height: $line-height-computed; + vertical-align: text-bottom; + width: $line-height-computed; + } } } diff --git a/app/assets/templates/single-post-viewer/single-post-interaction-counts_tpl.jst.hbs b/app/assets/templates/single-post-viewer/single-post-interaction-counts_tpl.jst.hbs index 221274487..dcf8cdd31 100644 --- a/app/assets/templates/single-post-viewer/single-post-interaction-counts_tpl.jst.hbs +++ b/app/assets/templates/single-post-viewer/single-post-interaction-counts_tpl.jst.hbs @@ -10,6 +10,12 @@ {{{personImage this "small" "micro"}}} {{/linkToAuthor}} {{/each}} + {{#if showMoreReshares}} + + + {{/if}} {{/if}} @@ -25,6 +31,12 @@ {{{personImage this "small" "micro"}}} {{/linkToAuthor}} {{/each}} + {{#if showMoreLikes}} + + + {{/if}} {{/if}} diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index 7c5071762..8f4ed6953 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -28,6 +28,7 @@ en: comma: "," edit: "Edit" no_results: "No results found" + show_all: "Show all" admins: dashboard: diff --git a/spec/javascripts/app/views/single-post-view/single_post_interaction_counts_spec.js b/spec/javascripts/app/views/single-post-view/single_post_interaction_counts_spec.js index 35abf7afe..0ff6959bc 100644 --- a/spec/javascripts/app/views/single-post-view/single_post_interaction_counts_spec.js +++ b/spec/javascripts/app/views/single-post-view/single_post_interaction_counts_spec.js @@ -1,6 +1,6 @@ describe("app.views.SinglePostInteractionCounts", function() { beforeEach(function() { - this.post = factory.post(); + this.post = factory.postWithInteractions(); this.view = new app.views.SinglePostInteractionCounts({model: this.post}); }); @@ -12,5 +12,151 @@ describe("app.views.SinglePostInteractionCounts", function() { this.post.interactions.trigger("change"); expect(app.views.SinglePostInteractionCounts.prototype.render).toHaveBeenCalled(); }); + + it("calls render when the likes change", function() { + spyOn(app.views.SinglePostInteractionCounts.prototype, "render"); + this.view.initialize(); + expect(app.views.SinglePostInteractionCounts.prototype.render).not.toHaveBeenCalled(); + this.post.interactions.likes.trigger("change"); + expect(app.views.SinglePostInteractionCounts.prototype.render).toHaveBeenCalled(); + }); + + it("calls render when the reshares change", function() { + spyOn(app.views.SinglePostInteractionCounts.prototype, "render"); + this.view.initialize(); + expect(app.views.SinglePostInteractionCounts.prototype.render).not.toHaveBeenCalled(); + this.post.interactions.reshares.trigger("change"); + expect(app.views.SinglePostInteractionCounts.prototype.render).toHaveBeenCalled(); + }); + }); + + describe("render", function() { + it("doesn't show a #show-all-likes link if there are no additional likes", function() { + this.view.render(); + expect(this.view.$("#show-all-likes").length).toBe(0); + }); + + it("shows a #show-all-likes link if there are additional likes", function() { + this.view.model.interactions.set("likes_count", this.view.model.interactions.likes.length + 1); + this.view.render(); + expect(this.view.$("#show-all-likes").length).toBe(1); + }); + + it("doesn't show a #show-all-reshares link if there are no additional reshares", function() { + this.view.render(); + expect(this.view.$("#show-all-reshares").length).toBe(0); + }); + + it("shows a #show-all-reshares link if there are additional reshares", function() { + this.view.model.interactions.set("reshares_count", this.view.model.interactions.reshares.length + 1); + this.view.render(); + expect(this.view.$("#show-all-reshares").length).toBe(1); + }); + }); + + describe("showAllLikes", function() { + it("is called when clicking #show-all-likes", function() { + spyOn(this.view, "showAllLikes"); + this.view.delegateEvents(); + this.view.model.interactions.set("likes_count", this.view.model.interactions.likes.length + 1); + this.view.render(); + expect(this.view.showAllLikes).not.toHaveBeenCalled(); + this.view.$("#show-all-likes").click(); + expect(this.view.showAllLikes).toHaveBeenCalled(); + }); + + it("calls _showAll", function() { + spyOn(this.view, "_showAll"); + this.view.showAllLikes($.Event()); + expect(this.view._showAll).toHaveBeenCalledWith("likes", this.view.model.interactions.likes); + }); + }); + + describe("showAllReshares", function() { + it("is called when clicking #show-all-reshares", function() { + spyOn(this.view, "showAllReshares"); + this.view.delegateEvents(); + this.view.model.interactions.set("reshares_count", this.view.model.interactions.reshares.length + 1); + this.view.render(); + expect(this.view.showAllReshares).not.toHaveBeenCalled(); + this.view.$("#show-all-reshares").click(); + expect(this.view.showAllReshares).toHaveBeenCalled(); + }); + + it("calls _showAll", function() { + spyOn(this.view, "_showAll"); + this.view.showAllReshares($.Event()); + expect(this.view._showAll).toHaveBeenCalledWith("reshares", this.view.model.interactions.reshares); + }); + }); + + describe("_showAll", function() { + beforeEach(function() { + this.view.model.interactions.set("likes_count", this.view.model.interactions.likes.length + 1); + this.view.model.interactions.set("reshares_count", this.view.model.interactions.reshares.length + 1); + this.view.render(); + }); + + context("with likes", function() { + it("hides the #show-all-likes link", function() { + expect(this.view.$("#show-all-likes")).not.toHaveClass("hidden"); + expect(this.view.$("#show-all-reshares")).not.toHaveClass("hidden"); + this.view._showAll("likes", this.view.model.interactions.likes); + expect(this.view.$("#show-all-likes")).toHaveClass("hidden"); + expect(this.view.$("#show-all-reshares")).not.toHaveClass("hidden"); + }); + + it("shows the likes loader", function() { + expect(this.view.$("#likes .loader")).toHaveClass("hidden"); + expect(this.view.$("#reshares .loader")).toHaveClass("hidden"); + this.view._showAll("likes", this.view.model.interactions.likes); + expect(this.view.$("#likes .loader")).not.toHaveClass("hidden"); + expect(this.view.$("#reshares .loader")).toHaveClass("hidden"); + }); + + it("calls #fetch on the model", function() { + spyOn(this.view.model.interactions.likes, "fetch"); + this.view._showAll("likes", this.view.model.interactions.likes); + expect(this.view.model.interactions.likes.fetch).toHaveBeenCalled(); + }); + + it("triggers 'change' after a successfull fetch", function() { + spyOn(this.view.model.interactions.likes, "trigger"); + this.view._showAll("likes", this.view.model.interactions.likes); + jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: "{\"id\": 1}"}); + expect(this.view.model.interactions.likes.trigger).toHaveBeenCalledWith("change"); + }); + }); + + context("with reshares", function() { + it("hides the #show-all-reshares link", function() { + expect(this.view.$("#show-all-likes")).not.toHaveClass("hidden"); + expect(this.view.$("#show-all-reshares")).not.toHaveClass("hidden"); + this.view._showAll("reshares", this.view.model.interactions.reshares); + expect(this.view.$("#show-all-likes")).not.toHaveClass("hidden"); + expect(this.view.$("#show-all-reshares")).toHaveClass("hidden"); + }); + + it("shows the reshares loader", function() { + expect(this.view.$("#likes .loader")).toHaveClass("hidden"); + expect(this.view.$("#reshares .loader")).toHaveClass("hidden"); + this.view._showAll("reshares", this.view.model.interactions.reshares); + expect(this.view.$("#likes .loader")).toHaveClass("hidden"); + expect(this.view.$("#reshares .loader")).not.toHaveClass("hidden"); + }); + + it("calls #fetch on the model", function() { + spyOn(this.view.model.interactions.reshares, "fetch"); + this.view._showAll("reshares", this.view.model.interactions.reshares); + expect(this.view.model.interactions.reshares.fetch).toHaveBeenCalled(); + }); + + it("triggers 'change' after a successfull fetch", function() { + spyOn(this.view.model.interactions.reshares, "trigger"); + this.view._showAll("reshares", this.view.model.interactions.reshares); + jasmine.Ajax.requests.mostRecent().respondWith({status: 200, responseText: "{\"id\": 1}"}); + expect(this.view.model.interactions.reshares.trigger).toHaveBeenCalledWith("change"); + }); + }); }); }); diff --git a/spec/javascripts/jasmine_helpers/factory.js b/spec/javascripts/jasmine_helpers/factory.js index 551fe87bc..ba97e5b71 100644 --- a/spec/javascripts/jasmine_helpers/factory.js +++ b/spec/javascripts/jasmine_helpers/factory.js @@ -21,6 +21,16 @@ var factory = { return _.extend(defaultAttrs, overrides); }, + reshare: function(overrides) { + var defaultAttrs = { + "created_at": "2012-01-04T00:55:30Z", + "author": this.author(), + "guid": this.guid(), + "id": this.id.next() + }; + return _.extend(defaultAttrs, overrides); + }, + aspectMembershipAttrs: function(overrides) { var id = this.id.next(); var defaultAttrs = { @@ -207,6 +217,24 @@ var factory = { return new app.models.Post(_.extend(defaultAttrs, overrides)); }, + postWithInteractions: function(overrides) { + var likes = _.range(10).map(function() { return factory.like(); }); + var reshares = _.range(15).map(function() { return factory.reshare(); }); + var comments = _.range(20).map(function() { return factory.comment(); }); + var defaultAttrs = _.extend(factory.postAttrs(), { + "author": this.author(), + "interactions": { + "reshares_count": 15, + "likes_count": 10, + "comments_count": 20, + "comments": comments, + "likes": likes, + "reshares": reshares + } + }); + return new app.models.Post(_.extend(defaultAttrs, overrides)); + }, + statusMessage : function(overrides){ //intentionally doesn't have an author to mirror creation process, maybe we should change the creation process return new app.models.StatusMessage(_.extend(factory.postAttrs(), overrides));