datagrid 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/app/assets/stylesheets/datagrid.css.sass +0 -4
- data/datagrid.gemspec +2 -2
- data/lib/datagrid/column_names_attribute.rb +11 -0
- data/lib/datagrid/columns.rb +19 -4
- data/lib/datagrid/drivers/abstract_driver.rb +8 -0
- data/lib/datagrid/drivers/active_record.rb +24 -6
- data/lib/datagrid/drivers/array.rb +4 -0
- data/lib/datagrid/drivers/mongo_mapper.rb +4 -0
- data/lib/datagrid/drivers/mongoid.rb +25 -1
- data/lib/datagrid/filters.rb +18 -16
- data/lib/datagrid/filters/base_filter.rb +1 -1
- data/lib/datagrid/filters/boolean_enum_filter.rb +1 -1
- data/lib/datagrid/filters/boolean_filter.rb +1 -1
- data/lib/datagrid/filters/composite_filters.rb +1 -1
- data/lib/datagrid/filters/date_filter.rb +5 -30
- data/lib/datagrid/filters/dynamic_filter.rb +52 -6
- data/lib/datagrid/filters/enum_filter.rb +8 -1
- data/lib/datagrid/form_builder.rb +33 -20
- data/lib/datagrid/locale/en.yml +3 -3
- data/lib/datagrid/renderer.rb +1 -1
- data/lib/datagrid/utils.rb +31 -0
- data/spec/datagrid/filters/dynamic_filter_spec.rb +88 -3
- data/spec/datagrid/filters/integer_filter_spec.rb +19 -0
- data/spec/datagrid/filters/string_filter_spec.rb +1 -0
- data/spec/datagrid/form_builder_spec.rb +32 -9
- data/spec/spec_helper.rb +1 -0
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.1
|
data/datagrid.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "datagrid"
|
8
|
-
s.version = "1.0.
|
8
|
+
s.version = "1.0.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Bogdan Gusiev"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-10-14"
|
13
13
|
s.description = "This allows you to easily build datagrid aka data tables with sortable columns and filters"
|
14
14
|
s.email = "agresso@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -18,6 +18,17 @@ module Datagrid
|
|
18
18
|
|
19
19
|
module ClassMethods
|
20
20
|
# Adds a filter that acts like a column selection
|
21
|
+
# All defined columns will be available to select/deselect
|
22
|
+
# as a multi-select enum filter.
|
23
|
+
# Columns with <tt>:mandatory => true</tt> option
|
24
|
+
# will always present in the grid table and won't be listed
|
25
|
+
# in column names selection
|
26
|
+
# Accepts same options as <tt>:enum</tt> filter
|
27
|
+
#
|
28
|
+
# Examples:
|
29
|
+
#
|
30
|
+
# column_names_filter(:header => "Choose columns")
|
31
|
+
#
|
21
32
|
def column_names_filter(options = {})
|
22
33
|
filter(:column_names, :enum, {
|
23
34
|
:select => :optional_columns_select,
|
data/lib/datagrid/columns.rb
CHANGED
@@ -174,7 +174,7 @@ module Datagrid
|
|
174
174
|
# * <tt>column_names</tt> - list of column names if you want to limit data only to specified columns
|
175
175
|
def rows(*column_names)
|
176
176
|
#TODO: find in batches
|
177
|
-
|
177
|
+
driver.batch_map(assets) do |asset|
|
178
178
|
self.row_for(asset, *column_names)
|
179
179
|
end
|
180
180
|
end
|
@@ -189,7 +189,7 @@ module Datagrid
|
|
189
189
|
end
|
190
190
|
|
191
191
|
# Return Array of Hashes where keys are column names and values are column values
|
192
|
-
# for each row in datagrid
|
192
|
+
# for each row in filtered datagrid relation.
|
193
193
|
#
|
194
194
|
# Example:
|
195
195
|
#
|
@@ -205,7 +205,7 @@ module Datagrid
|
|
205
205
|
# MyGrid.new.data_hash # => [{:name => "One"}, {:name => "Two"}]
|
206
206
|
#
|
207
207
|
def data_hash
|
208
|
-
|
208
|
+
driver.batch_map(assets) do |asset|
|
209
209
|
hash_for(asset)
|
210
210
|
end
|
211
211
|
end
|
@@ -268,12 +268,27 @@ module Datagrid
|
|
268
268
|
self.columns(*names)
|
269
269
|
end
|
270
270
|
|
271
|
-
# Finds a column by name
|
271
|
+
# Finds a column definition by name
|
272
272
|
def column_by_name(name)
|
273
273
|
self.class.column_by_name(name)
|
274
274
|
end
|
275
275
|
|
276
276
|
|
277
|
+
# Gives ability to have a different formatting for CSV and HTML column value.
|
278
|
+
#
|
279
|
+
# Example:
|
280
|
+
#
|
281
|
+
# column(:name) do |model|
|
282
|
+
# format(model.name) do |value|
|
283
|
+
# content_tag(:strong, value)
|
284
|
+
# end
|
285
|
+
# end
|
286
|
+
#
|
287
|
+
# column(:company) do |model|
|
288
|
+
# format(model.company.name) do
|
289
|
+
# render :partial => "company_with_logo", :locals => {:company => model.company }
|
290
|
+
# end
|
291
|
+
# end
|
277
292
|
def format(value, &block)
|
278
293
|
if block_given?
|
279
294
|
self.class.format(value, &block)
|
@@ -74,6 +74,14 @@ module Datagrid
|
|
74
74
|
raise NotImplementedError
|
75
75
|
end
|
76
76
|
|
77
|
+
def normalized_column_type(scope, field)
|
78
|
+
raise NotImplementedError
|
79
|
+
end
|
80
|
+
|
81
|
+
def batch_map(scope)
|
82
|
+
raise NotImplementedError
|
83
|
+
end
|
84
|
+
|
77
85
|
protected
|
78
86
|
def timestamp_class?(klass)
|
79
87
|
TIMESTAMP_CLASSES.include?(klass)
|
@@ -71,13 +71,31 @@ module Datagrid
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def contains(scope, field, value)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
field = prefix_table_name(scope, field)
|
75
|
+
scope.where("#{field} #{contains_predicate} ?", "%#{value}%")
|
76
|
+
end
|
77
|
+
|
78
|
+
def normalized_column_type(scope, field)
|
79
|
+
type = column_type(scope, field)
|
80
|
+
return nil unless type
|
81
|
+
{
|
82
|
+
[:string, :text, :time, :binary] => :string,
|
83
|
+
[:integer, :primary_key] => :integer,
|
84
|
+
[:float, :decimal] => :float,
|
85
|
+
[:date] => :date,
|
86
|
+
[:datetime, :timestamp] => :timestamp,
|
87
|
+
[:boolean] => :boolean
|
88
|
+
}.each do |keys, value|
|
89
|
+
return value if keys.include?(type)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def batch_map(scope, &block)
|
94
|
+
result = []
|
95
|
+
scope.find_each do |record|
|
96
|
+
result << yield(record)
|
80
97
|
end
|
98
|
+
result
|
81
99
|
end
|
82
100
|
|
83
101
|
protected
|
@@ -52,12 +52,36 @@ module Datagrid
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def contains(scope, field, value)
|
55
|
-
scope(field => Regexp.compile(Regexp.escape(value)))
|
55
|
+
scope.where(field => Regexp.compile(Regexp.escape(value)))
|
56
56
|
end
|
57
57
|
|
58
58
|
def column_names(scope)
|
59
59
|
to_scope(scope).klass.fields.keys
|
60
60
|
end
|
61
|
+
|
62
|
+
def normalized_column_type(scope, field)
|
63
|
+
type = to_scope(scope).klass.fields[field.to_s].try(:type)
|
64
|
+
return nil unless type
|
65
|
+
{
|
66
|
+
[BigDecimal , String, Symbol, Range, Array, Hash, ] => :string,
|
67
|
+
[Boolean] => :boolean,
|
68
|
+
|
69
|
+
[Date] => :date,
|
70
|
+
|
71
|
+
TIMESTAMP_CLASSES => :timestamp,
|
72
|
+
|
73
|
+
[Float] => :fload,
|
74
|
+
|
75
|
+
[Integer] => :integer,
|
76
|
+
}.each do |keys, value|
|
77
|
+
return value if keys.include?(type)
|
78
|
+
end
|
79
|
+
return :string
|
80
|
+
end
|
81
|
+
|
82
|
+
def batch_map(scope, &block)
|
83
|
+
scope.map(&block)
|
84
|
+
end
|
61
85
|
end
|
62
86
|
end
|
63
87
|
end
|
data/lib/datagrid/filters.rb
CHANGED
@@ -55,24 +55,26 @@ module Datagrid
|
|
55
55
|
#
|
56
56
|
# Arguments:
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
58
|
+
# * <tt>name</tt> - filter name
|
59
|
+
# * <tt>type</tt> - filter type that defines type case and GUI representation of a filter
|
60
|
+
# * <tt>options</tt> - hash of options
|
61
|
+
# * <tt>block</tt> - proc to apply the filter
|
62
62
|
#
|
63
63
|
# Available options:
|
64
64
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
65
|
+
# * <tt>:header</tt> - determines the header of the filter
|
66
|
+
# * <tt>:default</tt> - the default filter value. Able to accept a <tt>Proc</tt> in case default should be recalculated
|
67
|
+
# * <tt>:multiple</tt> - if true multiple values can be assigned to this filter.
|
68
|
+
# By default multiple values are parsed from string using `,` separator.
|
69
|
+
# But you can specify a different separator as option value. Default: false.
|
70
|
+
# * <tt>:allow_nil</tt> - determines if the value can be nil
|
71
|
+
# * <tt>:allow_blank</tt> - determines if the value can be blank
|
72
|
+
# * <tt>:before</tt> - determines the position of this filter,
|
73
|
+
# by adding it before the filter passed here (when using datagrid_form_for helper)
|
74
|
+
# * <tt>:after</tt> - determines the position of this filter,
|
75
|
+
# by adding it after the filter passed here (when using datagrid_form_for helper)
|
76
|
+
# * <tt>:dummy</tt> - if true, this filter will not be applied automatically
|
77
|
+
# and will be just displayed in form. In case you may want to apply it manually.
|
76
78
|
#
|
77
79
|
# See: https://github.com/bogdan/datagrid/wiki/Filters for examples
|
78
80
|
def filter(name, type = :default, options = {}, &block)
|
@@ -121,7 +123,7 @@ module Datagrid
|
|
121
123
|
self.class.filters
|
122
124
|
end
|
123
125
|
|
124
|
-
# Returns filter
|
126
|
+
# Returns filter value for given filter definition
|
125
127
|
def filter_value(filter)
|
126
128
|
self[filter.name]
|
127
129
|
end
|
@@ -12,26 +12,9 @@ class Datagrid::Filters::DateFilter < Datagrid::Filters::BaseFilter
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def parse(value)
|
15
|
-
|
16
|
-
return value if value.is_a?(Range)
|
17
|
-
if value.is_a?(String)
|
18
|
-
formats.each do |format|
|
19
|
-
begin
|
20
|
-
return Date.strptime(value, format)
|
21
|
-
rescue ArgumentError
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
return value.to_date if value.respond_to?(:to_date)
|
26
|
-
return value unless value.is_a?(String)
|
27
|
-
Date.parse(value)
|
28
|
-
rescue ArgumentError
|
29
|
-
nil
|
15
|
+
Datagrid::Utils.parse_date(value)
|
30
16
|
end
|
31
17
|
|
32
|
-
def formats
|
33
|
-
Array(Datagrid.configuration.date_formats)
|
34
|
-
end
|
35
18
|
|
36
19
|
def format(value)
|
37
20
|
if formats.any? && value
|
@@ -43,23 +26,15 @@ class Datagrid::Filters::DateFilter < Datagrid::Filters::BaseFilter
|
|
43
26
|
|
44
27
|
def default_filter_where(driver, scope, value)
|
45
28
|
if driver.is_timestamp?(scope, name)
|
46
|
-
value =
|
29
|
+
value = Datagrid::Utils.format_date_as_timestamp(value)
|
47
30
|
end
|
48
31
|
super(driver, scope, value)
|
49
32
|
end
|
50
33
|
|
51
34
|
protected
|
52
|
-
def format_value_timestamp(value)
|
53
|
-
if !value
|
54
|
-
value
|
55
|
-
elsif (range? && value.is_a?(Array))
|
56
|
-
[value.first.try(:beginning_of_day), value.last.try(:end_of_day)]
|
57
|
-
elsif value.is_a?(Range)
|
58
|
-
(value.first.beginning_of_day..value.last.end_of_day)
|
59
|
-
else
|
60
|
-
value.beginning_of_day..value.end_of_day
|
61
|
-
end
|
62
|
-
end
|
63
35
|
|
36
|
+
def formats
|
37
|
+
Array(Datagrid.configuration.date_formats)
|
38
|
+
end
|
64
39
|
end
|
65
40
|
|
@@ -6,12 +6,16 @@ class Datagrid::Filters::DynamicFilter < Datagrid::Filters::BaseFilter
|
|
6
6
|
|
7
7
|
def initialize(*)
|
8
8
|
super
|
9
|
-
options[:multiple] = true
|
10
9
|
options[:select] ||= default_select
|
10
|
+
unless options.has_key?(:include_blank)
|
11
|
+
options[:include_blank] = false
|
12
|
+
end
|
11
13
|
end
|
12
14
|
|
13
|
-
def
|
14
|
-
value
|
15
|
+
def parse_values(filter)
|
16
|
+
field, operation, value = filter
|
17
|
+
|
18
|
+
[field, operation, type_cast(field, value)]
|
15
19
|
end
|
16
20
|
|
17
21
|
def unapplicable_value?(filter)
|
@@ -21,15 +25,31 @@ class Datagrid::Filters::DynamicFilter < Datagrid::Filters::BaseFilter
|
|
21
25
|
|
22
26
|
def default_filter_where(driver, scope, filter)
|
23
27
|
field, operation, value = filter
|
24
|
-
driver.
|
28
|
+
date_conversion = value.is_a?(Date) && driver.is_timestamp?(scope, field)
|
25
29
|
case operation
|
26
30
|
when '='
|
31
|
+
if date_conversion
|
32
|
+
value = Datagrid::Utils.format_date_as_timestamp(value)
|
33
|
+
end
|
27
34
|
driver.where(scope, field, value)
|
28
35
|
when '=~'
|
29
|
-
|
36
|
+
if column_type(field) == :string
|
37
|
+
driver.contains(scope, field, value)
|
38
|
+
else
|
39
|
+
if date_conversion
|
40
|
+
value = Datagrid::Utils.format_date_as_timestamp(value)
|
41
|
+
end
|
42
|
+
driver.where(scope, field, value)
|
43
|
+
end
|
30
44
|
when '>='
|
45
|
+
if date_conversion
|
46
|
+
value = value.beginning_of_day
|
47
|
+
end
|
31
48
|
driver.greater_equal(scope, field, value)
|
32
49
|
when '<='
|
50
|
+
if date_conversion
|
51
|
+
value = value.end_of_day
|
52
|
+
end
|
33
53
|
driver.less_equal(scope, field, value)
|
34
54
|
else
|
35
55
|
raise "unknown operation: #{operation.inspect}"
|
@@ -38,7 +58,7 @@ class Datagrid::Filters::DynamicFilter < Datagrid::Filters::BaseFilter
|
|
38
58
|
|
39
59
|
def operations_select
|
40
60
|
%w(= =~ >= <=).map do |operation|
|
41
|
-
I18n.t(operation, :scope => "datagrid.filters.dynamic.operations")
|
61
|
+
[I18n.t(operation, :scope => "datagrid.filters.dynamic.operations").html_safe, operation]
|
42
62
|
end
|
43
63
|
end
|
44
64
|
|
@@ -54,4 +74,30 @@ class Datagrid::Filters::DynamicFilter < Datagrid::Filters::BaseFilter
|
|
54
74
|
}
|
55
75
|
end
|
56
76
|
|
77
|
+
def type_cast(field, value)
|
78
|
+
type = column_type(field)
|
79
|
+
return nil if value.blank?
|
80
|
+
case type
|
81
|
+
when :string
|
82
|
+
value.to_s
|
83
|
+
when :integer
|
84
|
+
value.is_a?(Numeric) || value =~ /^\d/ ? value.to_i : nil
|
85
|
+
when :float
|
86
|
+
value.is_a?(Numeric) || value =~ /^\d/ ? value.to_f : nil
|
87
|
+
when :date
|
88
|
+
Datagrid::Utils.parse_date(value)
|
89
|
+
when :timestamp
|
90
|
+
Datagrid::Utils.parse_date(value)
|
91
|
+
when :boolean
|
92
|
+
Datagrid::Utils.booleanize(value)
|
93
|
+
when nil
|
94
|
+
value
|
95
|
+
else
|
96
|
+
raise NotImplementedError, "unknown column type: #{type.inspect}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def column_type(field)
|
101
|
+
grid_class.driver.normalized_column_type(grid_class.scope, field)
|
102
|
+
end
|
57
103
|
end
|
@@ -6,6 +6,9 @@ class Datagrid::Filters::EnumFilter < Datagrid::Filters::BaseFilter
|
|
6
6
|
|
7
7
|
def initialize(*args)
|
8
8
|
super(*args)
|
9
|
+
if checkboxes?
|
10
|
+
options[:multiple] = true
|
11
|
+
end
|
9
12
|
raise Datagrid::ConfigurationError, ":select option not specified" unless options[:select]
|
10
13
|
end
|
11
14
|
|
@@ -15,7 +18,11 @@ class Datagrid::Filters::EnumFilter < Datagrid::Filters::BaseFilter
|
|
15
18
|
end
|
16
19
|
|
17
20
|
def strict
|
18
|
-
|
21
|
+
options[:strict]
|
22
|
+
end
|
23
|
+
|
24
|
+
def checkboxes?
|
25
|
+
options[:checkboxes]
|
19
26
|
end
|
20
27
|
|
21
28
|
end
|
@@ -22,7 +22,7 @@ module Datagrid
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def datagrid_boolean_filter(attribute_or_filter, options = {})
|
25
|
-
check_box(datagrid_get_attribute(attribute_or_filter), options)
|
25
|
+
check_box(datagrid_get_attribute(attribute_or_filter), options.reverse_merge(datagrid_extra_checkbox_options))
|
26
26
|
end
|
27
27
|
|
28
28
|
def datagrid_date_filter(attribute_or_filter, options = {})
|
@@ -31,8 +31,7 @@ module Datagrid
|
|
31
31
|
|
32
32
|
def datagrid_default_filter(attribute_or_filter, options = {})
|
33
33
|
filter = datagrid_get_filter(attribute_or_filter)
|
34
|
-
value
|
35
|
-
text_field filter.name, options.merge(:value => object.filter_value_as_string(filter))
|
34
|
+
text_field filter.name, options.reverse_merge(:value => object.filter_value_as_string(filter))
|
36
35
|
end
|
37
36
|
|
38
37
|
def datagrid_enum_filter(attribute_or_filter, options = {})
|
@@ -40,7 +39,16 @@ module Datagrid
|
|
40
39
|
if !options.has_key?(:multiple) && filter.multiple?
|
41
40
|
options[:multiple] = true
|
42
41
|
end
|
43
|
-
|
42
|
+
if filter.checkboxes?
|
43
|
+
filter.select(options).map do |element|
|
44
|
+
text, value = @template.send(:option_text_and_value, element)
|
45
|
+
id = [object_name, filter.name, value.underscore].join('_')
|
46
|
+
input = check_box(filter.name, options.merge(datagrid_extra_checkbox_options).reverse_merge(:id => id, :multiple => true), value, nil)
|
47
|
+
label(filter.name, input + text, :for => id)
|
48
|
+
end.join("\n").html_safe
|
49
|
+
else
|
50
|
+
select filter.name, filter.select(object) || [], {:include_blank => filter.include_blank, :prompt => filter.prompt, :include_hidden => false}, options
|
51
|
+
end
|
44
52
|
end
|
45
53
|
|
46
54
|
def datagrid_integer_filter(attribute_or_filter, options = {})
|
@@ -57,18 +65,18 @@ module Datagrid
|
|
57
65
|
field, operation, value = object.filter_value(filter)
|
58
66
|
options = options.merge(:name => input_name)
|
59
67
|
field_input = select(
|
60
|
-
filter.name,
|
61
|
-
filter.select(object) || [],
|
68
|
+
filter.name,
|
69
|
+
filter.select(object) || [],
|
62
70
|
{
|
63
71
|
:include_blank => filter.include_blank,
|
64
72
|
:prompt => filter.prompt,
|
65
73
|
:include_hidden => false,
|
66
74
|
:selected => field
|
67
|
-
},
|
75
|
+
},
|
68
76
|
add_html_classes(options, "field")
|
69
77
|
)
|
70
78
|
operation_input = select(
|
71
|
-
filter.name, filter.operations_select,
|
79
|
+
filter.name, filter.operations_select,
|
72
80
|
{:include_blank => false, :include_hidden => false, :prompt => false, :selected => operation },
|
73
81
|
add_html_classes(options, "operation")
|
74
82
|
)
|
@@ -83,7 +91,7 @@ module Datagrid
|
|
83
91
|
|
84
92
|
|
85
93
|
from_options = datagrid_range_filter_options(object, filter, :from, options)
|
86
|
-
to_options = datagrid_range_filter_options(object, filter, :to, options)
|
94
|
+
to_options = datagrid_range_filter_options(object, filter, :to, options)
|
87
95
|
# 2 inputs: "from date" and "to date" to specify a range
|
88
96
|
[
|
89
97
|
text_field(filter.name, from_options),
|
@@ -100,17 +108,17 @@ module Datagrid
|
|
100
108
|
type_method_map = {:from => :first, :to => :last}
|
101
109
|
options = add_html_classes(options, type)
|
102
110
|
options[:value] = filter.format(object[filter.name].try(type_method_map[type]))
|
103
|
-
# In case of datagrid ranged filter
|
111
|
+
# In case of datagrid ranged filter
|
104
112
|
# from and to input will have same id
|
105
|
-
options[:id] = if !options.key?(:id)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
113
|
+
options[:id] = if !options.key?(:id)
|
114
|
+
# Rails provides it's own default id for all inputs
|
115
|
+
# In order to prevent that we assign no id by default
|
116
|
+
options[:id] = nil
|
117
|
+
elsif options[:id].present?
|
118
|
+
# If the id was given we prefix it
|
119
|
+
# with from_ and to_ accordingly
|
120
|
+
options[:id] = [type, options[:id]].join("_")
|
121
|
+
end
|
114
122
|
options
|
115
123
|
end
|
116
124
|
|
@@ -140,11 +148,16 @@ module Datagrid
|
|
140
148
|
end
|
141
149
|
|
142
150
|
def add_html_classes(options, *classes)
|
143
|
-
Datagrid::Utils.add_html_classes(options, *classes)
|
151
|
+
Datagrid::Utils.add_html_classes(options, *classes)
|
152
|
+
end
|
153
|
+
|
154
|
+
def datagrid_extra_checkbox_options
|
155
|
+
::ActionPack::VERSION::MAJOR >= 4 ? {:include_hidden => false} : {}
|
144
156
|
end
|
145
157
|
|
146
158
|
class Error < StandardError
|
147
159
|
end
|
160
|
+
|
148
161
|
end
|
149
162
|
end
|
150
163
|
|
data/lib/datagrid/locale/en.yml
CHANGED
data/lib/datagrid/renderer.rb
CHANGED
@@ -38,7 +38,7 @@ module Datagrid
|
|
38
38
|
options[:html] ||= {}
|
39
39
|
options[:html][:class] ||= "datagrid #{html_class(grid)}"
|
40
40
|
if options[:cycle]
|
41
|
-
::Datagrid::Utils.warn_once("datagrid_table cycle option is deprecated. Use css to
|
41
|
+
::Datagrid::Utils.warn_once("datagrid_table cycle option is deprecated. Use css to style odd/even rows instead.")
|
42
42
|
end
|
43
43
|
assets = args.any? ? args.shift : grid.assets
|
44
44
|
paginate = options[:paginate]
|
data/lib/datagrid/utils.rb
CHANGED
@@ -54,6 +54,37 @@ module Datagrid
|
|
54
54
|
end
|
55
55
|
block.call(*args)
|
56
56
|
end
|
57
|
+
|
58
|
+
def parse_date(value)
|
59
|
+
return nil if value.blank?
|
60
|
+
return value if value.is_a?(Range)
|
61
|
+
if value.is_a?(String)
|
62
|
+
Array(Datagrid.configuration.date_formats).each do |format|
|
63
|
+
begin
|
64
|
+
return Date.strptime(value, format)
|
65
|
+
rescue ::ArgumentError
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return Date.parse(value) if value.is_a?(String)
|
70
|
+
return value.to_date if value.respond_to?(:to_date)
|
71
|
+
value
|
72
|
+
rescue ::ArgumentError
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def format_date_as_timestamp(value)
|
77
|
+
if !value
|
78
|
+
value
|
79
|
+
elsif value.is_a?(Array)
|
80
|
+
[value.first.try(:beginning_of_day), value.last.try(:end_of_day)]
|
81
|
+
elsif value.is_a?(Range)
|
82
|
+
(value.first.beginning_of_day..value.last.end_of_day)
|
83
|
+
else
|
84
|
+
value.beginning_of_day..value.end_of_day
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
57
88
|
end
|
58
89
|
end
|
59
90
|
end
|
@@ -14,24 +14,109 @@ describe Datagrid::Filters::DynamicFilter do
|
|
14
14
|
report.assets.should include(Entry.create!(:name => 'hello'))
|
15
15
|
report.assets.should_not include(Entry.create!(:name => 'bye'))
|
16
16
|
end
|
17
|
+
|
18
|
+
it "should support >= operation" do
|
19
|
+
report.condition = [:name, ">=", "d"]
|
20
|
+
report.assets.should include(Entry.create!(:name => 'x'))
|
21
|
+
report.assets.should include(Entry.create!(:name => 'd'))
|
22
|
+
report.assets.should_not include(Entry.create!(:name => 'a'))
|
23
|
+
end
|
24
|
+
|
17
25
|
it "should blank value" do
|
18
26
|
report.condition = [:name, "=", ""]
|
19
27
|
report.assets.should include(Entry.create!(:name => 'hello'))
|
20
28
|
end
|
21
|
-
|
29
|
+
|
30
|
+
it "should support =~ operation on strings" do
|
22
31
|
report.condition = [:name, "=~", "ell"]
|
23
32
|
report.assets.should include(Entry.create!(:name => 'hello'))
|
24
33
|
report.assets.should_not include(Entry.create!(:name => 'bye'))
|
25
34
|
end
|
26
|
-
|
35
|
+
|
36
|
+
it "should support =~ operation integers" do
|
37
|
+
report.condition = [:group_id, "=~", 2]
|
38
|
+
report.assets.should include(Entry.create!(:group_id => 2))
|
39
|
+
report.assets.should_not include(Entry.create!(:group_id => 1))
|
40
|
+
report.assets.should_not include(Entry.create!(:group_id => 3))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should support >= operation on integer" do
|
27
44
|
report.condition = [:group_id, ">=", 2]
|
28
45
|
report.assets.should include(Entry.create!(:group_id => 3))
|
29
46
|
report.assets.should_not include(Entry.create!(:group_id => 1))
|
30
47
|
end
|
31
|
-
|
48
|
+
|
49
|
+
it "should support <= operation on integer" do
|
32
50
|
report.condition = [:group_id, "<=", 2]
|
33
51
|
report.assets.should include(Entry.create!(:group_id => 1))
|
34
52
|
report.assets.should_not include(Entry.create!(:group_id => 3))
|
35
53
|
end
|
36
54
|
|
55
|
+
it "should support <= operation on integer with string value" do
|
56
|
+
report.condition = [:group_id, "<=", '2']
|
57
|
+
report.assets.should include(Entry.create!(:group_id => 1))
|
58
|
+
report.assets.should include(Entry.create!(:group_id => 2))
|
59
|
+
report.assets.should_not include(Entry.create!(:group_id => 3))
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should nullify incorrect value for integer" do
|
63
|
+
report.condition = [:group_id, "<=", 'aa']
|
64
|
+
report.condition.should == [:group_id, "<=", nil]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should nullify incorrect value for date" do
|
68
|
+
report.condition = [:shipping_date, "<=", 'aa']
|
69
|
+
report.condition.should == [:shipping_date, "<=", nil]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should nullify incorrect value for datetime" do
|
73
|
+
report.condition = [:created_at, "<=", 'aa']
|
74
|
+
report.condition.should == [:created_at, "<=", nil]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should support date comparation operation by timestamp column" do
|
78
|
+
report.condition = [:created_at, "<=", '1986-08-05']
|
79
|
+
report.condition.should == [:created_at, "<=", Date.parse('1986-08-05')]
|
80
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-04 01:01:01')))
|
81
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 23:59:59')))
|
82
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 00:00:00')))
|
83
|
+
report.assets.should_not include(Entry.create!(:created_at => DateTime.parse('1986-08-06 00:00:00')))
|
84
|
+
report.assets.should_not include(Entry.create!(:created_at => DateTime.parse('1986-08-06 23:59:59')))
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should support date = operation by timestamp column" do
|
88
|
+
report.condition = [:created_at, "=", '1986-08-05']
|
89
|
+
report.condition.should == [:created_at, "=", Date.parse('1986-08-05')]
|
90
|
+
report.assets.should_not include(Entry.create!(:created_at => DateTime.parse('1986-08-04 23:59:59')))
|
91
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 23:59:59')))
|
92
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 00:00:01')))
|
93
|
+
#TODO: investigate SQLite issue and uncomment this line
|
94
|
+
#report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 00:00:00')))
|
95
|
+
report.assets.should_not include(Entry.create!(:created_at => DateTime.parse('1986-08-06 23:59:59')))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should support date =~ operation by timestamp column" do
|
99
|
+
report.condition = [:created_at, "=~", '1986-08-05']
|
100
|
+
report.condition.should == [:created_at, "=~", Date.parse('1986-08-05')]
|
101
|
+
report.assets.should_not include(Entry.create!(:created_at => DateTime.parse('1986-08-04 23:59:59')))
|
102
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 23:59:59')))
|
103
|
+
report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 00:00:01')))
|
104
|
+
#TODO: investigate SQLite issue and uncomment this line
|
105
|
+
#report.assets.should include(Entry.create!(:created_at => DateTime.parse('1986-08-05 00:00:00')))
|
106
|
+
report.assets.should_not include(Entry.create!(:created_at => DateTime.parse('1986-08-06 23:59:59')))
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should support operations for invalid date" do
|
110
|
+
report.condition = [:shipping_date, "<=", '1986-08-05']
|
111
|
+
report.assets.should include(Entry.create!(:shipping_date => '1986-08-04'))
|
112
|
+
report.assets.should include(Entry.create!(:shipping_date => '1986-08-05'))
|
113
|
+
report.assets.should_not include(Entry.create!(:shipping_date => '1986-08-06'))
|
114
|
+
end
|
115
|
+
it "should support operations for invalid date" do
|
116
|
+
report.condition = [:shipping_date, "<=", Date.parse('1986-08-05')]
|
117
|
+
report.assets.should include(Entry.create!(:shipping_date => '1986-08-04'))
|
118
|
+
report.assets.should include(Entry.create!(:shipping_date => '1986-08-05'))
|
119
|
+
report.assets.should_not include(Entry.create!(:shipping_date => '1986-08-06'))
|
120
|
+
end
|
121
|
+
|
37
122
|
end
|
@@ -122,4 +122,23 @@ describe Datagrid::Filters::IntegerFilter do
|
|
122
122
|
report.assets.should_not include(Entry.create!( :group_id => 3))
|
123
123
|
end
|
124
124
|
|
125
|
+
it "should support multiple values" do
|
126
|
+
report = test_report(:group_id => "1,2") do
|
127
|
+
scope {Entry}
|
128
|
+
filter(:group_id, :string, :multiple => true)
|
129
|
+
end
|
130
|
+
report.assets.should include(Entry.create!( :group_id => 1))
|
131
|
+
report.assets.should include(Entry.create!( :group_id => 2))
|
132
|
+
report.assets.should_not include(Entry.create!( :group_id => 3))
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should support custom separator multiple values" do
|
136
|
+
report = test_report(:group_id => "1|2") do
|
137
|
+
scope {Entry}
|
138
|
+
filter(:group_id, :string, :multiple => '|')
|
139
|
+
end
|
140
|
+
report.assets.should include(Entry.create!( :group_id => 1))
|
141
|
+
report.assets.should include(Entry.create!( :group_id => 2))
|
142
|
+
report.assets.should_not include(Entry.create!( :group_id => 3))
|
143
|
+
end
|
125
144
|
end
|
@@ -20,6 +20,7 @@ describe Datagrid::Filters::StringFilter do
|
|
20
20
|
report.assets.should include(Entry.create!( :name => "one,1"))
|
21
21
|
report.assets.should include(Entry.create!( :name => "two,2"))
|
22
22
|
report.assets.should_not include(Entry.create!( :name => "one"))
|
23
|
+
report.assets.should_not include(Entry.create!( :name => "two"))
|
23
24
|
end
|
24
25
|
|
25
26
|
end
|
@@ -218,6 +218,29 @@ describe Datagrid::FormBuilder do
|
|
218
218
|
<option value="second">second</option></select>'
|
219
219
|
)}
|
220
220
|
end
|
221
|
+
context "with checkboxes option" do
|
222
|
+
let(:_filter) { :category_with_prompt }
|
223
|
+
it { should equal_to_dom(
|
224
|
+
'<select class="category_with_prompt enum_filter" id="report_category_with_prompt" name="report[category_with_prompt]"><option value="">My Prompt</option>
|
225
|
+
<option value="first">first</option>
|
226
|
+
<option value="second">second</option></select>'
|
227
|
+
)}
|
228
|
+
end
|
229
|
+
context "with checkboxes option" do
|
230
|
+
let(:_grid) do
|
231
|
+
test_report do
|
232
|
+
scope {Entry}
|
233
|
+
filter(:category, :enum, :select => ["first", "second"], :checkboxes => true)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
let(:_filter) { :category }
|
237
|
+
it { should equal_to_dom(
|
238
|
+
'
|
239
|
+
<label for="report_category_first"><input class="category enum_filter" id="report_category_first" name="report[category][]" type="checkbox" value="first" />first</label>
|
240
|
+
<label for="report_category_second"><input class="category enum_filter" id="report_category_second" name="report[category][]" type="checkbox" value="second" />second</label>
|
241
|
+
'
|
242
|
+
)}
|
243
|
+
end
|
221
244
|
end
|
222
245
|
|
223
246
|
context "with eboolean filter type" do
|
@@ -373,9 +396,9 @@ describe Datagrid::FormBuilder do
|
|
373
396
|
<option value="shipping_date">Shipping date</option>
|
374
397
|
<option value="created_at">Created at</option>
|
375
398
|
<option value="updated_at">Updated at</option></select><select class="condition dynamic_filter operation" id="report_condition" name="report[condition][]"><option value="=">=</option>
|
376
|
-
<option value="=~"
|
377
|
-
<option value=">=">&
|
378
|
-
<option value="<=">&
|
399
|
+
<option value="=~">≈</option>
|
400
|
+
<option value=">=">≥</option>
|
401
|
+
<option value="<=">≤</option></select><input class="condition dynamic_filter value" id="report_condition" name="report[condition][]" size="30" type="text">
|
379
402
|
HTML
|
380
403
|
end
|
381
404
|
it {should equal_to_dom(expected_html)}
|
@@ -389,9 +412,9 @@ describe Datagrid::FormBuilder do
|
|
389
412
|
<<-HTML
|
390
413
|
<select class="condition dynamic_filter field" id="report_condition" name="report[condition][]"><option value="id" selected>id</option>
|
391
414
|
<option value="name">name</option></select><select class="condition dynamic_filter operation" id="report_condition" name="report[condition][]"><option value="=">=</option>
|
392
|
-
<option value="=~"
|
393
|
-
<option value=">=" selected>&
|
394
|
-
<option value="<=">&
|
415
|
+
<option value="=~">≈</option>
|
416
|
+
<option value=">=" selected>≥</option>
|
417
|
+
<option value="<=">≤</option></select><input class="condition dynamic_filter value" id="report_condition" name="report[condition][]" size="30" type="text" value="1">
|
395
418
|
HTML
|
396
419
|
end
|
397
420
|
it {should equal_to_dom(expected_html)}
|
@@ -405,9 +428,9 @@ describe Datagrid::FormBuilder do
|
|
405
428
|
<<-HTML
|
406
429
|
<select class="condition dynamic_filter field" id="report_condition" name="report[condition][]"><option value="id">id</option>
|
407
430
|
<option value="name">name</option></select><select class="condition dynamic_filter operation" id="report_condition" name="report[condition][]"><option value="=">=</option>
|
408
|
-
<option value="=~"
|
409
|
-
<option value=">=">&
|
410
|
-
<option value="<=">&
|
431
|
+
<option value="=~">≈</option>
|
432
|
+
<option value=">=">≥</option>
|
433
|
+
<option value="<=">≤</option></select><input class="condition dynamic_filter value" id="report_condition" name="report[condition][]" size="30" type="text">
|
411
434
|
HTML
|
412
435
|
end
|
413
436
|
it {should equal_to_dom(expected_html)}
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datagrid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-10-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -344,7 +344,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
344
344
|
version: '0'
|
345
345
|
segments:
|
346
346
|
- 0
|
347
|
-
hash:
|
347
|
+
hash: 1961249610796694956
|
348
348
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
349
349
|
none: false
|
350
350
|
requirements:
|