]> source.dussan.org Git - redmine.git/commitdiff
Lists can be reordered with drag and drop (#12909).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 17 Apr 2016 07:40:39 +0000 (07:40 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 17 Apr 2016 07:40:39 +0000 (07:40 +0000)
git-svn-id: http://svn.redmine.org/redmine/trunk@15336 e93f8b46-1217-0410-a6f0-8f06a7374b81

14 files changed:
app/controllers/custom_fields_controller.rb
app/controllers/enumerations_controller.rb
app/controllers/issue_statuses_controller.rb
app/controllers/roles_controller.rb
app/controllers/trackers_controller.rb
app/helpers/application_helper.rb
app/views/custom_fields/_index.html.erb
app/views/custom_fields/index.html.erb
app/views/enumerations/index.html.erb
app/views/issue_statuses/index.html.erb
app/views/roles/index.html.erb
app/views/trackers/index.html.erb
public/javascripts/application.js
test/functional/trackers_controller_test.rb

index 3c2cf7cfa9db93fbc2e0812671a427cf9b96c26b..ab0d5019f9de4e8add7a89fb65b9f9e731fed77a 100644 (file)
@@ -54,11 +54,19 @@ class CustomFieldsController < ApplicationController
 
   def update
     if @custom_field.update_attributes(params[:custom_field])
-      flash[:notice] = l(:notice_successful_update)
       call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
-      redirect_back_or_default edit_custom_field_path(@custom_field)
+      respond_to do |format|
+        format.html {
+          flash[:notice] = l(:notice_successful_update)
+          redirect_back_or_default edit_custom_field_path(@custom_field)
+        }
+        format.js { render :nothing => true }
+      end
     else
-      render :action => 'edit'
+      respond_to do |format|
+        format.html { render :action => 'edit' }
+        format.js { render :nothing => true, :status => 422 }
+      end
     end
   end
 
index 05ca5152ad7c8c95986173118acc45dd5377b4b6..feb360398dd6bc79c0c19163a0bc1394d68c11fa 100644 (file)
@@ -57,10 +57,18 @@ class EnumerationsController < ApplicationController
 
   def update
     if @enumeration.update_attributes(params[:enumeration])
-      flash[:notice] = l(:notice_successful_update)
-      redirect_to enumerations_path
+      respond_to do |format|
+        format.html {
+          flash[:notice] = l(:notice_successful_update)
+          redirect_to enumerations_path
+        }
+        format.js { render :nothing => true }
+      end
     else
-      render :action => 'edit'
+      respond_to do |format|
+        format.html { render :action => 'edit' }
+        format.js { render :nothing => true, :status => 422 }
+      end
     end
   end
 
index 6d574fe87a5067c75f3ce34df1aedcbb522793a1..e49878f1dbf8eb3887b44147315b933dd80ceb83 100644 (file)
@@ -51,10 +51,18 @@ class IssueStatusesController < ApplicationController
   def update
     @issue_status = IssueStatus.find(params[:id])
     if @issue_status.update_attributes(params[:issue_status])
-      flash[:notice] = l(:notice_successful_update)
-      redirect_to issue_statuses_path(:page => params[:page])
+      respond_to do |format|
+        format.html {
+          flash[:notice] = l(:notice_successful_update)
+          redirect_to issue_statuses_path(:page => params[:page])
+        }
+        format.js { render :nothing => true }
+      end
     else
-      render :action => 'edit'
+      respond_to do |format|
+        format.html { render :action => 'edit' }
+        format.js { render :nothing => true, :status => 422 }
+      end
     end
   end
 
index 2732a89a11a643845c5aed74816b771c057faddf..2de185b5b60876e737c6c966d8560db22ee3fd51 100644 (file)
@@ -72,10 +72,18 @@ class RolesController < ApplicationController
 
   def update
     if @role.update_attributes(params[:role])
-      flash[:notice] = l(:notice_successful_update)
-      redirect_to roles_path(:page => params[:page])
+      respond_to do |format|
+        format.html {
+          flash[:notice] = l(:notice_successful_update)
+          redirect_to roles_path(:page => params[:page])
+        }
+        format.js { render :nothing => true }
+      end
     else
-      render :action => 'edit'
+      respond_to do |format|
+        format.html { render :action => 'edit' }
+        format.js { render :nothing => true, :status => 422 }
+      end
     end
   end
 
index 91784d16efb243806cb1d0541fe8905fe377e819..2b93753d008a317d1d47a21f74cd50bebd86070f 100644 (file)
@@ -59,12 +59,22 @@ class TrackersController < ApplicationController
   def update
     @tracker = Tracker.find(params[:id])
     if @tracker.update_attributes(params[:tracker])
-      flash[:notice] = l(:notice_successful_update)
-      redirect_to trackers_path(:page => params[:page])
-      return
+      respond_to do |format|
+        format.html {
+          flash[:notice] = l(:notice_successful_update)
+          redirect_to trackers_path(:page => params[:page])
+        }
+        format.js { render :nothing => true }
+      end
+    else
+      respond_to do |format|
+        format.html {
+          edit
+          render :action => 'edit'
+        }
+        format.js { render :nothing => true, :status => 422 }
+      end
     end
-    edit
-    render :action => 'edit'
   end
 
   def destroy
index f0910379184dfdd4510c330852656f7f41b86578..4d593485810883d61377cbd858d7146511165b2a 100644 (file)
@@ -468,6 +468,16 @@ module ApplicationHelper
             :title => l(:label_sort_lowest), :class => 'icon-only icon-move-bottom')
   end
 
