wice_grid 3.5.0 → 3.6.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.inch.yml +3 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +181 -0
  5. data/.travis.yml +22 -0
  6. data/{CHANGELOG → CHANGELOG.md} +95 -31
  7. data/Gemfile +4 -1
  8. data/README.md +1517 -0
  9. data/Rakefile +51 -7
  10. data/{SAVED_QUERIES_HOWTO.rdoc → SAVED_QUERIES_HOWTO.md} +34 -31
  11. data/TODO.md +16 -0
  12. data/lib/generators/wice_grid/add_migration_for_serialized_queries_generator.rb +4 -6
  13. data/lib/generators/wice_grid/install_generator.rb +2 -5
  14. data/lib/generators/wice_grid/templates/create_wice_grid_serialized_queries.rb +1 -0
  15. data/lib/generators/wice_grid/templates/wice_grid_config.rb +29 -34
  16. data/lib/wice/active_record_column_wrapper.rb +36 -17
  17. data/lib/wice/columns.rb +53 -52
  18. data/lib/wice/columns/column_action.rb +11 -13
  19. data/lib/wice/columns/column_boolean.rb +9 -11
  20. data/lib/wice/columns/column_bootstrap_datepicker.rb +48 -0
  21. data/lib/wice/columns/column_custom_dropdown.rb +22 -23
  22. data/lib/wice/columns/column_float.rb +2 -6
  23. data/lib/wice/columns/column_html5_datepicker.rb +31 -0
  24. data/lib/wice/columns/column_integer.rb +9 -13
  25. data/lib/wice/columns/column_jquery_datepicker.rb +49 -0
  26. data/lib/wice/columns/column_processor_index.rb +18 -13
  27. data/lib/wice/columns/column_rails_date_helper.rb +41 -0
  28. data/lib/wice/columns/column_rails_datetime_helper.rb +40 -0
  29. data/lib/wice/columns/column_range.rb +7 -11
  30. data/lib/wice/columns/column_string.rb +24 -20
  31. data/lib/wice/columns/common_date_datetime_mixin.rb +20 -0
  32. data/lib/wice/columns/common_js_date_datetime_conditions_generator_mixin.rb +39 -0
  33. data/lib/wice/columns/common_js_date_datetime_mixin.rb +15 -0
  34. data/lib/wice/columns/{column_date.rb → common_rails_date_datetime_conditions_generator_mixin.rb} +4 -22
  35. data/lib/wice/columns/common_standard_helper_date_datetime_mixin.rb +22 -0
  36. data/lib/wice/grid_output_buffer.rb +19 -10
  37. data/lib/wice/grid_renderer.rb +146 -85
  38. data/lib/wice/helpers/bs_calendar_helpers.rb +6 -7
  39. data/lib/wice/helpers/js_calendar_helpers.rb +19 -17
  40. data/lib/wice/helpers/wice_grid_misc_view_helpers.rb +18 -18
  41. data/lib/wice/helpers/wice_grid_serialized_queries_view_helpers.rb +44 -49
  42. data/lib/wice/helpers/wice_grid_view_helpers.rb +131 -134
  43. data/lib/wice/kaminari_monkey_patching.rb +3 -1
  44. data/lib/wice/table_column_matrix.rb +23 -8
  45. data/lib/wice/wice_grid_controller.rb +12 -16
  46. data/lib/wice/wice_grid_core_ext.rb +12 -20
  47. data/lib/wice/wice_grid_misc.rb +131 -53
  48. data/lib/wice/wice_grid_serialized_queries_controller.rb +10 -11
  49. data/lib/wice/wice_grid_serialized_query.rb +4 -3
  50. data/lib/wice/wice_grid_spreadsheet.rb +19 -18
  51. data/lib/wice_grid.rb +144 -135
  52. data/spec/schema.rb +9 -0
  53. data/spec/spec_helper.rb +75 -0
  54. data/spec/support/active_record.rb +11 -0
  55. data/spec/support/wice_grid_test_config.rb +172 -0
  56. data/spec/wice/grid_output_buffer_spec.rb +41 -0
  57. data/spec/wice/table_column_matrix_spec.rb +38 -0
  58. data/spec/wice/wice_grid_misc_spec.rb +159 -0
  59. data/spec/wice/wice_grid_spreadsheet_spec.rb +14 -0
  60. data/test/readme.txt +1 -1
  61. data/vendor/assets/javascripts/wice_grid_init.js.coffee +14 -8
  62. data/vendor/assets/stylesheets/wice_grid.scss +84 -0
  63. data/wice_grid.gemspec +32 -16
  64. metadata +217 -25
  65. data/README.rdoc +0 -1325
  66. data/lib/generators/wice_grid/templates/wice_grid.scss +0 -140
  67. data/lib/wice/columns/column_datetime.rb +0 -171
  68. data/vendor/assets/images/icons/grid/arrow_down.gif +0 -0
  69. data/vendor/assets/images/icons/grid/arrow_up.gif +0 -0
  70. data/vendor/assets/images/icons/grid/calendar_view_month.png +0 -0
  71. data/vendor/assets/images/icons/grid/collapse.gif +0 -0
  72. data/vendor/assets/images/icons/grid/delete.png +0 -0
  73. data/vendor/assets/images/icons/grid/expand.gif +0 -0
  74. data/vendor/assets/images/icons/grid/page_white_excel.png +0 -0
  75. data/vendor/assets/images/icons/grid/page_white_find.png +0 -0
  76. data/vendor/assets/images/icons/grid/table.png +0 -0
  77. data/vendor/assets/images/icons/grid/table_refresh.png +0 -0
  78. data/vendor/assets/images/icons/grid/tick_all.png +0 -0
  79. data/vendor/assets/images/icons/grid/untick_all.png +0 -0
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Wice
3
+ module Columns #:nodoc:
4
+ module CommonJsDateDatetimeConditionsGeneratorMixin #:nodoc:
5
+
6
+ def generate_conditions(table_alias, opts) #:nodoc:
7
+
8
+ datetime = @column_type == :datetime || @column_type == :timestamp
9
+
10
+ conditions = [[]]
11
+ if opts[:fr]
12
+ conditions[0] << " #{@column_wrapper.alias_or_table_name(table_alias)}.#{@column_wrapper.name} >= ? "
13
+ date = opts[:fr].to_date
14
+ if datetime
15
+ date = date.to_datetime
16
+ end
17
+ conditions << date
18
+ end
19
+
20
+ if opts[:to]
21
+ op = '<='
22
+ date = opts[:to].to_date
23
+ if datetime
24
+ date = (date + 1).to_datetime
25
+ op = '<'
26
+ end
27
+ conditions[0] << " #{@column_wrapper.alias_or_table_name(table_alias)}.#{@column_wrapper.name} #{op} ? "
28
+ conditions << date
29
+ end
30
+
31
+ return false if conditions.size == 1
32
+
33
+ conditions[0] = conditions[0].join(' and ')
34
+ conditions
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ module Wice
3
+ module Columns #:nodoc:
4
+ module CommonJsDateDatetimeMixin #:nodoc:
5
+
6
+ def prepare #:nodoc:
7
+ query, _, @name1, @dom_id = form_parameter_name_id_and_query(fr: '')
8
+ query2, _, @name2, @dom_id2 = form_parameter_name_id_and_query(to: '')
9
+
10
+ @queris_ids = [[query, @dom_id], [query2, @dom_id2]]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -1,24 +1,7 @@
1
+ # encoding: utf-8
1
2
  module Wice
