caboose-cms 0.4.151 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/caboose/admin_products.js +79 -0
  3. data/app/assets/javascripts/caboose/application.js +2 -1
  4. data/app/assets/javascripts/caboose/cart.js +168 -0
  5. data/app/assets/javascripts/caboose/checkout.js +151 -0
  6. data/app/assets/javascripts/caboose/checkout_module.js +312 -0
  7. data/app/assets/javascripts/caboose/checkout_step1.js +179 -0
  8. data/app/assets/javascripts/caboose/checkout_step2.js +39 -0
  9. data/app/assets/javascripts/caboose/checkout_step3.js +34 -0
  10. data/app/assets/javascripts/caboose/checkout_step4.js +97 -0
  11. data/app/assets/javascripts/caboose/main.js +99 -8
  12. data/app/assets/javascripts/caboose/product.js +284 -0
  13. data/app/assets/stylesheets/caboose/admin_products.css +86 -0
  14. data/app/assets/templates/caboose/cart/add_to_cart.jst.ejs +7 -0
  15. data/app/assets/templates/caboose/cart/line_items.jst.ejs +41 -0
  16. data/app/assets/templates/caboose/checkout/address.jst.ejs +53 -0
  17. data/app/assets/templates/caboose/checkout/forms/guest.jst.ejs +8 -0
  18. data/app/assets/templates/caboose/checkout/forms/register.jst.ejs +11 -0
  19. data/app/assets/templates/caboose/checkout/forms/signin.jst.ejs +7 -0
  20. data/app/assets/templates/caboose/checkout/line_items.jst.ejs +31 -0
  21. data/app/assets/templates/caboose/checkout/login.jst.ejs +21 -0
  22. data/app/assets/templates/caboose/checkout/payment.jst.ejs +5 -0
  23. data/app/assets/templates/caboose/checkout/shipping.jst.ejs +18 -0
  24. data/app/assets/templates/caboose/product/images.jst.ejs +8 -0
  25. data/app/assets/templates/caboose/product/options.jst.ejs +19 -0
  26. data/app/controllers/caboose/application_controller.rb +29 -1
  27. data/app/controllers/caboose/cart_controller.rb +52 -0
  28. data/app/controllers/caboose/categories_controller.rb +108 -0
  29. data/app/controllers/caboose/checkout_controller.rb +325 -0
  30. data/app/controllers/caboose/orders_controller.rb +439 -0
  31. data/app/controllers/caboose/product_images_controller.rb +38 -0
  32. data/app/controllers/caboose/products_controller.rb +737 -0
  33. data/app/controllers/caboose/reviews_controller.rb +15 -0
  34. data/app/controllers/caboose/variants_controller.rb +218 -0
  35. data/app/controllers/caboose/vendors_controller.rb +73 -0
  36. data/app/helpers/caboose/application_helper.rb +4 -0
  37. data/app/helpers/caboose/categories_helper.rb +82 -0
  38. data/app/helpers/caboose/checkout_helper.rb +20 -0
  39. data/app/helpers/caboose/products_helper.rb +8 -0
  40. data/app/mailers/caboose/orders_mailer.rb +30 -0
  41. data/app/models/caboose/address.rb +26 -0
  42. data/app/models/caboose/category.rb +89 -0
  43. data/app/models/caboose/category_membership.rb +10 -0
  44. data/app/models/caboose/core_plugin.rb +15 -37
  45. data/app/models/caboose/customization_membership.rb +10 -0
  46. data/app/models/caboose/discount.rb +16 -0
  47. data/app/models/caboose/line_item.rb +81 -0
  48. data/app/models/caboose/message.rb +20 -0
  49. data/app/models/caboose/order.rb +191 -0
  50. data/app/models/caboose/order_discount.rb +10 -0
  51. data/app/models/caboose/order_pdf.rb +78 -0
  52. data/app/models/caboose/payment_processors/authorizenet.rb +53 -0
  53. data/app/models/caboose/payment_processors/base.rb +39 -0
  54. data/app/models/caboose/payment_processors/payscape.rb +94 -0
  55. data/app/models/caboose/product.rb +145 -0
  56. data/app/models/caboose/product_image.rb +62 -0
  57. data/app/models/caboose/product_image_variant.rb +10 -0
  58. data/app/models/caboose/review.rb +13 -0
  59. data/app/models/caboose/schema.rb +205 -1
  60. data/app/models/caboose/search_filter.rb +191 -0
  61. data/app/models/caboose/shipping_calculator.rb +81 -0
  62. data/app/models/caboose/states.rb +61 -52
  63. data/app/models/caboose/tax_calculator.rb +23 -0
  64. data/app/models/caboose/tax_line.rb +9 -0
  65. data/app/models/caboose/variant.rb +99 -0
  66. data/app/models/caboose/vendor.rb +22 -0
  67. data/app/views/caboose/cart/index.html.erb +8 -0
  68. data/app/views/caboose/categories/admin_edit.html.erb +79 -0
  69. data/app/views/caboose/categories/admin_index.html.erb +11 -0
  70. data/app/views/caboose/categories/admin_new.html.erb +62 -0
  71. data/app/views/caboose/checkout/_address_form.html.erb +111 -0
  72. data/app/views/caboose/checkout/_billing_form.html.erb +47 -0
  73. data/app/views/caboose/checkout/_cart.html.erb +52 -0
  74. data/app/views/caboose/checkout/_confirm.html.erb +61 -0
  75. data/app/views/caboose/checkout/_order_discount.html.erb +40 -0
  76. data/app/views/caboose/checkout/_shipping_address.html.erb +10 -0
  77. data/app/views/caboose/checkout/_shipping_method.html.erb +2 -0
  78. data/app/views/caboose/checkout/_shipping_method_form.html.erb +21 -0
  79. data/app/views/caboose/checkout/billing.html.erb +11 -0
  80. data/app/views/caboose/checkout/discount.html.erb +11 -0
  81. data/app/views/caboose/checkout/empty.html.erb +2 -0
  82. data/app/views/caboose/checkout/error.html.erb +2 -0
  83. data/app/views/caboose/checkout/index.html.erb +43 -0
  84. data/app/views/caboose/checkout/login.html.erb +2 -0
  85. data/app/views/caboose/checkout/payment.html.erb +79 -0
  86. data/app/views/caboose/checkout/relay.html.erb +23 -0
  87. data/app/views/caboose/checkout/relay_old.html.erb +12 -0
  88. data/app/views/caboose/checkout/relay_postMessage.html.erb +19 -0
  89. data/app/views/caboose/checkout/shipping.html.erb +15 -0
  90. data/app/views/caboose/checkout/step_four.html.erb +93 -0
  91. data/app/views/caboose/checkout/step_one.html.erb +56 -0
  92. data/app/views/caboose/checkout/step_one_old.html.erb +13 -0
  93. data/app/views/caboose/checkout/step_three.html.erb +23 -0
  94. data/app/views/caboose/checkout/step_two.html.erb +52 -0
  95. data/app/views/caboose/checkout/step_two_old.html.erb +14 -0
  96. data/app/views/caboose/checkout/thanks.html.erb +5 -0
  97. data/app/views/caboose/orders/_admin_footer.html.erb +2 -0
  98. data/app/views/caboose/orders/_admin_header.html.erb +31 -0
  99. data/app/views/caboose/orders/_quickbooks_order.html.erb +0 -0
  100. data/app/views/caboose/orders/admin_delete_form.html.erb +21 -0
  101. data/app/views/caboose/orders/admin_edit.html.erb +271 -0
  102. data/app/views/caboose/orders/admin_index.html.erb +89 -0
  103. data/app/views/caboose/orders/admin_new.html.erb +42 -0
  104. data/app/views/caboose/orders/admin_print.html.erb +72 -0
  105. data/app/views/caboose/orders_mailer/customer_new_order.html.erb +1 -0
  106. data/app/views/caboose/orders_mailer/customer_status_updated.html.erb +1 -0
  107. data/app/views/caboose/orders_mailer/fulfillment_new_order.html.erb +1 -0
  108. data/app/views/caboose/orders_mailer/shipping_order_ready.html.erb +1 -0
  109. data/app/views/caboose/products/_admin_footer.html.erb +2 -0
  110. data/app/views/caboose/products/_admin_header.html.erb +32 -0
  111. data/app/views/caboose/products/_sort_options.html.erb +19 -0
  112. data/app/views/caboose/products/admin_add_upcs.html.erb +58 -0
  113. data/app/views/caboose/products/admin_delete_form.html.erb +21 -0
  114. data/app/views/caboose/products/admin_edit_categories.html.erb +73 -0
  115. data/app/views/caboose/products/admin_edit_category_images.html.erb +233 -0
  116. data/app/views/caboose/products/admin_edit_description.html.erb +38 -0
  117. data/app/views/caboose/products/admin_edit_general.html.erb +104 -0
  118. data/app/views/caboose/products/admin_edit_images.html.erb +236 -0
  119. data/app/views/caboose/products/admin_edit_options.html.erb +51 -0
  120. data/app/views/caboose/products/admin_edit_seo.html.erb +37 -0
  121. data/app/views/caboose/products/admin_edit_variant_columns.html.erb +75 -0
  122. data/app/views/caboose/products/admin_edit_variant_sort_order.html.erb +63 -0
  123. data/app/views/caboose/products/admin_edit_variants.html.erb +171 -0
  124. data/app/views/caboose/products/admin_edit_variants_single.html.erb +68 -0
  125. data/app/views/caboose/products/admin_group_variants.html.erb +433 -0
  126. data/app/views/caboose/products/admin_index.html.erb +95 -0
  127. data/app/views/caboose/products/admin_new.html.erb +41 -0
  128. data/app/views/caboose/products/admin_sort.html copy.erb +155 -0
  129. data/app/views/caboose/products/admin_sort.html.erb +254 -0
  130. data/app/views/caboose/products/details.html.erb +438 -0
  131. data/app/views/caboose/products/index.html.erb +46 -0
  132. data/app/views/caboose/products/not_available.html.erb +35 -0
  133. data/app/views/caboose/variants/admin_edit.html.erb +82 -0
  134. data/app/views/caboose/variants/admin_group.html.erb +184 -0
  135. data/app/views/caboose/variants/admin_new.html.erb +59 -0
  136. data/app/views/caboose/vendors/admin_edit.html.erb +24 -0
  137. data/app/views/caboose/vendors/admin_index.html.erb +30 -0
  138. data/app/views/caboose/vendors/admin_new.html.erb +34 -0
  139. data/app/views/layouts/caboose/store/_banner.html.erb +10 -0
  140. data/app/views/layouts/caboose/store/_banner2.html.erb +10 -0
  141. data/app/views/layouts/caboose/store/_footer.html.erb +55 -0
  142. data/app/views/layouts/caboose/store/_header.html.erb +69 -0
  143. data/app/views/layouts/caboose/store/_sidebar.html.erb +27 -0
  144. data/app/views/layouts/caboose/store/application.html.erb +33 -0
  145. data/app/views/layouts/caboose/store/authorize_net.erb +18 -0
  146. data/app/views/layouts/caboose/store/layout_about.html.erb +42 -0
  147. data/app/views/layouts/caboose/store/layout_blog.html.erb +159 -0
  148. data/app/views/layouts/caboose/store/layout_confirm.html.erb +85 -0
  149. data/app/views/layouts/caboose/store/layout_contact.html.erb +38 -0
  150. data/app/views/layouts/caboose/store/layout_default.html.erb +10 -0
  151. data/app/views/layouts/caboose/store/layout_detail.html.erb +114 -0
  152. data/app/views/layouts/caboose/store/layout_order.html.erb +77 -0
  153. data/app/views/layouts/caboose/store/layout_pricing.html.erb +182 -0
  154. data/app/views/layouts/caboose/store/layout_product.html.erb +110 -0
  155. data/app/views/layouts/caboose/store/layout_profile.html.erb +55 -0
  156. data/app/views/layouts/caboose/store/layout_single.html.erb +3 -0
  157. data/app/views/layouts/caboose/store/layout_testimonial.html.erb +110 -0
  158. data/app/views/layouts/caboose/store/layout_testing.html.erb +4 -0
  159. data/config/routes.rb +126 -0
  160. data/lib/caboose.rb +46 -1
  161. data/lib/caboose/engine.rb +39 -1
  162. data/lib/caboose/version.rb +1 -1
  163. data/lib/tasks/caboose.rake +12 -0
  164. metadata +151 -4
  165. data/app/assets/javascripts/caboose/admin_page_edit_content_bak.js +0 -164
  166. data/app/assets/javascripts/caboose/model/#Untitled-1# +0 -2
