diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb
index 11699c35ef7f3541bc3c0cf674b6291b5c248179..a7a9abfdfe5bbccd5b9fd42601596cbf9042a894 100644
--- a/app/controllers/watchers_controller.rb
+++ b/app/controllers/watchers_controller.rb
@@ -78,23 +78,43 @@ private
     @watched.set_watcher(user, watching)
     if params[:replace].present?
       if params[:replace].is_a? Array
-        replace_ids = params[:replace]
+        replace_selectors = params[:replace]
       else
-        replace_ids = [params[:replace]]
+        replace_selectors = params[:replace].split(',').map(&:strip)
       end
     else
-      replace_ids = ['watcher']
+      replace_selectors = ['#watcher']
     end
+
+    watcher_partial = lambda do
+      render_to_string(:partial => 'watchers/watchers', :locals => {:watched => @watched})
+    end
+
     respond_to do |format|
       format.html { redirect_to :back }
       format.js do
         render(:update) do |page|
-          replace_ids.each do |replace_id|
-            case replace_id
-            when 'watchers'
-              page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}
+          replace_selectors.each do |selector|
+            next if selector.blank?
+
+            case selector
+            when '#watchers'
+              page.select('#watchers').each do |node|
+                node.update watcher_partial.call
+              end
             else
-              page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids)
+              page.select(selector).each do |node|
+                options = {:replace => replace_selectors}
+
+                last_selector = selector.split(' ').last
+                if last_selector.starts_with? '.'
+                  options[:class] = last_selector[1..-1]
+                elsif last_selector.starts_with? '#'
+                  options[:id] = last_selector[1..-1]
+                end
+
+                node.replace watcher_link(@watched, user, options)
+              end
             end
           end
         end
diff --git a/app/helpers/watchers_helper.rb b/app/helpers/watchers_helper.rb
index 2695ce9f63e6bc50dd17f7c3e88ab28e12e13d40..b336233d1fa356d36ee42f3cf2ff9796b4100ef6 100644
--- a/app/helpers/watchers_helper.rb
+++ b/app/helpers/watchers_helper.rb
@@ -17,32 +17,28 @@
 
 module WatchersHelper
 
-  # Valid options
-  # * :id - the element id
-  # * :replace - a string or array of element ids that will be
-  #   replaced
-  def watcher_tag(object, user, options={:replace => 'watcher'})
-    id = options[:id]
-    id ||= options[:replace] if options[:replace].is_a? String
-    content_tag("span", watcher_link(object, user, options), :id => id)
-  end
-  
-  # Valid options
-  # * :replace - a string or array of element ids that will be
-  #   replaced
-  def watcher_link(object, user, options={:replace => 'watcher'})
+  # Create a link to watch/unwatch object
+  #
+  # * :replace - a string or array of strings with css selectors that will be updated, whenever the watcher status is changed
+  def watcher_link(object, user, options = {:replace => '.watcher_link', :class => 'watcher_link'})
+    options = options.with_indifferent_access
+    raise ArgumentError, 'Missing :replace option in options hash' if options['replace'].blank?
+
     return '' unless user && user.logged? && object.respond_to?('watched_by?')
+
     watched = object.watched_by?(user)
     url = {:controller => 'watchers',
            :action => (watched ? 'unwatch' : 'watch'),
            :object_type => object.class.to_s.underscore,
            :object_id => object.id,
-           :replace => options[:replace]}
-    link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
-                   {:url => url},
-                   :href => url_for(url),
-                   :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off'))
-  
+           :replace => options.delete('replace')}
+
+    url_options = {:url => url}
+
+    html_options = options.merge(:href => url_for(url))
+    html_options[:class] += watched ? ' icon icon-fav' : ' icon icon-fav-off'
+
+    link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)), url_options, html_options)
   end
   
   # Returns a comma separated list of users watching the given object
diff --git a/app/views/boards/show.rhtml b/app/views/boards/show.rhtml
index c4a08b29b648ab08334cf7edcf6883ec67b040e5..595038e8094c4f252e97e228083a831ef3cb2f96 100644
--- a/app/views/boards/show.rhtml
+++ b/app/views/boards/show.rhtml
@@ -5,7 +5,7 @@
                           {:controller => 'messages', :action => 'new', :board_id => @board},
                           :class => 'icon icon-add',
                           :onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %>
