Add 'show all' links to the SPV to fetch missing likes and reshares

This commit is contained in:
Steffen van Bergerem 2016-11-12 13:26:56 +01:00
parent 6bab65e603
commit 6b162110ce
No known key found for this signature in database
GPG key ID: 315C9787D548DC6B
6 changed files with 222 additions and 2 deletions

View file

@ -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

View file

@ -157,5 +157,11 @@
.author-name:hover {
text-decoration: none;
}
.loader {
height: $line-height-computed;
vertical-align: text-bottom;
width: $line-height-computed;
}
}
}

View file

@ -10,6 +10,12 @@
{{{personImage this "small" "micro"}}}
{{/linkToAuthor}}
{{/each}}
{{#if showMoreReshares}}
<div class="loader hidden">
<div class="spinner"></div>
</div>
<div id="show-all-reshares" class="btn btn-sm btn-link">{{t "show_all"}}</div>
{{/if}}
</div>
</div>
{{/if}}
@ -25,6 +31,12 @@
{{{personImage this "small" "micro"}}}
{{/linkToAuthor}}
{{/each}}
{{#if showMoreLikes}}
<div class="loader hidden">
<div class="spinner"></div>
</div>
<div id="show-all-likes" class="btn btn-sm btn-link">{{t "show_all"}}</div>
{{/if}}
</div>
</div>
{{/if}}

View file

@ -28,6 +28,7 @@ en:
comma: ","
edit: "Edit"
no_results: "No results found"
show_all: "Show all"
admins:
dashboard:

View file

@ -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");
});
});
});
});

View file

@ -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));