caboose-cms 0.5.64 → 0.5.66

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/caboose/admin.js +1 -1
  3. data/app/assets/javascripts/caboose/admin_edit_order.js +724 -0
  4. data/app/assets/javascripts/caboose/cart2.js +4 -4
  5. data/app/assets/javascripts/caboose/model/index_table.js +122 -80
  6. data/app/assets/stylesheets/caboose/admin_main.css +8 -0
  7. data/app/controllers/caboose/application_controller.rb +1 -1
  8. data/app/controllers/caboose/block_type_sources_controller.rb +1 -1
  9. data/app/controllers/caboose/block_types_controller.rb +1 -1
  10. data/app/controllers/caboose/calendars_controller.rb +1 -1
  11. data/app/controllers/caboose/cart_controller.rb +8 -1
  12. data/app/controllers/caboose/checkout_controller.rb +17 -9
  13. data/app/controllers/caboose/line_items_controller.rb +135 -0
  14. data/app/controllers/caboose/order_packages_controller.rb +304 -0
  15. data/app/controllers/caboose/orders_controller.rb +31 -74
  16. data/app/controllers/caboose/pages_controller.rb +2 -1
  17. data/app/controllers/caboose/product_images_controller.rb +11 -0
  18. data/app/controllers/caboose/products_controller.rb +25 -8
  19. data/app/controllers/caboose/shipping_addresses_controller.rb +46 -0
  20. data/app/controllers/caboose/shipping_packages_controller.rb +125 -54
  21. data/app/controllers/caboose/sites_controller.rb +2 -79
  22. data/app/controllers/caboose/smtp_controller.rb +52 -0
  23. data/app/controllers/caboose/store_controller.rb +94 -0
  24. data/app/controllers/caboose/vendors_controller.rb +25 -4
  25. data/app/models/caboose/address.rb +1 -3
  26. data/app/models/caboose/caboose_plugin.rb +1 -1
  27. data/app/models/caboose/category.rb +18 -0
  28. data/app/models/caboose/core_plugin.rb +21 -19
  29. data/app/models/caboose/order.rb +12 -7
  30. data/app/models/caboose/order_package.rb +5 -2
  31. data/app/models/caboose/order_transaction.rb +25 -0
  32. data/app/models/caboose/page.rb +1 -1
  33. data/app/models/caboose/schema.rb +50 -22
  34. data/app/models/caboose/shipping_calculator.rb +26 -30
  35. data/app/models/caboose/shipping_package.rb +45 -5
  36. data/app/models/caboose/store_config.rb +18 -6
  37. data/app/models/caboose/tax_calculator.rb +6 -5
  38. data/app/views/caboose/blocks/admin_edit.html.erb +1 -1
  39. data/app/views/caboose/line_items/admin_new.html.erb +100 -0
  40. data/app/views/caboose/orders/admin_edit.html.erb +21 -247
  41. data/app/views/caboose/orders/admin_edit_old.html.erb +155 -0
  42. data/app/views/caboose/orders/admin_new.html.erb +8 -23
  43. data/app/views/caboose/products/#Untitled-1# +0 -0
  44. data/app/views/caboose/products/admin_edit_images.html.erb +20 -4
  45. data/app/views/caboose/products/admin_index.html.erb +9 -3
  46. data/app/views/caboose/products/admin_sort.html.erb +138 -142
  47. data/app/views/caboose/roles/index.html.erb +1 -1
  48. data/app/views/caboose/shipping_packages/admin_edit.html.erb +52 -137
  49. data/app/views/caboose/shipping_packages/admin_index.html.erb +56 -19
  50. data/app/views/caboose/sites/_admin_header.html.erb +3 -5
  51. data/app/views/caboose/sites/admin_edit.html.erb +5 -3
  52. data/app/views/caboose/smtp/admin_edit.html.erb +41 -0
  53. data/app/views/caboose/station/index.html.erb +1 -1
  54. data/app/views/caboose/store/admin_edit.html.erb +96 -0
  55. data/app/views/caboose/vendors/admin_edit.html.erb +7 -3
  56. data/app/views/layouts/caboose/_station.html.erb +1 -1
  57. data/config/routes.rb +67 -25
  58. data/lib/caboose/engine.rb +1 -1
  59. data/lib/caboose/version.rb +1 -1
  60. metadata +28 -5
  61. data/app/views/caboose/shipping_packages/admin_new.html.erb +0 -33
  62. data/app/views/caboose/sites/admin_edit_smtp_config.html.erb +0 -51
  63. data/app/views/caboose/sites/admin_edit_store_config.html.erb +0 -77
