Commit c916579e2ebfddba26d985c3dff642dac103561b

Authored by Leandro Nunes dos Santos
2 parents 68fd5fb8 2e7d2cf5

Merge branch 'ActionItem2562' into ActionItem2520

app/controllers/public/comment_controller.rb
@@ -160,6 +160,15 @@ class CommentController < ApplicationController @@ -160,6 +160,15 @@ class CommentController < ApplicationController
160 end 160 end
161 end 161 end
162 end 162 end
  163 +
  164 + #FIXME make this test
  165 + def check_actions
  166 + comment = profile.comments_received.find(params[:id])
  167 + ids = @plugins.dispatch(:check_comment_actions, comment).collect do |action|
  168 + action.kind_of?(Proc) ? self.instance_eval(&action) : action
  169 + end.flatten.compact
  170 + render :json => {:ids => ids}
  171 + end
163 172
164 protected 173 protected
165 174
app/helpers/application_helper.rb
@@ -30,6 +30,8 @@ module ApplicationHelper @@ -30,6 +30,8 @@ module ApplicationHelper
30 30
31 include AccountHelper 31 include AccountHelper
32 32
  33 + include CommentHelper
  34 +
33 include BlogHelper 35 include BlogHelper
34 36
35 include ContentViewerHelper 37 include ContentViewerHelper
app/helpers/comment_helper.rb
@@ -21,5 +21,48 @@ module CommentHelper @@ -21,5 +21,48 @@ module CommentHelper
21 end 21 end
22 title 22 title
23 end 23 end
  24 +
  25 + def comment_actions(comment)
  26 + url = url_for(:profile => profile.identifier, :controller => :comment, :action => :check_actions, :id => comment.id)
  27 + links = links_for_comment_actions(comment)
  28 + content_tag(:li, link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger comment-trigger', :url => url), :class=> 'vcard') unless links.empty?
  29 + end
  30 +
  31 + private
  32 +
  33 + def links_for_comment_actions(comment)
  34 + actions = [link_for_report_abuse(comment), link_for_spam(comment), link_for_edit(comment), link_for_remove(comment)]
  35 + @plugins.dispatch(:comment_actions, comment).collect do |action|
  36 + actions << (action.kind_of?(Proc) ? self.instance_eval(&action) : action)
  37 + end
  38 + actions.flatten.compact
  39 + end
  40 +
  41 + def link_for_report_abuse(comment)
  42 + if comment.author
  43 + report_abuse_link = report_abuse(comment.author, :comment_link, comment)
  44 + {:link => report_abuse_link} if report_abuse_link
  45 + end
  46 + end
  47 +
  48 + def link_for_spam(comment)
  49 + if comment.spam?
  50 + {:link => link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, %s); return false;' % url_for(:profile => profile.identifier, :mark_comment_as_ham => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide')}
  51 + elsif (logged_in? && (user == profile || user.has_permission?(:moderate_comments, profile)))
  52 + {:link => link_to_function(_('Mark as SPAM'), 'remove_comment(this, %s, %s); return false;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :mark_as_spam, :id => comment.id).to_json, _('Are you sure you want to mark this comment as SPAM?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide')}
  53 + end
  54 + end
  55 +
  56 + def link_for_edit(comment)
  57 + if comment.author && comment.author == user
  58 + {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'colorbox')}
  59 + end
  60 + end
  61 +
  62 + def link_for_remove(comment)
  63 + if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile))
  64 + {:link => link_to_function(_('Remove'), 'remove_comment(this, %s, %s); return false ;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :destroy, :id => comment.id).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children')}
  65 + end
  66 + end
24 67
25 end 68 end
app/views/comment/_comment.rhtml
@@ -31,6 +31,21 @@ @@ -31,6 +31,21 @@
31 <% comment_balloon do %> 31 <% comment_balloon do %>
32 32
33 <div class="comment-details"> 33 <div class="comment-details">
  34 + <div class="comment-header">
  35 + <ul>
  36 + <div class="comment-actions">
  37 + <%= comment_actions(comment) %>
  38 + </div>
  39 + </ul>
  40 + <% unless comment.spam? %>
  41 + <%= link_to_function '',
  42 + "var f = add_comment_reply_form(this, %s); f.find('comment_title, textarea').val(''); return false" % comment.id,
  43 + :class => 'comment-footer comment-footer-link comment-footer-hide comment-actions-reply button',
  44 + :id => 'comment-reply-to-' + comment.id.to_s
  45 + %>
  46 + <% end %>
  47 + </div>
  48 +