+  def reorder_handle(object, options={})
+    data = {
+      :reorder_url => options[:url] || url_for(object),
+      :reorder_param => options[:param] || object.class.name.underscore
+    }
+    content_tag('span', '',
+      :class => "sort-handle ui-icon ui-icon-arrowthick-2-n-s",
+      :data => data)
+  end
+
   def breadcrumb(*args)
     elements = args.flatten
     elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil
index b0d3c277b20ae68c824c9e96162409998db50feb..7a5d372836c961e53a42ad7e692673d37a240eba 100644 (file)
@@ -1,4 +1,4 @@
-<table class="list">
+<table class="list custom_fields">
   <thead><tr>
     <th><%=l(:field_name)%></th>
     <th><%=l(:field_field_format)%></th>
@@ -7,7 +7,6 @@
       <th><%=l(:field_is_for_all)%></th>
       <th><%=l(:label_used_by)%></th>
     <% end %>
-    <th><%=l(:button_sort)%></th>
     <th></th>
   </tr></thead>
   <tbody>
@@ -21,8 +20,8 @@
       <td><%= checked_image custom_field.is_for_all? %></td>
       <td><%= l(:label_x_projects, :count => custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %></td>
       <% end %>
-      <td class="reorder"><%= reorder_links('custom_field', {:action => 'update', :id => custom_field, :back_url => back_url}, :put) %></td>
       <td class="buttons">
+        <%= reorder_handle(custom_field, :url => custom_field_path(custom_field), :param => 'custom_field') %>
         <%= delete_link custom_field_path(custom_field) %>
       </td>
     </tr>
index e4464132f51ebd29e7367b289202300d68a7a659..cf2193db52ae87668489901d47f9b6f249ef839f 100644 (file)
@@ -9,3 +9,7 @@
 <% else %>
   <p class="nodata"><%= l(:label_no_data) %></p>
 <% end %>
+
+<%= javascript_tag do %>
+  $(function() { $("table.custom_fields tbody").positionedItems(); });
+<% end %>
\ No newline at end of file
index d1fb9192636a442f39101e6cd8fc57400d9377fc..5f1d2eafbef390add8b47d47944e9e10bc21c375 100644 (file)
@@ -5,12 +5,11 @@
 
 <% enumerations = klass.shared %>
 <% if enumerations.any? %>
-<table class="list"><thead>
+<table class="list enumerations"><thead>
 <tr>
     <th><%= l(:field_name) %></th>
     <th><%= l(:field_is_default) %></th>
     <th><%= l(:field_active) %></th>
-    <th><%=l(:button_sort)%></th>
     <th></th>
 </tr></thead>
 <% enumerations.each do |enumeration| %>
     <td class="name"><%= link_to enumeration, edit_enumeration_path(enumeration) %></td>
     <td class="tick"><%= checked_image enumeration.is_default? %></td>
     <td class="tick"><%= checked_image enumeration.active? %></td>
-    <td class="reorder"><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}, :put) %></td>
-    <td class="buttons"><%= delete_link enumeration_path(enumeration) %></td>
+    <td class="buttons">
+      <%= reorder_handle(enumeration, :url => enumeration_path(enumeration), :param => 'enumeration') %>
+      <%= delete_link enumeration_path(enumeration) %>
+    </td>
 </tr>
 <% end %>
 </table>
@@ -30,3 +31,7 @@
 <% end %>
 
 <% html_title(l(:label_enumerations)) -%>
+
+<%= javascript_tag do %>
+  $(function() { $("table.enumerations tbody").positionedItems(); });
+<% end %>
\ No newline at end of file
index 59d6846914b611dadaf3f9cac020033c9b40ae79..8608402ca8c8efd4fd48f4d2dbf14cc241fd62ac 100644 (file)
@@ -5,14 +5,13 @@
 
 <h2><%=l(:label_issue_status_plural)%></h2>
 
-<table class="list">
+<table class="list issue_statuses">
   <thead><tr>
   <th><%=l(:field_status)%></th>
   <% if Issue.use_status_for_done_ratio? %>
   <th><%=l(:field_done_ratio)%></th>
   <% end %>
   <th><%=l(:field_is_closed)%></th>
-  <th><%=l(:button_sort)%></th>
   <th></th>
   </tr></thead>
   <tbody>
@@ -23,8 +22,8 @@
   <td><%= status.default_done_ratio %></td>
   <% end %>
   <td><%= checked_image status.is_closed? %></td>
-  <td class="reorder"><%= reorder_links('issue_status', {:action => 'update', :id => status, :page => params[:page]}, :put) %></td>
   <td class="buttons">
+    <%= reorder_handle(status) %>
     <%= delete_link issue_status_path(status) %>
   </td>
   </tr>
