Merge branch 'ajaxy-comments'

This commit is contained in:
Raphael Sofaer 2011-07-11 14:05:45 -07:00
commit eafe6a7c85
15 changed files with 177 additions and 132 deletions

View file

@ -47,7 +47,7 @@ class AspectsController < ApplicationController
:type => ['StatusMessage','ActivityStreams::Photo'], :type => ['StatusMessage','ActivityStreams::Photo'],
:order => session[:sort_order] + ' DESC', :order => session[:sort_order] + ' DESC',
:max_time => params[:max_time].to_i :max_time => params[:max_time].to_i
).includes({:comments => {:author => :profile}}, {:mentions => {:person => :profile}}) ).includes(:mentions => {:person => :profile})
@posts = PostsFake.new(posts) @posts = PostsFake.new(posts)
if params[:only_posts] if params[:only_posts]

View file

@ -6,7 +6,8 @@ class CommentsController < ApplicationController
include ApplicationHelper include ApplicationHelper
before_filter :authenticate_user! 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 rescue_from ActiveRecord::RecordNotFound do
render :nothing => true, :status => 404 render :nothing => true, :status => 404
@ -53,4 +54,14 @@ class CommentsController < ApplicationController
end end
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 end

View file

@ -4,11 +4,11 @@
module CommentsHelper module CommentsHelper
GSUB_THIS = "FIUSDHVIUSHDVIUBAIUHAPOIUXJM" GSUB_THIS = "FIUSDHVIUSHDVIUBAIUHAPOIUXJM"
def comment_toggle(count, commenting_disabled=false) def comment_toggle(post, commenting_disabled=false)
if count <= 3 if post.comments.size <= 3
str = link_to "#{t('stream_helper.hide_comments')}", '#', :class => "show_post_comments" str = link_to "#{t('stream_helper.hide_comments')}", post_comments_path(post.id), :class => "toggle_post_comments"
else 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 end
str str
end end

View file

@ -13,7 +13,7 @@ class Post < ActiveRecord::Base
xml_attr :public xml_attr :public
xml_attr :created_at 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 :likes, :conditions => {:positive => true}, :dependent => :delete_all
has_many :dislikes, :conditions => {:positive => false}, :class_name => 'Like', :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? def activity_streams?
false false
end end
# @return [Array<Comment>]
def last_three_comments
self.comments.order('created_at DESC').limit(3).includes(:author => :profile).reverse
end
end end

View file

@ -3,18 +3,16 @@
-# the COPYRIGHT file. -# the COPYRIGHT file.
- unless comments_expanded - unless comments_expanded
%ul.show_comments{:class => ("hidden" if comments.size <= 3)} %ul.show_comments{:class => ("hidden" if post.comments.size <= 3)}
%li %li
%b= comment_toggle(comments.size) %b= comment_toggle( post)
%ul.comments{:id => post.id, :class => ("hidden" if comments.size == 0 && !comments_expanded)} %ul.comments{:id => post.id, :class => ('loaded' if post.comments.size <= 3)}
-if comments.size > 3 -if post.comments.size > 3 && !comments_expanded
.older_comments{:class => ("hidden inactive" unless comments_expanded)} = render :partial => 'comments/comment', :collection => post.last_three_comments, :locals => {:post => post}
= render :partial => 'comments/comment', :collection => comments[0..-4], :locals => {:post => post}
= render :partial => 'comments/comment', :collection => comments[-3, 3], :locals => {:post => post}
-else -else
= render :partial => 'comments/comment', :collection => comments, :locals => {:post => post} = render :partial => 'comments/comment', :collection => post.comments, :locals => {:post => post}
- unless @commenting_disabled - unless @commenting_disabled
%li.comment.show .new_comment_form_wrapper{:class => ( 'hidden' if post.comments.size == 0)}
= new_comment_form(post.id, current_user) = new_comment_form(post.id, current_user)

View file

@ -0,0 +1 @@
= render :partial => 'comments/comment', :collection => @comments, :locals => {:post => @post}

View file

@ -59,4 +59,4 @@
- if post.likes_count > 0 - if post.likes_count > 0
= render "likes/likes_container", :post_id => post.id, :likes_count => post.likes_count, :current_user => current_user = 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)

View file

@ -16,7 +16,7 @@ Diaspora::Application.routes.draw do
resources :posts, :only => [:show, :destroy] do resources :posts, :only => [:show, :destroy] do
resources :likes, :only => [:create, :destroy, :index] resources :likes, :only => [:create, :destroy, :index]
resources :comments, :only => [:create, :destroy] resources :comments, :only => [:create, :destroy, :index]
end end
get 'bookmarklet' => 'status_messages#bookmarklet' get 'bookmarklet' => 'status_messages#bookmarklet'

View file

@ -7,11 +7,9 @@ When /^I open the comment box$/ do
end end
Then /^the first comment field should be open/ do Then /^the first comment field should be open/ do
css_query = "$('#main_stream .stream_element:first ul.comments:visible')" find("#main_stream .stream_element .new_comment").should be_visible
page.evaluate_script("#{css_query}.length").should == 1
end end
Then /^the first comment field should be closed$/ do Then /^the first comment field should be closed$/ do
css_query = "$('#main_stream .stream_element:first ul.comments:hidden')" find("#main_stream .stream_element .new_comment").should_not be_visible
page.evaluate_script("#{css_query}.length").should == 1
end end

View file