34 <div class="comment-created-at"> 49 <div class="comment-created-at">
35 <%= show_time(comment.created_at) %> 50 <%= show_time(comment.created_at) %>
36 </div> 51 </div>
@@ -41,7 +56,7 @@ @@ -41,7 +56,7 @@
41 </div> 56 </div>
42 </div> 57 </div>
43 58
44 - <div class="comment_reply post_comment_box closed"> 59 + <div class="comment_reply post_comment_box closed" id="comment_reply_to_<%= comment.id %>">
45 <% if @comment && @comment.errors.any? && @comment.reply_of_id.to_i == comment.id %> 60 <% if @comment && @comment.errors.any? && @comment.reply_of_id.to_i == comment.id %>
46 <%= error_messages_for :comment %> 61 <%= error_messages_for :comment %>
47 <script type="text/javascript"> 62 <script type="text/javascript">
@@ -51,36 +66,6 @@ @@ -51,36 +66,6 @@
51 }); 66 });
52 </script> 67 </script>
53 <% end %> 68 <% end %>
54 - <%= report_abuse(comment.author, :comment_link, comment) if comment.author %>  
55 -  
56 - <% if comment.spam? %>  
57 - &nbsp;  
58 - <%= link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, %s); return false;' % url_for(:profile => profile.identifier, :mark_comment_as_ham => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide') %>  
59 - <% else %>  
60 - <% if (logged_in? && (user == profile || user.has_permission?(:moderate_comments, profile))) %>  
61 - &nbsp;  
62 - <%= link_to_function(_('Mark as SPAM'), 'remove_comment(this, %s, %s); return false;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :mark_as_spam, :id => comment.id).to_json, _('Are you sure you want to mark this comment as SPAM?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide') %>  
63 - <% end %>  
64 - <% end %>  
65 -  
66 - <% if comment.author && comment.author == user %>  
67 - &nbsp;  
68 - <%= expirable_comment_link comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'colorbox' %>  
69 - <% end %>  
70 -  
71 - <% if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %>  
72 - &nbsp;  
73 - <%= link_to_function(_('Remove'), 'remove_comment(this, %s, %s); return false ;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :destroy, :id => comment.id).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children') %>  
74 - <% end %>  
75 -  
76 - <% unless comment.spam? %>  
77 - &nbsp;  
78 - <%= link_to_function _('Reply'),  
79 - "var f = add_comment_reply_form(this, %s); f.find('comment_title, textarea').val(''); return false" % comment.id,  
80 - :class => 'comment-footer comment-footer-link comment-footer-hide',  
81 - :id => 'comment-reply-to-' + comment.id.to_s  
82 - %>  
83 - <% end %>  
84 </div> 69 </div>
85 70
86 <% end %> 71 <% end %>
config/plugins/comment_actions 0 → 120000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/home/81665687568/projetos/noosfero_development/plugins/comment_actions
0 \ No newline at end of file 2 \ No newline at end of file
lib/noosfero/plugin.rb
@@ -339,6 +339,30 @@ class Noosfero::Plugin @@ -339,6 +339,30 @@ class Noosfero::Plugin
339 def comment_marked_as_ham(comment) 339 def comment_marked_as_ham(comment)
340 end 340 end
341 341
  342 + # Adds extra actions for comments
  343 + # returns = list of hashes or lambda block that creates a list of hashes
  344 + # example:
  345 + #
  346 + # def comment_actions(comment)
  347 + # [{:link => link_to_function(...)}]
  348 + # end
  349 + #
  350 + def comment_actions(comment)
  351 + nil
  352 + end
  353 +
  354 + # This method is called when the user click on comment actions menu.
  355 + # returns = list or lambda block that return ids of enabled menu items for comments
  356 + # example:
  357 + #
  358 + # def check_comment_actions(comment)
  359 + # ['#action1', '#action2']
  360 + # end
  361 + #
  362 + def check_comment_actions(comment)
  363 + []
  364 + end
  365 +
342 # -> Adds fields to the signup form 366 # -> Adds fields to the signup form
343 # returns = lambda block that creates html code 367 # returns = lambda block that creates html code
344 def signup_extra_contents 368 def signup_extra_contents
public/javascripts/add-and-join.js
@@ -100,4 +100,24 @@ jQuery(function($) { @@ -100,4 +100,24 @@ jQuery(function($) {
100 clicked.parent().find(".send-an-email").fadeOut(); 100 clicked.parent().find(".send-an-email").fadeOut();
101 }) 101 })
102 }) 102 })
  103 +
  104 + $(".comment-trigger").live('click', function(){
  105 + clicked = $(this);
  106 + url = clicked.attr("url");
  107 + $.get(url, function(data){
  108 + ids = [];
  109 + if(data && data.ids) {
  110 + for(var i=0; i<data.ids.length; i++) {
  111 + clicked.parent().find(data.ids[i]).fadeIn();
  112 + ids.push(data.ids[i]);
  113 + }
  114 + }
  115 + clicked.parent().find('.comment-action-extra').each(function() {
  116 + if($.inArray('#'+$(this).attr('id'), ids))
  117 + $(this).fadeOut();
  118 + });
  119 + })
  120 + return false;
  121 + })
  122 +
