caboose-cms 0.5.151 → 0.5.152
Sign up to get free protection for your applications and to get access to all the features.
- 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