commontator 4.0.2 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -5
  3. data/app/assets/stylesheets/commontator/comments.css +16 -5
  4. data/app/assets/stylesheets/commontator/comments.css~ +98 -0
  5. data/app/controllers/commontator/application_controller.rb +6 -3
  6. data/app/controllers/commontator/application_controller.rb~ +30 -0
  7. data/app/controllers/commontator/threads_controller.rb +2 -0
  8. data/app/controllers/commontator/threads_controller.rb~ +44 -0
  9. data/app/helpers/commontator/threads_helper.rb +1 -8
  10. data/app/helpers/commontator/threads_helper.rb~ +11 -0
  11. data/app/mailers/commontator/subscriptions_mailer.rb +2 -4
  12. data/app/mailers/commontator/subscriptions_mailer.rb~ +50 -0
  13. data/app/models/commontator/comment.rb +23 -19
  14. data/app/models/commontator/comment.rb~ +106 -0
  15. data/app/models/commontator/thread.rb +10 -10
  16. data/app/models/commontator/thread.rb~ +124 -0
  17. data/app/views/commontator/comments/_show.html.erb +36 -34
  18. data/app/views/commontator/comments/_show.html.erb~ +47 -0
  19. data/app/views/commontator/comments/_votes.html.erb +6 -2
  20. data/app/views/commontator/comments/_votes.html.erb~ +61 -0
  21. data/app/views/commontator/comments/delete.js.erb +2 -2
  22. data/app/views/commontator/comments/delete.js.erb~ +17 -0
  23. data/app/views/commontator/comments/update.js.erb +2 -2
  24. data/app/views/commontator/comments/update.js.erb~ +7 -0
  25. data/app/views/commontator/subscriptions_mailer/comment_created.html.erb +2 -2
  26. data/app/views/commontator/subscriptions_mailer/comment_created.html.erb~ +6 -0
  27. data/app/views/commontator/threads/_show.html.erb +3 -7
  28. data/app/views/commontator/threads/_show.html.erb~ +58 -0
  29. data/config/initializers/commontator.rb +52 -47
  30. data/config/initializers/commontator.rb~ +176 -0
  31. data/lib/commontator.rb +6 -7
  32. data/lib/commontator.rb~ +61 -0
  33. data/lib/commontator/controller_includes.rb +1 -3
  34. data/lib/commontator/controller_includes.rb~ +22 -0
  35. data/lib/commontator/shared_helper.rb +3 -8
  36. data/lib/commontator/shared_helper.rb~ +37 -0
  37. data/lib/commontator/version.rb +1 -1
  38. data/lib/commontator/version.rb~ +3 -0
  39. data/spec/app/controllers/commontator/comments_controller_spec.rb +64 -45
  40. data/spec/app/controllers/commontator/comments_controller_spec.rb~ +580 -0
  41. data/spec/app/controllers/commontator/subscriptions_controller_spec.rb +3 -3
  42. data/spec/app/controllers/commontator/subscriptions_controller_spec.rb~ +99 -0
  43. data/spec/app/controllers/commontator/threads_controller_spec.rb +15 -9
  44. data/spec/app/controllers/commontator/threads_controller_spec.rb~ +126 -0
  45. data/spec/app/helpers/commontator/application_helper_spec.rb +1 -1
  46. data/spec/app/helpers/commontator/application_helper_spec.rb~ +9 -0
  47. data/spec/app/helpers/commontator/threads_helper_spec.rb +1 -5
  48. data/spec/app/helpers/commontator/threads_helper_spec.rb~ +13 -0
  49. data/spec/app/models/commontator/comment_spec.rb +4 -3
  50. data/spec/app/models/commontator/comment_spec.rb~ +62 -0
  51. data/spec/dummy/config/application.rb +1 -1
  52. data/spec/dummy/config/application.rb~ +27 -0
  53. data/spec/dummy/config/initializers/commontator.rb +67 -55
  54. data/spec/dummy/config/initializers/commontator.rb~ +176 -0
  55. data/spec/dummy/config/initializers/commontator2.rb~ +169 -0
  56. data/spec/dummy/db/test.sqlite3 +0 -0
  57. data/spec/dummy/log/test.log +84489 -0
  58. data/spec/dummy/tmp/cache/assets/test/sprockets/02d4b791eb831cf2057bf4703a1218d1 +0 -0
  59. data/spec/dummy/tmp/cache/assets/test/sprockets/0f196a1a50363b0a076ec6e1ee5417f6 +0 -0
  60. data/spec/dummy/tmp/cache/assets/test/sprockets/a41c8be5379abec3c0d0d98e2f0d5609 +0 -0
  61. data/spec/dummy/tmp/cache/assets/test/sprockets/e1f674c11941d62aac1764ef3a7134e4 +0 -0
  62. data/spec/dummy/tmp/cache/assets/test/sprockets/e85565206c3e5fdf9dfeb367c85557b1 +0 -0
  63. data/spec/lib/commontator/commontable_config_spec.rb +1 -1
  64. data/spec/lib/commontator/commontable_config_spec.rb~ +26 -0
  65. data/spec/lib/commontator/commontator_config_spec.rb +5 -5
  66. data/spec/lib/commontator/commontator_config_spec.rb~ +26 -0
  67. data/spec/lib/commontator_spec.rb +6 -4
  68. data/spec/lib/commontator_spec.rb~ +28 -0
  69. data/spec/test_helper.rb +4 -4
  70. data/spec/test_helper.rb~ +37 -0
  71. metadata +46 -2
