caboose-cms 0.5.151 → 0.5.152
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.
- checksums.yaml +8 -8
- data/app/controllers/caboose/categories_controller.rb +12 -0
- data/app/controllers/caboose/products_controller.rb +23 -20
- data/app/models/caboose/schema.rb +4 -9
- data/app/views/caboose/products/admin_sort.html.erb +72 -234
- data/config/routes.rb +14 -13
- data/lib/caboose/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NTZhNjlmYTMzZjhhNmZmM2RiMzM1YzI4Mzg5NGU5OTkxZWYxZDkwZg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzBhZTUzN2Y5NTMzNTVjYzY0MDdkNThlOGU5NzIyNGE3MmUzNTJhNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZGNhMmJlZjIzNmJjOTI4OTQ4MTU3MDdiZjNlMWEzNTFkZjU4NGUyMmM2MWU1
|
10
|
+
Njc0NmI1NWMxNmE5MmMzNjhkMTQyZjY1MmZlZjQwZTJlYjc4NjU0OTI2ODIy
|
11
|
+
MDI4YzVjMGM5NWQ2MTkwZjExZDdkNDZiNTk5YTJlYjA3Yjk4YTY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OWUyM2EyNWU1ZDc3Njg4YWM3ZmMxMTMzOTE3ZWI1YzIwYmUxNDhhOWQ3ZDg4
|
14
|
+
ZTVhNTQ3NjQwZDM5YTZhNzM1MGVlNjYxNTFiMDEyZDA1NzY5MWJkMTA0ZTE3
|
15
|
+
MDNlZTNkYjE5ODNhNTViNTEwNjgzYmRhNDBlYzBiN2U3Y2I0NzE=
|
@@ -134,6 +134,18 @@ module Caboose
|
|
134
134
|
admin_options_helper(c, "#{prefix} - ")
|
135
135
|
end
|
136
136
|
end
|
137
|
+
|
138
|
+
# GET /admin/categories/:category_id/products/json
|
139
|
+
def admin_category_products
|
140
|
+
query = ["select P.id, P.title from store_category_memberships CM
|
141
|
+
left join store_products P on P.id = CM.product_id
|
142
|
+
where CM.category_id = ?
|
143
|
+
order by CM.sort_order, P.title", params[:id]]
|
144
|
+
rows = ActiveRecord::Base.connection.select_rows(ActiveRecord::Base.send(:sanitize_sql_array, query))
|
145
|
+
arr = rows.collect{ |row| { :id => row[0], :title => row[1] }}
|
146
|
+
render :json => arr
|
147
|
+
end
|
148
|
+
|
137
149
|
end
|
138
150
|
end
|
139
151
|
|
@@ -74,12 +74,13 @@ module Caboose
|
|
74
74
|
'price_gte' => '',
|
75
75
|
'price_lte' => '',
|
76
76
|
'alternate_id' => '',
|
77
|
-
'search_like' => ''
|
78
|
-
|
77
|
+
'search_like' => '',
|
78
|
+
'cm_category_id' => cat.id # This filters the CategoryMembership object that we'll be sorting on
|
79
79
|
}, {
|
80
80
|
'model' => 'Caboose::Product',
|
81
|
-
'sort' => if params[:sort] then params[:sort] else 'store_products.sort_order' end,
|
82
|
-
#'sort' => if params[:sort] then params[:sort] else '
|
81
|
+
#'sort' => if params[:sort] then params[:sort] else 'store_products.sort_order' end,
|
82
|
+
#'sort' => if params[:sort] then params[:sort] else 'store_category_memberships.sort_order' end,
|
83
|
+
'sort' => 'store_category_memberships.sort_order',
|
83
84
|
'base_url' => url_without_params,
|
84
85
|
'items_per_page' => 15,
|
85
86
|
'use_url_params' => false,
|
@@ -89,15 +90,15 @@ module Caboose
|
|
89
90
|
},
|
90
91
|
|
91
92
|
'includes' => {
|
92
|
-
|
93
|
-
'category_id' => [ 'categories'
|
94
|
-
'category_name' => [ 'categories'
|
95
|
-
'vendor_id' => [ 'vendor'
|
96
|
-
'vendor_name' => [ 'vendor'
|
97
|
-
'vendor_status' => [ 'vendor'
|
98
|
-
'price_gte' => [ 'variants'
|
99
|
-
'price_lte' => [ 'variants'
|
100
|
-
'variant_status' => [ 'variants'
|
93
|
+
'cm_category_id' => [ 'category_memberships' , 'category_id' ],
|
94
|
+
'category_id' => [ 'categories' , 'id' ],
|
95
|
+
'category_name' => [ 'categories' , 'name' ],
|
96
|
+
'vendor_id' => [ 'vendor' , 'id' ],
|
97
|
+
'vendor_name' => [ 'vendor' , 'name' ],
|
98
|
+
'vendor_status' => [ 'vendor' , 'status' ],
|
99
|
+
'price_gte' => [ 'variants' , 'price' ],
|
100
|
+
'price_lte' => [ 'variants' , 'price' ],
|
101
|
+
'variant_status' => [ 'variants' , 'status' ]
|
101
102
|
}
|
102
103
|
})
|
103
104
|
|
@@ -467,17 +468,19 @@ module Caboose
|
|
467
468
|
|
468
469
|
# GET /admin/products/sort
|
469
470
|
def admin_sort
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
471
|
+
#@products = Product.active
|
472
|
+
#@vendors = Vendor.active
|
473
|
+
#@categories = Category.all
|
474
474
|
render :layout => 'caboose/admin'
|
475
475
|
end
|
476
476
|
|
477
|
-
# PUT /admin/products/
|
477
|
+
# PUT /admin/categories/:category_id/products/sort-order
|
478
478
|
def admin_update_sort_order
|
479
|
-
params[:
|
480
|
-
|
479
|
+
cat_id = params[:category_id]
|
480
|
+
params[:product_ids].each_with_index do |product_id, i|
|
481
|
+
cm = CategoryMembership.where(:category_id => cat_id, :product_id => product_id).first
|
482
|
+
cm.sort_order = i
|
483
|
+
cm.save
|
481
484
|
end
|
482
485
|
render :json => { :success => true }
|
483
486
|
end
|
@@ -69,8 +69,7 @@ class Caboose::Schema < Caboose::Utilities::Schema
|
|
69
69
|
:shipping_carrier ,
|
70
70
|
:shipping_service_code ,
|
71
71
|
:shipping_service_name ,
|
72
|
-
:transaction_id ,
|
73
|
-
:transaction_id ,
|
72
|
+
:transaction_id ,
|
74
73
|
:transaction_service ,
|
75
74
|
:amount_discounted ,
|
76
75
|
:auth_code ,
|
@@ -248,7 +247,8 @@ class Caboose::Schema < Caboose::Utilities::Schema
|
|
248
247
|
],
|
249
248
|
Caboose::CategoryMembership => [
|
250
249
|
[ :category_id , :integer ],
|
251
|
-
[ :product_id , :integer ]
|
250
|
+
[ :product_id , :integer ],
|
251
|
+
[ :sort_order , :integer , { :default => 0 }]
|
252
252
|
],
|
253
253
|
Caboose::CustomizationMembership => [
|
254
254
|
[ :product_id , :integer ],
|
@@ -483,12 +483,7 @@ class Caboose::Schema < Caboose::Utilities::Schema
|
|
483
483
|
[ :on_sale , :boolean , { :default => false }],
|
484
484
|
[ :allow_gift_wrap , :boolean , { :default => false }],
|
485
485
|
[ :gift_wrap_price , :decimal , { :precision => 8, :scale => 2 }]
|
486
|
-
],
|
487
|
-
Caboose::ProductCategorySort => [
|
488
|
-
[ :product_id , :integer ],
|
489
|
-
[ :category_id , :integer ],
|
490
|
-
[ :sort_order , :integer ]
|
491
|
-
],
|
486
|
+
],
|
492
487
|
Caboose::ProductImage => [
|
493
488
|
[ :product_id , :integer ],
|
494
489
|
[ :alternate_id , :string ],
|
@@ -1,250 +1,88 @@
|
|
1
1
|
<h1>Sort Products</h1>
|
2
2
|
|
3
|
-
<
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<input name="search" type="search" placeholder="Search for Products" />
|
12
|
-
|
13
|
-
<select class="filter" name="vendor">
|
14
|
-
<option value="">-- Filter by Vendor --</option>
|
15
|
-
<% @vendors.each do |vendor| %>
|
16
|
-
<option value="<%= vendor.id %>"><%= vendor.name %></option>
|
17
|
-
<% end %>
|
18
|
-
</select>
|
19
|
-
</aside>
|
20
|
-
|
21
|
-
<article>
|
22
|
-
<ul id="target" class="sortable">
|
23
|
-
<% @products.each do |product| %>
|
24
|
-
<li data-id="<%= product.id %>"><%= product.title %></li>
|
25
|
-
<% end %>
|
26
|
-
</ul>
|
27
|
-
|
28
|
-
<input id="submit" type="button" value="Apply" /><br />
|
29
|
-
</article>
|
30
|
-
</section>
|
3
|
+
<p><select id="category_id">
|
4
|
+
<option value="">-- Select a category --</option>
|
5
|
+
<% Caboose::Category.options(@site.id).each do |cat| %>
|
6
|
+
<option value='<%= cat[:value] %>'><%= cat[:text] %></option>
|
7
|
+
<% end %>
|
8
|
+
</select></p>
|
9
|
+
<div id='products'></div>
|
10
|
+
<div id='message'></div>
|
31
11
|
|
32
12
|
<% content_for :caboose_js do %>
|
33
|
-
<%= javascript_include_tag('underscore') %>
|
34
13
|
<script type='text/javascript'>
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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();
|
53
|
-
|
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) );
|
61
|
-
}
|
14
|
+
|
15
|
+
$(document).ready(function() {
|
16
|
+
$('#category_id').change(function() {
|
17
|
+
update_products();
|
62
18
|
});
|
63
|
-
|
19
|
+
update_products();
|
20
|
+
});
|
64
21
|
|
65
|
-
function
|
22
|
+
function update_products()
|
23
|
+
{
|
24
|
+
var cat_id = $('#category_id').val();
|
25
|
+
if (cat_id == '')
|
26
|
+
{
|
27
|
+
$('#message').empty().html("<p class'note error'>Please select a category.</p>");
|
28
|
+
return;
|
29
|
+
}
|
66
30
|
|
67
|
-
|
31
|
+
$('#message').empty().html("<p class'loading'>Getting products...</p>");
|
68
32
|
$.ajax({
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
33
|
+
url: '/admin/categories/' + cat_id + '/products/json',
|
34
|
+
type: 'get',
|
35
|
+
success: function(products) {
|
36
|
+
var ul = $('<ul/>').attr('id', 'product_list');
|
37
|
+
$.each(products, function(i, p) {
|
38
|
+
ul.append($('<li/>').attr('id', 'product_' + p.id).data('id', p.id).html(p.title));
|
39
|
+
});
|
40
|
+
$('#message').empty();
|
41
|
+
$('#products').empty().append(ul);
|
42
|
+
$('#product_list').sortable({
|
43
|
+
stop: function(event, ui)
|
44
|
+
{
|
45
|
+
$.ajax({
|
46
|
+
url: '/admin/categories/' + $('#category_id').val() + '/products/sort-order',
|
47
|
+
type: 'put',
|
48
|
+
data: {
|
49
|
+
product_ids: $.map($('#product_list').sortable('toArray'), function(str, j) { return parseInt(str.replace('product_', '')); })
|
50
|
+
}
|
51
|
+
});
|
52
|
+
}
|
53
|
+
});
|
54
|
+
}
|
55
|
+
});
|
73
56
|
}
|
74
57
|
|
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
|
-
}
|
88
|
-
|
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);
|
98
|
-
}
|
99
|
-
|
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) {
|
110
|
-
|
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);
|
113
|
-
|
114
|
-
// Grab the selected elements and create the helper
|
115
|
-
var elements = item.parent().children('.' + selected_class).clone()
|
116
|
-
, helper = $('<li/>');
|
117
|
-
|
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) {
|
139
|
-
|
140
|
-
if ($(ui.item).parent().attr('id') != 'source') {
|
141
|
-
|
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) {
|
151
|
-
|
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
58
|
</script>
|
181
59
|
<% end %>
|
182
60
|
|
183
61
|
<% content_for :caboose_css do %>
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
background: #ccc;
|
209
|
-
cursor: pointer;
|
210
|
-
margin: 12px 0;
|
211
|
-
padding: 6px;
|
212
|
-
outline: none !important;
|
213
|
-
}
|
214
|
-
|
215
|
-
/* Lists */
|
216
|
-
|
217
|
-
ul.sortable {
|
218
|
-
border: 1px solid #ccc;
|
219
|
-
height: 250px;
|
220
|
-
list-style: none;
|
221
|
-
margin: 0;
|
222
|
-
overflow-x: hidden;
|
223
|
-
overflow-y: scroll;
|
224
|
-
padding: 0;
|
225
|
-
width: 350px;
|
226
|
-
-webkit-touch-callout: none;
|
227
|
-
-webkit-user-select: none;
|
228
|
-
-khtml-user-select: none;
|
229
|
-
-moz-user-select: none;
|
230
|
-
-ms-user-select: none;
|
231
|
-
user-select: none;
|
232
|
-
}
|
233
|
-
ul.sortable li {
|
234
|
-
box-sizing: border-box;
|
235
|
-
border-bottom: 1px solid #ccc;
|
236
|
-
cursor: pointer;
|
237
|
-
cursor: grab;
|
238
|
-
display: block;
|
239
|
-
padding: 6px;
|
240
|
-
width: 100%;
|
241
|
-
}
|
242
|
-
ul.sortable li.selected {
|
243
|
-
background: #3e9aff;
|
244
|
-
border-color: #fff;
|
245
|
-
color: #fff;
|
246
|
-
}
|
62
|
+
<style>
|
63
|
+
|
64
|
+
#product_list {
|
65
|
+
list-style: none;
|
66
|
+
margin: 0;
|
67
|
+
padding: 0;
|
68
|
+
width: 350px;
|
69
|
+
}
|
70
|
+
#product_list li {
|
71
|
+
box-sizing: border-box;
|
72
|
+
border-top: 1px solid #ccc;
|
73
|
+
border-bottom: 1px solid #ccc;
|
74
|
+
cursor: pointer;
|
75
|
+
cursor: grab;
|
76
|
+
display: block;
|
77
|
+
padding: 6px;
|
78
|
+
width: 100%;
|
79
|
+
}
|
80
|
+
|
81
|
+
#product_list li.selected {
|
82
|
+
background: #3e9aff;
|
83
|
+
border-color: #fff;
|
84
|
+
color: #fff;
|
85
|
+
}
|
247
86
|
|
248
|
-
|
249
|
-
|
250
|
-
<% end %>
|
87
|
+
</style>
|
88
|
+
<% end %>
|
data/config/routes.rb
CHANGED
@@ -413,14 +413,14 @@ Caboose::Engine.routes.draw do
|
|
413
413
|
|
414
414
|
get "/admin/products" => "products#admin_index"
|
415
415
|
get "/admin/products/json" => "products#admin_json"
|
416
|
-
get '/admin/products/sort' => 'products#admin_sort'
|
417
|
-
put
|
416
|
+
get '/admin/products/sort' => 'products#admin_sort'
|
417
|
+
put "/admin/categories/:category_id/products/sort-order" => "products#admin_update_sort_order"
|
418
418
|
put "/admin/products/update-vendor-status/:id" => "products#admin_update_vendor_status"
|
419
419
|
get "/admin/products/new" => "products#admin_new"
|
420
420
|
get "/admin/products/status-options" => "products#admin_status_options"
|
421
421
|
get "/admin/products/:id/general" => "products#admin_edit_general"
|
422
422
|
get "/admin/products/:id/description" => "products#admin_edit_description"
|
423
|
-
get "/admin/products/:id/categories" => "products#admin_edit_categories"
|
423
|
+
get "/admin/products/:id/categories" => "products#admin_edit_categories"
|
424
424
|
post "/admin/products/:id/categories" => "products#admin_add_to_category"
|
425
425
|
delete "/admin/products/:id/categories/:category_id" => "products#admin_remove_from_category"
|
426
426
|
|
@@ -480,16 +480,17 @@ Caboose::Engine.routes.draw do
|
|
480
480
|
#=============================================================================
|
481
481
|
# Categories
|
482
482
|
#=============================================================================
|
483
|
-
|
484
|
-
get "/admin/categories"
|
485
|
-
get "/admin/categories/new"
|
486
|
-
get "/admin/categories/options"
|
487
|
-
get '/admin/categories/status-options'
|
488
|
-
get "/admin/categories/:id"
|
489
|
-
|
490
|
-
|
491
|
-
post "/admin/categories"
|
492
|
-
|
483
|
+
|
484
|
+
get "/admin/categories" => "categories#admin_index"
|
485
|
+
get "/admin/categories/new" => "categories#admin_new"
|
486
|
+
get "/admin/categories/options" => "categories#admin_options"
|
487
|
+
get '/admin/categories/status-options' => 'categories#admin_status_options'
|
488
|
+
get "/admin/categories/:id/products/json" => "categories#admin_category_products"
|
489
|
+
get "/admin/categories/:id" => "categories#admin_edit"
|
490
|
+
put "/admin/categories/:id" => "categories#admin_update"
|
491
|
+
post "/admin/categories/:id" => "categories#admin_update"
|
492
|
+
post "/admin/categories" => "categories#admin_add"
|
493
|
+
delete "/admin/categories/:id" => "categories#admin_delete"
|
493
494
|
|
494
495
|
#=============================================================================
|
495
496
|
# Orders
|
data/lib/caboose/version.rb
CHANGED