caboose-cms 0.5.64 → 0.5.66

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 (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 %>