@@ -0,0 +1,106 @@
1
+ module Commontator
2
+ class Comment < ActiveRecord::Base
3
+ belongs_to :creator, :polymorphic => true
4
+ belongs_to :editor, :polymorphic => true
5
+ belongs_to :thread
6
+
7
+ has_one :commontable, :through => :thread
8
+
9
+ validates_presence_of :creator, :on => :create
10
+ validates_presence_of :editor, :on => :update
11
+ validates_presence_of :thread
12
+ validates_presence_of :body
13
+
14
+ validates_uniqueness_of :body, :scope => [:creator_type, :creator_id, :thread_id],
15
+ :message => 'has already been posted'
16
+
17
+ protected
18
+
19
+ cattr_accessor :acts_as_votable_initialized
20
+
21
+ public
22
+
23
+ def is_votable?
24
+ return true if acts_as_votable_initialized
25
+ return false unless self.class.respond_to?(:acts_as_votable)
26
+ self.class.acts_as_votable
27
+ self.class.acts_as_votable_initialized = true
28
+ end
29
+
30
+ def get_vote_by(user)
31
+ return nil unless is_votable?
32
+ votes.where(:voter_type => user.class.name, :voter_id => user.id).first
33
+ end
34
+
35
+ def is_modified?
36
+ !editor.nil?
37
+ end
38
+
39
+ def is_deleted?
40
+ !deleted_at.blank?
41
+ end
42
+
43
+ def delete_by(user)
44
+ return false if is_deleted?
45
+ self.deleted_at = Time.now
46
+ self.editor = user
47
+ self.save
48
+ end
49
+
50
+ def undelete_by(user)
51
+ return false unless is_deleted?
52
+ self.deleted_at = nil
53
+ self.editor = user
54
+ self.save
55
+ end
56
+
57
+ def created_timestamp
58
+ config = thread.config
59
+ "#{config.comment_create_verb_past.capitalize} on " + \
60
+ created_at.strftime(config.timestamp_format)
61
+ end
62
+
63
+ def updated_timestamp
64
+ config = thread.config
65
+ is_modified? ? ("Last #{config.comment_edit_verb_past} on " + \
66
+ updated_at.strftime(config.timestamp_format)) : ''
67
+ end
68
+
69
+ ##################
70
+ # Access Control #
71
+ ##################
72
+
73
+ def can_be_read_by?(user)
74
+ ((!is_deleted? || thread.config.deleted_comments_are_visible) &&\
75
+ thread.can_be_read_by?(user)) ||\
76
+ thread.can_be_edited_by?(user)
77
+ end
78
+
79
+ def can_be_created_by?(user)
80
+ !thread.is_closed? && user == creator && thread.can_be_read_by?(user)
81
+ end
82
+
83
+ def can_be_edited_by?(user)
84
+ (!thread.is_closed? && !is_deleted? &&\
85
+ (thread.comments.last == self || thread.config.can_edit_old_comments) &&\
86
+ user == creator && thread.config.can_edit_own_comments && thread.can_be_read_by?(user)) ||\
87
+ (thread.config.admin_can_edit_comments && thread.can_be_edited_by?(user))
88
+ end
89
+
90
+ def can_be_deleted_by?(user)
91
+ (!thread.is_closed? && (!is_deleted? || editor == user) &&\
92
+ (thread.comments.last == self || thread.config.can_delete_old_comments) &&\
93
+ user == creator && thread.config.can_delete_own_comments &&\
94
+ thread.can_be_read_by?(user)) ||\
95
+ thread.can_be_edited_by?(user)
96
+ end
97
+
98
+ def can_be_voted_on?
99
+ !thread.is_closed? && is_votable? && !is_deleted? && thread.config.can_vote_on_comments
100
+ end
101
+
102
+ def can_be_voted_on_by?(user)
103
+ can_be_voted_on? && user && user.is_commontator && user != creator && thread.can_be_read_by?(user)
104
+ end
105
+ end
106
+ end
@@ -101,24 +101,24 @@ module Commontator
101
101
  # Access Control #