@@ -0,0 +1,155 @@
1
+ <%
2
+ sa = @order.shipping_address
3
+ shipping_address = sa.address1
4
+ shipping_address << "<br />#{sa.address2}" if sa.address2 && sa.address2.length > 0
5
+ shipping_address << "<br />#{sa.city}, #{sa.state} #{sa.zip}"
6
+ captured = @order.financial_status == 'captured'
7
+ %>
8
+ <input type='hidden' name='order_id' id='order_id' value='<%= @order.id %>' />
9
+
10
+ <h1>Edit Order #<%= @order.id %></h1>
11
+
12
+ <table class='data'>
13
+ <tr>
14
+ <th><%= if @order.customer.nil? then 'Guest' else 'Customer' end %></th>
15
+ <th>Shipping Address</th>
16
+ <th>Shipping Method</th>
17
+ <th>Order Status</th>
18
+ <th>Payment Status</th>
19
+ <th>Transaction ID</th>
20
+ </tr>
21
+ <tr>
22
+ <td valign='top'>
23
+ <%= "#{@order.shipping_address.first_name} #{@order.shipping_address.last_name}" %><br />
24
+ <% if @order.customer %>
25
+ <a href="mailto:<%= "#{@order.customer.email}" %>"><%= "#{@order.customer.email}" %></a><br />
26
+ <% elsif @order.email %>
27
+ <a href="mailto:<%= @order.email %>"><%= @order.email %></a>
28
+ <% end %>
29
+ <%= @order.customer ? @order.customer.phone : @order.shipping_address.phone %>
30
+ </td>
31
+ <td valign='top'>
32
+ <%= "#{@order.shipping_address.first_name} #{@order.shipping_address.last_name}" %><br />
33
+ <%= raw shipping_address %>
34
+ </td>
35
+ <td valign='top' align='center'>
36
+ <% if @order.shipping_service_code %>
37
+ <%= @order.shipping_carrier %> <%= @order.shipping_service_name %>
38
+ <% else %>
39
+ Multiple packages
40
+ <% end %>
41
+ </td>
42
+ <td valign='top'>
43
+ <div id='order_<%= @order.id %>_status'></div>
44
+ </td>
45
+ <td valign='top' align='center'>
46
+ <%= @order.financial_status %>
47
+ <% if @order.financial_status == 'authorized' %>
48
+ for<br /><%= number_to_currency(@order.auth_amount) %>
49
+ <% end %>
50
+ </td>
51
+ <td valign="top" align='center'><%= @order.transaction_id %></td>
52
+ </tr>
53
+ </table><br />
54
+
55
+ <table class='data' width='100%'>
56
+ <tr>
57
+ <th>Package</th>
58
+ <th>Item</th>
59
+ <th>Status</th>
60
+ <th>Unit Price</th>
61
+ <th>Quantity</th>
62
+ <th>Subtotal</th>
63
+ </tr>
64
+ <% @order.packages.each do |op| %>
65
+ <% op.line_items.each_with_index do |li, i| %>
66
+ <tr>
67
+ <% if i == 0 %>
68
+ <td rowspan="<%= op.line_items.count %>">
69
+ <div id='orderpackage_<%= op.id %>_shipping_method_id'></div>
70
+ <div id='orderpackage_<%= op.id %>_status'></div>
71
+ </td>
72
+ <% end %>
73
+ <td>
74
+ <% if li.variant.nil? || li.variant.product.nil? %>
75
+ <% if li.variant.nil? %>
76
+ Unknown variant
77
+ <% else %>
78
+ <%= li.variant.sku %>
79
+ <% end %>
80
+ <% else %>
81
+ <a href='/admin/products/<%= li.variant.product.id %>/variants?highlight=<%= li.variant.id %>'><%= li.variant.product.title %></a><br />
82
+ <%= li.variant.sku %><br />
83
+ <%= li.variant.title %>
84
+ <% end %>
85
+ </td>
86
+ <td ><div id='lineitem_<%= li.id %>_status' ></div></td>
87
+ <td align='right'><%= number_to_currency(li.variant.price) %></td>
88
+ <td align='right'><% if captured %><%= li.quantity %><% else %><div id='lineitem_<%= li.id %>_quantity'></div><% end %></td>
89
+ <td align='right' id='li_<%= li.id %>_subtotal'><%= number_to_currency(li.price) %></td>
90
+ </tr>
91
+ <% end %>
92
+ <% end %>
93
+ <% @order.line_items.each do |li| %>
94
+ <% next if li.order_package_id %>
95
+ <tr>
96
+ <td><div id='assign_to_package'>Unpackaged! <a href='#' onclick="assign_to_package_form(<%= li.id %>);">Assign to package</a></div></td>
97
+ <td>
98
+ <% if li.variant.nil? || li.variant.product.nil? %>
99
+ <% if li.variant.nil? %>Unknown variant<% else %><%= li.variant.sku %><% end %>
100
+ <% else %>
101
+ <a href='/admin/products/<%= li.variant.product.id %>/variants?highlight=<%= li.variant.id %>'><%= li.variant.product.title %></a><br />
102
+ <%= li.variant.sku %><br />
103
+ <%= li.variant.title %>
104
+ <% end %>
105
+ </td>
106
+ <td ><div id='lineitem_<%= li.id %>_status' ></div></td>
107
+ <td align='right'><%= number_to_currency(li.variant.price) %></td>
108
+ <td align='right'><% if captured %><%= li.quantity %><% else %><div id='lineitem_<%= li.id %>_quantity'></div><% end %></td>
109
+ <td align='right' id='li_<%= li.id %>_subtotal'><%= number_to_currency(li.price) %></td>
110
+ </tr>
111
+ <% end %>
112
+ <tr><td colspan='5' align='right'>Subtotal </td><td align='right' id='subtotal' ><%= number_to_currency(@order.subtotal ) %></td></tr>
113
+ <tr><td colspan='5' align='right'>Tax </td><td align='right' id='tax' ><%= number_to_currency(@order.tax ) %></td></tr>
114
+ <tr><td colspan='5' align='right'><%= @order.shipping_service_code ? @order.shipping_service_code : '' %> Shipping &amp; Handling </td><td align='right' id='shipping'><%= number_to_currency(@order.shipping + @order.handling) %></td></tr>
115
+ <tr>
116
+ <td colspan='5' align='right'>Discount</td>
117
+ <td align='right'>
118
+ <% if captured && @order.discounts.any? %>
119
+ <%= number_to_currency(@order.amount_discounted || 0) %>
120
+ <% elsif @order.discounts.any? %>
121
+ <%= number_to_currency(@order.discounts.first.amount_current) %>
122
+ <% else %>
123
+ $0.00
124
+ <% end %>
125
+ </td>
126
+ </tr>
127
+ <tr><td colspan='5' align='right'>Total </td><td align='right' id='total' ><%= number_to_currency(@order.total ) %></td></tr>
128
+ </table>
129
+ <div id='message'></div>
130
+
131
+ <p>
132
+ <input type='button' value='< Back' onclick="window.location='/admin/orders';" />
133
+ <% if @order.financial_status == 'authorized' %>
134
+ <input type='button' value='Capture Funds' onclick="capture_funds(<%= @order.id %>);" />
135
+ <input type='button' value='Void' onclick="void_order(<%= @order.id %>);" />
136
+ <% end %>
137
+ <% if @order.financial_status == 'captured' %>
138
+ <input type='button' value='Refund' onclick="refund_order(<%= @order.id %>);" />
139
+ <% end %>
140
+ <input type='button' value='Resend Confirmation' onclick="resend_confirmation(<%= @order.id %>)" />
141
+ <input type='button' value='Print Order' onclick="print_order(<%= @order.id %>);" />
142
+
143
+ <% str = Caboose.plugin_hook('admin_edit_order_buttons', "", @order) %>
144
+ <% if str %><%= raw str %><% end %>
145
+ </p>
146
+
147
+ <% content_for :caboose_js do %>
148
+ <%= javascript_include_tag 'caboose/model/all' %>
149
+ <%= javascript_include_tag 'caboose/admin_edit_order' %>
150
+ <script type='text/javascript'>
151
+
152
+ var controller = new OrderController({ order_id: <%= raw Caboose.json(@order.id) %> });
153
+
154
+ </script>
155
+ <% end %>
@@ -1,13 +1,6 @@
1
1
  <h1>New Manual Order</h1>
