diff --git a/app/assets/javascripts/app/views/post_controls_view.js b/app/assets/javascripts/app/views/post_controls_view.js
new file mode 100644
index 000000000..796e8565a
--- /dev/null
+++ b/app/assets/javascripts/app/views/post_controls_view.js
@@ -0,0 +1,78 @@
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
+
+app.views.PostControls = app.views.Base.extend({
+ templateName: "post-controls",
+ className: "control-icons",
+
+ events: {
+ "click .remove_post": "destroyModel",
+ "click .hide_post": "hidePost",
+ "click .post_report": "report",
+ "click .block_user": "blockUser",
+ "click .create_participation": "createParticipation",
+ "click .destroy_participation": "destroyParticipation"
+ },
+
+ tooltipSelector: [".post_report",
+ ".block_user",
+ ".delete",
+ ".create_participation",
+ ".destroy_participation"].join(", "),
+
+ initialize: function(opts) {
+ this.model.bind("change", this.render, this);
+ this.post = opts.post;
+ },
+
+ presenter: function() {
+ return _.extend(this.defaultPresenter(), {
+ authorIsCurrentUser: app.currentUser.isAuthorOf(this.model)
+ });
+ },
+
+ blockUser: function(evt) {
+ if (evt) { evt.preventDefault(); }
+ if (!confirm(Diaspora.I18n.t("ignore_user"))) { return; }
+
+ this.model.blockAuthor().fail(function() {
+ app.flashMessages.error(Diaspora.I18n.t("ignore_failed"));
+ });
+ },
+
+ hidePost: function(evt) {
+ if (evt) { evt.preventDefault(); }
+ if (!confirm(Diaspora.I18n.t("confirm_dialog"))) { return; }
+
+ var self = this;
+ $.ajax({
+ url: Routes.shareVisibility(42),
+ type: "PUT",
+ data: {
+ /* eslint-disable camelcase */
+ post_id: this.model.id
+ /* eslint-enable camelcase */
+ }
+ }).done(function() {
+ self.post.remove();
+ }).fail(function() {
+ app.flashMessages.error(Diaspora.I18n.t("hide_post_failed"));
+ });
+ },
+
+ createParticipation: function(evt) {
+ if (evt) { evt.preventDefault(); }
+ var that = this;
+ $.post(Routes.postParticipation(this.model.get("id")), {}, function() {
+ that.model.set({participation: true});
+ });
+ },
+
+ destroyParticipation: function(evt) {
+ if (evt) { evt.preventDefault(); }
+ var that = this;
+ $.post(Routes.postParticipation(this.model.get("id")), {_method: "delete"}, function() {
+ that.model.set({participation: false});
+ });
+ }
+});
+// @license-end
diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js
index b298cd0ad..60812f6b9 100644
--- a/app/assets/javascripts/app/views/stream_post_views.js
+++ b/app/assets/javascripts/app/views/stream_post_views.js
@@ -5,38 +5,26 @@ app.views.StreamPost = app.views.Post.extend({
className : "stream_element loaded",
subviews : {
- ".feedback" : "feedbackView",
- ".likes" : "likesInfoView",
- ".reshares" : "resharesInfoView",
- ".comments" : "commentStreamView",
- ".post-content" : "postContentView",
- ".oembed" : "oEmbedView",
- ".opengraph" : "openGraphView",
- ".poll" : "pollView",
- ".status-message-location" : "postLocationStreamView"
+ ".feedback": "feedbackView",
+ ".comments": "commentStreamView",
+ ".likes": "likesInfoView",
+ ".reshares": "resharesInfoView",
+ ".post-controls": "postControlsView",
+ ".post-content": "postContentView",
+ ".oembed": "oEmbedView",
+ ".opengraph": "openGraphView",
+ ".poll": "pollView",
+ ".status-message-location": "postLocationStreamView"
},
events: {
"click .focus_comment_textarea": "focusCommentTextarea",
"click .show_nsfw_post": "removeNsfwShield",
- "click .toggle_nsfw_state": "toggleNsfwState",
-
- "click .remove_post": "destroyModel",
- "click .hide_post": "hidePost",
- "click .post_report": "report",
- "click .block_user": "blockUser",
-
- "click .create_participation": "createParticipation",
- "click .destroy_participation": "destroyParticipation"
+ "click .toggle_nsfw_state": "toggleNsfwState"
},
tooltipSelector : [".timeago",
".post_scope",
- ".post_report",
- ".block_user",
- ".delete",
- ".create_participation",
- ".destroy_participation",
".permalink"].join(", "),
initialize : function(){
@@ -51,6 +39,9 @@ app.views.StreamPost = app.views.Post.extend({
this.pollView = new app.views.Poll({model : this.model});
},
+ postControlsView: function() {
+ return new app.views.PostControls({model: this.model, post: this});
+ },
likesInfoView : function(){
return new app.views.LikesInfo({model : this.model});
@@ -87,60 +78,12 @@ app.views.StreamPost = app.views.Post.extend({
app.currentUser.toggleNsfwState();
},
-
- blockUser: function(evt){
- if(evt) { evt.preventDefault(); }
- if(!confirm(Diaspora.I18n.t("ignore_user"))) { return }
-
- this.model.blockAuthor()
- .fail(function() {
- app.flashMessages.error(Diaspora.I18n.t("ignore_failed"));
- });
- },
-
remove : function() {
$(this.el).slideUp(400, _.bind(function(){this.$el.remove()}, this));
app.stream.remove(this.model);
return this;
},
- hidePost : function(evt) {
- if(evt) { evt.preventDefault(); }
- if(!confirm(Diaspora.I18n.t("confirm_dialog"))) { return }
-
- var self = this;
- $.ajax({
- url : "/share_visibilities/42",
- type : "PUT",
- data : {
- post_id : this.model.id
- }
- }).done(function() {
- self.remove();
- })
- .fail(function() {
- app.flashMessages.error(Diaspora.I18n.t("hide_post_failed"));
- });
- },
-
- createParticipation: function (evt) {
- if(evt) { evt.preventDefault(); }
- var that = this;
- $.post(Routes.postParticipation(this.model.get("id")), {}, function () {
- that.model.set({participation: true});
- that.render();
- });
- },
-
- destroyParticipation: function (evt) {
- if(evt) { evt.preventDefault(); }
- var that = this;
- $.post(Routes.postParticipation(this.model.get("id")), { _method: "delete" }, function () {
- that.model.set({participation: false});
- that.render();
- });
- },
-
focusCommentTextarea: function(evt){
evt.preventDefault();
this.$(".new-comment-form-wrapper").removeClass("hidden");
@@ -148,6 +91,5 @@ app.views.StreamPost = app.views.Post.extend({
return this;
}
-
});
// @license-end
diff --git a/app/assets/templates/post-controls_tpl.jst.hbs b/app/assets/templates/post-controls_tpl.jst.hbs
new file mode 100644
index 000000000..560f366f4
--- /dev/null
+++ b/app/assets/templates/post-controls_tpl.jst.hbs
@@ -0,0 +1,24 @@
+{{#if authorIsCurrentUser}}
+
+
+
+{{else}}
+
+
+
+
+
+
+ {{#if participation}}
+
+
+
+ {{else}}
+
+
+
+ {{/if}}
+
+
+
+{{/if}}
diff --git a/app/assets/templates/stream-element_tpl.jst.hbs b/app/assets/templates/stream-element_tpl.jst.hbs
index 2520c1e67..2c65c427a 100644
--- a/app/assets/templates/stream-element_tpl.jst.hbs
+++ b/app/assets/templates/stream-element_tpl.jst.hbs
@@ -7,34 +7,7 @@
{{#if loggedIn}}
-
- {{#unless preview}}
- {{#if authorIsCurrentUser}}
-
-
-
- {{else}}
-
-
-
-
-
-
- {{#if participation}}
-
-
-
- {{else}}
-
-
-
- {{/if}}
-
-
-
- {{/if}}
- {{/unless}}
-
+
{{/if}}
diff --git a/spec/javascripts/app/views/post_controls_view_spec.js b/spec/javascripts/app/views/post_controls_view_spec.js
new file mode 100644
index 000000000..01a5385cd
--- /dev/null
+++ b/spec/javascripts/app/views/post_controls_view_spec.js
@@ -0,0 +1,200 @@
+describe("app.views.PostControls", function() {
+ describe("render", function() {
+ beforeEach(function() {
+ this.model = factory.post();
+ this.view = new app.views.PostControls({model: this.model});
+ });
+
+ context("in a post of the current user", function() {
+ beforeEach(function() {
+ app.currentUser = new app.models.User(this.model.attributes.author);
+ this.view.render();
+ });
+
+ it("shows a delete button", function() {
+ expect(this.view.$(".delete.remove_post").length).toBe(1);
+ });
+
+ it("doesn't show a report button", function() {
+ expect(this.view.$(".post_report").length).toBe(0);
+ });
+
+ it("doesn't show an ignore button", function() {
+ expect(this.view.$(".block_user").length).toBe(0);
+ });
+
+ it("doesn't show participation buttons", function() {
+ expect(this.view.$(".create_participation").length).toBe(0);
+ expect(this.view.$(".destroy_participation").length).toBe(0);
+ });
+
+ it("doesn't show a hide button", function() {
+ expect(this.view.$(".delete.hide_post").length).toBe(0);
+ });
+ });
+
+ context("in a post of another user", function() {
+ beforeEach(function() {
+ this.view.render();
+ });
+
+ it("doesn't show a delete button", function() {
+ expect(this.view.$(".delete.remove_post").length).toBe(0);
+ });
+
+ it("shows a report button", function() {
+ expect(this.view.$(".post_report").length).toBe(1);
+ });
+
+ it("shows an ignore button", function() {
+ expect(this.view.$(".block_user").length).toBe(1);
+ });
+
+ it("shows a create participation button", function() {
+ expect(this.view.$(".create_participation").length).toBe(1);
+ expect(this.view.$(".destroy_participation").length).toBe(0);
+ });
+
+ it("shows a destroy participation button if the user participated", function() {
+ this.model.set({participation: true});
+ this.view.render();
+ expect(this.view.$(".create_participation").length).toBe(0);
+ expect(this.view.$(".destroy_participation").length).toBe(1);
+ });
+
+ it("shows a hide button", function() {
+ expect(this.view.$(".delete.hide_post").length).toBe(1);
+ });
+ });
+ });
+
+ describe("events", function() {
+ beforeEach(function() {
+ this.model = factory.post();
+ });
+
+ it("calls destroyModel when removing a post", function() {
+ spyOn(app.views.PostControls.prototype, "destroyModel");
+ app.currentUser = new app.models.User(this.model.attributes.author);
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ this.view.$(".remove_post.delete").click();
+ expect(app.views.PostControls.prototype.destroyModel).toHaveBeenCalled();
+ });
+
+ it("calls hidePost when hiding a post", function() {
+ spyOn(app.views.PostControls.prototype, "hidePost");
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ this.view.$(".hide_post.delete").click();
+ expect(app.views.PostControls.prototype.hidePost).toHaveBeenCalled();
+ });
+
+ it("calls report when reporting a post", function() {
+ spyOn(app.views.PostControls.prototype, "report");
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ this.view.$(".post_report").click();
+ expect(app.views.PostControls.prototype.report).toHaveBeenCalled();
+ });
+
+ it("calls blockUser when blocking the user", function() {
+ spyOn(app.views.PostControls.prototype, "blockUser");
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ this.view.$(".block_user").click();
+ expect(app.views.PostControls.prototype.blockUser).toHaveBeenCalled();
+ });
+
+ it("calls createParticipation when creating a participation", function() {
+ spyOn(app.views.PostControls.prototype, "createParticipation");
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ this.view.$(".create_participation").click();
+ expect(app.views.PostControls.prototype.createParticipation).toHaveBeenCalled();
+ });
+
+ it("calls destroyParticipation when destroying a participation", function() {
+ spyOn(app.views.PostControls.prototype, "destroyParticipation");
+ this.model.set({participation: true});
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ this.view.$(".destroy_participation").click();
+ expect(app.views.PostControls.prototype.destroyParticipation).toHaveBeenCalled();
+ });
+ });
+
+ describe("initialize", function() {
+ it("rerenders the view when the model has been changed", function() {
+ spyOn(app.views.PostControls.prototype, "render");
+ this.model = factory.post();
+ this.view = new app.views.PostControls({model: this.model});
+ expect(app.views.PostControls.prototype.render).not.toHaveBeenCalled();
+ this.model.trigger("change");
+ expect(app.views.PostControls.prototype.render).toHaveBeenCalled();
+ });
+ });
+
+ describe("blockUser", function() {
+ beforeEach(function() {
+ spyOn(window, "confirm").and.returnValue(true);
+ this.model = factory.post();
+ this.view = new app.views.PostControls({model: this.model});
+ this.view.render();
+ });
+
+ it("asks for a confirmation", function() {
+ this.view.blockUser();
+ expect(window.confirm).toHaveBeenCalledWith(Diaspora.I18n.t("ignore_user"));
+ });
+
+ it("calls blockAuthor", function() {
+ spyOn(this.model, "blockAuthor").and.callThrough();
+ this.view.blockUser();
+ expect(this.model.blockAuthor).toHaveBeenCalled();
+ });
+
+ it("shows a flash message when errors occur", function() {
+ spyOn(app.flashMessages, "error");
+ this.view.blockUser();
+ jasmine.Ajax.requests.mostRecent().respondWith({status: 422});
+ expect(app.flashMessages.error).toHaveBeenCalledWith(Diaspora.I18n.t("ignore_failed"));
+ });
+ });
+
+ describe("hidePost", function() {
+ beforeEach(function() {
+ spyOn(window, "confirm").and.returnValue(true);
+ this.postView = {remove: function() { return; }};
+ this.model = factory.post();
+ this.view = new app.views.PostControls({model: this.model, post: this.postView});
+ this.view.render();
+ });
+
+ it("asks for a confirmation", function() {
+ this.view.hidePost();
+ expect(window.confirm).toHaveBeenCalledWith(Diaspora.I18n.t("confirm_dialog"));
+ });
+
+ it("sends an ajax request with the correct post id", function() {
+ this.view.hidePost();
+ expect(jasmine.Ajax.requests.mostRecent().url).toBe(Routes.shareVisibility(42));
+ expect(jasmine.Ajax.requests.mostRecent().data().post_id).toEqual(["" + this.model.get("id")]);
+ expect(jasmine.Ajax.requests.mostRecent().method).toBe("PUT");
+ });
+
+ it("removes the post on success", function() {
+ spyOn(this.view.post, "remove");
+ this.view.hidePost();
+ jasmine.Ajax.requests.mostRecent().respondWith({status: 204});
+ expect(this.view.post.remove).toHaveBeenCalled();
+ });
+
+ it("shows a flash message when errors occur", function() {
+ spyOn(app.flashMessages, "error");
+ this.view.hidePost();
+ jasmine.Ajax.requests.mostRecent().respondWith({status: 422});
+ expect(app.flashMessages.error).toHaveBeenCalledWith(Diaspora.I18n.t("hide_post_failed"));
+ });
+ });
+});