102
102
  ##################
103
103
 
104
- # Reader and poster capabilities
104
+ # Reader capabilities (user can be nil or false)
105
105
  def can_be_read_by?(user)
106
- (!commontable.nil? && \
107
- (!is_closed? || config.closed_threads_are_readable) && \
108
- config.can_read_thread_proc.call(self, user)) || \
109
- can_be_edited_by?(user)
106
+ (!commontable.nil? &&\
107
+ (!is_closed? || config.closed_threads_are_readable) &&\
108
+ config.can_read_thread_proc.call(self, user)) ||\
109
+ can_be_edited_by?(user)
110
110
  end
111
111
 
112
112
  # Thread moderator capabilities
113
113
  def can_be_edited_by?(user)
114
- (!commontable.nil? && \
115
- config.can_edit_thread_proc.call(self, user)) || \
116
- (!user.nil? && user.is_commontator && \
117
- user.commontator_config.user_admin_proc.call(user))
114
+ !commontable.nil? && user && user.is_commontator &&\
115
+ (user.commontator_config.user_admin_proc.call(user) ||\
116
+ config.can_edit_thread_proc.call(self, user))
118
117
  end
119
118
 
120
119
  def can_subscribe?(user)
121
- !commontable.nil? && config.can_subscribe_to_thread && !is_closed? && can_be_read_by?(user)
120
+ !is_closed? && user && user.is_commontator &&\
121
+ config.can_subscribe_to_thread && can_be_read_by?(user)
122
122
  end
123
123
  end
124
124
  end