2
2
 
3
- <p><select name='product_id' id='product_id' onchange='populate_variants();'>
4
- <option value=''>-- Select a product --</option>
5
- <% @products.each do |p| %>
6
- <option value='<%= p.id %>'><%= p.title %></option>
7
- <% end %>
8
- </select>
9
- <span id='variant_id_container'></span>
10
- </p>
3
+ <p>This will create a new order that you can populate and then send to the customer for payment.</p>
11
4
 
12
5
  <p>
13
6
  <input type='button' value='< Back' onclick="window.location='/admin/orders';" />
@@ -17,23 +10,15 @@
17
10
  <% content_for :caboose_js do %>
18
11
  <script type='text/javascript'>
19
12
 
20
- var modal = false;
21
- $(window).load(function() {
22
- modal = new CabooseModal('95%');
23
- });
24
-
25
- function populate_variants()
13
+ function create_order()
26
14
  {
27
- $('#variant_id_container').empty().append("<p class='loading'>Getting variants...</p>");
28
- var product_id = $('#product_id').val();
15
+ $('#message').empty().append("<p class='loading'>Creating order...</p>");
29
16
  $.ajax({
30
- url: '/admin/products/' + product_id + '/variants/json',
31
- success: function(variants) {
32
- var select = $('<select/>').attr('id', 'variant_id');
33
- $.each(variants, function(i, v) {
34
- select.append($('<option/>').val(v.id).html(v.title));
35
- });
36
- $('#variant_id_container').empty().append(select);
17
+ url: '/admin/orders',
18
+ type: 'post',
19
+ success: function(resp) {
20
+ if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
21
+ if (resp.redirect) window.location = resp.redirect;
37
22
  }
38
23
  });
39
24
  }
@@ -14,10 +14,12 @@ p = @product
14
14
 
15
15
  <div id='images'>
16
16
  <% if p.product_images.count > 0 %>
17
- <% p.product_images.each do |img| %>
18
- <% url = img.image.url(:tiny) %>
19
- <div id='img_<%= img.id %>_container'><a href="javascript:select_image(<%= img.id %>);"><img src='<%= url %>' width='75' /></a></div>
20
- <% end %>
17
+ <ul id='images_list' class='clearfix'>
18
+ <% p.product_images.reorder(:position).each do |img| %>
19
+ <% url = img.image.url(:tiny) %>
20
+ <li id='img_<%= img.id %>'><div id='img_<%= img.id %>_container'><a href="javascript:select_image(<%= img.id %>);"><img src='<%= url %>' width='75' /></a></div></li>
21
+ <% end %>
22
+ </ul>
21
23
  <% else %>
22
24
  <p>This product doesn't have any images yet.</p>
23
25
  <% end %>
@@ -34,6 +36,8 @@ p = @product
34
36
  #images div { display: inline-block; }
35
37
  #images div img { border: #000 4px solid; }
36
38
  #images div.selected img { border: #ff3333 4px solid; }
39
+ #images_list { list-style: none; margin: 0; padding: 0; }
40
+ #images_list li { list-style: none; margin: 0 10px 10px 0; padding: 0; float: left; }
37
41
  </style>
38
42
  <% end %>
39
43
  <% content_for :caboose_js do %>
@@ -43,6 +47,18 @@ $(document).ready(function() {
43
47
  <% if p.product_images.count > 0 %>
44
48
  select_image(<%= p.product_images[0].id %>);
45
49
  <% end %>
50
+ $('#images_list').sortable({
51
+ stop: function(e, ui) {
52
+ var arr = $('#images_list').sortable('toArray')
53
+ ids = $.map(arr, function(id, i) { return parseInt(id.replace('img_', '')); });
54
+ $.ajax({
55
+ url: '/admin/product-images/sort-order',
56
+ type: 'put',
57
+ data: { product_image_ids: ids },
58
+ success: function(resp) {}
59
+ });
60
+ }
61
+ });
46
62
  });
47
63
 
48
64
  variants = false;
@@ -7,9 +7,15 @@
7
7
  </p>
8
8
 
9
9
  <form action="/admin/products" method="get" id="search_form" style="margin: 0 0 12px">
10
- <input type="text" name="search_like" placeholder="Title or Vendor Name" value="<%= params[:search_like] %>" style="width: 350px" />
11
- <input type="submit" value="Search" />
12
- <input type="button" value="Clear" onclick="window.location='/admin/products'" />
10
+ <p><input type="text" name="search_like" placeholder="Title or Vendor Name" value="<%= params[:search_like] %>" style="width: 350px" /></p>
11
+ <p><select type="text" name="category_id" placeholder="Category" value="<%= params[:search_like] %>" style="width: 350px">
12
+ <option value=''>-- Category --</option>
13
+ <% @category_options.each do |cat| %><option value="<%= cat[:value] %>"<% if cat[:value] == params[:category_id] %> selected='true'<% end %>><%= cat[:text] %></option><% end %>
14
+ </select></p>
15
+ <p>
16
+ <input type="submit" value="Search" />
17
+ <input type="button" value="Clear" onclick="window.location='/admin/products'" />
18
+ </p>
13
19
  </form>
14
20
 
15
21
  <div id='products'></div>
@@ -11,8 +11,7 @@
11
11
  <input name="search" type="search" placeholder="Search for Products" />
12
12
 
13
13
  <select class="filter" name="vendor">
14
- <option value="">-- Filter by Vendor --</option>
15
-
14
+ <option value="">-- Filter by Vendor --</option>
16
15
  <% @vendors.each do |vendor| %>
17
16
  <option value="<%= vendor.id %>"><%= vendor.name %></option>
18
17
  <% end %>
@@ -31,157 +30,154 @@
31
30
  </section>
32
31
 
33
32
  <% content_for :caboose_js do %>
34
- <%= javascript_include_tag('underscore') %>
35
- <%= javascript_include_tag('caboose/jquery-ui') %>
33
+ <%= javascript_include_tag('underscore') %>
34
+ <script type='text/javascript'>
35
+ window.products = <%= @products.to_json.html_safe %>;
36
+ window.results = window.products; // Used to store filtered results
37
+
38
+ // Delay method
39
+ var delay = (function(){
40
+ var timer = 0;
41
+ return function(callback, ms){
42
+ clearTimeout (timer);
43
+ timer = setTimeout(callback, ms);
44
+ };
45
+ })();
46
+
47
+ // Filter
48
+ function filter(event) {
49
+ var $source = $('ul#source')
50
+ , $search = $('input[name=search]')
51
+ , search_string = $search.val() === $search.attr('placeholder') ? undefined : $search.val().trim().toUpperCase()
52
+ , vendor_id = $('select[name=vendor]').val();
36
53
 
37
- <script>
38
-
39
- window.products = <%= @products.to_json.html_safe %>;
40
- window.results = window.products; // Used to store filtered results
41
-
42
- // Delay method
43
- var delay = (function(){
44
- var timer = 0;
45
- return function(callback, ms){
46
- clearTimeout (timer);
47
- timer = setTimeout(callback, ms);
48
- };
49
- })();
50
-
51
- // Filter
52
- function filter(event) {
53
- var $source = $('ul#source')
54
- , $search = $('input[name=search]')
55
- , search_string = $search.val() === $search.attr('placeholder') ? undefined : $search.val().trim().toUpperCase()
56
- , vendor_id = $('select[name=vendor]').val();
57
-
58
- $source.empty();
59
-
60
- _.each(window.products, function(product) {
61
- if (!search_string && !vendor_id
62
- || search_string && product.title.toUpperCase().indexOf(search_string) > -1
63
- || vendor_id && product.vendor_id == vendor_id) {
64
- $source.append( $('<li/>').attr('data-id', product.id).text(product.title) );
65
- }
66
- });
54
+ $source.empty();
55
+
56
+ _.each(window.products, function(product) {
57
+ if (!search_string && !vendor_id
58
+ || search_string && product.title.toUpperCase().indexOf(search_string) > -1
59
+ || vendor_id && product.vendor_id == vendor_id) {
60
+ $source.append( $('<li/>').attr('data-id', product.id).text(product.title) );
67
61
  }
68
-
69
- function update(event) {
62
+ });
63
+ }
64
+
65
+ function update(event) {
66
+
67
+ // Send the ordered array to the server to make it official
68
+ $.ajax({
69
+ type: 'put',
70
+ url: '/admin/products/update-sort-order',
71
+ data: { product_ids: $('ul#target').sortable('toArray', { attribute: 'data-id' }) }
72
+ });
73
+ }
74
+
75
+ $(document).ready(function() {
76
+ var selected_class = 'selected';
77
+
78
+ // Selection rules
79
+ $('ul.sortable').on('click', 'li', function(event) {
80
+ $element = $(this);
81
+
82
+ if (event.shiftKey && $last_element) {
83
+ if ($element.index() < $last_element.index()) {
84
+ $element.nextUntil($last_element).addClass(selected_class);
85
+ } else {
86
+ $element.prevUntil($last_element).addClass(selected_class);
87
+ }
70
88
 
71
- // Send the ordered array to the server to make it official
72
- $.ajax({
73
- type: 'put',
74
- url: '/admin/products/update-sort-order',
75
- data: { product_ids: $('ul#target').sortable('toArray', { attribute: 'data-id' }) }
76
- });
89
+ $element.toggleClass(selected_class);
90
+ } else if (event.ctrlKey || event.metaKey) {
91
+ if ($element.hasClass(selected_class)) {
92
+ $element.removeClass(selected_class);
93
+ } else {
94
+ $element.addClass(selected_class);
95
+ }
96
+ } else {
97
+ $element.addClass(selected_class).siblings().removeClass(selected_class);
77
98
  }
78
99
 
79
- $(document).ready(function() {
80
- var selected_class = 'selected';
100
+ $last_element = $element;
101
+ });
102
+
103
+ // Setup sortable lists
104
+ $('ul#source').sortable({
105
+ delay: 150,
106
+ revert: 0,
107
+ connectWith: 'ul#target',
108
+
109
+ helper: function(event, item) {
81
110
 
82
- // Selection rules
83
- $('ul.sortable').on('click', 'li', function(event) {
84
- $element = $(this);
85
-
86
- if (event.shiftKey && $last_element) {
87
- if ($element.index() < $last_element.index()) {
88
- $element.nextUntil($last_element).addClass(selected_class);
89
- } else {
90
- $element.prevUntil($last_element).addClass(selected_class);
91
- }
92
-
93
- $element.toggleClass(selected_class);
94
- } else if (event.ctrlKey || event.metaKey) {
95
- if ($element.hasClass(selected_class)) {
96
- $element.removeClass(selected_class);
97
- } else {
98
- $element.addClass(selected_class);
99
- }
100
- } else {
101
- $element.addClass(selected_class).siblings().removeClass(selected_class);
102
- }
103
-
104
- $last_element = $element;
105
- });
111
+ // If the user just clicked and immediately drug an element
112
+ if ( !item.hasClass(selected_class) ) item.addClass(selected_class).siblings().removeClass(selected_class);
106
113
 
107
- // Setup sortable lists
108
- $('ul#source').sortable({
109
- delay: 150,
110
- revert: 0,
111
- connectWith: 'ul#target',
112
-
113
- helper: function(event, item) {
114
-
115
- // If the user just clicked and immediately drug an element
116
- if ( !item.hasClass(selected_class) ) item.addClass(selected_class).siblings().removeClass(selected_class);
117
-
118
- // Grab the selected elements and create the helper
119
- var elements = item.parent().children('.' + selected_class).clone()
120
- , helper = $('<li/>');
121
-
122
- // Add the elements to the item multidrag data attribute
123
- item.data('multidrag', elements).siblings('.' + selected_class);
124
-
125
- // Pass back the helper
126
- return helper.append(elements);
127
- },
128
-
129
- start: function(event, ui) {
130
-
131
- // Make sure the item stays visible on #source
132
- $(ui.item).show();
133
-
134
- // Clone the original item and note the previous one, to reappend after jquery ui takes it away
135
- item_clone = $(ui.item).clone();
136
- previous_item = $(ui.item).prev();
137
-
138
- // Remove selected status from ul#target
139
- $('ul#target li.selected').removeClass('selected');
140
- },
114
+ // Grab the selected elements and create the helper
115
+ var elements = item.parent().children('.' + selected_class).clone()
116
+ , helper = $('<li/>');
141
117
 
142
- beforeStop: function(event, ui) {
143
-
144
- if ($(ui.item).parent().attr('id') != 'source') {
145
-
146
- // Remove duplicate items from old positions
147
- ui.item.data('multidrag').each(function(index, element) {
148
- var $element = $(element);
149
- $('ul#target li[data-id=' + $element.attr('data-id') + ']').not('.selected').remove()
150
- });
151
- }
152
- },
153
-
154
- stop: function(event, ui) {
155
-
156
- if ($(ui.item).parent().attr('id') == 'source') return false;
157
-
158
- // Clear multidrag data
159
- ui.item.after( ui.item.data('multidrag') ).remove();
160
-
161
- // If the previous item is defined append the clone just after, otherwise prepend to #source
162
- if (previous_item.length) {
163
- previous_item.after(item_clone);
164
- } else {
165
- $('ul#source').prepend(item_clone);
166
- }
167
-
168
- // Update sort order
169
- update(event, ui);
170
- }
171
- });
118
+ // Add the elements to the item multidrag data attribute
119
+ item.data('multidrag', elements).siblings('.' + selected_class);
120
+
121
+ // Pass back the helper
122
+ return helper.append(elements);
123
+ },
124
+
125
+ start: function(event, ui) {
126
+
127
+ // Make sure the item stays visible on #source
128
+ $(ui.item).show();
129
+
130
+ // Clone the original item and note the previous one, to reappend after jquery ui takes it away
131
+ item_clone = $(ui.item).clone();
132
+ previous_item = $(ui.item).prev();
133
+
134
+ // Remove selected status from ul#target
135
+ $('ul#target li.selected').removeClass('selected');
136
+ },
137
+
138
+ beforeStop: function(event, ui) {
172
139
 
173
- // Update sort order when done sorting
174
- $('ul#target').sortable({ stop: update });
140
+ if ($(ui.item).parent().attr('id') != 'source') {
175
141
 
176
- // Filter when the vendor select box change
177
- $('select').on('change', filter);
142
+ // Remove duplicate items from old positions
143
+ ui.item.data('multidrag').each(function(index, element) {
144
+ var $element = $(element);
145
+ $('ul#target li[data-id=' + $element.attr('data-id') + ']').not('.selected').remove()
146
+ });
147
+ }
148
+ },
149
+
150
+ stop: function(event, ui) {
178
151
 
179
- // Filter, after a delay, when there is a keyup event in the search
180
- $('input[type=search]').on('keyup', function(event) {
181
- delay(function() { filter(event) }, 600);
182
- });
183
- });
184
- </script>
152
+ if ($(ui.item).parent().attr('id') == 'source') return false;
153
+
154
+ // Clear multidrag data
155
+ ui.item.after( ui.item.data('multidrag') ).remove();
156
+
157
+ // If the previous item is defined append the clone just after, otherwise prepend to #source
158
+ if (previous_item.length) {
159
+ previous_item.after(item_clone);
160
+ } else {
161
+ $('ul#source').prepend(item_clone);
162
+ }
163
+
164
+ // Update sort order
165
+ update(event, ui);
166
+ }
167
+ });
168
+
169
+ // Update sort order when done sorting
170
+ $('ul#target').sortable({ stop: update });
171
+
172
+ // Filter when the vendor select box change
173
+ $('select').on('change', filter);
174
+
175
+ // Filter, after a delay, when there is a keyup event in the search
176
+ $('input[type=search]').on('keyup', function(event) {
177
+ delay(function() { filter(event) }, 600);
178
+ });
179
+ });
180
+ </script>
185
181
  <% end %>
186
182
 
187
183
  <% content_for :caboose_css do %>