103 }); 123 });
public/javascripts/application.js
@@ -314,11 +314,17 @@ function toggleSubmenu(trigger, title, link_list) { @@ -314,11 +314,17 @@ function toggleSubmenu(trigger, title, link_list) {
314 content.append('<h4>' + title + '</h4>'); 314 content.append('<h4>' + title + '</h4>');
315 jQuery.each(link_list, function(index, link_hash) { 315 jQuery.each(link_list, function(index, link_hash) {
316 for (label in link_hash) { 316 for (label in link_hash) {
317 - options = "";  
318 - jQuery.each(link_hash[label], function(option, value){  
319 - options += option +'="'+ value + '" ';  
320 - })  
321 - list.append('<li><a '+ options +'>' + label + '</a></li>'); 317 + if(link_hash[label]!=null) {
  318 + if(label=='link' && jQuery.type(link_hash[label])=="string") {
  319 + list.append('<li>' + link_hash[label] + '</li>');
  320 + } else {
  321 + options = "";
  322 + jQuery.each(link_hash[label], function(option, value){
  323 + options += option +'="'+ value + '" ';
  324 + })
  325 + list.append('<li><a '+ options +'>' + label + '</a></li>');
  326 + }
  327 + }
322 } 328 }
323 }); 329 });
324 content.append(list); 330 content.append(list);
@@ -342,9 +348,9 @@ function hideAllSubmenus() { @@ -342,9 +348,9 @@ function hideAllSubmenus() {
342 // Hide visible ballons when clicked outside them 348 // Hide visible ballons when clicked outside them
343 jQuery(document).ready(function() { 349 jQuery(document).ready(function() {
344 jQuery('body').live('click', function() { hideAllSubmenus(); }); 350 jQuery('body').live('click', function() { hideAllSubmenus(); });
345 - jQuery('.menu-submenu-trigger').click(function(e) { e.stopPropagation(); });  
346 - jQuery('.simplemenu-trigger').click(function(e) { e.stopPropagation(); });  
347 - jQuery('#chat-online-users').click(function(e) { e.stopPropagation(); }); 351 + jQuery('.menu-submenu-trigger').live('click', function(e) { e.stopPropagation(); });
  352 + jQuery('.simplemenu-trigger').live('click', function(e) { e.stopPropagation(); });
  353 + jQuery('#chat-online-users').live('click', function(e) { e.stopPropagation(); });
348 }); 354 });
349 355
350 function input_javascript_ordering_stuff() { 356 function input_javascript_ordering_stuff() {
@@ -710,8 +716,8 @@ jQuery(function($) { @@ -710,8 +716,8 @@ jQuery(function($) {
710 }); 716 });
711 717
712 function add_comment_reply_form(button, comment_id) { 718 function add_comment_reply_form(button, comment_id) {
713 - var container = jQuery(button).parents('.comment_reply');  
714 - 719 + //var container = jQuery(button).parents('.comment_reply');
  720 + var container = jQuery('#comment_reply_to_'+comment_id);
715 var f = container.find('.comment_form'); 721 var f = container.find('.comment_form');
716 if (f.length == 0) { 722 if (f.length == 0) {
717 comments_div = jQuery(button).parents('.comments'); 723 comments_div = jQuery(button).parents('.comments');
public/stylesheets/application.css
@@ -1802,13 +1802,32 @@ a.button.disabled, input.disabled { @@ -1802,13 +1802,32 @@ a.button.disabled, input.disabled {
1802 #content .profile-list-block ul { 1802 #content .profile-list-block ul {
1803 width: 200px; 1803 width: 200px;
1804 } 1804 }
1805 -#content .common-profile-list-block li {  
1806 - margin: 0px; 1805 +#content .comment-header .comment-actions-reply {
  1806 + float: right;
  1807 + background-image: url(/designs/icons/tango/Tango/16x16/actions/go-jump.png);
  1808 + height: 12px;
  1809 +}
  1810 +#content .comment-header ul {
  1811 + float: right;
  1812 + margin: 1px 0px 14px 0px;
  1813 +}
  1814 +#content .comment-actions .menu-submenu-header, #content .comment-actions .menu-submenu-footer, #content .comment-actions .menu-submenu h4 {
  1815 + display: none;
  1816 +}
  1817 +#content .comment-actions .menu-submenu ul {
  1818 + border: 1px solid #888a85;
  1819 + background-color: #efefef;
  1820 + padding-right: 2px;
  1821 + height: auto;
  1822 + display: block;
  1823 +}
  1824 +#content .common-profile-list-block li, #content .comment-actions li {
  1825 + margin: 0px !important;
1807 padding: 0px; 1826 padding: 0px;
1808 list-style: none; 1827 list-style: none;
1809 position: relative; 1828 position: relative;
1810 } 1829 }
1811 -.common-profile-list-block .vcard a { 1830 +.common-profile-list-block .vcard a, .comment-actions .vcard a {
1812 display: block; 1831 display: block;
1813 height: 112px; 1832 height: 112px;
1814 max-height: 112px; 1833 max-height: 112px;
@@ -1819,7 +1838,7 @@ a.button.disabled, input.disabled { @@ -1819,7 +1838,7 @@ a.button.disabled, input.disabled {
1819 text-align: center; 1838 text-align: center;
1820 overflow: hidden; 1839 overflow: hidden;
1821 font-size: 11px; 1840 font-size: 11px;
1822 - text-decoration: none; 1841 + text-decoration: none !important;
1823 color: #000; 1842 color: #000;
1824 position: relative; 1843 position: relative;
1825 cursor: pointer; /* work arround bug for MSIE */ 1844 cursor: pointer; /* work arround bug for MSIE */
@@ -4575,11 +4594,17 @@ h1#agenda-title { @@ -4575,11 +4594,17 @@ h1#agenda-title {
4575 } 4594 }
4576 /* Profile balloon */ 4595 /* Profile balloon */
4577 4596
4578 -.common-profile-list-block .vcard { 4597 +.common-profile-list-block .vcard, .comment-actions .vcard {
4579 position: relative !important; 4598 position: relative !important;
4580 float: left; 4599 float: left;
4581 } 4600 }
4582 -.common-profile-list-block .vcard .menu-submenu-trigger, .menu-submenu-trigger { 4601 +#content .comment-actions .vcard {
  4602 + padding-right: 20px;
  4603 +}
  4604 +#content .comment-actions .vcard .menu-submenu-trigger {
  4605 + display: block;
  4606 +}
  4607 +.common-profile-list-block .vcard .menu-submenu-trigger, .menu-submenu-trigger, .comment-actions .vcard .menu-submenu-trigger {
4583 display: none; 4608 display: none;
4584 width: 16px; 4609 width: 16px;
4585 height: 16px; 4610 height: 16px;
@@ -4593,7 +4618,7 @@ h1#agenda-title { @@ -4593,7 +4618,7 @@ h1#agenda-title {
4593 -moz-border-radius: 5px; 4618 -moz-border-radius: 5px;
4594 -webkit-border-radius: 5px; 4619 -webkit-border-radius: 5px;
4595 } 4620 }
4596 -.common-profile-list-block .vcard .menu-submenu-trigger:hover, .menu-submenu-trigger:hover { 4621 +.common-profile-list-block .vcard .menu-submenu-trigger:hover, .menu-submenu-trigger:hover, .comment-actions .vcard .menu-submenu-trigger:hover {
4597 background: #fff url(/images/top-arrow.png) center center no-repeat; 4622 background: #fff url(/images/top-arrow.png) center center no-repeat;
4598 border: 1px solid #ccc; 4623 border: 1px solid #ccc;
4599 } 4624 }
@@ -4612,6 +4637,10 @@ h1#agenda-title { @@ -4612,6 +4637,10 @@ h1#agenda-title {
4612 padding: 0; 4637 padding: 0;
4613 text-align: left; 4638 text-align: left;
4614 } 4639 }
  4640 +.comment-details .menu-submenu {
  4641 + bottom: 0px;
  4642 + right: -134px;
  4643 +}
4615 .box-2 .menu-submenu, .box-3 .menu-submenu { 4644 .box-2 .menu-submenu, .box-3 .menu-submenu {
4616 bottom: 78px; 4645 bottom: 78px;
4617 right: -44px; 4646 right: -44px;
@@ -4646,7 +4675,7 @@ h1#agenda-title { @@ -4646,7 +4675,7 @@ h1#agenda-title {
4646 .msie7 #search-results .menu-submenu-trigger { 4675 .msie7 #search-results .menu-submenu-trigger {
4647 width: 20px !important; 4676 width: 20px !important;
4648 } 4677 }
4649 -.common-profile-list-block .vcard .menu-submenu a { 4678 +.common-profile-list-block .vcard .menu-submenu a, .comment-actions .vcard .menu-submenu a {
4650 float: none; 4679 float: none;
4651 display: block; 4680 display: block;
4652 height: auto; 4681 height: auto;
test/functional/comment_controller_test.rb
@@ -493,7 +493,7 @@ class CommentControllerTest &lt; ActionController::TestCase @@ -493,7 +493,7 @@ class CommentControllerTest &lt; ActionController::TestCase
493 assert_equal 'Comment edited', Comment.find(comment.id).body 493 assert_equal 'Comment edited', Comment.find(comment.id).body
494 end 494 end
495 495
496 - should 'not crash on update comment if comment does not exist' do 496 + should 'not crash on update comment if comment does not exist' do
497 login_as profile.identifier 497 login_as profile.identifier
498 page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') 498 page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
499 499
@@ -501,4 +501,18 @@ class CommentControllerTest &lt; ActionController::TestCase @@ -501,4 +501,18 @@ class CommentControllerTest &lt; ActionController::TestCase
501 assert_response 404 501 assert_response 404
502 end 502 end
503 503
  504 + should 'returns ids of menu items that has to be displayed' do
  505 + class TestActionPlugin < Noosfero::Plugin
  506 + def check_comment_actions(c)
  507 + ['action1', 'action2']
  508 + end
  509 + end
  510 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestActionPlugin.new])
  511 + login_as profile.identifier
  512 + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
  513 + comment = fast_create(Comment, :body => 'Original comment', :source_id => page.id, :source_type => 'Article')
  514 + xhr :post, :check_actions, :profile => profile.identifier, :id => comment.id
  515 + assert_match /\{\"ids\":\[\"action1\",\"action2\"\]\}/, @response.body
  516 + end
  517 +
504 end 518 end
test/functional/content_viewer_controller_test.rb
@@ -1047,7 +1047,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -1047,7 +1047,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1047 comment.save! 1047 comment.save!
1048 login_as 'testuser' 1048 login_as 'testuser'
1049 get :view_page, :profile => 'testuser', :page => [ 'test' ] 1049 get :view_page, :profile => 'testuser', :page => [ 'test' ]
1050 - assert_tag :tag => 'a', :attributes => { :class => /comment-footer-link/ }, :content => 'Reply' 1050 + assert_tag :tag => 'a', :attributes => { :class => /comment-actions-reply/ }
1051 end 1051 end
1052 1052
1053 should 'display reply to comment button if not authenticated' do 1053 should 'display reply to comment button if not authenticated' do
@@ -1057,7 +1057,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -1057,7 +1057,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1057 comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala') 1057 comment = article.comments.build(:author => profile, :title => 'a comment', :body => 'lalala')
1058 comment.save! 1058 comment.save!
1059 get :view_page, :profile => 'testuser', :page => [ 'test' ] 1059 get :view_page, :profile => 'testuser', :page => [ 'test' ]
1060 - assert_tag :tag => 'a', :attributes => { :class => /comment-footer-link/ }, :content => 'Reply' 1060 + assert_tag :tag => 'a', :attributes => { :class => /comment-actions-reply/ }
1061 end 1061 end
1062 1062
1063 should 'display replies if comment has replies' do 1063 should 'display replies if comment has replies' do
test/unit/comment_helper_test.rb 0 → 100644
@@ -0,0 +1,104 @@ @@ -0,0 +1,104 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class CommentHelperTest < ActiveSupport::TestCase
  4 +
  5 + include CommentHelper
  6 + include ActionView::Helpers::TagHelper
  7 + include NoosferoTestHelper
  8 +
  9 + def setup
  10 + @user = create_user('usertest').person
  11 + @profile = @user
  12 + self.stubs(:logged_in?).returns(true)
  13 + self.stubs(:report_abuse).returns('<a href="#">link</a>')
  14 + self.stubs(:expirable_comment_link).returns('<a href="#">link</a>')
  15 + @plugins.stubs(:dispatch).returns([])
  16 + end
  17 +
  18 + attr_reader :user, :profile
  19 +
  20 + should 'show menu if it has links for actions' do
  21 + comment = Comment.new
  22 + menu = comment_actions(comment)
  23 + assert menu
  24 + end
  25 +
  26 + should 'do not show menu if it has no actions' do
  27 + comment = Comment.new
  28 + self.stubs(:links_for_comment_actions).returns([])
  29 + menu = comment_actions(comment)
  30 + assert !menu
  31 + end
  32 +
  33 + should 'do not show menu if it has nil actions only' do
  34 + comment = Comment.new
  35 + self.stubs(:link_for_report_abuse).returns(nil)
  36 + self.stubs(:link_for_spam).returns(nil)
  37 + self.stubs(:link_for_edit).returns(nil)
  38 + self.stubs(:link_for_remove).returns(nil)
  39 + menu = comment_actions(comment)
  40 + assert !menu
  41 + end
  42 +
  43 + should 'include actions of plugins in menu' do
  44 + comment = Comment.new
  45 + plugin_action = {:link => 'plugin_action'}
  46 + @plugins.stubs(:dispatch).returns([plugin_action])
  47 + links = links_for_comment_actions(comment)
  48 + assert_includes links, plugin_action
  49 + end
  50 +
  51 + should 'include lambda actions of plugins in menu' do
  52 + comment = Comment.new
  53 + plugin_action = lambda{[{:link => 'plugin_action'}, {:link => 'plugin_action2'}]}
  54 + @plugins.stubs(:dispatch).returns([plugin_action])
  55 + links = links_for_comment_actions(comment)
  56 + assert_includes links, {:link => 'plugin_action'}
  57 + assert_includes links, {:link => 'plugin_action2'}
  58 + end
  59 +
  60 + should 'return link for report abuse action when comment has a author' do
  61 + comment = Comment.new
  62 + comment.author = user
  63 + link = link_for_report_abuse(comment)
  64 + assert link
  65 + end
  66 +
  67 + should 'do not return link for report abuse action when comment has no author' do
  68 + comment = Comment.new
  69 + link = link_for_report_abuse(comment)
  70 + assert !link
  71 + end
  72 +
  73 + should 'return link for mark comment as spam' do
  74 + comment = Comment.new
  75 + link = link_for_spam(comment)
  76 + assert_match /Mark as SPAM/, link[:link]
  77 + end
  78 +
  79 + should 'return link for mark comment as not spam' do
  80 + comment = Comment.new
  81 + comment.spam = true
  82 + link = link_for_spam(comment)
  83 + assert_match /Mark as NOT SPAM/, link[:link]
  84 + end
  85 +
  86 + should 'do not return link for edit comment' do
  87 + comment = Comment.new
  88 + link = link_for_edit(comment)
  89 + assert !link
  90 + end
  91 +
  92 + should 'return link for edit comment' do
  93 + comment = Comment.new
  94 + comment.author = user
  95 + link = link_for_edit(comment)
  96 + assert link
  97 + end
  98 +
  99 + def link_to_function(content, url, options = {})
  100 + link_to(content, url, options)
  101 + end
  102 +
  103 +end
  104 +