@@ -0,0 +1,124 @@
1
+ module Commontator
2
+ class Thread < ActiveRecord::Base
3
+ belongs_to :closer, :polymorphic => true
4
+ belongs_to :commontable, :polymorphic => true
5
+
6
+ has_many :comments, :dependent => :destroy
7
+ has_many :subscriptions, :dependent => :destroy
8
+
9
+ validates_presence_of :commontable, :unless => :is_closed?
10
+ validates_uniqueness_of :commontable_id, :scope => :commontable_type, :allow_nil => true
11
+
12
+ def config
13
+ commontable.try(:commontable_config) || Commontator
14
+ end
15
+
16
+ def ordered_comments
17
+ (config.can_vote_on_comments && config.comments_ordered_by_votes) ? \
18
+ comments.order("cached_votes_down - cached_votes_up") : comments
19
+ end
20
+
21
+ def is_closed?
22
+ !closed_at.blank?
23
+ end
24
+
25
+ def subscribers
26
+ subscriptions.collect{|s| s.subscriber}
27
+ end
28
+
29
+ def active_subscribers
30
+ subscribers.select{|s| s.is_commontator && s.commontator_config.subscription_email_enable_proc.call(s)}
31
+ end
32
+
33
+ def subscription_for(subscriber)
34
+ return nil if subscriber.nil? || !subscriber.is_commontator
35
+ subscriber.subscriptions.where(:thread_id => self.id).first
36
+ end
37
+
38
+ def is_subscribed?(subscriber)
39
+ !subscription_for(subscriber).blank?
40
+ end
41
+
42
+ def subscribe(subscriber)
43
+ return false if is_subscribed?(subscriber) || !subscriber.is_commontator
44
+ subscription = Subscription.new
45
+ subscription.subscriber = subscriber
46
+ subscription.thread = self
47
+ subscription.save
48
+ end
49
+
50
+ def unsubscribe(subscriber)
51
+ subscription = subscription_for(subscriber)
52
+ return false if subscription.blank?
53
+ subscription.destroy
54
+ end
55
+
56
+ def add_unread_except_for(subscriber)
57
+ Subscription.transaction do
58
+ subscriptions.each{|s| s.add_unread unless s.subscriber == subscriber}
59
+ end
60
+ end
61
+
62
+ def mark_as_read_for(subscriber)
63
+ return if !subscription_for(subscriber)
64
+ subscription_for(subscriber).mark_as_read
65
+ end
66
+
67
+ def close(user = nil)
68
+ return false if is_closed?
69
+ self.closed_at = Time.now
70
+ self.closer = user
71
+ save
72
+ end
73
+
74
+ def reopen
75
+ return false unless is_closed? && !commontable.nil?
76
+ self.closed_at = nil
77
+ save
78
+ end
79
+
80
+ # Creates a new empty thread and assigns it to the commontable
81
+ # The old thread is kept in the database for archival purposes
82
+ def clear(user = nil)
83
+ return if commontable.blank?
84
+ new_thread = Thread.new
85
+ new_thread.commontable = commontable
86
+ with_lock do
87
+ self.commontable = nil
88
+ self.closed_at = Time.now
89
+ self.closer = user
90
+ save!
91
+ new_thread.save!
92
+ subscriptions.each do |s|
93
+ s.thread = new_thread
94
+ s.save!
95
+ s.mark_as_read
96
+ end
97
+ end
98
+ end
99
+
100
+ ##################
101
+ # Access Control #
102
+ ##################
103
+
104
+ # Reader capabilities (user can be nil or false)
105
+ def can_be_read_by?(user)
106
+ (!commontable.nil? &&\
107
+ (!is_closed? || config.closed_threads_are_readable) &&\
108
+ config.can_read_thread_proc.call(self, user)) ||\
109
+ can_be_edited_by?(user)
110
+ end
111
+
112
+ # Thread moderator capabilities
113
+ def can_be_edited_by?(user)
114
+ !commontable.nil? && user && user.is_commontator &&\
115
+ (user.commontator_config.user_admin_proc.call(user) ||\
116
+ config.can_edit_thread_proc.call(self, user))
117
+ end
118
+
119
+ def can_subscribe?(user)
120
+ can_be_read_by?(user) && !is_closed? && user &&\
121
+ user.is_commontator && config.can_subscribe_to_thread
122
+ end
123
+ end
124
+ end
@@ -4,41 +4,43 @@
4
4
  %>
5
5
 
6
6
  <div id="comment_<%= comment.id.to_s %>_div" class="comment">
7
- <span id="comment_<%= comment.id.to_s %>_commontator_span" class="comment_commontator">
8
- <% if !user.nil? && user.commontator_config.user_name_clickable %>
9
- <%= link_to commontator_name(comment.creator), main_app.polymorphic_path(comment.creator) %>
10
- <% else %>
11
- <%= commontator_name(comment.creator) %>
7
+ <div id="comment_<%= comment.id.to_s %>_top_div" class="comment_div">
8
+ <span id="comment_<%= comment.id.to_s %>_commontator_span" class="comment_commontator">
9
+ <% if user && user.commontator_config.user_name_clickable %>
10
+ <%= link_to commontator_name(comment.creator), main_app.polymorphic_path(comment.creator) %>
11
+ <% else %>
12
+ <%= commontator_name(comment.creator) %>
13
+ <% end %>
14
+ </span>
15
+ <span id="comment_<%= comment.id.to_s %>_actions_span" class="comment_actions">
16
+ <%= render :partial => 'commontator/comments/actions',
17
+ :locals => {:comment => comment,
18
+ :user => user} %>
19
+ </span>
20
+ </div>
21
+ <div id="comment_<%= comment.id.to_s %>_middle_div" class="comment_div">
22
+ <span id="comment_<%= comment.id.to_s %>_gravatar_image_span" class="comment_gravatar_image">
23
+ <%= commontator_gravatar_image comment.creator %>
24
+ </span>
25
+ <span id="comment_<%= comment.id.to_s %>_votes_span" class="comment_votes">
26
+ <%= render :partial => 'commontator/comments/votes',
27
+ :locals => {:comment => comment,
28
+ :user => user} %>
29
+ </span>
30
+ <div id="comment_<%= comment.id.to_s %>_body_div" class="comment_body">
31
+ <%= render :partial => 'commontator/comments/body',
32
+ :locals => {:comment => comment} %>
33
+ </div>
34
+ </div>
35
+ <div id="comment_<%= comment.id.to_s %>_bottom_div" class="comment_div">
36
+ <span id="comment_<%= comment.id.to_s %>_created_timestamp_span" class="comment_timestamp">
37
+ <%= comment.created_timestamp %>
38
+ </span>
39
+ <br/>
40
+ <span id="comment_<%= comment.id.to_s %>_updated_timestamp_span" class="comment_timestamp">
41
+ <% if comment.is_modified? %>
42
+ <%= comment.updated_timestamp %><%= " by #{commontator_name(comment.editor)}" %>
12
43
  <% end %>