2
-
3
3
  module Columns #:nodoc:
4
-
5
- class ViewColumnDate < ViewColumnDatetime #:nodoc:
6
-
7
- def chunk_names
8
- %w(year month day)
9
- end
10
-
11
- def render_standard_filter_internal(params) #:nodoc:
12
- '<div class="date-filter">' +
13
- select_date(params[:fr], {include_blank: true, prefix: @name1, id: @dom_id}) + '<br/>' +
14
- select_date(params[:to], {include_blank: true, prefix: @name2, id: @dom_id2}) +
15
- '</div>'
16
- end
17
-
18
- end
19
-
20
-
21
- class ConditionsGeneratorColumnDate < ConditionsGeneratorColumn #:nodoc:
4
+ module CommonJsDateDatetimeConditionsGeneratorMixin #:nodoc:
22
5
 
23
6
  def generate_conditions(table_alias, opts) #:nodoc:
24
7
  conditions = [[]]
@@ -37,8 +20,7 @@ module Wice
37
20
  conditions[0] = conditions[0].join(' and ')
38
21
  conditions
39
22
  end
40
- end
41
23
 
24
+ end
42
25
  end
43
-
44
- end
26
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ module Wice
3
+ module Columns #:nodoc:
4
+ module CommonStandardDateDatetimeMixin #:nodoc:
5
+
6
+ def prepare #:nodoc:
7
+ x = lambda do|sym|
8
+ chunk_names.map do|datetime_chunk_name|
9
+ triple = form_parameter_name_id_and_query(sym => { datetime_chunk_name => '' })
10
+ [triple[0], triple[3]]
11
+ end
12
+ end
13
+
14
+ @queris_ids = x.call(:fr) + x.call(:to)
15
+
16
+ _, _, @name1, _ = form_parameter_name_id_and_query(fr: '')
17
+ _, _, @name2, _ = form_parameter_name_id_and_query(to: '')
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -1,40 +1,49 @@
1
+ # encoding: utf-8
1
2
  module Wice
