datagrid 1.0.0 → 1.0.1
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.
- 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:
|