13
- &nbsp;&nbsp;
14
- <span id="comment_<%= comment.id.to_s %>_timestamp_span" class="comment_timestamp">
15
- <%= comment.timestamp %><%= " by #{commontator_name(comment.editor)}" if comment.is_modified? %>
16
44
  </span>
17
- </span>
18
-
19
- <span id="comment_<%= comment.id.to_s %>_actions_span" class="comment_actions">
20
- <%= render :partial => 'commontator/comments/actions',
21
- :locals => {:comment => comment,
22
- :user => user} %>
23
- </span>
24
-
25
- <br clear="all"/>
26
-
27
- <span id="comment_<%= comment.id.to_s %>_gravatar_image_span" class="comment_gravatar_image">
28
- <%= commontator_gravatar_image comment.creator %>
29
- </span>
30
-
31
- <span id="comment_<%= comment.id.to_s %>_votes_span" class="comment_votes">
32
- <%= render :partial => 'commontator/comments/votes',
33
- :locals => {:comment => comment,
34
- :user => user} %>
35
- </span>
36
-
37
- <div id="comment_<%= comment.id.to_s %>_body_div" class="comment_body">
38
- <%= render :partial => 'commontator/comments/body',
39
- :locals => {:comment => comment} %>
40
45
  </div>
41
-
42
46
  </div>
43
-
44
- <br clear="all"/>
@@ -0,0 +1,47 @@
1
+ <% # Clients of this partial must supply the following variables:
2
+ # comment
3
+ # user
4
+ %>
5
+
6
+ <div id="comment_<%= comment.id.to_s %>_div" class="comment">
7
+ <div id="comment_<%= comment.id.to_s %>_top_div" class="comment_div">
8
+ <span id="comment_<%= comment.id.to_s %>_commontator_span" class="comment_commontator">
9
+ <% if user && user.commontator_config.user_name_clickable %>
10
+ <%= link_to commontator_name(comment.creator), main_app.polymorphic_path(comment.creator) %>
11
+ <% else %>
12
+ <%= commontator_name(comment.creator) %>
13
+ <% end %>
14
+ </span>
15
+ <span id="comment_<%= comment.id.to_s %>_actions_span" class="comment_actions">
16
+ <%= render :partial => 'commontator/comments/actions',
17
+ :locals => {:comment => comment,
18
+ :user => user} %>
19
+ </span>
20
+ </div>
21
+ <div id="comment_<%= comment.id.to_s %>_middle_div" class="comment_div">
22
+ <span id="comment_<%= comment.id.to_s %>_gravatar_image_span" class="comment_gravatar_image">
23
+ <%= commontator_gravatar_image comment.creator %>
24
+ </span>
25
+ <span id="comment_<%= comment.id.to_s %>_votes_span" class="comment_votes">
26
+ <%= render :partial => 'commontator/comments/votes',
27
+ :locals => {:comment => comment,
28
+ :user => user} %>
29
+ </span>
30
+ <div id="comment_<%= comment.id.to_s %>_body_div" class="comment_body">
31
+ <%= render :partial => 'commontator/comments/body',
32
+ :locals => {:comment => comment} %>
33
+ </div>
34
+ </div>
35
+ <div id="comment_<%= comment.id.to_s %>_bottom_div" class="comment_div">
36
+ <span id="comment_<%= comment.id.to_s %>_created_timestamp_span" class="comment_timestamp">
37
+ <%= comment.created_timestamp %>
38
+ </span>
39
+ <br/>
40
+ <span id="comment_<%= comment.id.to_s %>_updated_timestamp_span" class="comment_timestamp">
41
+ <% if comment.is_modified? %>
42
+ <%= comment.updated_timestamp %><%= " by #{commontator_name(comment.editor)}" %>
43
+ <% end %>
44
+ </span>
45
+ <% end %>
46
+ </div>
47
+ </div>
@@ -1,4 +1,4 @@
1
- <% # Clients of this partial must provide the following variable:
1
+ <% # Clients of this partial must provide the following variables:
2
2
  # comment