@@ -33,3 +32,7 @@
 </table>
 
 <% html_title(l(:label_issue_status_plural)) -%>
+
+<%= javascript_tag do %>
+  $(function() { $("table.issue_statuses tbody").positionedItems(); });
+<% end %>
index f9855f181467722b4320aae50c7e7c16063838fe..8f059648b4570071858b71a1f831ebe8cb1812c3 100644 (file)
@@ -5,22 +5,17 @@
 
 <h2><%=l(:label_role_plural)%></h2>
 
-<table class="list">
+<table class="list roles">
   <thead><tr>
     <th><%=l(:label_role)%></th>
-    <th><%=l(:button_sort)%></th>
   <th></th>
   </tr></thead>
   <tbody>
 <% for role in @roles %>
-  <tr class="<%= cycle("odd", "even") %>">
+  <tr class="<%= cycle("odd", "even") %> <%= role.builtin? ? "builtin" : "givable" %>">
   <td class="name"><%= content_tag(role.builtin? ? 'em' : 'span', link_to(role.name, edit_role_path(role))) %></td>
-  <td class="reorder">
-  <% unless role.builtin? %>
-    <%= reorder_links('role', {:action => 'update', :id => role, :page => params[:page]}, :put) %>
-  <% end %>
-  </td>
   <td class="buttons">
+    <%= reorder_handle(role) unless role.builtin? %>
     <%= link_to l(:button_copy), new_role_path(:copy => role), :class => 'icon icon-copy' %>
     <%= delete_link role_path(role) unless role.builtin? %>
   </td>
@@ -30,3 +25,7 @@
 </table>
 
 <% html_title(l(:label_role_plural)) -%>
+
+<%= javascript_tag do %>
+  $(function() { $("table.roles tbody").positionedItems({items: ".givable"}); });
+<% end %>
\ No newline at end of file
index 9dd253eccfe916f71ebf96a8145fe40c0ce2bf2c..5f40cf0ee818be696727d7716e0b3fe210fab49f 100644 (file)
@@ -5,11 +5,10 @@
 
 <h2><%=l(:label_tracker_plural)%></h2>
 
-<table class="list">
+<table class="list trackers">
   <thead><tr>
   <th><%=l(:label_tracker)%></th>
   <th></th>
-  <th><%=l(:button_sort)%></th>
   <th></th>
   </tr></thead>
   <tbody>
       </span>
     <% end %>
   </td>
-  <td class="reorder">
-    <%= reorder_links('tracker', {:action => 'update', :id => tracker, :page => params[:page]}, :put) %>
-  </td>
   <td class="buttons">
+    <%= reorder_handle(tracker) %>
     <%= delete_link tracker_path(tracker) %>
   </td>
   </tr>
@@ -35,3 +32,7 @@
 </table>
 
 <% html_title(l(:label_tracker_plural)) -%>
+
+<%= javascript_tag do %>
+  $(function() { $("table.trackers tbody").positionedItems(); });
+<% end %>
index 3409bc64c3db9a33d1997dac94f1e3356c44eb5d..f791addab585935a410e362676f59198e1c292c0 100644 (file)
@@ -590,6 +590,45 @@ function beforeShowDatePicker(input, inst) {
   $(input).datepicker("option", "defaultDate", default_date);
 }
 
+(function($){
+  $.fn.positionedItems = function(sortableOptions, options){
+    var settings = $.extend({
+      firstPosition: 1
+    }, options );
+
+    return this.sortable($.extend({
+      handle: ".sort-handle",
+      helper: function(event, ui){
+        ui.children().each(function(){
+          $(this).width($(this).width());
+        });
+        return ui;
+      },
+      update: function(event, ui) {
+        var sortable = $(this);
+        var url = ui.item.find(".sort-handle").data("reorder-url");
+        var param = ui.item.find(".sort-handle").data("reorder-param");
+        var data = {};
+        data[param] = {position: ui.item.index() + settings['firstPosition']};
+        $.ajax({
+          url: url,
+          type: 'put',
+          dataType: 'script',
+          data: data,
+          success: function(data){
+            sortable.children(":even").removeClass("even").addClass("odd");
+            sortable.children(":odd").removeClass("odd").addClass("even");
+          },
+          error: function(jqXHR, textStatus, errorThrown){
+            alert(jqXHR.status);
+            sortable.sortable("cancel");
+          }
+        });
+      },
+    }, sortableOptions));
+  }
+}( jQuery ));
+
 function initMyPageSortable(list, url) {
   $('#list-'+list).sortable({
     connectWith: '.block-receiver',
index f3d7a1c0f78bda617f7cd2ed033d84bd8f71af27..a2664f295f0fa6816f6a1aef7c581fbecfa5bd3a 100644 (file)
@@ -152,7 +152,7 @@ class TrackersControllerTest < ActionController::TestCase
 
   def test_move_lower
    tracker = Tracker.find_by_position(1)
-   put :update, :id => 1, :tracker => { :move_to => 'lower' }
+   put :update, :id => 1, :tracker => { :position => '2' }
    assert_equal 2, tracker.reload.position
   end