From ed5f218559fe3a1d410c9cca18d9ee3359712b39 Mon Sep 17 00:00:00 2001 From: Steffen van Bergerem Date: Sun, 13 Nov 2016 21:07:01 +0100 Subject: [PATCH] Only clear comment textarea when comment submission was successful fixes #5094 --- .../app/models/post/interactions.js | 5 +- .../app/views/comment_stream_view.js | 38 +++-- .../app/models/post/interacations_spec.js | 47 ++++++ .../app/views/comment_stream_view_spec.js | 134 +++++++++++++++--- 4 files changed, 198 insertions(+), 26 deletions(-) diff --git a/app/assets/javascripts/app/models/post/interactions.js b/app/assets/javascripts/app/models/post/interactions.js index 51b40227e..a94ca6775 100644 --- a/app/assets/javascripts/app/models/post/interactions.js +++ b/app/assets/javascripts/app/models/post/interactions.js @@ -91,14 +91,17 @@ app.models.Post.Interactions = Backbone.Model.extend({ app.instrument("track", "Unlike"); }, - comment : function (text) { + comment: function(text, options) { var self = this; + options = options || {}; this.comments.make(text).fail(function () { app.flashMessages.error(Diaspora.I18n.t("failed_to_comment")); + if (options.error) { options.error(); } }).done(function() { self.post.set({participation: true}); self.trigger('change'); //updates after sync + if (options.success) { options.success(); } }); this.trigger("change"); //updates count in an eager manner diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js index 48df8afad..05ba192db 100644 --- a/app/assets/javascripts/app/views/comment_stream_view.js +++ b/app/assets/javascripts/app/views/comment_stream_view.js @@ -25,6 +25,8 @@ app.views.CommentStream = app.views.Base.extend({ postRenderTemplate : function() { this.model.comments.each(this.appendComment, this); + this.commentBox = this.$(".comment_box"); + this.commentSubmitButton = this.$("input[name='commit']"); }, presenter: function(){ @@ -38,15 +40,35 @@ app.views.CommentStream = app.views.Base.extend({ createComment: function(evt) { if(evt){ evt.preventDefault(); } - var commentText = $.trim(this.$('.comment_box').val()); - this.$(".comment_box").val(""); - this.$(".comment_box").css("height", ""); - if(commentText) { - this.model.comment(commentText); - return this; - } else { - this.$(".comment_box").focus(); + var commentText = $.trim(this.commentBox.val()); + if (commentText === "") { + this.commentBox.focus(); + return; } + + this.disableCommentBox(); + + this.model.comment(commentText, { + success: function() { + this.commentBox.val(""); + this.enableCommentBox(); + autosize.update(this.commentBox); + }.bind(this), + error: function() { + this.enableCommentBox(); + this.commentBox.focus(); + }.bind(this) + }); + }, + + disableCommentBox: function() { + this.commentBox.prop("disabled", true); + this.commentSubmitButton.prop("disabled", true); + }, + + enableCommentBox: function() { + this.commentBox.removeAttr("disabled"); + this.commentSubmitButton.removeAttr("disabled"); }, keyDownOnCommentBox: function(evt) { diff --git a/spec/javascripts/app/models/post/interacations_spec.js b/spec/javascripts/app/models/post/interacations_spec.js index 0f7b9926c..f26ffe4f8 100644 --- a/spec/javascripts/app/models/post/interacations_spec.js +++ b/spec/javascripts/app/models/post/interacations_spec.js @@ -198,4 +198,51 @@ describe("app.models.Post.Interactions", function(){ expect(this.interactions.userReshare()).toBeTruthy(); }); }); + + describe("comment", function() { + it("calls make on the comments collection", function() { + spyOn(this.interactions.comments, "make").and.callThrough(); + this.interactions.comment("text"); + expect(this.interactions.comments.make).toHaveBeenCalledWith("text"); + }); + + context("on success", function() { + it("sets the participation flag for the post", function() { + expect(this.post.get("participation")).toBeFalsy(); + this.interactions.comment("text"); + jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess); + expect(this.post.get("participation")).toBeTruthy(); + }); + + it("triggers a change on the model", function() { + spyOn(this.interactions, "trigger"); + this.interactions.comment("text"); + jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess); + expect(this.interactions.trigger).toHaveBeenCalledWith("change"); + }); + + it("calls the success function if one is given", function() { + var success = jasmine.createSpy(); + this.interactions.comment("text", {success: success}); + jasmine.Ajax.requests.mostRecent().respondWith(ajaxSuccess); + expect(success).toHaveBeenCalled(); + }); + }); + + context("on error", function() { + it("doesn't set the participation flag for the post", function() { + expect(this.post.get("participation")).toBeFalsy(); + this.interactions.comment("text"); + jasmine.Ajax.requests.mostRecent().respondWith({status: 400}); + expect(this.post.get("participation")).toBeFalsy(); + }); + + it("calls the error function if one is given", function() { + var error = jasmine.createSpy(); + this.interactions.comment("text", {error: error}); + jasmine.Ajax.requests.mostRecent().respondWith({status: 400}); + expect(error).toHaveBeenCalled(); + }); + }); + }); }); diff --git a/spec/javascripts/app/views/comment_stream_view_spec.js b/spec/javascripts/app/views/comment_stream_view_spec.js index 104cb3c7a..bec0ce5a2 100644 --- a/spec/javascripts/app/views/comment_stream_view_spec.js +++ b/spec/javascripts/app/views/comment_stream_view_spec.js @@ -21,6 +21,37 @@ describe("app.views.CommentStream", function(){ }); }); + describe("postRenderTemplate", function() { + beforeEach(function() { + this.view.render(); + }); + + it("calls appendComment for all comments in the collection", function() { + this.view.model.comments.push(factory.comment({id: 1})); + this.view.model.comments.push(factory.comment({id: 27})); + this.view.model.comments.push(factory.comment({id: 3})); + spyOn(this.view, "appendComment"); + this.view.postRenderTemplate(); + expect(this.view.appendComment.calls.allArgs().map(function(args) { + return args[0].get("id"); + })).toEqual([1, 27, 3]); + }); + + it("sets commentBox", function() { + this.view.commentBox = undefined; + this.view.postRenderTemplate(); + expect(this.view.commentBox).toBeDefined(); + expect(this.view.commentBox).toEqual(this.view.$(".comment_box")); + }); + + it("sets commentSubmitButton", function() { + this.view.commentSubmitButton = undefined; + this.view.postRenderTemplate(); + expect(this.view.commentSubmitButton).toBeDefined(); + expect(this.view.commentSubmitButton).toEqual(this.view.$("input[name='commit']")); + }); + }); + describe("createComment", function() { beforeEach(function() { this.view.render(); @@ -29,6 +60,20 @@ describe("app.views.CommentStream", function(){ this.view.expandComments(); }); + it("doesn't fire an AJAX request when there are only spaces in the comment box", function() { + this.view.commentBox.val(" "); + jasmine.Ajax.requests.reset(); + this.view.createComment(); + expect(jasmine.Ajax.requests.count()).toBe(0); + }); + + it("calls disableCommentBox", function() { + spyOn(this.view, "disableCommentBox"); + this.view.commentBox.val("text"); + this.view.createComment(); + expect(this.view.disableCommentBox).toHaveBeenCalled(); + }); + context("submission", function() { beforeEach(function() { this.view.$(".comment_box").val('a new comment'); @@ -43,31 +88,86 @@ describe("app.views.CommentStream", function(){ expect(params.text).toEqual("a new comment"); }); - it("adds the comment to the view", function() { - this.request.respondWith({status: 200, responseText: '[]'}); - expect(this.view.$(".comment-content p").text()).toEqual("a new comment"); + context("on success", function() { + it("adds the comment to the view", function() { + this.request.respondWith({status: 200, responseText: "[]"}); + expect(this.view.$(".comment-content p").text()).toEqual("a new comment"); + }); + + it("resets the comment box value", function() { + this.request.respondWith({status: 200, responseText: "[]"}); + expect(this.view.commentBox.val()).toBe(""); + }); + + it("calls enableCommentBox", function() { + spyOn(this.view, "enableCommentBox"); + this.request.respondWith({status: 200, responseText: "[]"}); + expect(this.view.enableCommentBox).toHaveBeenCalled(); + }); + + it("calls autosize.update for the commentBox", function() { + spyOn(autosize, "update"); + this.request.respondWith({status: 200, responseText: "[]"}); + expect(autosize.update).toHaveBeenCalledWith(this.view.commentBox); + }); }); - it("doesn't add the comment to the view, when the request fails", function(){ - this.request.respondWith({status: 500}); + context("on error", function() { + it("doesn't add the comment to the view", function() { + this.request.respondWith({status: 500}); + expect(this.view.$(".comment-content p").text()).not.toEqual("a new comment"); + expect(this.view.$(".flash-message")).toBeErrorFlashMessage( + "Failed to comment. Maybe the author is ignoring you?" + ); + }); - expect(this.view.$(".comment-content p").text()).not.toEqual("a new comment"); - expect(this.view.$(".flash-message")).toBeErrorFlashMessage( - "Failed to comment. Maybe the author is ignoring you?" - ); + it("doesn't reset the comment box value", function() { + this.request.respondWith({status: 500}); + expect(this.view.commentBox.val()).toBe("a new comment"); + }); + + it("calls enableCommentBox", function() { + spyOn(this.view, "enableCommentBox"); + this.request.respondWith({status: 500}); + expect(this.view.enableCommentBox).toHaveBeenCalled(); + }); }); }); + }); - it("clears the comment box when there are only spaces", function() { - this.view.$(".comment_box").val(' '); - this.view.createComment(); - expect(this.view.$(".comment_box").val()).toEqual(""); + describe("disableCommentBox", function() { + beforeEach(function() { + this.view.render(); }); - it("resets comment box height", function() { - this.view.$(".comment_box").val('a new comment'); - this.view.createComment(); - expect(this.view.$(".comment_box").attr("style")).not.toContain("height"); + it("disables the comment box", function() { + this.view.commentBox.removeAttr("disabled"); + this.view.disableCommentBox(); + expect(this.view.commentBox.prop("disabled")).toBeTruthy(); + }); + + it("disables the comment submit button", function() { + this.view.commentSubmitButton.removeAttr("disabled"); + this.view.disableCommentBox(); + expect(this.view.commentSubmitButton.prop("disabled")).toBeTruthy(); + }); + }); + + describe("enableCommentBox", function() { + beforeEach(function() { + this.view.render(); + }); + + it("removes the 'disabled' attribute from the comment box", function() { + this.view.commentBox.prop("disabled", true); + this.view.enableCommentBox(); + expect(this.view.commentBox.prop("disabled")).toBeFalsy(); + }); + + it("removes the 'disabled' attribute from the comment submit button", function() { + this.view.commentSubmitButton.prop("disabled", true); + this.view.enableCommentBox(); + expect(this.view.commentSubmitButton.prop("disabled")).toBeFalsy(); }); });