@@ -0,0 +1,75 @@
1
+ <%
2
+ p = @product
3
+ %>
4
+ <%= render :partial => 'caboose/products/admin_header' %>
5
+
6
+ <p class='note'>Check which columns you want to show in the list of variants.</p>
7
+ <table>
8
+ <tr>
9
+ <td valign='top'>
10
+ <div id='variantcol_1_option1' ></div>
11
+ <div id='variantcol_1_option2' ></div>
12
+ <div id='variantcol_1_option3' ></div>
13
+ </td><td valign='top'>
14
+ <div id='variantcol_1_status' ></div>
15
+ <div id='variantcol_1_sku' ></div>
16
+ <div id='variantcol_1_barcode' ></div>
17
+ <div id='variantcol_1_price' ></div>
18
+ <div id='variantcol_1_quantity_in_stock' ></div>
19
+ </td><td valign='top'>
20
+ <div id='variantcol_1_weight' ></div>
21
+ <div id='variantcol_1_length' ></div>
22
+ <div id='variantcol_1_width' ></div>
23
+ <div id='variantcol_1_height' ></div>
24
+ <div id='variantcol_1_cylinder' ></div>
25
+ </td><td valign='top'>
26
+ <div id='variantcol_1_requires_shipping' ></div>
27
+ <div id='variantcol_1_allow_backorder' ></div>
28
+ <div id='variantcol_1_taxable' ></div>
29
+ </td>
30
+ </tr>
31
+ </table>
32
+ <div id='message'></div>
33
+ <p><input type='button' value='< Back' onclick="window.location='/admin/products/<%= p.id %>/variants';" /></p>
34
+
35
+ <%= render :partial => 'caboose/products/admin_footer' %>
36
+ <% content_for :caboose_js do %>
37
+ <script type='text/javascript'>
38
+
39
+ $(document).ready(function() {
40
+ <% p.variants.each do |v| %>
41
+ new ModelBinder({
42
+ name: 'VariantCol',
43
+ id: 1,
44
+ update_url: '/admin/products/<%= p.id %>/variant-cols',
45
+ authenticity_token: '<%= form_authenticity_token %>',
46
+ attributes: [
47
+ <% if p.option1 %>{ name: 'option1' , nice_name: <%= raw Caboose.json(p.option1) %> , type: 'checkbox', align: 'right', value: <%= @cols['option1' ] == true ? true : false %>, width: 150 },<% end %>
48
+ <% if p.option2 %>{ name: 'option2' , nice_name: <%= raw Caboose.json(p.option2) %> , type: 'checkbox', align: 'right', value: <%= @cols['option1' ] == true ? true : false %>, width: 150 },<% end %>
49
+ <% if p.option3 %>{ name: 'option3' , nice_name: <%= raw Caboose.json(p.option3) %> , type: 'checkbox', align: 'right', value: <%= @cols['option1' ] == true ? true : false %>, width: 150 },<% end %>
50
+ { name: 'status' , nice_name: 'Status' , type: 'checkbox', align: 'right', value: <%= @cols['status' ] == true ? true : false %>, width: 150 },
51
+ { name: 'sku' , nice_name: 'SKU' , type: 'checkbox', align: 'right', value: <%= @cols['sku' ] == true ? true : false %>, width: 150 },
52
+ { name: 'barcode' , nice_name: 'Barcode' , type: 'checkbox', align: 'right', value: <%= @cols['barcode' ] == true ? true : false %>, width: 150 },
53
+ { name: 'price' , nice_name: 'Price' , type: 'checkbox', align: 'right', value: <%= @cols['price' ] == true ? true : false %>, width: 150 },
54
+ { name: 'quantity_in_stock' , nice_name: 'Quantity' , type: 'checkbox', align: 'right', value: <%= @cols['quantity_in_stock'] == true ? true : false %>, width: 150 },
55
+ { name: 'weight' , nice_name: 'Weight (grams)' , type: 'checkbox', align: 'right', value: <%= @cols['weight' ] == true ? true : false %>, width: 175 },
56
+ { name: 'length' , nice_name: 'Length (in)' , type: 'checkbox', align: 'right', value: <%= @cols['length' ] == true ? true : false %>, width: 175 },
57
+ { name: 'width' , nice_name: 'Width (in)' , type: 'checkbox', align: 'right', value: <%= @cols['width' ] == true ? true : false %>, width: 175 },
58
+ { name: 'height' , nice_name: 'Height (in)' , type: 'checkbox', align: 'right', value: <%= @cols['height' ] == true ? true : false %>, width: 175 },
59
+ { name: 'cylinder' , nice_name: 'Cylinder' , type: 'checkbox', align: 'right', value: <%= @cols['cylinder' ] == true ? true : false %>, width: 175 },
60
+ { name: 'requires_shipping' , nice_name: 'Requires shipping' , type: 'checkbox', align: 'right', value: <%= @cols['requires_shipping'] == true ? true : false %>, width: 200 },
61
+ { name: 'taxable' , nice_name: 'Taxable' , type: 'checkbox', align: 'right', value: <%= @cols['taxable' ] == true ? true : false %>, width: 200 },
62
+ { name: 'allow_backorder' , nice_name: 'Allow backorder' , type: 'checkbox', align: 'right', value: <%= @cols['allow_backorder' ] == true ? true : false %>, width: 200 },
63
+
64
+ ]
65
+ });
66
+ <% end %>
67
+ });
68
+
69
+ var modal = false;
70
+ $(window).load(function() {
71
+ modal = new CabooseModal(800);
72
+ });
73
+
74
+ </script>
75
+ <% end %>
@@ -0,0 +1,63 @@
1
+ <%
2
+ p = @product
3
+ %>
4
+
5
+ <%= render :partial => 'caboose/products/admin_header' %>
6
+
7
+ <div id='options'>
8
+ <% if p.option1 %><div id='option1_container'><h2><%= p.option1 %></h2><ul id='option1'><% p.option1_values.each do |option| %><li id='values_<%= option %>'><%= option %></li><% end %></ul></div><% end %>
9
+ <% if p.option2 %><div id='option2_container'><h2><%= p.option2 %></h2><ul id='option2'><% p.option2_values.each do |option| %><li id='values_<%= option %>'><%= option %></li><% end %></ul></div><% end %>
10
+ <% if p.option3 %><div id='option3_container'><h2><%= p.option3 %></h2><ul id='option3'><% p.option3_values.each do |option| %><li id='values_<%= option %>'><%= option %></li><% end %></ul></div><% end %>
11
+ </div>
12
+
13
+ <div id='message'></div>
14
+
15
+ <%= render :partial => 'caboose/products/admin_footer' %>
16
+
17
+ <% content_for :caboose_css do %>
18
+ <style type='text/css'>
19
+ #options div { width: 33%; float: left; }
20
+ #options ul { margin: 0 10px 0 0; padding: 0; list-style: none; }
21
+ #options li { margin: 0; padding: 4px 8px; list-style: none; border: #ccc 1px solid; }
22
+ #message { clear: left; }
23
+ </style>
24
+ <% end %>
25
+
26
+ <% content_for :caboose_js do %>
27
+ <script type='text/javascript'>
28
+
29
+ $(document).ready(function() {
30
+ $('#option1').sortable({
31
+ update: function(event, ui) {
32
+ $.ajax({
33
+ url: '/admin/products/<%= p.id %>/variants/option1-sort-order',
34
+ type: 'put',
35
+ data: $('#option1').sortable('serialize'),
36
+ success: function(resp) {}
37
+ });
38
+ }
39
+ });
40
+ $('#option2').sortable({
41
+ update: function(event, ui) {
42
+ $.ajax({
43
+ url: '/admin/products/<%= p.id %>/variants/option2-sort-order',
44
+ type: 'put',
45
+ data: $('#option2').sortable('serialize'),
46
+ success: function(resp) {}
47
+ });
48
+ }
49
+ });
50
+ $('#option3').sortable({
51
+ update: function(event, ui) {
52
+ $.ajax({
53
+ url: '/admin/products/<%= p.id %>/variants/option3-sort-order',
54
+ type: 'put',
55
+ data: $('#option3').sortable('serialize'),
56
+ success: function(resp) {}
57
+ });
58
+ }
59
+ });
60
+ });
61
+
62
+ </script>
63
+ <% end %>
@@ -0,0 +1,171 @@
1
+ <% content_for :caboose_css do %>
2
+ <style>
3
+ ul {
4
+ list-style-type: square;
5
+ padding: 0 0 0 24px;
6
+ margin: 12px 0 24px;
7
+ }
8
+ </style>
9
+ <% end %>
10
+
11
+ <%
12
+ p = @product
13
+ v = @variant
14
+ %>
15
+
16
+ <%= render :partial => 'caboose/products/admin_header' %>
17
+
18
+ <p style='font-size: 75%;'><a href='/admin/products/<%= p.id %>/variant-cols'>Edit visible columns</a></p>
19
+
20
+ <div id='message'><%
21
+ # Make sure we're not trying to highlight a deleted variant
22
+ if @highlight_variant_id
23
+ v = Variant.where(:id => @highlight_variant_id).first
24
+ if v.nil?
25
+ %><p class='note error'>The variant you want to highlight is not in the database.</p><%
26
+ elsif v.status == 'Deleted'
27
+ %><p class='note error'>The variant you want to highlight has been deleted.</p><%
28
+ end
29
+ end
30
+ %></div>
31
+
32
+ <div id='variants_wrapper'>
33
+ <table id='variants'>
34
+ <tr>
35
+ <th>&nbsp;</th>
36
+ <% if @cols['option1' ] && p.option1 %><th valign='bottom'><%= p.option1 %></th><% end %>
37
+ <% if @cols['option2' ] && p.option2 %><th valign='bottom'><%= p.option2 %></th><% end %>
38
+ <% if @cols['option3' ] && p.option3 %><th valign='bottom'><%= p.option3 %></th><% end %>
39
+ <% if @cols['status' ] == true %><th valign='bottom'>Status </th><% end %>
40
+ <% if @cols['alternate_id' ] == true %><th valign='bottom'>Alternate ID </th><% end %>
41
+ <% if @cols['barcode' ] == true %><th valign='bottom'>Barcode </th><% end %>
42
+ <% if @cols['price' ] == true %><th valign='bottom'>Price </th><% end %>
43
+ <% if @cols['quantity_in_stock' ] == true %><th valign='bottom'>Quantity </th><% end %>
44
+ <% if @cols['weight' ] == true %><th valign='bottom'>Weight </th><% end %>
45
+ <% if @cols['length' ] == true %><th valign='bottom'>Length </th><% end %>
46
+ <% if @cols['width' ] == true %><th valign='bottom'>Width </th><% end %>
47
+ <% if @cols['height' ] == true %><th valign='bottom'>Height </th><% end %>
48
+ <% if @cols['cylinder' ] == true %><th valign='bottom'>Cylinder </th><% end %>
49
+ <% if @cols['requires_shipping' ] == true %><th valign='bottom'>Requires Shipping </th><% end %>
50
+ <% if @cols['allow_backorder' ] == true %><th valign='bottom'>Allow Backorder </th><% end %>
51
+ <% if @cols['taxable' ] == true %><th valign='bottom'>Taxable </th><% end %>
52
+ <th>&nbsp;</th>
53
+ <th>&nbsp;</th>
54
+ </tr>
55
+ <tbody id='variants_tbody'>
56
+ <% p.variants.where(:status => ['Active', 'Inactive']).each do |v| %>
57
+ <tr id='variant_<%= v.id %>' <% if @highlight_variant_id && v.id == @highlight_variant_id %>class='highlight'<% end %>>
58
+ <td class='sort_handle'>&nbsp;</td>
59
+ <% if @cols['option1' ] && p.option1 %><td><div id='variant_<%= v.id %>_option1' ></div></td><% end %>
60
+ <% if @cols['option2' ] && p.option2 %><td><div id='variant_<%= v.id %>_option2' ></div></td><% end %>
61
+ <% if @cols['option3' ] && p.option3 %><td><div id='variant_<%= v.id %>_option3' ></div></td><% end %>
62
+ <% if @cols['status' ] == true %><td><div id='variant_<%= v.id %>_status' ></div></td><% end %>
63
+ <% if @cols['alternate_id' ] == true %><td><div id='variant_<%= v.id %>_alternate_id' ></div></td><% end %>
64
+ <% if @cols['barcode' ] == true %><td><div id='variant_<%= v.id %>_barcode' ></div></td><% end %>
65
+ <% if @cols['price' ] == true %><td><div id='variant_<%= v.id %>_price' ></div></td><% end %>
66
+ <% if @cols['quantity_in_stock' ] == true %><td><div id='variant_<%= v.id %>_quantity_in_stock' ></div></td><% end %>
67
+ <% if @cols['weight' ] == true %><td><div id='variant_<%= v.id %>_weight' ></div></td><% end %>
68
+ <% if @cols['length' ] == true %><td><div id='variant_<%= v.id %>_length' ></div></td><% end %>
69
+ <% if @cols['width' ] == true %><td><div id='variant_<%= v.id %>_width' ></div></td><% end %>
70
+ <% if @cols['height' ] == true %><td><div id='variant_<%= v.id %>_height' ></div></td><% end %>
71
+ <% if @cols['cylinder' ] == true %><td><div id='variant_<%= v.id %>_cylinder' ></div></td><% end %>
72
+ <% if @cols['requires_shipping' ] == true %><td><div id='variant_<%= v.id %>_requires_shipping' ></div></td><% end %>
73
+ <% if @cols['allow_backorder' ] == true %><td><div id='variant_<%= v.id %>_allow_backorder' ></div></td><% end %>
74
+ <% if @cols['taxable' ] == true %><td><div id='variant_<%= v.id %>_taxable' ></div></td><% end %>
75
+ <td class='edit'><a href='/admin/products/<%= p.id %>/variants/<%= v.id %>/edit'>Edit</a></td>
76
+ <td class='delete'><a href='#' onclick='delete_variant(<%= v.id %>);'>Delete</a></td>
77
+ </tr>
78
+ <% end %>
79
+ </tbody>
80
+ </table>
81
+ </div>
82
+
83
+ <p><input type='button' value='New Variant' onclick="add_variant(<%= p.id %>);" /></p>
84
+
85
+ <form id="add-multiple" action="/admin/products/<%= @product.id %>/variants/add-multiple" method="post">
86
+ <p style="margin: 0 0 12px"><small>CSV format: Alternate ID, Quantity, Price<%= ', ' if @product.option1 || @product.option2 || @product.option3 %><%= [@product.option1, @product.option2, @product.option3].compact.join(', ') %></small></p>
87
+ <textarea id="variants_csv" name="variants_csv" rows="8" cols="12" style="min-width: 500px; min-height: 250px; margin: 0 0 16px; padding: 12px"></textarea><br />
88
+ <input type="submit" value="Submit" />
89
+ <p class="message" style="margin: 12px 0 0; color: red"></p>
90
+ </form>
91
+
92
+ <%= render :partial => 'caboose/products/admin_footer' %>
93
+
94
+ <% content_for :caboose_css do %>
95
+ <style type='text/css'>
96
+ tr.highlight td { background: #ffff99 }
97
+ td.sort_handle { background: #ccc; width: 20px; }
98
+ </style>
99
+ <% end %>
100
+
101
+ <% content_for :caboose_js do %>
102
+ <script type='text/javascript'>
103
+
104
+ $(document).ready(function() {
105
+ $('form#add-multiple').on('submit', function(event) {
106
+ event.preventDefault();
107
+ var $form = $(event.target);
108
+
109
+ $.ajax({
110
+ type: $form.attr('method'),
111
+ url: $form.attr('action'),
112
+ data: $form.serialize(),
113
+ success: function(response) {
114
+ console.log(response);
115
+ if (response.success) {
116
+ location.reload();
117
+ } else {
118
+ $form.find('.message').empty().text(response.error);
119
+ }
120
+ }
121
+ });
122
+ });
123
+
124
+ <% p.variants.each do |v| %>
125
+ new ModelBinder({
126
+ name: 'Variant',
127
+ id: <%= v.id %>,
128
+ update_url: '/admin/variants/<%= v.id %>',
129
+ authenticity_token: '<%= form_authenticity_token %>',
130
+ attributes: [
131
+ <% if @cols['option1' ] && p.option1 %>{ name: 'option1' , nice_name: <%= raw Caboose.json(p.option1) %> , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.option1 ) %>, width: 75, fixed_placeholder: false },<% end %>
132
+ <% if @cols['option2' ] && p.option2 %>{ name: 'option2' , nice_name: <%= raw Caboose.json(p.option2) %> , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.option2 ) %>, width: 75, fixed_placeholder: false },<% end %>
133
+ <% if @cols['option3' ] && p.option3 %>{ name: 'option3' , nice_name: <%= raw Caboose.json(p.option3) %> , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.option3 ) %>, width: 75, fixed_placeholder: false },<% end %>
134
+ <% if @cols['status' ] == true %>{ name: 'status' , nice_name: 'Status' , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.status ) %>, width: 75, fixed_placeholder: false },<% end %>
135
+ <% if @cols['alternate_id' ] == true %>{ name: 'alternate_id' , nice_name: 'Alternate ID' , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.alternate_id ) %>, width: 75, fixed_placeholder: false },<% end %>
136
+ <% if @cols['sku' ] == true %>{ name: 'sku' , nice_name: 'SKU' , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.sku ) %>, width: 75, fixed_placeholder: false },<% end %>
137
+ <% if @cols['barcode' ] == true %>{ name: 'barcode' , nice_name: 'Barcode' , type: 'text' , align: 'left' , value: <%= raw Caboose.json(v.barcode ) %>, width: 75, fixed_placeholder: false },<% end %>
138
+ <% if @cols['price' ] == true %>{ name: 'price' , nice_name: 'Price' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.price ) %>, width: 75, fixed_placeholder: false },<% end %>
139
+ <% if @cols['quantity_in_stock' ] == true %>{ name: 'quantity_in_stock' , nice_name: 'Quantity' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.quantity_in_stock ) %>, width: 50, fixed_placeholder: false },<% end %>
140
+ <% if @cols['weight' ] == true %>{ name: 'weight' , nice_name: 'Weight (grams)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.weight ) %>, width: 50, fixed_placeholder: false },<% end %>
141
+ <% if @cols['length' ] == true %>{ name: 'length' , nice_name: 'Length (in)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.length ) %>, width: 50, fixed_placeholder: false },<% end %>
142
+ <% if @cols['width' ] == true %>{ name: 'width' , nice_name: 'Width (in)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.width ) %>, width: 50, fixed_placeholder: false },<% end %>
143
+ <% if @cols['height' ] == true %>{ name: 'height' , nice_name: 'Height (in)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.height ) %>, width: 50, fixed_placeholder: false },<% end %>
144
+ <% if @cols['cylinder' ] == true %>{ name: 'cylinder' , nice_name: 'Cylinder' , type: 'checkbox' , align: 'center', value: <%= raw Caboose.json(v.cylinder ) %>, width: 50, fixed_placeholder: false },<% end %>
145
+ <% if @cols['requires_shipping' ] == true %>{ name: 'requires_shipping' , nice_name: 'Requires shipping' , type: 'checkbox' , align: 'center', value: <%= raw Caboose.json(v.requires_shipping ) %>, width: 50, fixed_placeholder: false },<% end %>
146
+ <% if @cols['taxable' ] == true %>{ name: 'taxable' , nice_name: 'Taxable' , type: 'checkbox' , align: 'center', value: <%= raw Caboose.json(v.taxable ) %>, width: 50, fixed_placeholder: false },<% end %>
147
+ <% if @cols['allow_backorder' ] == true %>{ name: 'allow_backorder' , nice_name: 'Allow backorder' , type: 'checkbox' , align: 'center', value: <%= raw Caboose.json(v.allow_backorder ) %>, width: 50, fixed_placeholder: false } <% end %>
148
+ ]
149
+ });
150
+ <% end %>
151
+
152
+ $('#variants_tbody').sortable({
153
+ handle: '.sort_handle',
154
+ update: function(event, ui) {
155
+ $.ajax({
156
+ url: '/admin/products/<%= p.id %>/variants/sort-order',
157
+ type: 'put',
158
+ data: $('#variants_tbody').sortable('serialize', { key: 'variant_ids[]' }),
159
+ success: function(resp) {}
160
+ });
161
+ }
162
+ });
163
+ });
164
+
165
+ var modal = false;
166
+ $(window).load(function() {
167
+ modal = new CabooseModal('100%');
168
+ });
169
+
170
+ </script>
171
+ <% end %>
@@ -0,0 +1,68 @@
1
+ <%
2
+ p = @product
3
+ v = @variant
4
+ %>
5
+ <%= render :partial => 'caboose/products/admin_header' %>
6
+
7
+ <p style='font-size: 75%;'><a href='/admin/products/<%= p.id %>/options'>Need options like color or size?</a></p>
8
+
9
+ <table>
10
+ <tr>
11
+ <td valign='top'>
12
+ <div id='variant_<%= v.id %>_alternate_id' ></div>
13
+ <div id='variant_<%= v.id %>_sku' ></div>
14
+ <div id='variant_<%= v.id %>_barcode' ></div>
15
+ <div id='variant_<%= v.id %>_price' ></div>
16
+ <div id='variant_<%= v.id %>_quantity_in_stock' ></div>
17
+ <div id='variant_<%= v.id %>_allow_backorder' ></div>
18
+ <div id='variant_<%= v.id %>_taxable' ></div>
19
+ </td><td valign='top'>
20
+ <div id='variant_<%= v.id %>_status' ></div>
21
+ <div id='variant_<%= v.id %>_requires_shipping' ></div>
22
+ <div id='variant_<%= v.id %>_weight' ></div>
23
+ <div id='variant_<%= v.id %>_cylinder' ></div>
24
+ <div id='variant_<%= v.id %>_length' ></div>
25
+ <div id='variant_<%= v.id %>_width' ></div>
26
+ <div id='variant_<%= v.id %>_height' ></div>
27
+ </td>
28
+ </tr>
29
+ </table>
30
+ <div id='message'></div>
31
+
32
+ <%= render :partial => 'caboose/products/admin_footer' %>
33
+
34
+ <% content_for :caboose_js do %>
35
+ <script type='text/javascript'>
36
+
37
+ $(document).ready(function() {
38
+ m = new ModelBinder({
39
+ name: 'Variant',
40
+ id: <%= v.id %>,
41
+ update_url: '/admin/variants/<%= v.id %>',
42
+ authenticity_token: '<%= form_authenticity_token %>',
43
+ attributes: [
44
+ { name: 'status' , nice_name: 'Status' , type: 'select' , align: 'right' , value: <%= raw Caboose.json(v.status ) %>, text: <%= raw Caboose.json(v.status) %>, width: 250, options_url: '/admin/variants/status-options' },
45
+ { name: 'alternate_id' , nice_name: 'Alternate ID' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.alternate_id ) %>, width: 250 },
46
+ { name: 'sku' , nice_name: 'SKU' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.sku ) %>, width: 250 },
47
+ { name: 'barcode' , nice_name: 'Barcode' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.barcode ) %>, width: 250 },
48
+ { name: 'price' , nice_name: 'Price' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(sprintf("%.2f", v.price || 0 ) ) %>, width: 250 },
49
+ { name: 'quantity_in_stock' , nice_name: 'Quantity' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.quantity_in_stock ) %>, width: 250 },
50
+ { name: 'weight' , nice_name: 'Weight (grams)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.weight ) %>, width: 250 },
51
+ { name: 'length' , nice_name: 'Length (in)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.length ) %>, width: 250 },
52
+ { name: 'width' , nice_name: 'Width (in)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.width ) %>, width: 250 },
53
+ { name: 'height' , nice_name: 'Height (in)' , type: 'text' , align: 'right' , value: <%= raw Caboose.json(v.height ) %>, width: 250 },
54
+ { name: 'cylinder' , nice_name: 'Cylinder' , type: 'checkbox' , align: 'right' , value: <%= raw Caboose.json(v.cylinder ) %>, width: 250 },
55
+ { name: 'requires_shipping' , nice_name: 'Requires shipping' , type: 'checkbox' , align: 'right' , value: <%= raw Caboose.json(v.requires_shipping ) %>, width: 250 },
56
+ { name: 'taxable' , nice_name: 'Taxable' , type: 'checkbox' , align: 'right' , value: <%= raw Caboose.json(v.taxable ) %>, width: 250 },
57
+ { name: 'allow_backorder' , nice_name: 'Allow backorder' , type: 'checkbox' , align: 'right' , value: <%= raw Caboose.json(v.allow_backorder ) %>, width: 250 }
58
+ ]
59
+ });
60
+ });
61
+
62
+ var modal = false;
63
+ $(window).load(function() {
64
+ modal = new CabooseModal(800);
65
+ });
66
+
67
+ </script>
68
+ <% end %>
@@ -0,0 +1,433 @@
1
+ <% content_for :caboose_css do %>
2
+ <style>
3
+
4
+ /**
5
+ * Sidebar
6
+ */
7
+
8
+ .sidebar { padding: 0 12px; }
9
+ .sidebar, .sidebar > section { overflow: hidden; }
10
+
11
+ .sidebar > aside {
12
+ float: left;
13
+ margin-right: 12px;
14
+ width: 300px;
15
+ }
16
+
17
+ /**
18
+ * Media
19
+ */
20
+
21
+ .media, .media > section { overflow: hidden; }
22
+
23
+ .media > aside {
24
+ float: left;
25
+ margin-right: 6px;
26
+ }
27
+
28
+ /**
29
+ * Forms
30
+ */
31
+
32
+ form { overflow: hidden; }
33
+ form *, button { outline: none !important; }
34
+ button { cursor: pointer; }
35
+
36
+ /* filters */
37
+
38
+ form#filters { display: none; }
39
+
40
+ form#filters fieldset {
41
+ border: none;
42
+ margin: 12px 0;
43
+ padding: 0;
44
+ }
45
+
46
+ form#filters select {
47
+ height: 350px;
48
+ padding: 6px;
49
+ }
50
+
51
+ form#filters label,
52
+ form#filters input[type=text],
53
+ form#filters select {
54
+ box-sizing: border-box;
55
+ display: block;
56
+ width: 100%;
57
+ }
58
+
59
+ form#filters label + input,
60
+ form#filters input + label,
61
+ form#filters label + select,
62
+ form#filters select + label { margin: 12px 0 0; }
63
+
64
+ input#category-filter,
65
+ input#vendor-filter { border-bottom: none; }
66
+
67
+ /*select#categories.filtered option { display: none; }
68
+ select#categories.filtered option.show { display: block; }*/
69
+
70
+ /* variants */
71
+
72
+ form#variants fieldset {
73
+ border: none;
74
+ margin: 0;
75
+ padding: 0;
76
+ }
77
+ form#variants fieldset + fieldset { margin: 24px 0 0; }
78
+
79
+ form#variants label {
80
+ background: #eee;
81
+ display: block;
82
+ margin: 0 0 12px;
83
+ padding: 12px;
84
+ }
85
+ form#variants label,
86
+ form#variants label * { cursor: pointer; }
87
+
88
+ form#variants input[type=checkbox] {
89
+ height: 16px;
90
+ left: auto;
91
+ position: relative;
92
+ top: auto;
93
+ }
94
+
95
+ form#variants ul.info {
96
+ font-size: 12px;
97
+ list-style-type: none;
98
+ padding: 0 0 0 12px;
99
+ }
100
+
101
+ form#variants ul.info li { margin: 0 0 6px; }
102
+
103
+ </style>
104
+ <% end %>
105
+
106
+ <%= render partial: 'caboose/products/admin_header' %>
107
+
108
+ <button id="toggle-filters">Toggle Filters</button>
109
+ <button id="toggle-info">Toggle Variant Info</button>
110
+
111
+ <div class="sidebar">
112
+ <aside>
113
+ <form id="filters" action="/admin/products/<%= @product.id %>/variants/group" method="get">
114
+ <h4><label for="title">Title</label></h4>
115
+ <input id="title" name="title" type="text" />
116
+
117
+ <h4><label for="categories">Categories</label></h4>
118
+ <input id="category-filter" type="text" autocomplete="off" />
119
+ <select id="categories" name="category_ids[]" multiple>
120
+
121
+ <% @categories.each do |category| %>
122
+ <option value="<%= category.id %>"
123
+ <%= 'selected="selected"' if params[:category_ids] and params[:category_ids].include?(category.id.to_s) %>
124
+ ><%= category.url.gsub('/products/', '') %></option>
125
+ <% end %>
126
+ </select>
127
+
128
+ <h4><label for="vendors">Vendors</label><h4>
129
+ <input id="vendor-filter" type="text" autocomplete="off" />
130
+ <select id="vendors" name="vendor_ids[]" multiple>
131
+ <% @vendors.each do |vendor| %>
132
+ <option value="<%= vendor.id %>"
133
+ <%= 'selected="selected"' if params[:vendor_ids] and params[:vendor_ids].include?(vendor.id.to_s) %>
134
+ ><%= vendor.name %></option>
135
+ <% end %>
136
+ </select>
137
+
138
+ <fieldset>
139
+ <input id="clear" type="button" value="Clear" />
140
+ <input type="submit" value="Filter" />
141
+ </fieldset>
142
+ </form>
143
+ </aside>
144
+
145
+ <section>
146
+ <h4>Variants</h4>
147
+
148
+ <% if @variants.any? %>
149
+ <form id="variants" action="/admin/products/<%= @product.id %>/variants/add" method="post" data-product-id="<%= @product.id %>">
150
+ <fieldset>
151
+ <input class="remove" type="button" value="Remove these variants" />
152
+ <input class="check" type="button" value="Toggle Variants" />
153
+ <input type="submit" value="Add To Product" />
154
+ </fieldset>
155
+
156
+ <fieldset>
157
+ <% @variants.each do |variant| %>
158
+ <label>
159
+ <div class="media">
160
+ <aside><input name="variant_ids[]" type="checkbox" value="<%= variant.id %>" /></aside>
161
+
162
+ <section>
163
+ <%= variant.product.title %>
164
+
165
+ <ul class="info">
166
+ <li><strong>SKU:</strong> <%= variant.sku %></li>
167
+ <li><strong>Vendor:</strong> <%= variant.product.vendor.name %></li>
168
+
169
+ <% if variant.option1 %>
170
+ <li><strong><%= variant.product.option1 %>:</strong> <%= variant.option1 %></li>
171
+ <% end %>
172
+
173
+ <% if variant.option2 %>
174
+ <li><strong><%= variant.product.option2 %>:</strong> <%= variant.option2 %></li>
175
+ <% end %>
176
+
177
+ <% if variant.option3 %>
178
+ <li><strong><%= variant.product.option3 %>:</strong> <%= variant.option3 %></li>
179
+ <% end %>
180
+ </ul>
181
+ </section>
182
+ </div>
183
+ </label>
184
+ <% end %>
185
+ </fieldset>
186
+
187
+ <fieldset>
188
+ <input class="remove" type="button" value="Remove these variants" />
189
+ <input class="check" type="button" value="Toggle Variants" />
190
+ <input type="submit" value="Add To Product" />
191
+ </fieldset>
192
+ </form>
193
+ <% else %>
194
+ <p>No variants to show.</p>
195
+ <% end %>
196
+ </section>
197
+ </div>
198
+
199
+ <%= render partial: 'caboose/products/admin_footer' %>
200
+
201
+ <% content_for :caboose_js do %>
202
+ <%= javascript_include_tag 'underscore' %>
203
+
204
+ <script>
205
+ window.count = <%= @variants.count %>;
206
+
207
+ // Define categories
208
+ window.categories = <%= @categories.collect { |category|
209
+ { id: category.id.to_s, url: category.url.gsub('/products/', ''), selected: false }
210
+ }.compact.to_json.html_safe %>;
211
+
212
+ // Define vendors
213
+ window.vendors = <%= @vendors.collect { |vendor|
214
+ { id: vendor.id.to_s, name: vendor.name, selected: false }
215
+ }.compact.to_json.html_safe %>;
216
+
217
+ $(document).ready(function() {
218
+
219
+ // Events
220
+ $('form#variants').on('submit', check_for_variants);
221
+ $('button#toggle-filters').on('click', toggle_filters);
222
+ $(document).on('click', '#categories option', persist_categories);
223
+ $(document).on('click', '#vendors option', persist_vendors);
224
+ $('input#category-filter').on('keyup', filter_categories);
225
+ $('input#vendor-filter').on('keyup', filter_vendors);
226
+ $('form#filters input#clear').on('click', clear_filters);
227
+ $('button#toggle-info').on('click', toggle_variant_info);
228
+ $('form#variants input.remove').on('click', remove_variants);
229
+ $('form#variants input.check').on('click', toggle_variants);
230
+
231
+ // Show filters if there are no variants
232
+ if (window.count == 0) toggle_filters();
233
+
234
+ // Check for filters to persist initially
235
+
236
+ $('#categories option:selected').each(function(value, option) {
237
+ window.categories[ _.indexOf(_.pluck(window.categories, 'id'), $(this).val()) ].selected = true;
238
+ });
239
+
240
+ $('#vendors option:selected').each(function(value, option) {
241
+ window.vendors[ _.indexOf(_.pluck(window.vendors, 'id'), $(this).val()) ].selected = true;
242
+ });
243
+ });
244
+
245
+ // submit form#variants
246
+ function check_for_variants(event) {
247
+ event.preventDefault();
248
+
249
+ var $form = $('form#variants');
250
+
251
+ if ($('input:checked', $form).length) {
252
+ $form.off('submit').submit();
253
+ } else {
254
+ alert('No variants selected');
255
+ }
256
+ }
257
+
258
+ // click button#toggle
259
+ function toggle_filters() {
260
+ $('form#filters').toggle();
261
+ }
262
+
263
+ // click #categories option
264
+ function persist_categories() {
265
+ var selected_ids = _.map($('#categories option:selected'), function(option) { return option.value })
266
+ , persisted_categories = _.where(window.categories, {selected: true})
267
+ , clicked_id = $(this).val()
268
+ , clicked_selected = $(this).prop('selected');
269
+
270
+ // Make sure the clicked_id is in the selected_ids selected or no
271
+ // It will be disabled if the selected status is false
272
+ if (!_.contains(selected_ids, clicked_id)) selected_ids.push(clicked_id);
273
+
274
+ // Set the selected status
275
+ _.each(persisted_categories, function(category) {
276
+
277
+ // Only change the selected status if it's listed on the page; for usability
278
+ if ($('#categories option[value=' + category.id + ']').length) {
279
+ category.selected = _.contains(selected_ids, category.id);
280
+ }
281
+ });
282
+
283
+ // For each selected ID set the selected status
284
+ _.each(selected_ids, function(id) {
285
+ var selected = id == clicked_id ? clicked_selected : true;
286
+ window.categories[ _.indexOf(_.pluck(window.categories, 'id'), id) ].selected = selected;
287
+ });
288
+ }
289
+
290
+ // click #vendors option
291
+ function persist_vendors() {
292
+ var selected_ids = _.map($('#vendors option:selected'), function(option) { return option.value })
293
+ , persisted_vendors = _.where(window.vendors, {selected: true})
294
+ , clicked_id = $(this).val()
295
+ , clicked_selected = $(this).prop('selected');
296
+
297
+ // Make sure the clicked_id is in the selected_ids selected or no
298
+ // It will be disabled if the selected status is false
299
+ if (!_.contains(selected_ids, clicked_id)) selected_ids.push(clicked_id);
300
+
301
+ // Set the selected status
302
+ _.each(persisted_vendors, function(vendor) {
303
+
304
+ // Only change the selected status if it's listed on the page; for usability
305
+ if ($('#vendors option[value=' + vendor.id + ']').length) {
306
+ vendor.selected = _.contains(selected_ids, vendor.id);
307
+ }
308
+ });
309
+
310
+ // For each selected ID set the selected status
311
+ _.each(selected_ids, function(id) {
312
+ var selected = id == clicked_id ? clicked_selected : true;
313
+ window.vendors[ _.indexOf(_.pluck(window.vendors, 'id'), id) ].selected = selected;
314
+ });
315
+ }
316
+
317
+ // keyup #category-filter
318
+ function filter_categories() {
319
+ var $categories = $('#categories');
320
+
321
+ // Get value to test against from input
322
+ var string = $('#category-filter').val().toLowerCase();
323
+
324
+ // Filter category names
325
+ var filtered_categories = _.filter(window.categories, function(category) {
326
+ return category.url.toLowerCase().indexOf(string) != -1;
327
+ });
328
+
329
+ // Empty category select box
330
+ $categories.empty();
331
+
332
+ // Append filtered category names
333
+ _.each(filtered_categories, function(category) {
334
+ var $option = $('<option/>');
335
+
336
+ // Add value and text
337
+ $option.val(category.id);
338
+ $option.text(category.url);
339
+
340
+ // Mark as selected if it was persisted
341
+ if (category.selected) $option.attr('selected', 'selected');
342
+
343
+ // Append to container
344
+ $categories.append($option);
345
+ });
346
+ }
347
+
348
+ // keyup #vendor-filter
349
+ function filter_vendors() {
350
+ var $vendors = $('#vendors');
351
+
352
+ // Get value to test against from input
353
+ var string = $('#vendor-filter').val().toLowerCase();
354
+
355
+ // Filter category names
356
+ var filtered_vendors = _.filter(window.vendors, function(vendor) {
357
+ return vendor.name.toLowerCase().indexOf(string) != -1;
358
+ });
359
+
360
+ // Empty category select box
361
+ $vendors.empty();
362
+
363
+ // Append filtered category names
364
+ _.each(filtered_vendors, function(vendor) {
365
+ var $option = $('<option/>');
366
+
367
+ // Add value and text
368
+ $option.val(vendor.id);
369
+ $option.text(vendor.name);
370
+
371
+ // Mark as selected if it was persisted
372
+ if (vendor.selected) $option.attr('selected', 'selected');
373
+
374
+ // Append to container
375
+ $vendors.append($option);
376
+ });
377
+ }
378
+
379
+ // form#filters input#clear
380
+ function clear_filters() {
381
+ var $filters = $('form#fitlers');
382
+
383
+ // Clear all textboxes
384
+ $('form#filters input[type=text]').val('');
385
+
386
+ // Clear all selects
387
+ $('form#filters option:selected').removeAttr('selected');
388
+
389
+ // Clear persisted options
390
+ _.each(window.categories, function(category) { category.selected = false });
391
+ _.each(window.vendors, function(vendor) { vendor.selected = false });
392
+ }
393
+
394
+ // click button#toggle-info
395
+ function toggle_variant_info() {
396
+ $('ul.info').toggle();
397
+ }
398
+
399
+ // click form#variants input.check
400
+ function toggle_variants() {
401
+ var $variants = $('form#variants input[type=checkbox]:checked');
402
+
403
+ // If there are checked checkboxes, uncheck them; Otherwise, check everything
404
+ if ($variants.length > 0) {
405
+ $variants.prop('checked', false)
406
+ } else {
407
+ $('form#variants input[type=checkbox]').prop('checked', true);
408
+ }
409
+ }
410
+
411
+ // click form#variants input.remove
412
+ function remove_variants() {
413
+ var confirmed = confirm('Are you sure you want remove these items?');
414
+
415
+ if (confirmed) {
416
+ var $variants = $('form#variants input[type=checkbox]:checked');
417
+
418
+ if ($variants.length > 0) {
419
+ $.ajax({
420
+ type: 'post',
421
+ url: '/admin/products/' + $('form#variants').data('product-id') + '/variants/remove',
422
+ data: $('form#variants').serialize(),
423
+ success: function(response) {
424
+ console.log('foobar');
425
+ }
426
+ })
427
+ } else {
428
+ alert('No variants selected');
429
+ }
430
+ }
431
+ }
432
+ </script>
433
+ <% end %>