2
-
3
3
  class GridOutputBuffer < String #:nodoc:
4
4
 
5
+ # defines behavior for rendering nonexistent filters.
6
+ # If return_empty_strings_for_nonexistent_filters is true, a call to render a non existent filter will raise an exception
7
+ # If return_empty_strings_for_nonexistent_filters is false (CSV mode), no exception will be raised.
5
8
  attr_accessor :return_empty_strings_for_nonexistent_filters
6
9
 
10
+ # initializes a grid output buffer
7
11
  def initialize(*attrs)
8
12
  super(*attrs)
9
13
  @filters = HashWithIndifferentAccess.new
10
14
  end
11
15
 
16
+ # returns HTML code the grid
12
17
  def to_s
13
18
  super.html_safe
14
19
  end
15
20
 
21
+ # stores HTML code for a detached filter
16
22
  def add_filter(detach_with_id, filter_code)
17
- raise WiceGridException.new("Detached ID #{detach_with_id} is already used!") if @filters.has_key? detach_with_id
23
+ fail WiceGridException.new("Detached ID #{detach_with_id} is already used!") if @filters.key? detach_with_id
18
24
  @filters[detach_with_id] = filter_code
19
25
  end
20
26
 
21
- def filter_for detach_with_id
22
- unless @filters.has_key? detach_with_id
27
+ # returns HTML code for a detached filter
28
+ def filter_for(detach_with_id)
29
+ unless @filters.key? detach_with_id
23
30
  if @return_empty_strings_for_nonexistent_filters
24
31
  return ''
25
32
  else
26
- raise WiceGridException.new("No filter with Detached ID '#{detach_with_id}'!")
33
+ fail WiceGridException.new("No filter with Detached ID '#{detach_with_id}'!")
27
34
  end
28
35
  end
29
- if @filters[detach_with_id] == false
30
- raise WiceGridException.new("Filter with Detached ID '#{detach_with_id}' has already been requested once! There cannot be two instances of the same filter on one page")
36
+
37
+ unless @filters[detach_with_id]
38
+ fail WiceGridException.new("Filter with Detached ID '#{detach_with_id}' has already been requested once! There cannot be two instances of the same filter on one page")
31
39
  end
40
+
32
41
  res = @filters[detach_with_id]
33
42
  @filters[detach_with_id] = false
34
- return res
43
+ res
35
44
  end
36
45
 
46
+ # returns HTML code for a detached filter
37
47
  alias_method :[], :filter_for
38
-
39
48
  end
40
- end
49
+ end
@@ -1,32 +1,49 @@
1
+ # encoding: utf-8
1
2
  module Wice
2
- class GridRenderer
3
3
 
4
+ # Instance of `GridRenderer` is injected into the top level block of the `grid` helper.
5
+ # `g.column`, `g.action_column` are all examples of methods of `GridRenderer`
6
+ class GridRenderer
4
7
  include ActionView::Helpers::TagHelper
5
8
  include ActionView::Helpers::CaptureHelper
6
9
  include ActionView::Helpers::TextHelper
7
10
  include ActionView::Helpers::AssetTagHelper
8
11
  include ActionView::Helpers::JavaScriptHelper
9
12
 
10
- attr_reader :page_parameter_name
13
+ # a Proc object for the after_row block
11
14
  attr_reader :after_row_handler
15
+
16
+ # a Proc object for the before_row block
12
17
  attr_reader :before_row_handler
18
+
19
+ # a Proc object for the replace_row block
13
20
  attr_reader :replace_row_handler
21
+
22
+ # Configuration or a Proc object for the blank_slate block
14
23
  attr_reader :blank_slate_handler
24
+
25
+ # a Proc object which returns contents of the last row
15
26
  attr_reader :last_row_handler
27
+
28
+ # reference to the WiceGrid instance
16
29
  attr_reader :grid
30
+
31
+ # Contents of <caption></caption>
17
32
  attr_reader :kaption
18
33
 