-<%= watcher_tag(@board, User.current) %>
+  <%= watcher_link(@board, User.current) %>
 </div>
 
 <div id="add-message" style="display:none;">
diff --git a/app/views/issues/_action_menu.rhtml b/app/views/issues/_action_menu.rhtml
index 0ec82ecdee28bc0b0649bd638b2a83137f916583..b1af5785a740e88c3f657563accf8d395f415a16 100644
--- a/app/views/issues/_action_menu.rhtml
+++ b/app/views/issues/_action_menu.rhtml
@@ -1,8 +1,7 @@
 <div class="contextual">
 <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
 <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
-<% replace_watcher ||= 'watcher' %>
-<%= watcher_tag(@issue, User.current, {:id => replace_watcher, :replace => ['watchers','watcher','watcher2']}) %>
+<%= watcher_link(@issue, User.current, {:class => 'watcher_link', :replace => ['#watchers', '.watcher_link']}) %>
 <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
 <%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %>
 <%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %>
diff --git a/app/views/messages/show.rhtml b/app/views/messages/show.rhtml
index a27b5d1144a3ea45b1d56942ee853dcc8706c82a..1f3c7a1cd6006228d97b528d4fd1f1cf8711a0b6 100644
--- a/app/views/messages/show.rhtml
+++ b/app/views/messages/show.rhtml
@@ -2,7 +2,7 @@
                link_to(h(@board.name), {:controller => 'boards', :action => 'show', :project_id => @project, :id => @board}) %>
 
 <div class="contextual">
-    <%= watcher_tag(@topic, User.current) %>
+    <%= watcher_link(@topic, User.current) %>
     <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'quote', :id => @topic} }, :class => 'icon icon-comment') unless @topic.locked? %>
     <%= link_to(l(:button_edit), {:action => 'edit', :id => @topic}, :class => 'icon icon-edit') if @message.editable_by?(User.current) %>
     <%= link_to(l(:button_delete), {:action => 'destroy', :id => @topic}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del') if @message.destroyable_by?(User.current) %>
diff --git a/app/views/wiki/date_index.html.erb b/app/views/wiki/date_index.html.erb
index a0327cf4cb66a605089c4538329448643ef9585c..611f18b229d3db9937b6fec84dbf429cba510f83 100644
--- a/app/views/wiki/date_index.html.erb
+++ b/app/views/wiki/date_index.html.erb
@@ -1,5 +1,5 @@
 <div class="contextual">
-<%= watcher_tag(@wiki, User.current) %>
+  <%= watcher_link(@wiki, User.current) %>
 </div>
 
 <h2><%= l(:label_index_by_date) %></h2>
diff --git a/app/views/wiki/index.html.erb b/app/views/wiki/index.html.erb
index d42ee9662640ffc0b7cc8ab5b1b30fd968cd721c..e542085225b8475b5513767d0b427926eab1fcc9 100644
--- a/app/views/wiki/index.html.erb
+++ b/app/views/wiki/index.html.erb
@@ -1,5 +1,5 @@
 <div class="contextual">
-<%= watcher_tag(@wiki, User.current) %>
+  <%= watcher_link(@wiki, User.current) %>
 </div>
 
 <h2><%= l(:label_index_by_title) %></h2>
diff --git a/app/views/wiki/show.rhtml b/app/views/wiki/show.rhtml
index c17dd482405dc869b7867f9ad03d61f3a6af059c..dd3d00d0c987c407aa91b3ffeb67418cccb7eb7f 100644
--- a/app/views/wiki/show.rhtml
+++ b/app/views/wiki/show.rhtml
@@ -1,7 +1,7 @@
 <div class="contextual">
 <% if @editable %>
 <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) if @content.version == @page.content.version %>
-<%= watcher_tag(@page, User.current) %>
+<%= watcher_link(@page, User.current) %>
 <%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %>
 <%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %>
 <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') if @content.version == @page.content.version %>