From 00cc1d5b918c13b9ec320f922aacf2b7c6cbabac Mon Sep 17 00:00:00 2001
From: Eric Davis <edavis@littlestreamsoftware.com>
Date: Fri, 25 Sep 2009 12:33:07 -0700
Subject: [PATCH] Add a second action menu to IssuesController#show. (#4331)

Will have the update, log time, watch, copy, etc buttons.  Had to rework
how the watchers button works since it requires a unique DOM id for the
Ajax response.  Also modified the WatchersController to be able to replace
multiple sections of the page, e.g. two Watch links.
---
 app/controllers/watchers_controller.rb      |   17 ++++++++++++++++-
 app/helpers/watchers_helper.rb              |   19 +++++++++++++++----
 app/views/issues/_action_menu.rhtml         |    9 +++++++++
 app/views/issues/show.rhtml                 |   12 ++++--------
 test/functional/watchers_controller_test.rb |   23 ++++++++++++++++++++++-
 5 files changed, 66 insertions(+), 14 deletions(-)
 create mode 100644 app/views/issues/_action_menu.rhtml

diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb
index 3d4ed54..694718e 100644
--- a/app/controllers/watchers_controller.rb
+++ b/app/controllers/watchers_controller.rb
@@ -72,9 +72,24 @@ private
   
   def set_watcher(user, watching)
     @watched.set_watcher(user, watching)
+    if params[:replace].present?
+      if params[:replace].is_a? Array
+        replace_ids = params[:replace]
+      else
+        replace_ids = [params[:replace]]
+      end
+    else
+      replace_ids = 'watcher'
+    end
     respond_to do |format|
       format.html { redirect_to :back }
-      format.js { render(:update) {|page| page.replace_html 'watcher', watcher_link(@watched, user)} }
+      format.js do
+        render(:update) do |page|
+          replace_ids.each do |replace_id|
+            page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids)
+          end
+        end
+      end
     end
   rescue ::ActionController::RedirectBackError
     render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true
diff --git a/app/helpers/watchers_helper.rb b/app/helpers/watchers_helper.rb
index 333b0d2..3529b8e 100644
--- a/app/helpers/watchers_helper.rb
+++ b/app/helpers/watchers_helper.rb
@@ -16,17 +16,28 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 module WatchersHelper
-  def watcher_tag(object, user)
-    content_tag("span", watcher_link(object, user), :id => 'watcher')
+
+  # 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
   
-  def watcher_link(object, user)
+  # Valid options
+  # * :replace - a string or array of element ids that will be
+  #   replaced
+  def watcher_link(object, user, options={:replace => 'watcher'})
     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}           
+           :object_id => object.id,
+           :replace => options[:replace]}
     link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
                    {:url => url},
                    :href => url_for(url),
diff --git a/app/views/issues/_action_menu.rhtml b/app/views/issues/_action_menu.rhtml
new file mode 100644
index 0000000..390488e
--- /dev/null
+++ b/app/views/issues/_action_menu.rhtml
@@ -0,0 +1,9 @@
+<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 => 'edit', :issue_id => @issue}, :class => 'icon icon-time-add' %>
+<% replace_watcher ||= 'watcher' %>
+<%= watcher_tag(@issue, User.current, {:id => replace_watcher, :replace => ['watcher','watcher2']}) %>
+<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
+<%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %>
+<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
+</div>
diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml
index 73262be..914e557 100644
--- a/app/views/issues/show.rhtml
+++ b/app/views/issues/show.rhtml
@@ -1,11 +1,4 @@
-<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 => 'edit', :issue_id => @issue}, :class => 'icon icon-time-add' %>
-<%= watcher_tag(@issue, User.current) %>
-<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
-<%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %>
-<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
-</div>
+<%= render :partial => 'action_menu' %>
 
 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
 
@@ -93,6 +86,9 @@
 <%= render :partial => 'history', :locals => { :journals => @journals } %>
 </div>
 <% end %>
+
+<%= render :partial => 'action_menu', :locals => {:replace_watcher => 'watcher2' } %>
+
 <div style="clear: both;"></div>
 
 <% if authorize_for('issues', 'edit') %>
diff --git a/test/functional/watchers_controller_test.rb b/test/functional/watchers_controller_test.rb
index d36f783..cf97788 100644
--- a/test/functional/watchers_controller_test.rb
+++ b/test/functional/watchers_controller_test.rb
@@ -47,6 +47,16 @@ class WatchersControllerTest < ActionController::TestCase
     end
     assert Issue.find(1).watched_by?(User.find(3))
   end
+
+  def test_watch_with_multiple_replacements
+    @request.session[:user_id] = 3
+    assert_difference('Watcher.count') do
+      xhr :post, :watch, :object_type => 'issue', :object_id => '1', :replace => ['watch_item_1','watch_item_2']
+      assert_response :success
+      assert_select_rjs :replace_html, 'watch_item_1'
+      assert_select_rjs :replace_html, 'watch_item_2'
+    end
+  end
   
   def test_unwatch
     @request.session[:user_id] = 3
@@ -57,7 +67,18 @@ class WatchersControllerTest < ActionController::TestCase
     end
     assert !Issue.find(1).watched_by?(User.find(3))
   end
-  
+
+  def test_unwatch_with_multiple_replacements
+    @request.session[:user_id] = 3
+    assert_difference('Watcher.count', -1) do
+      xhr :post, :unwatch, :object_type => 'issue', :object_id => '2', :replace => ['watch_item_1', 'watch_item_2']
+      assert_response :success
+      assert_select_rjs :replace_html, 'watch_item_1'
+      assert_select_rjs :replace_html, 'watch_item_2'
+    end
+    assert !Issue.find(1).watched_by?(User.find(3))
+  end
+
   def test_new_watcher
     @request.session[:user_id] = 2
     assert_difference('Watcher.count') do
-- 
1.6.5