19
- @@order_parameter_name = "order"
20
- @@order_direction_parameter_name = "order_direction"
21
- @@page_parameter_name = "page"
34
+ # HTTP parameter for the order field
35
+ ORDER_PARAMETER_NAME = 'order'
36
+
37
+ # HTTP parameter for the order direction (asc/desc)
38
+ ORDER_DIRECTION_PARAMETER_NAME = 'order_direction'
22
39
 
23
40
  def initialize(grid, view) #:nodoc:
24
- @grid = grid
25
- @grid.renderer = self
26
- @columns = []
27
- @columns_table = {}
41
+ @grid = grid
42
+ @grid.renderer = self
43
+ @columns = []
44
+ @columns_table = {}
28
45
  @action_column_present = false
29
- @view = view
46
+ @view = view
30
47
  end
31
48
 
32
49
  def config #:nodoc:
@@ -37,7 +54,6 @@ module Wice
37
54
  @view.controller
38
55
  end
39
56
 
40
-
41
57
  def add_column(vc) #:nodoc:
42
58
  @columns_table[vc.fully_qualified_attribute_name] = vc if vc.attribute
43
59
  @columns << vc
@@ -52,7 +68,7 @@ module Wice
52
68
  end
53
69
 
54
70
  def each_column_label(filter = nil) #:nodoc:
55
- filter_columns(filter).each{|col| yield col.name}
71
+ filter_columns(filter).each { |col| yield col.name }
56
72
  end
57
73
 
58
74
  def column_labels(filter = nil) #:nodoc:
@@ -60,12 +76,12 @@ module Wice
60
76
  end
61
77
 
62
78
  def each_column(filter = nil) #:nodoc:
63
- filter_columns(filter).each{|col| yield col}
79
+ filter_columns(filter).each { |col| yield col }
64
80
  end
65
81
 
66
82
  def each_column_aware_of_one_last_one(filter = nil) #:nodoc:
67
83
  cols = filter_columns(filter)
68
- cols[0..-2].each{|col| yield col, false}
84
+ cols[0..-2].each { |col| yield col, false }
69
85
  yield cols.last, true
70
86
  end
71
87
 
@@ -74,23 +90,24 @@ module Wice
74
90
  end
75
91
 
76
92
  def select_for(filter) #:nodoc:
77
- filter_columns(filter).select{|col| yield col}
93
+ filter_columns(filter).select { |col| yield col }
78
94
  end
79
95
 
80
96
  def find_one_for(filter) #:nodoc:
81
- filter_columns(filter).find{|col| yield col}
97
+ filter_columns(filter).find { |col| yield col }
82
98
  end
83
99
 
84
-
85
100
  def each_column_with_attribute #:nodoc:
86
- @columns.select(&:attribute).each{|col| yield col}
101
+ @columns.select(&:attribute).each { |col| yield col }
87
102
  end
88
103
 
89
104
  alias_method :each, :each_column
90
105
  include Enumerable
91
106
 
92
107
  def csv_export_icon #:nodoc:
