diff --git a/app/controllers/aspects_controller.rb b/app/controllers/aspects_controller.rb index 8c94858d3fadadeb70f8af4c45ba963c8828ad58..57f67a52d10019ae3da54eef47ffd5aab5000cb6 100644 --- a/app/controllers/aspects_controller.rb +++ b/app/controllers/aspects_controller.rb @@ -28,7 +28,7 @@ class AspectsController < ApplicationController redirect_to getting_started_path return end - + # redirect to aspects creation if @aspects.blank? redirect_to new_aspect_path @@ -47,7 +47,7 @@ class AspectsController < ApplicationController :type => ['StatusMessage','ActivityStreams::Photo'], :order => session[:sort_order] + ' DESC', :max_time => params[:max_time].to_i - ).includes({:comments => {:author => :profile}}, {:mentions => {:person => :profile}}) + ).includes(:mentions => {:person => :profile}) @posts = PostsFake.new(posts) if params[:only_posts] diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index d472e457fd462fbfbc2abc6b42b180348b81cfe0..3965c87d62e17ab99db2341e5e4e9aa8b00ed8a5 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -6,7 +6,8 @@ class CommentsController < ApplicationController include ApplicationHelper before_filter :authenticate_user! - respond_to :html, :mobile + respond_to :html, :mobile, :only => [:create, :destroy] + respond_to :js, :only => [:index] rescue_from ActiveRecord::RecordNotFound do render :nothing => true, :status => 404 @@ -53,4 +54,14 @@ class CommentsController < ApplicationController end end + def index + @post = current_user.find_visible_post_by_id(params[:post_id]) + if @post + @comments = @post.comments.includes(:author => :profile) + render :layout => false + else + raise ActiveRecord::RecordNotFound.new + end + end + end diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb index 574f859966de6b7ec7f5e90c27d3a1a1f9e084a4..ef1a2bcedd6b9da83e450c65e6d070f01f45ac9f 100644 --- a/app/helpers/comments_helper.rb +++ b/app/helpers/comments_helper.rb @@ -4,11 +4,11 @@ module CommentsHelper GSUB_THIS = "FIUSDHVIUSHDVIUBAIUHAPOIUXJM" - def comment_toggle(count, commenting_disabled=false) - if count <= 3 - str = link_to "#{t('stream_helper.hide_comments')}", '#', :class => "show_post_comments" + def comment_toggle(post, commenting_disabled=false) + if post.comments.size <= 3 + str = link_to "#{t('stream_helper.hide_comments')}", post_comments_path(post.id), :class => "toggle_post_comments" else - str = link_to "#{t('stream_helper.show_more_comments', :number => count-3)}", '#', :class => "show_post_comments" + str = link_to "#{t('stream_helper.show_more_comments', :number => post.comments.size - 3)}", post_comments_path(post.id), :class => "toggle_post_comments" end str end diff --git a/app/models/post.rb b/app/models/post.rb index db3434726b0987f69db8e3e5bc77a0fcb514fe81..97de06edccdd879d63c0c33613076ea341acf42e 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -13,7 +13,7 @@ class Post < ActiveRecord::Base xml_attr :public xml_attr :created_at - has_many :comments, :order => 'created_at ASC', :dependent => :destroy + has_many :comments, :dependent => :destroy has_many :likes, :conditions => {:positive => true}, :dependent => :delete_all has_many :dislikes, :conditions => {:positive => false}, :class_name => 'Like', :dependent => :delete_all @@ -111,5 +111,10 @@ class Post < ActiveRecord::Base def activity_streams? false end + + # @return [Array<Comment>] + def last_three_comments + self.comments.order('created_at DESC').limit(3).includes(:author => :profile).reverse + end end diff --git a/app/views/comments/_comments.haml b/app/views/comments/_comments.haml index a4e155b999473e593a3abce4d7c8ba6dcc3aab95..304550afccb81dcd0a69e2d7e9be74e0bad94557 100644 --- a/app/views/comments/_comments.haml +++ b/app/views/comments/_comments.haml @@ -3,18 +3,16 @@ -# the COPYRIGHT file. - unless comments_expanded - %ul.show_comments{:class => ("hidden" if comments.size <= 3)} + %ul.show_comments{:class => ("hidden" if post.comments.size <= 3)} %li - %b= comment_toggle(comments.size) + %b= comment_toggle( post) -%ul.comments{:id => post.id, :class => ("hidden" if comments.size == 0 && !comments_expanded)} - -if comments.size > 3 - .older_comments{:class => ("hidden inactive" unless comments_expanded)} - = render :partial => 'comments/comment', :collection => comments[0..-4], :locals => {:post => post} - = render :partial => 'comments/comment', :collection => comments[-3, 3], :locals => {:post => post} +%ul.comments{:id => post.id, :class => ('loaded' if post.comments.size <= 3)} + -if post.comments.size > 3 && !comments_expanded + = render :partial => 'comments/comment', :collection => post.last_three_comments, :locals => {:post => post} -else - = render :partial => 'comments/comment', :collection => comments, :locals => {:post => post} + = render :partial => 'comments/comment', :collection => post.comments, :locals => {:post => post} - - unless @commenting_disabled - %li.comment.show - = new_comment_form(post.id, current_user) +- unless @commenting_disabled + .new_comment_form_wrapper{:class => ( 'hidden' if post.comments.size == 0)} + = new_comment_form(post.id, current_user) diff --git a/app/views/comments/index.html.haml b/app/views/comments/index.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..83963707982936feb7a8dd54cfd39e5fc2365b58 --- /dev/null +++ b/app/views/comments/index.html.haml @@ -0,0 +1 @@ += render :partial => 'comments/comment', :collection => @comments, :locals => {:post => @post} diff --git a/app/views/shared/_stream_element.html.haml b/app/views/shared/_stream_element.html.haml index 9cd085270c6be97c7db1ca8868cfc6568dbc72bb..113f47c28e8f49e4f20e96cff78a9a239d7eb701 100644 --- a/app/views/shared/_stream_element.html.haml +++ b/app/views/shared/_stream_element.html.haml @@ -59,4 +59,4 @@ - if post.likes_count > 0 = render "likes/likes_container", :post_id => post.id, :likes_count => post.likes_count, :current_user => current_user - = render "comments/comments", :post => post, :comments => post.comments, :current_user => current_user, :commenting_disabled => (defined?(@commenting_disabled) && @commenting_disabled) + = render "comments/comments", :post => post, :current_user => current_user, :commenting_disabled => (defined?(@commenting_disabled) && @commenting_disabled) diff --git a/config/routes.rb b/config/routes.rb index b65608746fc2953c19367bfeec7a72e411d97998..1a79267626e6adab3a57a7e22d9cfcd82d1418a1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,7 +16,7 @@ Diaspora::Application.routes.draw do resources :posts, :only => [:show, :destroy] do resources :likes, :only => [:create, :destroy, :index] - resources :comments, :only => [:create, :destroy] + resources :comments, :only => [:create, :destroy, :index] end get 'bookmarklet' => 'status_messages#bookmarklet' diff --git a/features/step_definitions/comment_steps.rb b/features/step_definitions/comment_steps.rb index b4c5fad5bf5fb1e1d96d1ed1cd722a65a9304151..514be350450bbee8f56042be5e5c6b2c73915bde 100644 --- a/features/step_definitions/comment_steps.rb +++ b/features/step_definitions/comment_steps.rb @@ -7,11 +7,9 @@ When /^I open the comment box$/ do end Then /^the first comment field should be open/ do - css_query = "$('#main_stream .stream_element:first ul.comments:visible')" - page.evaluate_script("#{css_query}.length").should == 1 + find("#main_stream .stream_element .new_comment").should be_visible end Then /^the first comment field should be closed$/ do - css_query = "$('#main_stream .stream_element:first ul.comments:hidden')" - page.evaluate_script("#{css_query}.length").should == 1 + find("#main_stream .stream_element .new_comment").should_not be_visible end diff --git a/lib/fake.rb b/lib/fake.rb index 4aaccd51953c71adfdda65a6cf6a6b947f523295..3466e018d9b563ae39221e24799d4834ac0deaa5 100644 --- a/lib/fake.rb +++ b/lib/fake.rb @@ -6,9 +6,6 @@ class PostsFake author_ids = [] posts.each do |p| author_ids << p.author_id - p.comments.each do |c| - author_ids << c.author_id - end end people = Person.where(:id => author_ids).includes(:profile) @@ -17,9 +14,6 @@ class PostsFake @post_fakes = posts.map do |post| f = Fake.new(post, self) - f.comments = post.comments.map do |comment| - Fake.new(comment, self) - end f end end @@ -29,7 +23,6 @@ class PostsFake end class Fake - attr_accessor :comments attr_reader :model def initialize(model, fakes_collection) @fakes_collection = fakes_collection diff --git a/public/javascripts/stream.js b/public/javascripts/stream.js index 55d03ce999e9e4bcc053be65bab12ac95e229518..690f476129a2c7f8799c70ab377da5c04a84d86a 100644 --- a/public/javascripts/stream.js +++ b/public/javascripts/stream.js @@ -52,7 +52,7 @@ var Stream = { }, setUpComments: function(){ - $("a.show_post_comments:not(.show)", this.selector).live('click', Stream.toggleComments); + $("a.toggle_post_comments:not(.show)", this.selector).live('click', Stream.toggleComments); // comment link form focus $(".focus_comment_textarea", this.selector).live('click', function(evt) { Stream.focusNewComment($(this), evt); @@ -66,7 +66,7 @@ var Stream = { var element = $(this), target = element.parents(".comment"), post = element.closest(".stream_element"), - toggler = post.find(".show_post_comments"); + toggler = post.find(".toggle_post_comments"); target.hide("blind", { direction: "vertical" }, 300, function() { $(this).remove(); @@ -126,42 +126,58 @@ var Stream = { toggleComments: function(evt) { evt.preventDefault(); - var $this = $(this), - showUl = $(this).closest("li"), - commentBlock = $this.closest(".stream_element").find("ul.comments", ".content"), - commentBlockMore = $this.closest(".stream_element").find(".older_comments", ".content") - - if( commentBlockMore.hasClass("inactive") ) { - commentBlockMore.fadeIn(150, function() { - commentBlockMore.removeClass("inactive"); - commentBlockMore.removeClass("hidden"); + + var $toggler = $(this), + comments = $toggler.closest('.stream_element').find('ul.comments'); + + if (comments.hasClass('loaded') && !comments.hasClass('hidden')){ + Stream.hideComments.apply($toggler); + }else { + Stream.showComments.apply($toggler); + } + }, + showComments: function(){ + var commentList = this.closest('.stream_element').find('ul.comments'), + toggle = this; + + if( commentList.hasClass('loaded') ){ + toggle.html(Diaspora.widgets.i18n.t("comments.hide")); + commentList.removeClass('hidden'); + } + else { + toggle.append("<img alt='loading' src='/images/ajax-loader.gif' />"); + $.ajax({ + url: this.attr('href'), + success: function(data){ + toggle.html(Diaspora.widgets.i18n.t("comments.hide")); + commentList.html(data) + .addClass('loaded'); + Diaspora.widgets.publish("stream/scrolled") + } }); - $this.html(Diaspora.widgets.i18n.t("comments.hide")); - } else { - if(commentBlock.hasClass("hidden")) { - commentBlock.removeClass("hidden"); - showUl.css("margin-bottom","-1em"); - $this.html(Diaspora.widgets.i18n.t("comments.hide")); - }else{ - commentBlock.addClass("hidden"); - showUl.css("margin-bottom","1em"); - $this.html(Diaspora.widgets.i18n.t("comments.show")); - } } }, + hideComments: function(){ + var commentList = this.closest('.stream_element').find('ul.comments'); + commentList.addClass('hidden'); + this.html(Diaspora.widgets.i18n.t("comments.show")); + }, + focusNewComment: function(toggle, evt) { evt.preventDefault(); - var commentBlock = toggle.closest(".stream_element").find("ul.comments", ".content"); + var post = toggle.closest(".stream_element"); + var commentBlock = post.find(".new_comment_form_wrapper"); + var textarea = post.find(".new_comment textarea"); if(commentBlock.hasClass("hidden")) { commentBlock.removeClass("hidden"); - commentBlock.find("textarea").focus(); + textarea.focus(); } else { if(commentBlock.children().length <= 1) { commentBlock.addClass("hidden"); } else { - commentBlock.find("textarea").focus(); + textarea.focus(); } } } diff --git a/public/javascripts/web-socket-receiver.js b/public/javascripts/web-socket-receiver.js index 76761a29aa8d260fd542eb18b90ee9fb49ea5f68..ddd36e35486e3874e9b9fa8f599036b9610bfe3e 100644 --- a/public/javascripts/web-socket-receiver.js +++ b/public/javascripts/web-socket-receiver.js @@ -97,16 +97,16 @@ var WebSocketReceiver = { $(html).fadeIn("fast", function(){}) ); } else { - $('.comments li:last', post).before( + $('.comments', post).append( $(html).fadeIn("fast", function(){}) ); } - var toggler = $('.show_post_comments', post).parent(); + var toggler = $('.toggle_post_comments', post).parent(); if(toggler.length > 0){ toggler.html( - toggler.html().replace(/\d+/,$('.comments', post).find('li').length -1) + toggler.html().replace(/\d+/,$('.comments', post).find('li').length) ); if( !$(".comments", post).is(':visible') ) { diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass index c13d41ee456747493cd9cd9ac00ca95f35f27e0d..f4b960511a89513bbc7ca6a5abf756555422fa23 100644 --- a/public/stylesheets/sass/application.sass +++ b/public/stylesheets/sass/application.sass @@ -481,11 +481,6 @@ ul.as-selections :font :size 1em - .comments - :padding - :bottom 6px - > li:last-child - :border-bottom none .comment_box :width 475px :margin @@ -552,23 +547,6 @@ ul.as-selections :background none :border none - -.stream ul.comments - :padding - :bottom 6px - - > li:last-child - :border-bottom none - - .avatar - :width 30px - :height 30px - - .comment_box - :margin - :bottom 5px - - .submit_button :text :align right @@ -576,8 +554,12 @@ ul.as-selections ul.comments, ul.show_comments, .likes_container + + .avatar + :width 30px + :height 30px + :margin 0 - :top 0.5em :padding 0 :font @@ -587,14 +569,6 @@ ul.show_comments, :position relative - form - textarea - :width 365px - :height 21px - - input - :display none - li :list :style none @@ -603,12 +577,6 @@ ul.show_comments, :border :bottom 1px dotted #aaa - .new_comment - :min-height 35px - p - :margin - :bottom 0 - .from :font :size 1em @@ -627,7 +595,7 @@ ul.show_comments, :padding :left 36px :right 10px - + p :margin :bottom 0 @@ -636,41 +604,68 @@ ul.show_comments, .right :right 4px - form + .avatar + :position absolute + :display inline + +ul.show_comments + :padding + :bottom 6px + :margin + :top 6px + +form.new_comment + :padding 8px 5px + .avatar + :position absolute + :display inline + :width 30px + :height 30px + + :min-height 35px + + input + :display none + + :margin + :bottom -4px + + :font + :size 1em + + .submit_button + input :margin - :top -5px - :bottom -4px - :font - :size 1em + :right 0 - .submit_button - input - :margin - :right 0 + textarea + :width 365px + :height 21px - textarea - :font - :size 1em - :margin - :bottom -3px + :font + :size 1em + :margin + :top 0 + :bottom -3px - p - :position relative - :left 35px + p + :margin + :bottom 0 + :top -10px + :position relative + :left 35px - .avatar - :position absolute - :display inline + &.open + .submit_button + :display block + :margin + :top 5px + :bottom 2px + :right 2px + + input + :display inline-block - form.open - .submit_button - :display block - :margin - :top 5px - :bottom 2px - :right 2px - input - :display inline-block .comments .timeago @@ -2209,8 +2204,6 @@ h3,h4 ul.show_comments - :margin - :bottom -0.5em :border :top 1px dotted #aaa diff --git a/spec/controllers/comments_controller_spec.rb b/spec/controllers/comments_controller_spec.rb index 31a0e3ad8c782111d2663b74ced3cbc31adcd15c..e7a38b33096c6f086fe88d6a9b35dcea11e29b32 100644 --- a/spec/controllers/comments_controller_spec.rb +++ b/spec/controllers/comments_controller_spec.rb @@ -117,4 +117,25 @@ describe CommentsController do response.body.strip.should be_empty end end + + describe '#index' do + before do + @message = bob.post(:status_message, :text => "hey", :to => bob.aspects.first.id) + @comments = [alice, bob, eve].map{ |u| u.comment("hey", :post => @message) } + end + it 'returns all the comments for a post' do + get :index, :post_id => @message.id, :format => 'js' + assigns[:comments].should == @comments + end + it 'returns a 404 on a nonexistent post' do + get :index, :post_id => 235236, :format => 'js' + response.status.should == 404 + end + it 'returns a 404 on a post that is not visible to the signed in user' do + message = eve.post(:status_message, :text => "hey", :to => eve.aspects.first.id) + bob.comment("hey", :post => @message) + get :index, :post_id => message.id, :format => 'js' + response.status.should == 404 + end + end end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index a591c399caea2638f25bde79fd8a3900a079db99..274f1ce0833f560aeb373b9dfb27974bdb59f3c8 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -51,6 +51,15 @@ describe Post do end end - describe '#receive' do + describe '#last_three_comments' do + it 'returns the last three comments of a post' do + post = bob.post :status_message, :text => "hello", :to => 'all' + created_at = Time.now - 100 + comments = [alice, eve, bob, alice].map do |u| + created_at = created_at + 10 + u.comment("hey", :post => post, :created_at => created_at) + end + post.last_three_comments.map{|c| c.id}.should == comments[1,3].map{|c| c.id} + end end end