3
3
  # user
4
4
  %>
@@ -30,7 +30,11 @@
30
30
  </span>
31
31
 
32
32
  <span id="comment_<%= comment.id %>_vote_count_span" class="comment_vote_count">
33
- <p>+ <%= comment.upvotes.size %><br><br>- <%= comment.downvotes.size %></p>
33
+ <% if comment.thread.config.combine_upvotes_and_downvotes %>
34
+ <p><%= "%+d" % (comment.upvotes.size - comment.downvotes.size) %></p>
35
+ <% else %>
36
+ <p>+<%= comment.upvotes.size %>/-<%= comment.downvotes.size %></p>
37
+ <% end %>
34
38
  </span>
35
39
 
36
40
  <span id="comment_<%= comment.id %>_downvote_span" class="comment_downvote">
@@ -0,0 +1,61 @@
1
+ <% # Clients of this partial must provide the following variables:
2
+ # comment
3
+ # user
4
+ %>
5
+
6
+ <% if comment.can_be_voted_on? %>
7
+ <% can_vote = comment.can_be_voted_on_by?(user) %>
8
+ <% vote = comment.get_vote_by(user) %>
9
+
10
+ <span id="comment_<%= comment.id %>_upvote_span" class="comment_upvote">
11
+ <% if can_vote && (vote.blank? || !vote.vote_flag) %>
12
+ <%= form_tag commontator.upvote_comment_path(comment),
13
+ :method => :put,
14
+ :remote => true do %>
15
+ <%= image_submit_tag "commontator/upvote.png",
16
+ :onmouseover => "this.src='/assets/commontator/upvote_hover.png'",
17
+ :onmouseout => "this.src='/assets/commontator/upvote.png'" %>
18
+ <% end %>
19
+ <% elsif can_vote %>
20
+ <%= form_tag commontator.unvote_comment_path(comment),
21
+ :method => :put,
22
+ :remote => true do %>
23
+ <%= image_submit_tag "commontator/upvote_hover.png",
24
+ :onmouseover => "this.src='/assets/commontator/upvote.png'",
25
+ :onmouseout => "this.src='/assets/commontator/upvote_hover.png'" %>
26
+ <% end %>
27
+ <% else %>
28
+ <%= image_tag "commontator/upvote_hover.png" %>
29
+ <% end %>
30
+ </span>
31
+
32
+ <span id="comment_<%= comment.id %>_vote_count_span" class="comment_vote_count">
33
+ <% if comment.thread.config.combine_upvotes_and_downvotes %>
34
+ <p>+<%= "%+d" % (comment.upvotes.size - comment.downvotes.size) %></p>
35
+ <% else %>
36
+ <p>+<%= comment.upvotes.size %>/-<%= comment.downvotes.size %></p>
37
+ <% end %>
38
+ </span>
39
+
40
+ <span id="comment_<%= comment.id %>_downvote_span" class="comment_downvote">
41
+ <% if can_vote && (vote.blank? || vote.vote_flag) %>
42
+ <%= form_tag commontator.downvote_comment_path(comment),
43
+ :method => :put,
44
+ :remote => true do %>
45
+ <%= image_submit_tag "commontator/downvote.png",
46
+ :onmouseover => "this.src='/assets/commontator/downvote_hover.png'",
47
+ :onmouseout => "this.src='/assets/commontator/downvote.png'" %>
48
+ <% end %>
49
+ <% elsif can_vote %>
50
+ <%= form_tag commontator.unvote_comment_path(comment),
51
+ :method => :put,
52
+ :remote => true do %>
53
+ <%= image_submit_tag "commontator/downvote_hover.png",
54
+ :onmouseover => "this.src='/assets/commontator/downvote.png'",
55
+ :onmouseout => "this.src='/assets/commontator/downvote_hover.png'" %>
56
+ <% end %>
57
+ <% else %>
58
+ <%= image_tag "commontator/downvote_hover.png" %>
59
+ <% end %>
60
+ </span>
61
+ <% end %>