93
- content_tag(:div, '',
108
+ content_tag(
109
+ :div,
110
+ content_tag(:i, '', class: 'fa fa-file-excel-o'),
94
111
  title: NlMessage['csv_export_tooltip'],
95
112
  class: 'clickable export-to-csv-button'
96
113
  )
@@ -99,7 +116,7 @@ module Wice
99
116
  def pagination_panel(number_of_columns, hide_csv_button) #:nodoc:
100
117
  panel = yield
101
118
 
102
- render_csv_button = @grid.export_to_csv_enabled && ! hide_csv_button
119
+ render_csv_button = @grid.export_to_csv_enabled && !hide_csv_button
103
120
 
104
121
  if panel.nil?
105
122
  if render_csv_button
@@ -116,9 +133,9 @@ module Wice
116
133
  end
117
134
  end
118
135
 
119
- # Takes one argument and adds the <caption></caption> tag to the table with the argument value as
120
- # the contents of <caption>.
121
- def caption kaption
136
+ # Takes one argument and adds the <caption></caption> tag to the table with the
137
+ # argument value as the contents of <caption>.
138
+ def caption(kaption)
122
139
  @kaption = kaption
123
140
  end
124
141
 
@@ -140,9 +157,8 @@ module Wice
140
157
  # +g.column+ definition. If the block returns +nil+ or +false+ no checkbox will be rendered.
141
158
 
142
159
  def action_column(opts = {}, &block)
143
-
144
160
  if @action_column_present
145
- raise Wice::WiceGridException.new('There can be only one action column in a WiceGrid')
161
+ fail Wice::WiceGridException.new('There can be only one action column in a WiceGrid')
146
162
  end
147
163
 
148
164
  options = {
@@ -150,7 +166,7 @@ module Wice
150
166
  html: {},
151
167
  select_all_buttons: true,
152
168
  object_property: :id,
153
- html_check_box: true,
169
+ html_check_box: true
154
170
  }
155
171
 
156
172
  opts.assert_valid_keys(options.keys)
@@ -182,7 +198,7 @@ module Wice
182
198
  # * <tt>:class</tt> - a shortcut for <tt>html: {class: 'css_class'}</tt>
183
199
  # * <tt>:attribute</tt> - name of a database column (which normally correspond to a model attribute with the
184
200
  # same name). By default the field is assumed to belong to the default table (see documentation for the
185
- # +initialize_grid+ method). Parameter <tt>:model</tt> allows to specify another table. Presence of
201
+ # +initialize_grid+ method). Parameter <tt>:assoc</tt> (association) allows to specify another joined table. Presence of
186
202
  # this parameter
187
203
  # * adds sorting capabilities by this field
188
204
  # * automatically creates a filter based on the type of the field unless parameter <tt>:filter</tt> is set to false.
@@ -202,7 +218,7 @@ module Wice
202
218
  # list of available filters.
203
219
  # * <tt>:ordering</tt> - Enable/disable ordering links in the column titles. The default is +true+
204
220
  # (i.e. if <tt>:attribute</tt> is defined, ordering is enabled)
205
- # * <tt>:model</tt> - Name of the model class to which <tt>:attribute</tt> belongs to if this is not the main table.
221
+ # * <tt>:assoc</tt> - Name of the model association. <tt>:attribute</tt> belongs to the table joined via this association.
206
222
  # * <tt>:table_alias</tt> - In case there are two joined assocations both referring to the same table, ActiveRecord
207
223
  # constructs a query where the second join provides an alias for the joined table. Setting <tt>:table_alias</tt>
208
224
  # to this alias will enable WiceGrid to order and filter by columns belonging to different associatiations but
@@ -258,9 +274,6 @@ module Wice
258
274
  # to false will prohibit the column from inclusion into the export.
259
275
  # * <tt>:in_html</tt> - When CSV export is enabled and it is needed to use a column for CSV export only and ignore it
260
276
  # in HTML, set this parameter to false.
261
- # * <tt>:helper_style</tt> - Changes the flavor of Date and DateTime filters. The values are:
262
- # * <tt>:standard</tt> - the default Rails Date/DateTime helper
263
- # * <tt>:calendar</tt> - a Javascript popup calendar control
264
277
  # * <tt>:negation</tt> - turn on/off the negation checkbox in string filters
265
278
  # * <tt>:auto_reload</tt> - a boolean value specifying if a change in a filter triggers reloading of the grid. Works with all
266
279
  # filter types including the JS calendar, the only exception is the standard Rails date/datetime filters.
@@ -282,44 +295,59 @@ module Wice
282
295
 
283
296
  def column(opts = {}, &block)
284
297
  options = {
285
- allow_multiple_selection: Defaults::ALLOW_MULTIPLE_SELECTION,
286
- ordering: true,
298
+ allow_multiple_selection: ConfigurationProvider.value_for(:ALLOW_MULTIPLE_SELECTION),
299
+ assoc: nil,
287
300
  attribute: nil,
288
- auto_reload: Defaults::AUTO_RELOAD,
301
+ auto_reload: ConfigurationProvider.value_for(:AUTO_RELOAD),
289
302
  boolean_filter_false_label: NlMessage['boolean_filter_false_label'],
290
303
  boolean_filter_true_label: NlMessage['boolean_filter_true_label'],
291
304
  class: nil,
292
- name: '',
293
305
  custom_filter: nil,
294
306
  detach_with_id: nil,
295
- filter_all_label: Defaults::CUSTOM_FILTER_ALL_LABEL,
296
- helper_style: Defaults::HELPER_STYLE,
297
- in_csv: true,
298
- in_html: true,
299
- model: nil,
300
- negation: Defaults::NEGATION_IN_STRING_FILTERS,
301
307
  filter: true,
308
+ filter_all_label: ConfigurationProvider.value_for(:CUSTOM_FILTER_ALL_LABEL),
302
309
  filter_type: nil,
303
- table_alias: nil,
304
- html: {}
310
+ html: {},
311
+ in_csv: true,
312
+ in_html: true,
313
+ model: nil, # will throw an exception with instructions
314
+ name: '',
315
+ negation: ConfigurationProvider.value_for(:NEGATION_IN_STRING_FILTERS),
316
+ ordering: true,
317
+ table_alias: nil
305
318
  }
306
319
 
307
320
  opts.assert_valid_keys(options.keys)
308
321
  options.merge!(opts)
309
322
 
310
- unless options[:model].nil?
311
- options[:model] = options[:model].constantize if options[:model].is_a? String
312
- raise WiceGridArgumentError.new("Option :model can be either a class or a string instance") unless options[:model].is_a? Class
323
+ assocs = nil
324
+
325
+ if options[:model]
326
+ fail WiceGridArgumentError.new('Instead of specifying a model of a joined table please use assoc: :name_of_association')
327
+ end
328
+
329
+ unless options[:assoc].nil?
330
+
331
+ unless options[:assoc].is_a?(Symbol) ||
332
+ (options[:assoc].is_a?(Array) && ! options[:assoc].empty? && options[:assoc].all?{ |assoc| assoc.is_a?(Symbol)})
333
+
334
+ fail WiceGridArgumentError.new('Option :assoc can only be a symbol or an array of symbols')
335
+ end
336
+
337
+ assocs = options[:assoc].is_a?(Symbol) ? [options[:assoc]] : options[:assoc]
338
+
339
+ options[:model] = get_model_from_associations(@grid.klass, assocs)
313
340
  end
314
341
 
315
342
  if options[:attribute].nil? && options[:model]
316
- raise WiceGridArgumentError.new("Option :model is only used together with :attribute")
343
+ fail WiceGridArgumentError.new('Option :assoc is only used together with :attribute')
317
344
  end
318
345
 
319
346
  if options[:attribute] && options[:attribute].index('.')
320
- raise WiceGridArgumentError.new("Invalid attribute name #{options[:attribute]}. An attribute name must not contain a table name!")
347
+ fail WiceGridArgumentError.new("Invalid attribute name #{options[:attribute]}. An attribute name must not contain a table name!")
321
348
  end
322
349
 
350
+
323
351
  if options[:class]
324
352
  options[:html] ||= {}
325
353
  Wice::WgHash.add_or_append_class_value!(options[:html], options[:class])
@@ -327,29 +355,41 @@ module Wice
327
355
  end
328
356
 
329
357
  if block.nil?
330
- if ! options[:attribute].blank?
331
- block = lambda{|obj| obj.send(options[:attribute])}
358
+ if !options[:attribute].blank?
359
+ if assocs.nil?
360
+ block = ->(obj) { obj.send(options[:attribute]) }
361
+ else
362
+ messages = assocs + [ options[:attribute] ]
363
+ block = ->(obj) { obj.deep_send(*messages) }
364
+ end
332
365
  else
333
- raise WiceGridArgumentError.new(
334
- "Missing column block without attribute defined. You can only omit the block if attribute is present.")
366
+ fail WiceGridArgumentError.new(
367
+ 'Missing column block without attribute defined. You can only omit the block if attribute is present.')
335
368
  end
336
369
  end
337
370
 
338
371
  klass = Columns::ViewColumn
339
372
  if options[:attribute] &&
340
- col_type_and_table_name = @grid.declare_column(options[:attribute], options[:model],
341
- options[:custom_filter], options[:table_alias], options[:filter_type])
342
-
373
+ col_type_and_table_name = @grid.declare_column(
374
+ column_name: options[:attribute],
375
+ model: options[:model],
376
+ custom_filter_active: options[:custom_filter],
377
+ table_alias: options[:table_alias],
378
+ filter_type: options[:filter_type],
379
+ assocs: assocs
380
+ )
381
+
382
+ # [ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::Column, String, Boolean]
343
383
  db_column, table_name, main_table = col_type_and_table_name
344
384
  col_type = db_column.type
345
385
 
346
386
  if options[:custom_filter]
347
387
 
348
388
  custom_filter = if options[:custom_filter] == :auto
349
- lambda{ @grid.distinct_values_for_column(db_column) } # Thank God Ruby has higher order functions!!!
389
+ -> { @grid.distinct_values_for_column(db_column) } # Thank God Ruby has higher order functions!!!
350
390
 
351
391
  elsif options[:custom_filter].class == Symbol
352
- lambda{ @grid.distinct_values_for_column_in_resultset([options[:custom_filter]])}
392
+ -> { @grid.distinct_values_for_column_in_resultset([options[:custom_filter]]) }
353
393
 
354
394
  elsif options[:custom_filter].class == Hash
355
395
  options[:custom_filter].keys
@@ -360,19 +400,19 @@ module Wice
360
400
  if options[:custom_filter].empty?
361
401
  []
362
402
  elsif Wice::WgEnumerable.all_items_are_of_class(options[:custom_filter], Symbol)
363
- lambda{ @grid.distinct_values_for_column_in_resultset(options[:custom_filter]) }
403
+ -> { @grid.distinct_values_for_column_in_resultset(options[:custom_filter]) }
364
404
 
365
405
  elsif Wice::WgEnumerable.all_items_are_of_class(options[:custom_filter], String) || WgEnumerable.all_items_are_of_class(options[:custom_filter], Numeric)
366
- options[:custom_filter].map{|i| [i,i]}
406
+ options[:custom_filter].map { |i| [i, i] }
367
407
 
368
408
  elsif Wice::WgEnumerable.all_items_are_of_class(options[:custom_filter], Array)
369
409
  options[:custom_filter]
370
410
  else
371
- raise WiceGridArgumentError.new(
372
- ':custom_filter can equal :auto, an array of string and/or numbers (direct values for the dropdown), ' +
373
- 'a homogeneous array of symbols (a sequence of methods to send to AR objects in the result set to ' +
374
- 'retrieve unique values for the dropdown), a Symbol (a shortcut for a one member array of symbols), ' +
375
- 'a hash where keys are labels and values are values for the dropdown option, or an array of two-item arrays, ' +
411
+ fail WiceGridArgumentError.new(
412
+ ':custom_filter can equal :auto, an array of string and/or numbers (direct values for the dropdown), ' \
413
+ 'a homogeneous array of symbols (a sequence of methods to send to AR objects in the result set to ' \
414
+ 'retrieve unique values for the dropdown), a Symbol (a shortcut for a one member array of symbols), ' \
415
+ 'a hash where keys are labels and values are values for the dropdown option, or an array of two-item arrays, ' \
376
416
  'each of which contains the label (first element) and the value (second element) for a dropdown option'
377
417
  )
378
418
  end
@@ -382,6 +422,18 @@ module Wice
382
422
  elsif options[:filter_type]
383
423
  klass = Columns.get_view_column_processor(options[:filter_type])
384
424
  else
425
+
426
+ col_type = case col_type
427
+ when :date
428
+ Wice::Defaults::DEFAULT_FILTER_FOR_DATE
429
+ when :datetime
430
+ Wice::Defaults::DEFAULT_FILTER_FOR_DATETIME
431
+ when :timestamp
432
+ Wice::Defaults::DEFAULT_FILTER_FOR_DATETIME
433
+ else
434
+ col_type
435
+ end
436
+
385
437
  klass = Columns.get_view_column_processor(col_type)
386
438
  end # custom_filter
387
439
 
@@ -391,14 +443,30 @@ module Wice
391
443
 
392
444
  vc.negation = options[:negation] if vc.respond_to? :negation=
393
445
 
394
- vc.filter_all_label = options[:filter_all_label] if vc.kind_of?(Columns.get_view_column_processor(:custom))
395
- if vc.kind_of?(Columns.get_view_column_processor(:boolean))
446
+ vc.filter_all_label = options[:filter_all_label] if vc.is_a?(Columns.get_view_column_processor(:custom))
447
+ if vc.is_a?(Columns.get_view_column_processor(:boolean))
396
448
  vc.boolean_filter_true_label = options[:boolean_filter_true_label]
397
449
  vc.boolean_filter_false_label = options[:boolean_filter_false_label]
398
450
  end
399
451
  add_column(vc)
400
452
  end
401
453
 
454
+ def get_model_from_associations(model, assocs) # :nodoc:
455
+ if assocs.empty?
456
+ model
457
+ else
458
+ head = assocs[0]
459
+ tail = assocs[1..-1]
460
+
461
+ if reflection = model.reflect_on_association(head)
462
+ next_model = reflection.klass
463
+ get_model_from_associations(next_model, tail)
464
+ else
465
+ fail WiceGridArgumentError.new("Association #{head} not found in #{model}")
466
+ end
467
+ end
468
+ end
469
+
402
470
  # Optional method inside the +grid+ block, to which every ActiveRecord instance is injected, just like +column+.
403
471
  # Unlike +column+, it returns a hash which will be used as HTML attributes for the row with the given ActiveRecord instance.
404
472
  #
@@ -431,28 +499,28 @@ module Wice
431
499
  def last_row(&block)
432
500
  @last_row_handler = block
433
501
  end
502
+
434
503
  # The output of the block submitted to +blank_slate+ is rendered instead of the whole grid if no filters are active
435
504
  # and there are no records to render.
436
505
  # In addition to the block style two other variants are accepted:
437
506
  # * <tt>g.blank_slate "some text to be rendered"</tt>
438
507
  # * <tt>g.blank_slate partial: "partial_name"</tt>
439
508
  def blank_slate(opts = nil, &block)
440
- if (opts.is_a?(Hash) && opts.has_key?(:partial) && block.nil?) || (opts.is_a?(String) && block.nil?)
509
+ if (opts.is_a?(Hash) && opts.key?(:partial) && block.nil?) || (opts.is_a?(String) && block.nil?)
441
510
  @blank_slate_handler = opts
442
511
  elsif opts.nil? && block
443
512
  @blank_slate_handler = block
444
513
  else
445
- raise WiceGridArgumentError.new("blank_slate accepts only a string, a block, or template: 'path_to_template' ")
514
+ fail WiceGridArgumentError.new("blank_slate accepts only a string, a block, or template: 'path_to_template' ")
446
515
  end
447
516
  end
448
517
 
449
-
450
518
  def get_row_attributes(ar_object) #:nodoc:
451
519
  if @row_attributes_handler
452
520
  row_attributes = @row_attributes_handler.call(ar_object)
453
521
  row_attributes = {} if row_attributes.blank?
454
522
  unless row_attributes.is_a?(Hash)
455
- raise WiceGridArgumentError.new("row_attributes block must return a hash containing HTML attributes. The returned value is #{row_attributes.inspect}")
523
+ fail WiceGridArgumentError.new("row_attributes block must return a hash containing HTML attributes. The returned value is #{row_attributes.inspect}")
456
524
  end
457
525
  row_attributes
458
526
  else
@@ -460,13 +528,12 @@ module Wice
460
528
  end
461
529
  end
462
530
 
463
-
464
531
  def no_filter_needed? #:nodoc:
465
- not @columns.inject(false){|a,b| a || b.filter_shown? }
532
+ !@columns.inject(false) { |a, b| a || b.filter_shown? }
466
533
  end
467
534
 
468
535
  def no_filter_needed_in_main_table? #:nodoc:
469
- not @columns.inject(false){|a,b| a || b.filter_shown_in_main_table? }
536
+ !@columns.inject(false) { |a, b| a || b.filter_shown_in_main_table? }
470
537
  end
471
538
 
472
539
  def base_link_for_filter(controller, extra_parameters = {}) #:nodoc:
@@ -500,19 +567,17 @@ module Wice
500
567
  controller.url_for(new_params)
501
568
  end
502
569
 
503
-
504
570
  def column_link(column, direction, params, extra_parameters = {}) #:nodoc:
505
-
506
- column_attribute_name = if column.attribute.index('.') or column.main_table
571
+ column_attribute_name = if column.attribute.index('.') || column.main_table
507
572
  column.attribute
508
573
  else
509
574
  column.table_alias_or_table_name + '.' + column.attribute
510
575
  end
511
576
 
512
- query_params = {@grid.name => {
513
- @@order_parameter_name => column_attribute_name,
514
- @@order_direction_parameter_name => direction
515
- }}
577
+ query_params = { @grid.name => {
578
+ ORDER_PARAMETER_NAME => column_attribute_name,
579
+ ORDER_DIRECTION_PARAMETER_NAME => direction
580
+ } }
516
581
 
517
582
  cleaned_params = Wice::WgHash.deep_clone params
518
583
  cleaned_params.merge!(extra_parameters)
@@ -520,16 +585,13 @@ module Wice
520
585
  cleaned_params.delete(:controller)
521
586
  cleaned_params.delete(:action)
522
587
 
523
-
524
588
  query_params = Wice::WgHash.rec_merge(cleaned_params, query_params)
525
589
 
526
590
  '?' + query_params.to_query
527
591
  end
528
592
 
529
-
530
593
  protected
531
594
 
532
-
533
595
  def filter_columns(method_name = nil) #:nodoc:
534
596
  method_name ? @columns.select(&method_name) : @columns
535
597
  end
@@ -541,8 +603,7 @@ module Wice
541
603
  # /foo?grid=some_value --> /foo?grid=some_value
542
604
 
543
605
  empty_hash_rx = Regexp.new "([&?])#{Regexp.escape @grid.name}=([&?]|$)" # c.f., issue #140
544
- url.gsub(empty_hash_rx, '\1').gsub /\?+$/, ''
606
+ url.gsub(empty_hash_rx, '\1').gsub(/\?+$/, '')
545
607
  end
546
-
547
608
  end
548
609
  end