@ -6,9 +6,6 @@ class PostsFake
author_ids = [] author_ids = []
posts.each do |p| posts.each do |p|
author_ids << p.author_id author_ids << p.author_id
p.comments.each do |c|
author_ids << c.author_id
end
end end
people = Person.where(:id => author_ids).includes(:profile) people = Person.where(:id => author_ids).includes(:profile)
@ -17,9 +14,6 @@ class PostsFake
@post_fakes = posts.map do |post| @post_fakes = posts.map do |post|
f = Fake.new(post, self) f = Fake.new(post, self)
f.comments = post.comments.map do |comment|
Fake.new(comment, self)
end
f f
end end
end end
@ -29,7 +23,6 @@ class PostsFake
end end
class Fake class Fake
attr_accessor :comments
attr_reader :model attr_reader :model
def initialize(model, fakes_collection) def initialize(model, fakes_collection)
@fakes_collection = fakes_collection @fakes_collection = fakes_collection

View file

@ -52,7 +52,7 @@ var Stream = {
}, },
setUpComments: function(){ 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 // comment link form focus
$(".focus_comment_textarea", this.selector).live('click', function(evt) { $(".focus_comment_textarea", this.selector).live('click', function(evt) {
Stream.focusNewComment($(this), evt); Stream.focusNewComment($(this), evt);
@ -66,7 +66,7 @@ var Stream = {
var element = $(this), var element = $(this),
target = element.parents(".comment"), target = element.parents(".comment"),
post = element.closest(".stream_element"), post = element.closest(".stream_element"),
toggler = post.find(".show_post_comments"); toggler = post.find(".toggle_post_comments");
target.hide("blind", { direction: "vertical" }, 300, function() { target.hide("blind", { direction: "vertical" }, 300, function() {
$(this).remove(); $(this).remove();
@ -126,42 +126,58 @@ var Stream = {
toggleComments: function(evt) { toggleComments: function(evt) {
evt.preventDefault(); 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") ) { var $toggler = $(this),
commentBlockMore.fadeIn(150, function() { comments = $toggler.closest('.stream_element').find('ul.comments');
commentBlockMore.removeClass("inactive");
commentBlockMore.removeClass("hidden"); 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) { focusNewComment: function(toggle, evt) {
evt.preventDefault(); 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")) { if(commentBlock.hasClass("hidden")) {
commentBlock.removeClass("hidden"); commentBlock.removeClass("hidden");
commentBlock.find("textarea").focus(); textarea.focus();
} else { } else {
if(commentBlock.children().length <= 1) { if(commentBlock.children().length <= 1) {
commentBlock.addClass("hidden"); commentBlock.addClass("hidden");
} else { } else {
commentBlock.find("textarea").focus(); textarea.focus();
} }
} }
} }

View file

@ -97,16 +97,16 @@ var WebSocketReceiver = {
$(html).fadeIn("fast", function(){}) $(html).fadeIn("fast", function(){})
); );
} else { } else {
$('.comments li:last', post).before( $('.comments', post).append(
$(html).fadeIn("fast", function(){}) $(html).fadeIn("fast", function(){})
); );
} }
var toggler = $('.show_post_comments', post).parent(); var toggler = $('.toggle_post_comments', post).parent();
if(toggler.length > 0){ if(toggler.length > 0){
toggler.html( 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') ) { if( !$(".comments", post).is(':visible') ) {

View file

@ -481,11 +481,6 @@ ul.as-selections
:font :font
:size 1em :size 1em
.comments
:padding
:bottom 6px
> li:last-child
:border-bottom none
.comment_box .comment_box
:width 475px :width 475px
:margin :margin
@ -552,23 +547,6 @@ ul.as-selections
:background none :background none
:border 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 .submit_button
:text :text
:align right :align right
@ -576,8 +554,12 @@ ul.as-selections
ul.comments, ul.comments,
ul.show_comments, ul.show_comments,
.likes_container .likes_container
.avatar
:width 30px
:height 30px
:margin 0 :margin 0
:top 0.5em
:padding 0 :padding 0
:font :font
@ -587,14 +569,6 @@ ul.show_comments,
:position relative :position relative
form
textarea
:width 365px
:height 21px
input
:display none
li li
:list :list
:style none :style none
@ -603,12 +577,6 @@ ul.show_comments,
:border :border
:bottom 1px dotted #aaa :bottom 1px dotted #aaa
.new_comment
:min-height 35px
p
:margin
:bottom 0
.from .from
:font :font
:size 1em :size 1em
@ -636,10 +604,32 @@ ul.show_comments,
.right .right
:right 4px :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 :margin
:top -5px
:bottom -4px :bottom -4px
:font :font
:size 1em :size 1em
@ -649,29 +639,34 @@ ul.show_comments,
:right 0 :right 0
textarea textarea
:width 365px
:height 21px
:font :font
:size 1em :size 1em
:margin :margin
:top 0
:bottom -3px :bottom -3px
p p
:margin
:bottom 0
:top -10px
:position relative :position relative
:left 35px :left 35px
.avatar &.open
:position absolute
:display inline
form.open
.submit_button .submit_button
:display block :display block
:margin :margin
:top 5px :top 5px
:bottom 2px :bottom 2px
:right 2px :right 2px
input input
:display inline-block :display inline-block
.comments .comments
.timeago .timeago
:color #999 :color #999
@ -2209,8 +2204,6 @@ h3,h4
ul.show_comments ul.show_comments
:margin
:bottom -0.5em
:border :border
:top 1px dotted #aaa :top 1px dotted #aaa

View file

@ -117,4 +117,25 @@ describe CommentsController do
response.body.strip.should be_empty response.body.strip.should be_empty
end end
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 end

View file

@ -51,6 +51,15 @@ describe Post do
end end
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
end end