tabulatr2 0.9.19 → 0.9.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/Gemfile +1 -1
- data/README.md +38 -0
- data/app/assets/javascripts/tabulatr/_storage.js +3 -3
- data/app/views/tabulatr/_tabulatr_filter_dialog.html.slim +5 -0
- data/app/views/tabulatr/_tabulatr_table.html.slim +1 -1
- data/lib/tabulatr/data/data.rb +4 -0
- data/lib/tabulatr/data/dsl.rb +5 -0
- data/lib/tabulatr/data/filtering.rb +9 -2
- data/lib/tabulatr/data/pagination.rb +1 -1
- data/lib/tabulatr/rails/action_controller.rb +1 -0
- data/lib/tabulatr/rails/action_view.rb +2 -3
- data/lib/tabulatr/renderer/columns_from_block.rb +16 -3
- data/lib/tabulatr/renderer/filter.rb +22 -0
- data/lib/tabulatr/renderer/renderer.rb +17 -7
- data/lib/tabulatr/version.rb +1 -1
- data/spec/controller/application_controller_spec.rb +34 -0
- data/spec/dummy/app/tabulatr_data/vendor_tabulatr_data.rb +15 -0
- data/spec/dummy/app/views/tabulatr/filter/_product_price_range.html.slim +9 -0
- data/spec/dummy/app/views/vendors/index.html.slim +1 -0
- data/spec/features/tabulatrs_spec.rb +18 -0
- data/spec/lib/tabulatr/data/dsl_spec.rb +21 -3
- data/spec/lib/tabulatr/data/filtering_spec.rb +50 -14
- data/spec/lib/tabulatr/data/pagination_spec.rb +1 -1
- data/spec/lib/tabulatr/renderer/columns_from_block_spec.rb +21 -0
- data/spec/lib/tabulatr/renderer/filter_spec.rb +15 -0
- data/spec/lib/tabulatr/renderer/renderer_spec.rb +13 -1
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8628bfd7be6d2d9e801984acaeef9057dd98aa24
|
4
|
+
data.tar.gz: 07d356b31c00175e286fdb09d84681ec71a41492
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c313558231faee3dbbe107378401c04e517aba77caafd879b03f2104ef77dcdc7df50516fe01e078f801f3ad158185f8a8603bde668cb41f308b926de5b9d04
|
7
|
+
data.tar.gz: e4835fbbb8ed8be42acf6ffde94deb2d3b8e8ba0e4e2948c4ef15002a0fa2534a9f560570c3f753a822def719e35b2b82bcaddd8a3eeb7d1160369bc0d24a49e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## 0.9.20
|
2
|
+
* Add `filter` to DSL to define custom filters
|
3
|
+
|
4
|
+
Example:
|
5
|
+
```
|
6
|
+
filter :product_price_range do |relation, value|
|
7
|
+
relation = relation.joins(:products)
|
8
|
+
if value == 'low'
|
9
|
+
relation.group("vendors.id").having('AVG(products.price) <= 100')
|
10
|
+
elsif value == 'high'
|
11
|
+
relation.group("vendors.id").having('AVG(products.price) > 100')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
```
|
15
|
+
* Add `current_user` local to Tabulatr::Data by default if available
|
16
|
+
and not already present
|
17
|
+
|
1
18
|
## 0.9.17
|
2
19
|
* If a batch action is executed without checking any rows it
|
3
20
|
will be applied to all rows in the current filter
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -184,6 +184,44 @@ class UserTabulatrData < Tabulatr::Data
|
|
184
184
|
end
|
185
185
|
```
|
186
186
|
|
187
|
+
### Custom filters
|
188
|
+
|
189
|
+
You're also able to create custom filters with the `filter` method to create more advanced
|
190
|
+
filters which are independent of the displayed columns.
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
class UserTabulatrData < Tabulatr::Data
|
194
|
+
filter :age_range do |relation, value|
|
195
|
+
if value == 'upto_18'
|
196
|
+
relation.where("birthday > ?", Date.today-18.years)
|
197
|
+
elsif value == 'over_18'
|
198
|
+
relation.where("birthday <= ?", Date.today-18.years)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
This code will look for a partial to render in `tabulatr/filter/_age_range.*`.
|
205
|
+
You can override this path by specifying the `partial` argument of the `filter` method.
|
206
|
+
It will call it's block with the ActiveRecord::Relation and the submitted value after
|
207
|
+
the user submits the filter form.
|
208
|
+
|
209
|
+
```erb
|
210
|
+
# tabulatr/filter/_age_range.html.erb
|
211
|
+
|
212
|
+
<div class='form-group'>
|
213
|
+
<label class='control-label' for="<%= input_id %>">Age range</label>
|
214
|
+
<select id="<%= input_id %>" name="<%= input_name %>">
|
215
|
+
<option value=''>None</option>
|
216
|
+
<option value='upto_18'>0 - 17</option>
|
217
|
+
<option value='over_18'>18+</option>
|
218
|
+
</select>
|
219
|
+
</div>
|
220
|
+
```
|
221
|
+
|
222
|
+
As you can see there are two locales defined which should be used for your custom form
|
223
|
+
field: `input_name` and `input_id`
|
224
|
+
|
187
225
|
### Row formatting
|
188
226
|
|
189
227
|
To provide row specific HTML-Attributes call `row`:
|
@@ -19,8 +19,8 @@ $(function(){
|
|
19
19
|
elem = $('[name="'+ objKeys[i] +'"]');
|
20
20
|
if(elem.length > 0){
|
21
21
|
var val = currentStorage[objKeys[i]];
|
22
|
-
elem.val(val);
|
23
|
-
formParent = elem.parents('.
|
22
|
+
elem.val(val).trigger('change');
|
23
|
+
formParent = elem.parents('.tabulatr-filter-row');
|
24
24
|
if(formParent.length > 0 && val && val.length > 0){
|
25
25
|
$('.tabulatr-outer-wrapper[data-table-id="'+this.id+'"]').addClass('filtered')
|
26
26
|
}
|
@@ -34,7 +34,7 @@ $(function(){
|
|
34
34
|
localStorage.removeItem(this.id);
|
35
35
|
$('table#'+ this.id).find('th.sorted').removeClass('sorted').removeAttr('data-sorted');
|
36
36
|
$('form[data-table='+ this.id +'] input.search').val('');
|
37
|
-
$('[data-table
|
37
|
+
$('.tabulatr_filter_form[data-table="'+ this.id +'"]').find('input[type=text], input[type=hidden], select').val('');
|
38
38
|
$('.tabulatr_filter_form[data-table='+ this.id +'] input[name="'+ tableName +'_sort"]').val('');
|
39
39
|
this.updateTable({page: 1}, true);
|
40
40
|
};
|
@@ -103,3 +103,8 @@
|
|
103
103
|
= label_tag "check_box_#{key}", key
|
104
104
|
- else
|
105
105
|
input.tabulatr_filter.form-control type="text" data-tabulatr-attribute="#{name}" name="#{iname}[like]"
|
106
|
+
- filter.each do |f|
|
107
|
+
.row.tabulatr-filter-row
|
108
|
+
.col-xs-12
|
109
|
+
= render f.to_partial_path, {input_name: "#{formatted_name}_filter[#{f.name}]",
|
110
|
+
input_id: "#{formatted_name}_#{f.name}"}
|
@@ -21,7 +21,7 @@
|
|
21
21
|
|
22
22
|
- opts = { columns: columns, table_options: table_options, \
|
23
23
|
klass: klass, classname: classname, table_id: table_id,
|
24
|
-
formatted_name: formatted_name }
|
24
|
+
formatted_name: formatted_name, filter: filter }
|
25
25
|
|
26
26
|
.row.tabulatr-outer-wrapper data-table-id=table_id
|
27
27
|
.tabulatr-filter-col data-table-id=table_id
|
data/lib/tabulatr/data/data.rb
CHANGED
data/lib/tabulatr/data/dsl.rb
CHANGED
@@ -157,6 +157,11 @@ module Tabulatr::Data::DSL
|
|
157
157
|
@row = block
|
158
158
|
end
|
159
159
|
|
160
|
+
def filter(name, partial: nil, &block)
|
161
|
+
@filters ||= []
|
162
|
+
@filters << Tabulatr::Renderer::Filter.new(name, partial: partial, &block)
|
163
|
+
end
|
164
|
+
|
160
165
|
end
|
161
166
|
|
162
167
|
Tabulatr::Data.send :extend, Tabulatr::Data::DSL
|
@@ -45,12 +45,13 @@ module Tabulatr::Data::Filtering
|
|
45
45
|
return unless filter_params
|
46
46
|
assoc_filters = filter_params.delete :__association
|
47
47
|
apply_association_filters(assoc_filters) if assoc_filters.present?
|
48
|
-
filter_params.each do |
|
49
|
-
name, value =
|
48
|
+
filter_params.each do |param|
|
49
|
+
name, value = param
|
50
50
|
next unless value.present?
|
51
51
|
|
52
52
|
table_name, method_name = name.split(':').map(&:to_sym)
|
53
53
|
column = table_columns.find{|c| c.table_name == table_name && c.name == method_name}
|
54
|
+
column = filters.find{|f| f.name.to_sym == name.to_sym} if column.nil?
|
54
55
|
apply_condition(column, value)
|
55
56
|
end
|
56
57
|
end
|
@@ -78,6 +79,7 @@ module Tabulatr::Data::Filtering
|
|
78
79
|
when :like then apply_like_condition(n, v[:like])
|
79
80
|
when :date then apply_date_condition(n, v[:date])
|
80
81
|
when :range then apply_range_condition(n, v)
|
82
|
+
when :custom then apply_custom_filter(n, v)
|
81
83
|
else raise "Wrong filter type for #{n.name}: #{n.filter}"
|
82
84
|
end
|
83
85
|
end
|
@@ -134,6 +136,11 @@ module Tabulatr::Data::Filtering
|
|
134
136
|
@relation = @relation.where(column.table_name => { column.name => value })
|
135
137
|
end
|
136
138
|
|
139
|
+
def apply_custom_filter(filter, value)
|
140
|
+
filter_result = filter.block.(@relation, value)
|
141
|
+
handle_search_result(filter_result)
|
142
|
+
end
|
143
|
+
|
137
144
|
private
|
138
145
|
|
139
146
|
def execute_provided_search_block!(query)
|
@@ -30,6 +30,7 @@ class ActionController::Base
|
|
30
30
|
klass = relation.respond_to?(:klass) ? relation.klass : relation
|
31
31
|
respond_to do |format|
|
32
32
|
format.json {
|
33
|
+
locals[:current_user] ||= current_user if respond_to?(:current_user)
|
33
34
|
records = klass.tabulatr(relation, tabulatr_data_class).data_for_table(params, locals: locals, controller: self, &block)
|
34
35
|
render json: records.to_tabulatr_json(serializer)
|
35
36
|
records
|
@@ -23,13 +23,12 @@
|
|
23
23
|
|
24
24
|
class ActionView::Base
|
25
25
|
# render the table in a view
|
26
|
-
def table_for(klass, columns: [], tabulatr_data_class: nil, **opts, &block)
|
26
|
+
def table_for(klass, columns: [], filter: [], tabulatr_data_class: nil, **opts, &block)
|
27
27
|
@_tabulatr_table_index += 1
|
28
|
-
Tabulatr::Renderer.build_table(klass, self, opts, columns, tabulatr_data_class, &block)
|
28
|
+
Tabulatr::Renderer.build_table(klass, self, opts, columns, filter, tabulatr_data_class, &block)
|
29
29
|
end
|
30
30
|
|
31
31
|
def static_table_for(records, opts={}, &block)
|
32
32
|
Tabulatr::Renderer.build_static_table(records, self, opts, &block)
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
@@ -23,12 +23,13 @@
|
|
23
23
|
|
24
24
|
class Tabulatr::Renderer
|
25
25
|
class ColumnsFromBlock
|
26
|
-
attr_accessor :columns, :klass, :table_data
|
26
|
+
attr_accessor :columns, :klass, :table_data, :filters
|
27
27
|
|
28
28
|
def initialize(klass, table_data_object)
|
29
29
|
@klass = klass
|
30
30
|
@table_data = table_data_object
|
31
31
|
@columns ||= []
|
32
|
+
@filters ||= []
|
32
33
|
end
|
33
34
|
|
34
35
|
def column(name, opts={}, &block)
|
@@ -65,11 +66,19 @@ class Tabulatr::Renderer
|
|
65
66
|
@columns << Buttons.from(opts.merge(klass: klass, filter: false, sortable: false, output: output), &block)
|
66
67
|
end
|
67
68
|
|
69
|
+
def filter(name, partial: nil, &block)
|
70
|
+
if table_data
|
71
|
+
found_filter = fetch_filter_from_table_data(name)
|
72
|
+
@filters << found_filter if found_filter.present?
|
73
|
+
else
|
74
|
+
@filters << Tabulatr::Renderer::Filter.new(name, partial: partial, &block)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
68
78
|
def self.process(klass, table_data_object = nil, &block)
|
69
79
|
i = self.new(klass, table_data_object)
|
70
80
|
yield(i)
|
71
|
-
|
72
|
-
c
|
81
|
+
i
|
73
82
|
end
|
74
83
|
|
75
84
|
private
|
@@ -78,5 +87,9 @@ class Tabulatr::Renderer
|
|
78
87
|
column = table_data.table_columns.find{|tc| tc.table_name == table_name && tc.name == name}
|
79
88
|
column.update_options(opts, &block)
|
80
89
|
end
|
90
|
+
|
91
|
+
def fetch_filter_from_table_data name
|
92
|
+
table_data.filters.find{|f| f.name.to_sym == name.to_sym}
|
93
|
+
end
|
81
94
|
end
|
82
95
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Tabulatr::Renderer::Filter
|
2
|
+
|
3
|
+
attr_accessor :name, :partial, :block
|
4
|
+
|
5
|
+
def initialize(name, partial: nil, &block)
|
6
|
+
@name = name
|
7
|
+
@block = block
|
8
|
+
@partial = partial
|
9
|
+
end
|
10
|
+
|
11
|
+
def filter
|
12
|
+
:custom
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_partial_path
|
16
|
+
if partial.present?
|
17
|
+
partial
|
18
|
+
else
|
19
|
+
"tabulatr/filter/#{name.to_s.downcase.underscore}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -57,16 +57,17 @@ class Tabulatr::Renderer
|
|
57
57
|
@classname = @klass.name.underscore
|
58
58
|
end
|
59
59
|
|
60
|
-
def build_table(columns, tabulatr_data_class, &block)
|
60
|
+
def build_table(columns, filters, tabulatr_data_class, &block)
|
61
61
|
if tabulatr_data_class.present?
|
62
62
|
tdc = tabulatr_data_class.constantize.new(@klass)
|
63
63
|
else
|
64
64
|
tdc = "#{@klass.name}TabulatrData".constantize.new(@klass)
|
65
65
|
end
|
66
66
|
if block_given?
|
67
|
-
@columns = ColumnsFromBlock.process
|
68
|
-
elsif columns.any?
|
67
|
+
@columns = ColumnsFromBlock.process(@klass, tdc, &block).columns
|
68
|
+
elsif columns.any? || filters.any?
|
69
69
|
@columns = get_requested_columns(tdc.table_columns, columns)
|
70
|
+
@filters = get_requested_filters(tdc.filters, filters)
|
70
71
|
else
|
71
72
|
@columns = tdc.table_columns
|
72
73
|
end
|
@@ -77,12 +78,13 @@ class Tabulatr::Renderer
|
|
77
78
|
classname: @classname,
|
78
79
|
tabulatr_data: tdc,
|
79
80
|
table_id: generate_id,
|
80
|
-
formatted_name: Tabulatr::Utility.formatted_name(@klass.name)
|
81
|
+
formatted_name: Tabulatr::Utility.formatted_name(@klass.name),
|
82
|
+
filter: tdc.filters || []
|
81
83
|
})
|
82
84
|
end
|
83
85
|
|
84
86
|
def build_static_table(records, &block)
|
85
|
-
@columns = ColumnsFromBlock.process
|
87
|
+
@columns = ColumnsFromBlock.process(@klass, &block).columns
|
86
88
|
|
87
89
|
@view.render(partial: '/tabulatr/tabulatr_static_table', locals: {
|
88
90
|
columns: @columns,
|
@@ -103,8 +105,8 @@ class Tabulatr::Renderer
|
|
103
105
|
new(klass, view, toptions).build_static_table(records, &block)
|
104
106
|
end
|
105
107
|
|
106
|
-
def self.build_table(klass, view, toptions={}, columns, tabulatr_data_class, &block)
|
107
|
-
new(klass, view, toptions).build_table(columns, tabulatr_data_class, &block)
|
108
|
+
def self.build_table(klass, view, toptions={}, columns, filters, tabulatr_data_class, &block)
|
109
|
+
new(klass, view, toptions).build_table(columns, filters, tabulatr_data_class, &block)
|
108
110
|
end
|
109
111
|
|
110
112
|
private
|
@@ -121,6 +123,13 @@ class Tabulatr::Renderer
|
|
121
123
|
end.flatten
|
122
124
|
end
|
123
125
|
|
126
|
+
def get_requested_filters(available_filters, requested_filters)
|
127
|
+
requested_filters.collect do |f|
|
128
|
+
result = available_filters.find{|filter| filter.name.to_sym == f.to_sym }
|
129
|
+
result or raise "Can't find filter '#{f}'"
|
130
|
+
end.flatten
|
131
|
+
end
|
132
|
+
|
124
133
|
end
|
125
134
|
|
126
135
|
require_relative './column'
|
@@ -129,3 +138,4 @@ require_relative './action'
|
|
129
138
|
require_relative './buttons'
|
130
139
|
require_relative './checkbox'
|
131
140
|
require_relative './columns_from_block'
|
141
|
+
require_relative './filter'
|
data/lib/tabulatr/version.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
# RSpec.configure do |c|
|
4
|
+
# c.infer_base_class_for_anonymous_controllers = false
|
5
|
+
# end
|
6
|
+
|
7
|
+
describe ApplicationController, type: :controller do
|
8
|
+
controller do
|
9
|
+
def index
|
10
|
+
tabulatr_for Product
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_user
|
14
|
+
"Han Solo"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "passing locales to Tabulatr::Data" do
|
19
|
+
it "implicitly creates a current_user local if not already present" do
|
20
|
+
request.accept = "application/json"
|
21
|
+
Product.create!(:title => 'bar', :active => true, :price => 10.0)
|
22
|
+
fake_response = double({foo: 'bar'})
|
23
|
+
|
24
|
+
expect_any_instance_of(Tabulatr::Data).to receive(:data_for_table).with(
|
25
|
+
{"pagesize"=>"20", "arguments"=>"products:title", "controller"=>"anonymous", "action"=>"index"},
|
26
|
+
{:locals=>{current_user: "Han Solo"}, controller: controller}
|
27
|
+
).and_return(fake_response)
|
28
|
+
expect(fake_response).to receive(:to_tabulatr_json).and_return({})
|
29
|
+
|
30
|
+
get :index, pagesize: 20, arguments: 'products:title'
|
31
|
+
expect(response.code).to eq '200'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class VendorTabulatrData < Tabulatr::Data
|
2
|
+
|
3
|
+
column :name
|
4
|
+
column :url
|
5
|
+
column :active
|
6
|
+
|
7
|
+
filter :product_price_range do |relation, value|
|
8
|
+
relation = relation.joins(:products)
|
9
|
+
if value == 'low'
|
10
|
+
relation.group("vendors.id").having('AVG(products.price) <= 100')
|
11
|
+
elsif value == 'high'
|
12
|
+
relation.group("vendors.id").having('AVG(products.price) > 100')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
= table_for Vendor, paginate: true
|
@@ -215,6 +215,24 @@ feature "Tabulatr" do
|
|
215
215
|
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'bar')
|
216
216
|
expect(page).to have_selector('td[data-tabulatr-column-name="products:title"]', text: 'foo')
|
217
217
|
end
|
218
|
+
|
219
|
+
scenario 'custom filters', js: true do
|
220
|
+
Product.create!([{title: 'foo', price: 7.5, vendor: @vendor1}, {title: 'bar', price: 90, vendor: @vendor1}])
|
221
|
+
Product.create!([{title: 'baz', price: 125, vendor: @vendor2}, {title: 'fubar', price: 133.3, vendor: @vendor2}, {title: 'fiz', price: 97, vendor: @vendor2}])
|
222
|
+
visit vendors_path
|
223
|
+
expect(page).to have_css(".tabulatr_table tbody tr", count: 2)
|
224
|
+
click_link 'Filter'
|
225
|
+
within(".tabulatr_filter_form") do
|
226
|
+
select("> 100 Euro", from: "vendor_filter[product_price_range]")
|
227
|
+
end
|
228
|
+
expect(page).to have_css(".tabulatr_table tbody tr", count: 1)
|
229
|
+
expect(page).to have_css('.tabulatr_table tbody td', text: @vendor2.name)
|
230
|
+
within(".tabulatr_filter_form") do
|
231
|
+
select("<= 100 Euro", from: "vendor_filter[product_price_range]")
|
232
|
+
end
|
233
|
+
expect(page).to have_css(".tabulatr_table tbody tr", count: 1)
|
234
|
+
expect(page).to have_css('.tabulatr_table tbody td', text: @vendor1.name)
|
235
|
+
end
|
218
236
|
end
|
219
237
|
|
220
238
|
feature "Sorting" do
|
@@ -7,11 +7,12 @@ describe Tabulatr::Data::DSL do
|
|
7
7
|
|
8
8
|
before(:each) do
|
9
9
|
DummyDSLClass.instance_variable_set('@table_columns', [])
|
10
|
+
DummyDSLClass.instance_variable_set('@filters', [])
|
11
|
+
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
10
12
|
end
|
11
13
|
|
12
14
|
describe '#column' do
|
13
15
|
it 'escapes table and column names' do
|
14
|
-
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
15
16
|
DummyDSLClass.column(:active)
|
16
17
|
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
17
18
|
expect(table_column.filter_sql).to match(/\"products\".\"active\"/)
|
@@ -21,11 +22,28 @@ describe Tabulatr::Data::DSL do
|
|
21
22
|
|
22
23
|
describe '#association' do
|
23
24
|
it 'escapes table and column names' do
|
24
|
-
allow(DummyDSLClass).to receive(:main_class).and_return(Product)
|
25
25
|
DummyDSLClass.association(:vendor, :name)
|
26
26
|
table_column = DummyDSLClass.instance_variable_get('@table_columns').first
|
27
27
|
expect(table_column.filter_sql).to match(/\"vendors\".\"name\"/)
|
28
28
|
expect(table_column.sort_sql).to match(/\"vendors\".\"name\"/)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
|
+
describe '#filter' do
|
33
|
+
it 'adds filters' do
|
34
|
+
DummyDSLClass.filter(:price_range)
|
35
|
+
expect(DummyDSLClass.instance_variable_get('@filters').map(&:name)).to match_array([:price_range])
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'can hold multiple filters' do
|
39
|
+
DummyDSLClass.filter(:price_range)
|
40
|
+
DummyDSLClass.filter(:category_select)
|
41
|
+
expect(DummyDSLClass.instance_variable_get('@filters').map(&:name)).to match_array([:price_range, :category_select])
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'accepts a partial attribute' do
|
45
|
+
DummyDSLClass.filter(:simple_filter, partial: 'my_custom_filter')
|
46
|
+
expect(DummyDSLClass.instance_variable_get('@filters').first.partial).to eq 'my_custom_filter'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -3,23 +3,28 @@ require 'rails_helper'
|
|
3
3
|
describe Tabulatr::Data::Filtering do
|
4
4
|
class DummyFilteringClass
|
5
5
|
include Tabulatr::Data::Filtering
|
6
|
-
end
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
@dummy.instance_variable_set('@relation', Product.all)
|
11
|
-
@yesterday = Product.create!(publish_at: DateTime.new(2013, 12, 31, 0, 0))
|
12
|
-
@today = Product.create!(publish_at: DateTime.new(2014, 1, 1, 15, 0))
|
13
|
-
@week_one = Product.create!(publish_at: DateTime.new(2013, 12, 30, 0, 0))
|
14
|
-
@week_two = Product.create!(publish_at: DateTime.new(2014, 1, 5, 8, 0))
|
15
|
-
@last_seven_days = Product.create!(publish_at: DateTime.new(2013, 12, 26, 0, 0))
|
16
|
-
@last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 3, 0, 0))
|
17
|
-
@outside_last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 2, 23, 59))
|
18
|
-
@this_month = Product.create!(publish_at: DateTime.new(2014, 1, 15, 0, 0))
|
19
|
-
@next_year = Product.create!(publish_at: DateTime.new(2015, 1, 1, 12, 0))
|
20
|
-
allow(Date).to receive(:today).and_return(Date.new(2014,1,1))
|
7
|
+
def table_columns; []; end
|
8
|
+
def filters; []; end
|
21
9
|
end
|
10
|
+
|
22
11
|
describe '.apply_date_condition' do
|
12
|
+
before(:each) do
|
13
|
+
@dummy = DummyFilteringClass.new
|
14
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
15
|
+
@yesterday = Product.create!(publish_at: DateTime.new(2013, 12, 31, 0, 0))
|
16
|
+
@today = Product.create!(publish_at: DateTime.new(2014, 1, 1, 15, 0))
|
17
|
+
@week_one = Product.create!(publish_at: DateTime.new(2013, 12, 30, 0, 0))
|
18
|
+
@week_two = Product.create!(publish_at: DateTime.new(2014, 1, 5, 8, 0))
|
19
|
+
@last_seven_days = Product.create!(publish_at: DateTime.new(2013, 12, 26, 0, 0))
|
20
|
+
@last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 3, 0, 0))
|
21
|
+
@outside_last_thirty_days = Product.create!(publish_at: DateTime.new(2013, 12, 2, 23, 59))
|
22
|
+
@this_month = Product.create!(publish_at: DateTime.new(2014, 1, 15, 0, 0))
|
23
|
+
@next_year = Product.create!(publish_at: DateTime.new(2015, 1, 1, 12, 0))
|
24
|
+
allow(Date).to receive(:today).and_return(Date.new(2014,1,1))
|
25
|
+
end
|
26
|
+
|
27
|
+
|
23
28
|
it "filters for 'today'" do
|
24
29
|
fake_obj = double(filter_sql: 'publish_at')
|
25
30
|
@dummy.apply_date_condition(fake_obj, {simple: 'today'})
|
@@ -78,6 +83,12 @@ describe Tabulatr::Data::Filtering do
|
|
78
83
|
end
|
79
84
|
|
80
85
|
describe '.apply_search' do
|
86
|
+
|
87
|
+
before(:each) do
|
88
|
+
@dummy = DummyFilteringClass.new
|
89
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
90
|
+
end
|
91
|
+
|
81
92
|
it 'allows to alter the ActiveRecord::Relation' do
|
82
93
|
@dummy.instance_variable_set('@search',
|
83
94
|
->(query, relation){ relation.joins(:vendor).where(%{vendors.name LIKE '%#{query}%'})})
|
@@ -110,4 +121,29 @@ describe Tabulatr::Data::Filtering do
|
|
110
121
|
expect{@dummy.apply_search('test')}.to raise_error
|
111
122
|
end
|
112
123
|
end
|
124
|
+
|
125
|
+
describe '.apply_filters' do
|
126
|
+
before(:each) do
|
127
|
+
@dummy = DummyFilteringClass.new
|
128
|
+
@dummy.instance_variable_set('@relation', Product.all)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'applies given filters to the relation' do
|
132
|
+
bl = ->(relation, value){ relation.where(price: value) }
|
133
|
+
allow(@dummy).to receive(:filters).and_return([Tabulatr::Renderer::Filter.new(:custom_filter, &bl)])
|
134
|
+
matched_product = Product.create(price: 10)
|
135
|
+
unmatched_product = Product.create(price: 11)
|
136
|
+
expect{@dummy.apply_filters({'custom_filter' => '10'})}.to_not raise_error
|
137
|
+
result = @dummy.instance_variable_get('@relation')
|
138
|
+
expect(result).to match_array([matched_product])
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'only searches for a filter if there is no column with that name' do
|
142
|
+
fake_column = double(table_name: :custom, name: nil)
|
143
|
+
allow(@dummy).to receive(:table_columns).and_return([fake_column])
|
144
|
+
allow(@dummy).to receive(:filters).and_return([Tabulatr::Renderer::Filter.new(:custom)])
|
145
|
+
expect(@dummy).to receive(:apply_condition).with(fake_column, '10')
|
146
|
+
@dummy.apply_filters({'custom' => '10'})
|
147
|
+
end
|
148
|
+
end
|
113
149
|
end
|
@@ -10,7 +10,7 @@ describe Tabulatr::Data::Pagination do
|
|
10
10
|
end
|
11
11
|
describe '.compute_pagination' do
|
12
12
|
it "computes an offset" do
|
13
|
-
count =
|
13
|
+
count = (1..20).to_a
|
14
14
|
@dummy.instance_variable_set('@relation', count)
|
15
15
|
pagination = @dummy.compute_pagination(1, 10)
|
16
16
|
expect(pagination[:offset]).to be 0
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Tabulatr::Renderer::ColumnsFromBlock do
|
4
|
+
|
5
|
+
class TabulatrFakeData < Tabulatr::Data
|
6
|
+
filter :foo_and_bar
|
7
|
+
filter :not_requested_filter
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#filter' do
|
11
|
+
it 'finds filters if tabulatr_data is given' do
|
12
|
+
allow_any_instance_of(TabulatrFakeData).to receive(:table_columns).and_return([])
|
13
|
+
td = TabulatrFakeData.new(Product)
|
14
|
+
cfb = Tabulatr::Renderer::ColumnsFromBlock.process(Product, td) do |c|
|
15
|
+
c.filter :foo_and_bar
|
16
|
+
c.filter :not_available_filter
|
17
|
+
end
|
18
|
+
expect(cfb.filters.map(&:name)).to match_array([:foo_and_bar])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Tabulatr::Renderer::Filter do
|
4
|
+
describe '#to_partial_path' do
|
5
|
+
it 'guesses the partial_path by name if no partial is given' do
|
6
|
+
filter = Tabulatr::Renderer::Filter.new('dynamic_select')
|
7
|
+
expect(filter.to_partial_path).to eq 'tabulatr/filter/dynamic_select'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'uses the given partial name if given' do
|
11
|
+
filter = Tabulatr::Renderer::Filter.new('some_filter', partial: 'my_filters/simple_filter')
|
12
|
+
expect(filter.to_partial_path).to eq 'my_filters/simple_filter'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,6 +2,10 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
describe Tabulatr::Renderer do
|
4
4
|
|
5
|
+
class FakeRendererSpecTabulatrData < Tabulatr::Data
|
6
|
+
filter :simple_filter
|
7
|
+
end
|
8
|
+
|
5
9
|
def double_view
|
6
10
|
view = double(controller: double(controller_name: 'products', action_name: 'index'), render: '')
|
7
11
|
view.instance_variable_set('@_tabulatr_table_index', 0)
|
@@ -28,10 +32,18 @@ describe Tabulatr::Renderer do
|
|
28
32
|
describe '#build_table' do
|
29
33
|
it 'gets columns by their names' do
|
30
34
|
renderer = Tabulatr::Renderer.new(Product, double_view)
|
31
|
-
renderer.build_table(['_buttons'], 'ProductTabulatrData')
|
35
|
+
renderer.build_table(['_buttons'], [], 'ProductTabulatrData')
|
32
36
|
columns = renderer.instance_variable_get('@columns')
|
33
37
|
expect(columns.count).to be(1)
|
34
38
|
expect(columns.first).to be_instance_of(Tabulatr::Renderer::Buttons)
|
35
39
|
end
|
40
|
+
|
41
|
+
it 'gets filters by their names' do
|
42
|
+
allow_any_instance_of(Tabulatr::Data).to receive(:table_columns).and_return([])
|
43
|
+
renderer = Tabulatr::Renderer.new(Product, double_view)
|
44
|
+
renderer.build_table([], [:simple_filter], 'FakeRendererSpecTabulatrData')
|
45
|
+
filters = renderer.instance_variable_get('@filters')
|
46
|
+
expect(filters.map(&:name)).to match_array([:simple_filter])
|
47
|
+
end
|
36
48
|
end
|
37
49
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tabulatr2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Horn
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-05-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
@@ -165,12 +165,14 @@ files:
|
|
165
165
|
- lib/tabulatr/renderer/checkbox.rb
|
166
166
|
- lib/tabulatr/renderer/column.rb
|
167
167
|
- lib/tabulatr/renderer/columns_from_block.rb
|
168
|
+
- lib/tabulatr/renderer/filter.rb
|
168
169
|
- lib/tabulatr/renderer/renderer.rb
|
169
170
|
- lib/tabulatr/utility/request_data_not_included_error.rb
|
170
171
|
- lib/tabulatr/utility/unexpected_search_result_error.rb
|
171
172
|
- lib/tabulatr/utility/utility.rb
|
172
173
|
- lib/tabulatr/version.rb
|
173
174
|
- lib/tabulatr2.rb
|
175
|
+
- spec/controller/application_controller_spec.rb
|
174
176
|
- spec/dummy/.gitignore
|
175
177
|
- spec/dummy/README.rdoc
|
176
178
|
- spec/dummy/Rakefile
|
@@ -190,6 +192,7 @@ files:
|
|
190
192
|
- spec/dummy/app/models/tag.rb
|
191
193
|
- spec/dummy/app/models/vendor.rb
|
192
194
|
- spec/dummy/app/tabulatr_data/product_tabulatr_data.rb
|
195
|
+
- spec/dummy/app/tabulatr_data/vendor_tabulatr_data.rb
|
193
196
|
- spec/dummy/app/views/layouts/application.html.erb
|
194
197
|
- spec/dummy/app/views/products/count_tags.html.erb
|
195
198
|
- spec/dummy/app/views/products/implicit_columns.html.erb
|
@@ -199,6 +202,8 @@ files:
|
|
199
202
|
- spec/dummy/app/views/products/stupid_array.html.erb
|
200
203
|
- spec/dummy/app/views/products/with_batch_actions.html.erb
|
201
204
|
- spec/dummy/app/views/products/with_styling.html.erb
|
205
|
+
- spec/dummy/app/views/tabulatr/filter/_product_price_range.html.slim
|
206
|
+
- spec/dummy/app/views/vendors/index.html.slim
|
202
207
|
- spec/dummy/bin/bundle
|
203
208
|
- spec/dummy/bin/rails
|
204
209
|
- spec/dummy/bin/rake
|
@@ -241,6 +246,8 @@ files:
|
|
241
246
|
- spec/lib/tabulatr/data/sorting_spec.rb
|
242
247
|
- spec/lib/tabulatr/json_builder_spec.rb
|
243
248
|
- spec/lib/tabulatr/renderer/checkbox_spec.rb
|
249
|
+
- spec/lib/tabulatr/renderer/columns_from_block_spec.rb
|
250
|
+
- spec/lib/tabulatr/renderer/filter_spec.rb
|
244
251
|
- spec/lib/tabulatr/renderer/renderer_spec.rb
|
245
252
|
- spec/rails_helper.rb
|
246
253
|
- spec/spec_helper.rb
|
@@ -273,6 +280,7 @@ specification_version: 4
|
|
273
280
|
summary: A tight DSL to build tables of ActiveRecord models with sorting, pagination,
|
274
281
|
finding/filtering, selecting and batch actions.
|
275
282
|
test_files:
|
283
|
+
- spec/controller/application_controller_spec.rb
|
276
284
|
- spec/dummy/.gitignore
|
277
285
|
- spec/dummy/README.rdoc
|
278
286
|
- spec/dummy/Rakefile
|
@@ -292,6 +300,7 @@ test_files:
|
|
292
300
|
- spec/dummy/app/models/tag.rb
|
293
301
|
- spec/dummy/app/models/vendor.rb
|
294
302
|
- spec/dummy/app/tabulatr_data/product_tabulatr_data.rb
|
303
|
+
- spec/dummy/app/tabulatr_data/vendor_tabulatr_data.rb
|
295
304
|
- spec/dummy/app/views/layouts/application.html.erb
|
296
305
|
- spec/dummy/app/views/products/count_tags.html.erb
|
297
306
|
- spec/dummy/app/views/products/implicit_columns.html.erb
|
@@ -301,6 +310,8 @@ test_files:
|
|
301
310
|
- spec/dummy/app/views/products/stupid_array.html.erb
|
302
311
|
- spec/dummy/app/views/products/with_batch_actions.html.erb
|
303
312
|
- spec/dummy/app/views/products/with_styling.html.erb
|
313
|
+
- spec/dummy/app/views/tabulatr/filter/_product_price_range.html.slim
|
314
|
+
- spec/dummy/app/views/vendors/index.html.slim
|
304
315
|
- spec/dummy/bin/bundle
|
305
316
|
- spec/dummy/bin/rails
|
306
317
|
- spec/dummy/bin/rake
|
@@ -343,6 +354,8 @@ test_files:
|
|
343
354
|
- spec/lib/tabulatr/data/sorting_spec.rb
|
344
355
|
- spec/lib/tabulatr/json_builder_spec.rb
|
345
356
|
- spec/lib/tabulatr/renderer/checkbox_spec.rb
|
357
|
+
- spec/lib/tabulatr/renderer/columns_from_block_spec.rb
|
358
|
+
- spec/lib/tabulatr/renderer/filter_spec.rb
|
346
359
|
- spec/lib/tabulatr/renderer/renderer_spec.rb
|
347
360
|
- spec/rails_helper.rb
|
348
361
|
- spec/spec_helper.rb
|