Unverified Commit 8e6df0b1 authored by cmrd Senya's avatar cmrd Senya
Browse files

Comments expansion refactoring

If you look at comment expand process with javascript debugger, you
will notice that at first comments get added to existing stream ("add"
event handler of model.comments gets launched because of model.comments.fetch).
Then the comment stream gets empty and then filled by the postRenderTemplate
handler.

This patch removes comments rerendering on the expansion. The fetching process is
changed so that older comments are added to the correct place, so the order
looks nice without rerendering. Thus, unnecessary job of rerendering is avoided.
parent 8deef544
Loading
Loading
Loading
Loading
+32 −17
Original line number Diff line number Diff line
@@ -21,16 +21,10 @@ app.views.CommentStream = app.views.Base.extend({

  setupBindings: function() {
    this.model.comments.bind('add', this.appendComment, this);
    this.model.bind("commentsExpanded", this.storeTextareaValue, this);
    this.model.bind("commentsExpanded", this.render, this);
  },

  postRenderTemplate : function() {
    this.model.comments.each(this.appendComment, this);

    // add autoexpanders to new comment textarea
    this.$("textarea").val(this.textareaValue);
    autosize.update(this.$("textarea"));
  },

  presenter: function(){
@@ -62,34 +56,55 @@ app.views.CommentStream = app.views.Base.extend({
    }
  },

  _insertPoint: 0, // An index of the comment added in the last call of this.appendComment

  // This adjusts this._insertPoint according to timestamp value
  _moveInsertPoint: function(timestamp, commentBlocks) {
    if (commentBlocks.length === 0) {
      this._insertPoint = 0;
      return;
    }

    if (this._insertPoint > commentBlocks.length) {
      this._insertPoint = commentBlocks.length;
    }

    while (this._insertPoint > 0 && timestamp < commentBlocks.eq(this._insertPoint - 1).find("time").attr("datetime")) {
      this._insertPoint--;
    }
    while (this._insertPoint < commentBlocks.length &&
        timestamp > commentBlocks.eq(this._insertPoint).find("time").attr("datetime")) {
      this._insertPoint++;
    }
  },

  appendComment: function(comment) {
    // Set the post as the comment's parent, so we can check
    // on post ownership in the Comment view.
    comment.set({parent : this.model.toJSON()});

    this.$(".comments").append(new app.views.Comment({
      model: comment
    }).render().el);
    var commentHtml = new app.views.Comment({model: comment}).render().el;
    var commentBlocks = this.$(".comments div.comment.media");
    this._moveInsertPoint(comment.get("created_at"), commentBlocks);
    if (this._insertPoint === commentBlocks.length) {
      this.$(".comments").append(commentHtml);
    } else {
      commentBlocks.eq(this._insertPoint).before(commentHtml);
    }
    this._insertPoint++;
  },

  commentTextareaFocused: function(){
    this.$("form").removeClass('hidden').addClass("open");
  },

  storeTextareaValue: function(){
    this.textareaValue = this.$('textarea').val();
  },

  expandComments: function(evt){
    if(evt){ evt.preventDefault(); }
    var self = this;

    this.model.comments.fetch({
      success : function(resp){
        self.model.set({
          comments : resp.models,
          all_comments_loaded : true
        });
        self.$("div.comment.show_comments").addClass("hidden");

        self.model.trigger("commentsExpanded", self);
      }
+6 −8
Original line number Diff line number Diff line
{{#unless all_comments_loaded}}
<div class="show_comments comment {{#unless showExpandCommentsLink}} hidden {{/unless}}">
  <div class="media">
    <a href="/posts/{{id}}#comments" class="toggle_post_comments">
@@ -6,7 +5,6 @@
    </a>
  </div>
</div>
{{/unless}}

<div class="comments"> </div>

+18 −14
Original line number Diff line number Diff line
@@ -5,20 +5,11 @@ describe("app.views.CommentStream", function(){
  });

  describe("binds", function() {
    it("re-renders on a commentsExpanded trigger", function(){
      spyOn(this.view, "render");
    it("calls appendComment on insertion to the comments collection", function() {
      spyOn(this.view, "appendComment");
      this.view.setupBindings();
      this.view.model.trigger("commentsExpanded");
      expect(this.view.render).toHaveBeenCalled();
    });
  });

  describe("postRenderTemplate", function(){
    it("autoResizes the new comment textarea", function(){
      spyOn(window.autosize, "update");
      this.view.postRenderTemplate();
      expect(window.autosize.update).toHaveBeenCalled();
      expect(window.autosize.update.calls.mostRecent().args[0].selector).toBe("textarea");
      this.view.model.comments.push(factory.comment());
      expect(this.view.appendComment).toHaveBeenCalled();
    });
  });

@@ -79,10 +70,23 @@ describe("app.views.CommentStream", function(){
      this.view.appendComment(comment);
      expect(comment.set).toHaveBeenCalled();
    });

    it("sorts comments in the right order", function() {
      this.view.render();
      this.view.appendComment(factory.comment({"created_at": new Date(2000).toJSON(), "text": "2"}));
      this.view.appendComment(factory.comment({"created_at": new Date(4000).toJSON(), "text": "4"}));
      this.view.appendComment(factory.comment({"created_at": new Date(5000).toJSON(), "text": "5"}));
      this.view.appendComment(factory.comment({"created_at": new Date(6000).toJSON(), "text": "6"}));
      this.view.appendComment(factory.comment({"created_at": new Date(1000).toJSON(), "text": "1"}));
      this.view.appendComment(factory.comment({"created_at": new Date(3000).toJSON(), "text": "3"}));

      expect(this.view.$(".comments div.comment.media").length).toEqual(6);
      expect(this.view.$(".comments div.comment.media div.comment-content p").text()).toEqual("123456");
    });
  });

  describe("expandComments", function() {
    it("refills the comment textbox on success", function() {
    it("doesn't drop the comment textbox value on success", function() {
      this.view.render();
      this.view.$("textarea").val("great post!");
      this.view.expandComments();