effective_datatables 3.7.10 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +32 -32
  4. data/app/assets/images/dataTables/sort-down.svg +1 -0
  5. data/app/assets/images/dataTables/sort-up.svg +1 -0
  6. data/app/assets/images/dataTables/sort.svg +1 -0
  7. data/app/assets/javascripts/dataTables/buttons/{buttons.bootstrap.js → buttons.bootstrap4.js} +7 -15
  8. data/app/assets/javascripts/dataTables/dataTables.bootstrap4.js +184 -0
  9. data/app/assets/javascripts/dataTables/responsive/dataTables.responsive.js +30 -11
  10. data/app/assets/javascripts/dataTables/responsive/{responsive.bootstrap.js → responsive.bootstrap4.js} +6 -6
  11. data/app/assets/javascripts/effective_datatables/bulk_actions.js.coffee +43 -43
  12. data/app/assets/javascripts/effective_datatables/events.js.coffee +7 -4
  13. data/app/assets/javascripts/effective_datatables/filters.js.coffee +0 -1
  14. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +45 -49
  15. data/app/assets/javascripts/effective_datatables/overrides.js +12 -0
  16. data/app/assets/javascripts/effective_datatables/reset.js.coffee +1 -1
  17. data/app/assets/javascripts/effective_datatables.js +4 -4
  18. data/app/assets/stylesheets/dataTables/buttons/{buttons.bootstrap.scss → buttons.bootstrap4.css} +68 -1
  19. data/app/assets/stylesheets/dataTables/{dataTables.bootstrap.scss → dataTables.bootstrap4.css} +44 -29
  20. data/app/assets/stylesheets/dataTables/responsive/{responsive.bootstrap.scss → responsive.bootstrap4.css} +3 -3
  21. data/app/assets/stylesheets/effective_datatables/_overrides.scss +72 -152
  22. data/app/assets/stylesheets/effective_datatables.scss +3 -4
  23. data/app/controllers/effective/datatables_controller.rb +6 -39
  24. data/app/helpers/effective_datatables_helper.rb +55 -50
  25. data/app/helpers/effective_datatables_private_helper.rb +47 -179
  26. data/app/models/effective/datatable.rb +16 -44
  27. data/app/models/effective/datatable_column.rb +0 -1
  28. data/app/models/effective/datatable_column_tool.rb +2 -4
  29. data/app/models/effective/datatable_dsl_tool.rb +3 -11
  30. data/app/models/effective/datatable_value_tool.rb +23 -23
  31. data/app/models/effective/effective_datatable/attributes.rb +13 -5
  32. data/app/models/effective/effective_datatable/collection.rb +3 -18
  33. data/app/models/effective/effective_datatable/compute.rb +6 -17
  34. data/app/models/effective/effective_datatable/cookie.rb +20 -19
  35. data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +25 -14
  36. data/app/models/effective/effective_datatable/dsl/datatable.rb +28 -70
  37. data/app/models/effective/effective_datatable/dsl/filters.rb +5 -5
  38. data/app/models/effective/effective_datatable/dsl.rb +3 -8
  39. data/app/models/effective/effective_datatable/format.rb +50 -95
  40. data/app/models/effective/effective_datatable/params.rb +3 -8
  41. data/app/models/effective/effective_datatable/resource.rb +76 -137
  42. data/app/models/effective/effective_datatable/state.rb +15 -30
  43. data/app/views/effective/datatables/_actions_column.html.haml +8 -1
  44. data/app/views/effective/datatables/_bulk_actions_column.html.haml +1 -1
  45. data/app/views/effective/datatables/_filters.html.haml +11 -12
  46. data/app/views/effective/datatables/_resource_column.html.haml +8 -11
  47. data/config/effective_datatables.rb +14 -12
  48. data/config/routes.rb +0 -1
  49. data/lib/effective_datatables/engine.rb +4 -14
  50. data/lib/effective_datatables/version.rb +1 -1
  51. data/lib/effective_datatables.rb +4 -57
  52. metadata +20 -31
  53. data/app/assets/config/effective_datatables_manifest.js +0 -3
  54. data/app/assets/images/dataTables/sort_asc.png +0 -0
  55. data/app/assets/images/dataTables/sort_both.png +0 -0
  56. data/app/assets/images/dataTables/sort_desc.png +0 -0
  57. data/app/assets/javascripts/dataTables/dataTables.bootstrap.js +0 -182
  58. data/app/assets/javascripts/dataTables/locales/en.lang +0 -33
  59. data/app/assets/javascripts/dataTables/locales/es.lang +0 -36
  60. data/app/assets/javascripts/dataTables/locales/nl.lang +0 -30
  61. data/app/assets/javascripts/effective_datatables/flash.js.coffee +0 -31
  62. data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +0 -217
  63. data/app/assets/javascripts/effective_datatables/overrides.js.coffee +0 -7
  64. data/app/assets/javascripts/effective_datatables/reorder.js.coffee +0 -43
  65. data/app/assets/stylesheets/effective_datatables/_filters.scss +0 -7
  66. data/app/views/effective/datatables/_reorder_column.html.haml +0 -5
  67. data/config/locales/en.yml +0 -12
  68. data/config/locales/es.yml +0 -12
  69. data/config/locales/nl.yml +0 -12
@@ -1,21 +1,18 @@
1
1
  # These aren't expected to be called by a developer. They are internal methods.
2
- # These aren't expected to be called by a developer. They are internal methods.
3
2
  module EffectiveDatatablesPrivateHelper
4
3
 
5
4
  # https://datatables.net/reference/option/columns
6
5
  def datatable_columns(datatable)
7
- sortable = datatable.sortable?
8
-
9
6
  datatable.columns.map do |name, opts|
10
7
  {
11
- className: opts[:col_class],
12
8
  name: name,
9
+ title: content_tag(:span, opts[:label].presence),
10
+ className: opts[:col_class],
13
11
  responsivePriority: opts[:responsive],
14
12
  search: datatable.state[:search][name],
15
13
  searchHtml: datatable_search_tag(datatable, name, opts),
16
- sortable: (opts[:sort] && sortable),
17
- title: datatable_label_tag(datatable, name, opts),
18
- visible: datatable.state[:visible][name]
14
+ sortable: (opts[:sort] && !datatable.simple?),
15
+ visible: datatable.state[:visible][name],
19
16
  }
20
17
  end.to_json.html_safe
21
18
  end
@@ -26,207 +23,78 @@ module EffectiveDatatablesPrivateHelper
26
23
  end
27
24
  end
28
25
 
29
- def datatable_display_order(datatable)
30
- (datatable.sortable? ? [datatable.order_index, datatable.order_direction] : false).to_json.html_safe
31
- end
32
-
33
26
  def datatable_reset(datatable)
34
- link_to(content_tag(:span, t('effective_datatables.reset')), '#', class: 'btn btn-link btn-sm buttons-reset-search')
35
- end
36
-
37
- def datatable_reorder(datatable)
38
- return unless datatable.reorder? && EffectiveDatatables.authorized?(self, :update, datatable.collection_class)
39
- link_to(content_tag(:span, t('effective_datatables.reorder')), '#', class: 'btn btn-link btn-sm buttons-reorder', disabled: true)
40
- end
41
-
42
- def datatable_new_resource_button(datatable, name, column)
43
- return unless column[:inline] && (column[:actions][:new] != false)
44
-
45
- action = { action: :new, class: ['btn', column[:btn_class].presence].compact.join(' '), 'data-remote': true }
46
-
47
- if column[:actions][:new].kind_of?(Hash) # This might be active_record_array_collection?
48
- action = action.merge(column[:actions][:new])
49
-
50
- effective_resource = (datatable.effective_resource || datatable.fallback_effective_resource)
51
- klass = (column[:actions][:new][:klass] || effective_resource.try(:klass) || datatable.collection_class)
52
- elsif Array(datatable.effective_resource.try(:actions)).include?(:new)
53
- effective_resource = datatable.effective_resource
54
- klass = effective_resource.klass
55
- else
56
- return
57
- end
58
-
59
- # Will only work if permitted
60
- render_resource_actions(klass, actions: { t('effective_datatables.new') => action }, effective_resource: effective_resource)
61
- end
62
-
63
- def datatable_label_tag(datatable, name, opts)
64
- case opts[:as]
65
- when :actions
66
- content_tag(:span, t('effective_datatables.actions'), style: 'display: none;')
67
- when :bulk_actions
68
- content_tag(:span, t('effective_datatables.bulk_actions'), style: 'display: none;')
69
- when :reorder
70
- content_tag(:span, t('effective_datatables.reorder'), style: 'display: none;')
71
- else
72
- content_tag(:span, opts[:label].presence)
73
- end
27
+ link_to(content_tag(:span, 'Reset'), '#', class: 'btn btn-link btn-sm buttons-reset-search')
74
28
  end
75
29
 
76
30
  def datatable_search_tag(datatable, name, opts)
77
- return datatable_new_resource_button(datatable, name, opts) if name == :_actions
78
-
79
31
  return if opts[:search] == false
80
32
 
81
33
  # Build the search
82
- @_effective_datatables_form_builder || simple_form_for(:datatable_search, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| @_effective_datatables_form_builder = f }
34
+ @_effective_datatables_form_builder || effective_form_with(scope: :datatable_search, url: '#') { |f| @_effective_datatables_form_builder = f }
83
35
  form = @_effective_datatables_form_builder
84
36
 
85
- include_blank = opts[:search].key?(:include_blank) ? opts[:search][:include_blank] : opts[:label]
86
- pattern = opts[:search][:pattern]
87
- placeholder = opts[:search][:placeholder] || ''
88
- title = opts[:search][:title] || opts[:label]
89
- wrapper_html = { class: 'datatable_search' }
90
-
91
37
  collection = opts[:search].delete(:collection)
92
38
  value = datatable.state[:search][name]
93
39
 
94
- input_html = {
40
+ options = opts[:search].except(:fuzzy).merge!(
95
41
  name: nil,
42
+ feedback: false,
43
+ label: false,
96
44
  value: value,
97
- title: title,
98
- pattern: pattern,
99
- data: {'column-name' => name, 'column-index' => opts[:index]}
100
- }.delete_if { |k, v| v.blank? && k != :name }
45
+ data: { 'column-name': name, 'column-index': opts[:index] }
46
+ )
101
47
 
102
- case opts[:search][:as]
48
+ case options.delete(:as)
103
49
  when :string, :text, :number
104
- form.input name, label: false, required: false, value: value,
105
- as: :string,
106
- placeholder: placeholder,
107
- wrapper_html: wrapper_html,
108
- input_html: input_html
109
- when :effective_obfuscation
110
- input_html[:pattern] ||= '[0-9]{3}-?[0-9]{4}-?[0-9]{3}'
111
- input_html[:title] = 'Expected format: XXX-XXXX-XXX'
112
-
113
- form.input name, label: false, required: false, value: value,
114
- as: :string,
115
- placeholder: placeholder,
116
- wrapper_html: wrapper_html,
117
- input_html: input_html
50
+ form.text_field name, options
118
51
  when :date, :datetime
119
- form.input name, label: false, required: false, value: value,
120
- as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_picker) ? :effective_date_picker : :string),
121
- placeholder: placeholder,
122
- wrapper_html: wrapper_html,
123
- input_group: false,
124
- input_html: input_html,
125
- date_linked: false,
126
- input_js: { useStrict: true, keepInvalid: true }
127
- # Keep invalid format like "2015-11" so we can still search by year, month or day
52
+ form.date_field name, options.reverse_merge(
53
+ date_linked: false, prepend: false, input_js: { useStrict: true, keepInvalid: true }
54
+ )
128
55
  when :time
129
- form.input name, label: false, required: false, value: value,
130
- as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_time_picker) ? :effective_time_picker : :string),
131
- placeholder: placeholder,
132
- wrapper_html: wrapper_html,
133
- input_group: false,
134
- input_html: input_html,
135
- date_linked: false,
136
- input_js: { useStrict: false, keepInvalid: true }
56
+ form.time_field name, options.reverse_merge(
57
+ date_linked: false, prepend: false, input_js: { useStrict: false, keepInvalid: true }
58
+ )
137
59
  when :select, :boolean
138
- form.input name, label: false, required: false, value: value,
139
- as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :select),
140
- collection: collection,
141
- selected: opts[:search][:value],
142
- multiple: opts[:search][:multiple],
143
- grouped: opts[:search][:grouped],
144
- polymorphic: opts[:search][:polymorphic],
145
- template: opts[:search][:template],
146
- include_blank: include_blank,
147
- wrapper_html: wrapper_html,
148
- input_html: input_html,
149
- input_js: { placeholder: placeholder }
60
+ options[:input_js] = (options[:input_js] || {}).reverse_merge(placeholder: '')
61
+ form.select name, collection, options
150
62
  when :bulk_actions
151
- input_html[:data]['role'] = 'bulk-actions'
152
-
153
- form.input name, label: false, required: false, value: nil,
154
- as: :boolean,
155
- input_html: input_html
156
- end
157
- end
158
-
159
- def render_datatable_filters(datatable)
160
- raise 'expected datatable to be present' unless datatable
161
-
162
- datatable.view ||= self
163
- return unless datatable._scopes.present? || datatable._filters.present?
164
-
165
- if datatable._filters_form_required?
166
- render partial: 'effective/datatables/filters', locals: { datatable: datatable }
167
- else
168
- render(partial: 'effective/datatables/filters', locals: { datatable: datatable }).gsub('<form', '<div').gsub('/form>', '/div>').html_safe
63
+ options[:data]['role'] = 'bulk-actions-all'
64
+ form.check_box name, options.merge(custom: false)
169
65
  end
170
-
171
66
  end
172
67
 
173
68
  def datatable_filter_tag(form, datatable, name, opts)
174
- as = opts[:as].to_s.chomp('_field').to_sym
69
+ placeholder = opts.delete(:label)
70
+
71
+ collection = opts.delete(:collection)
175
72
  value = datatable.state[:filter][name]
176
- collection = opts[:collection]
177
- input_html = opts[:input_html] || {}
178
73
 
179
- attributes = {
74
+ options = opts.except(:parse).merge(
75
+ placeholder: placeholder,
76
+ feedback: false,
77
+ label: false,
180
78
  value: value,
181
- selected: value,
182
- as: as,
183
- collection: collection,
184
- label: opts[:label],
185
- required: input_html.delete(:required) || opts[:required],
186
- multiple: input_html.delete(:multiple) || opts[:multiple],
187
- include_blank: input_html.delete(:include_blank) || opts[:include_blank],
188
- group_method: input_html.delete(:group_method),
189
- group_label_method: input_html.delete(:group_label_method),
190
- value_method: input_html.delete(:value_method),
191
- label_method: input_html.delete(:label_method),
192
- input_html: (({name: ''} unless datatable._filters_form_required?) || {}).merge(input_html),
193
- input_js: ({ placeholder: ''} if as == :effective_select),
194
- wrapper_html: {class: 'form-group-sm'}
195
- }.compact
196
-
197
- form.input name, **attributes
198
- end
199
-
200
- def datatable_scope_tag(form, datatable, opts = {})
201
- collection = datatable._scopes.map { |name, opts| [opts[:label], name] }
202
- value = datatable.state[:scope]
79
+ wrapper: { class: 'form-group col-auto'},
80
+ autocomplete: 'off'
81
+ )
203
82
 
204
- form.input :scope, label: false, required: false, checked: value,
205
- as: (defined?(EffectiveFormInputs) ? :effective_radio_buttons : :radio_buttons),
206
- collection: collection,
207
- buttons: true,
208
- wrapper_html: {class: 'btn-group-sm'}
209
- end
210
-
211
- def render_datatable_charts(datatable)
212
- raise 'expected datatable to be present' unless datatable
213
-
214
- datatable.view ||= self
215
- return unless datatable._charts.present?
216
-
217
- datatable._charts.map { |name, _| render_datatable_chart(datatable, name) }.join.html_safe
218
- end
219
-
220
- def render_datatable_chart(datatable, name)
221
- raise 'expected datatable to be present' unless datatable
83
+ options[:name] = '' unless datatable._filters_form_required?
222
84
 
223
- datatable.view ||= self
224
- return unless datatable._charts[name].present?
225
-
226
- chart = datatable._charts[name]
227
- chart_data = datatable.to_json[:charts][name][:data]
228
-
229
- render partial: chart[:partial], locals: { datatable: datatable, chart: chart, chart_data: chart_data }
85
+ case options.delete(:as)
86
+ when :date
87
+ form.date_field name, options
88
+ when :datetime
89
+ form.datetime_field name, options
90
+ when :time
91
+ form.time_field name, options
92
+ when :select, :boolean
93
+ options[:input_js] = (options[:input_js] || {}).reverse_merge(placeholder: placeholder)
94
+ form.select name, collection, options
95
+ else
96
+ form.text_field name, options
97
+ end
230
98
  end
231
99
 
232
100
  end
@@ -1,7 +1,7 @@
1
1
  module Effective
2
2
  class Datatable
3
3
  attr_reader :attributes # Anything that we initialize our table with. That's it. Can't be changed by state.
4
- attr_reader :effective_resource
4
+ attr_reader :resource
5
5
  attr_reader :state
6
6
 
7
7
  # Hashes of DSL options
@@ -15,8 +15,6 @@ module Effective
15
15
 
16
16
  # The collection itself. Only evaluated once.
17
17
  attr_accessor :_collection
18
- attr_accessor :_collection_apply_belongs_to
19
- attr_accessor :_collection_apply_scope
20
18
 
21
19
  # The view
22
20
  attr_reader :view
@@ -33,10 +31,10 @@ module Effective
33
31
  include Effective::EffectiveDatatable::Resource
34
32
  include Effective::EffectiveDatatable::State
35
33
 
36
- def initialize(view = nil, attributes = nil)
34
+ def initialize(view = nil, attributes = {})
37
35
  (attributes = view; view = nil) if view.kind_of?(Hash)
38
36
 
39
- @attributes = (attributes || {})
37
+ @attributes = initial_attributes(attributes)
40
38
  @state = initial_state
41
39
 
42
40
  @_aggregates = {}
@@ -47,7 +45,6 @@ module Effective
47
45
  @_form = {}
48
46
  @_scopes = {}
49
47
 
50
- raise 'expected a hash of arguments' unless @attributes.kind_of?(Hash)
51
48
  raise 'collection is defined as a method. Please use the collection do ... end syntax.' unless collection.nil?
52
49
  self.view = view if view
53
50
  end
@@ -57,23 +54,21 @@ module Effective
57
54
  @view = (view.respond_to?(:view_context) ? view.view_context : view)
58
55
  raise 'expected view to respond to params' unless @view.respond_to?(:params)
59
56
 
60
- assert_attributes!
57
+ load_cookie!
61
58
  load_attributes!
62
59
 
63
60
  # We need early access to filter and scope, to define defaults from the model first
64
- # This means filters do know about attributes but not about columns.
61
+ # This means filters do knows about attributes but not about columns.
65
62
  initialize_filters if respond_to?(:initialize_filters)
66
63
  load_filters!
67
64
  load_state!
68
65
 
69
- # Bulk actions called first so it can add the bulk_actions_col first
70
- initialize_bulk_actions if respond_to?(:initialize_bulk_actions)
71
-
72
66
  # Now we initialize all the columns. columns knows about attributes and filters and scope
73
67
  initialize_datatable if respond_to?(:initialize_datatable)
74
68
  load_columns!
75
69
 
76
70
  # Execute any additional DSL methods
71
+ initialize_bulk_actions if respond_to?(:initialize_bulk_actions)
77
72
  initialize_charts if respond_to?(:initialize_charts)
78
73
 
79
74
  # Load the collection. This is the first time def collection is called on the Datatable itself
@@ -83,10 +78,9 @@ module Effective
83
78
  # Figure out the class, and if it's activerecord, do all the resource discovery on it
84
79
  load_resource!
85
80
 
86
- # Check everything is okay
87
- validate_datatable!
81
+ # If attributes match a belongs_to column, scope the collection and remove the column
82
+ apply_belongs_to_attributes!
88
83
 
89
- # Save for next time
90
84
  save_cookie!
91
85
  end
92
86
 
@@ -123,18 +117,11 @@ module Effective
123
117
  )
124
118
  end
125
119
 
126
- # Inline crud
127
- def inline?
128
- attributes[:inline] == true
129
- end
130
-
131
- # Reordering
132
- def reorder?
133
- columns.key?(:_reorder)
134
- end
135
-
136
- def sortable?
137
- !reorder? && attributes[:sortable] != false
120
+ # When simple only a table will be rendered with
121
+ # no sorting, no filtering, no export buttons, no pagination, no per page, no colReorder
122
+ # default sorting only, default visibility only, all records returned, and responsive enabled
123
+ def simple?
124
+ attributes[:simple] == true
138
125
  end
139
126
 
140
127
  # Whether the filters must be rendered as a <form> or we can keep the normal <div> behaviour
@@ -142,12 +129,12 @@ module Effective
142
129
  _form[:verb].present?
143
130
  end
144
131
 
145
- def html_class
146
- Array(attributes[:class] || EffectiveDatatables.html_class).join(' ').presence
132
+ def table_html_class
133
+ attributes[:class] || EffectiveDatatables.html_class
147
134
  end
148
135
 
149
136
  def to_param
150
- "#{self.class.name.underscore.parameterize}-#{[self.class, attributes].hash.abs.to_s.last(12)}"
137
+ @to_param ||= "#{self.class.name.underscore.parameterize}-#{cookie_param}"
151
138
  end
152
139
 
153
140
  def columns
@@ -162,14 +149,6 @@ module Effective
162
149
  @dsl_tool ||= DatatableDslTool.new(self)
163
150
  end
164
151
 
165
- def resource
166
- raise('depecated. Please use .effective_resource instead')
167
- end
168
-
169
- def fallback_effective_resource
170
- @fallback_effective_resource ||= Effective::Resource.new('', namespace: controller_namespace)
171
- end
172
-
173
152
  private
174
153
 
175
154
  def column_tool
@@ -180,12 +159,5 @@ module Effective
180
159
  @value_tool ||= DatatableValueTool.new(self)
181
160
  end
182
161
 
183
- def validate_datatable!
184
- if reorder?
185
- raise 'cannot use reorder with an Array collection' unless active_record_collection?
186
- raise 'cannot use reorder with a non-Integer column' if effective_resource.sql_type(columns[:_reorder][:reorder]) != :integer
187
- end
188
- end
189
-
190
162
  end
191
163
  end
@@ -1,4 +1,3 @@
1
- # In practice this is just a regular hash with the aggregate, format, search, sort do syntax that saves a block
2
1
  module Effective
3
2
  class DatatableColumn
4
3
  attr_accessor :attributes
@@ -43,7 +43,7 @@ module Effective
43
43
  Rails.logger.info "COLUMN TOOL: order_column #{column.to_s} #{direction} #{sql_column}" if EffectiveDatatables.debug
44
44
 
45
45
  if column[:sql_as_column]
46
- collection.order("#{sql_column} #{datatable.effective_resource.sql_direction(direction)}")
46
+ collection.order("#{sql_column} #{datatable.resource.sql_direction(direction)}")
47
47
  else
48
48
  Effective::Resource.new(collection)
49
49
  .order(column[:name], direction, as: column[:as], sort: column[:sort], sql_column: column[:sql_column], limit: datatable.limit)
@@ -75,10 +75,8 @@ module Effective
75
75
  def search_column(collection, value, column, sql_column)
76
76
  Rails.logger.info "COLUMN TOOL: search_column #{column.to_s} #{value} #{sql_column}" if EffectiveDatatables.debug
77
77
 
78
- operation = (column[:search][:fuzzy] && column[:as] == :string) ? :matches : :eq
79
-
80
78
  Effective::Resource.new(collection)
81
- .search(column[:name], value, as: column[:as], operation: operation, column: sql_column)
79
+ .search(column[:name], value, as: column[:as], fuzzy: column[:search][:fuzzy], sql_column: sql_column)
82
80
  end
83
81
 
84
82
  def paginate(collection)
@@ -16,24 +16,16 @@ module Effective
16
16
  @view = datatable.view
17
17
  end
18
18
 
19
- def method_missing(method, *args, &block)
19
+ def method_missing(method, *args)
20
20
  # Catch a common error
21
21
  if [:bulk_actions, :charts, :collection, :filters].include?(method) && in_datatables_do_block
22
22
  raise "#{method} block must be declared outside the datatable do ... end block"
23
23
  end
24
24
 
25
25
  if datatable.respond_to?(method)
26
- if block_given?
27
- datatable.send(method, *args) { yield }
28
- else
29
- datatable.send(method, *args)
30
- end
26
+ datatable.send(method, *args)
31
27
  elsif view.respond_to?(method)
32
- if block_given?
33
- view.send(method, *args) { yield }
34
- else
35
- view.send(method, *args)
36
- end
28
+ view.send(method, *args)
37
29
  else
38
30
  super
39
31
  end
@@ -74,12 +74,13 @@ module Effective
74
74
  collection
75
75
  end
76
76
 
77
- def search_column(collection, original, column, index)
78
- Rails.logger.info "VALUE TOOL: search_column #{column.to_s} #{original} #{index}" if EffectiveDatatables.debug
77
+ def search_column(collection, value, column, index)
78
+ Rails.logger.info "VALUE TOOL: search_column #{column.to_s} #{value} #{index}" if EffectiveDatatables.debug
79
79
 
80
+ macros = Effective::Resource.new('').macros
80
81
  fuzzy = column[:search][:fuzzy]
81
82
 
82
- term = Effective::Attribute.new(column[:as]).parse(original, name: column[:name])
83
+ term = Effective::Attribute.new(column[:as]).parse(value, name: column[:name])
83
84
  term_downcased = term.to_s.downcase
84
85
 
85
86
  # term == 'nil' rescue false is a Rails 4.1 fix, where you can't compare a TimeWithZone to 'nil'
@@ -89,19 +90,18 @@ module Effective
89
90
 
90
91
  # See effective_resources gem search() method # relation.rb
91
92
  collection.select! do |row|
92
- obj = row[index]
93
- value = obj_to_value(row[index], column, row)
93
+ obj = obj_to_value(row[index], column, row)
94
94
 
95
95
  case column[:as]
96
96
  when :boolean
97
- if term
98
- ['Yes', 'yes', true, 'true', '1'].include?(value)
97
+ if fuzzy
98
+ term ? (obj == true) : (obj != true)
99
99
  else
100
- ['No', 'no', false, 'false', '0'].include?(value)
100
+ obj == term
101
101
  end
102
102
  when :datetime, :date
103
103
  end_at = (
104
- case (original.to_s.scan(/(\d+)/).flatten).length
104
+ case (value.to_s.scan(/(\d+)/).flatten).length
105
105
  when 1 ; term.end_of_year # Year
106
106
  when 2 ; term.end_of_month # Year-Month
107
107
  when 3 ; term.end_of_day # Year-Month-Day
@@ -111,35 +111,35 @@ module Effective
111
111
  else term
112
112
  end
113
113
  )
114
- value >= term && value <= end_at
114
+ obj >= term && obj <= end_at
115
115
  when :time
116
- (value.hour == term.hour) && (term.min == 0 ? true : (value.min == term.min))
116
+ (obj.hour == term.hour) && (term.min == 0 ? true : (obj.min == term.min))
117
117
  when :decimal, :currency
118
- if fuzzy && (term.round(0) == term) && original.to_s.include?('.') == false
118
+ if fuzzy && (term.round(0) == term) && value.to_s.include?('.') == false
119
119
  if term < 0
120
- value <= term && value > (term - 1.0)
120
+ obj <= term && obj > (term - 1.0)
121
121
  else
122
- value >= term && value < (term + 1.0)
122
+ obj >= term && obj < (term + 1.0)
123
123
  end
124
124
  else
125
- value == term
125
+ obj == term
126
126
  end
127
127
  when :duration
128
- if fuzzy && (term % 60 == 0) && original.to_s.include?('m') == false
128
+ if fuzzy && (term % 60 == 0) && value.to_s.include?('m') == false
129
129
  if term < 0
130
- value <= term && value > (term - 60)
130
+ obj <= term && obj > (term - 60)
131
131
  else
132
- value >= term && value < (term + 60)
132
+ obj >= term && obj < (term + 60)
133
133
  end
134
134
  else
135
- value == term
135
+ obj == term
136
136
  end
137
- when *datatable.association_macros, :resource
137
+ when *macros, :resource
138
138
  Array(obj).any? do |resource|
139
139
  Array(term).any? do |term|
140
140
  matched = false
141
141
 
142
- if term.kind_of?(Integer) && resource.respond_to?(:id) && resource.respond_to?(:to_param)
142
+ if term.kind_of?(Integer) && resource.respond_to?(:to_param)
143
143
  matched = (resource.id == term || resource.to_param == term)
144
144
  end
145
145
 
@@ -148,9 +148,9 @@ module Effective
148
148
  end
149
149
  else # :string, :text, :email
150
150
  if fuzzy
151
- value.to_s.downcase.include?(term_downcased)
151
+ obj.to_s.downcase.include?(term_downcased)
152
152
  else
153
- value == term || (value.to_s == term.to_s)
153
+ obj == term || (obj.to_s == term.to_s)
154
154
  end
155
155
  end
156
156
  end || collection
@@ -4,14 +4,22 @@ module Effective
4
4
 
5
5
  private
6
6
 
7
- def assert_attributes!
8
- if datatables_ajax_request? || datatables_inline_request?
9
- raise 'expected attributes to be present' unless attributes.present?
10
- end
7
+ def initial_attributes(args)
8
+ raise "#{self.class.name}.new() expected Hash like arguments" unless args.kind_of?(Hash)
9
+ args
11
10
  end
12
11
 
13
12
  def load_attributes!
14
- @attributes[:namespace] ||= view.controller_path.split('/')[0...-1].join('/')
13
+ if datatables_ajax_request?
14
+ raise 'expected cookie to be present' unless cookie
15
+ raise 'expected attributes cookie to be present' unless cookie[:attributes]
16
+
17
+ @attributes = cookie.delete(:attributes)
18
+ end
19
+
20
+ unless datatables_ajax_request?
21
+ @attributes[:_n] ||= view.controller_path.split('/')[0...-1].join('/').presence
22
+ end
15
23
  end
16
24
 
17
25
  end
@@ -7,23 +7,10 @@ module Effective
7
7
  @collection_class # Will be either User/Post/etc or Array
8
8
  end
9
9
 
10
- # User.all
11
10
  def active_record_collection?
12
11
  @active_record_collection == true
13
12
  end
14
13
 
15
- # [User<1>, User<2>, Post<1>, Page<3>]
16
- def active_record_array_collection?
17
- @active_record_array_collection == true
18
- end
19
-
20
- def active_record_polymorphic_array_collection?
21
- return false unless active_record_array_collection?
22
- return @active_record_polymorphic_array_collection unless @active_record_polymorphic_array_collection.nil?
23
- @active_record_polymorphic_array_collection = collection.map { |obj| obj.class }.uniq.length > 1
24
- end
25
-
26
- # [[1, 'foo'], [2, 'bar']]
27
14
  def array_collection?
28
15
  @array_collection == true
29
16
  end
@@ -34,13 +21,11 @@ module Effective
34
21
  raise 'No collection defined. Please add a collection with collection do ... end' if collection.nil?
35
22
 
36
23
  @collection_class = (collection.respond_to?(:klass) ? collection.klass : self.class)
37
-
38
24
  @active_record_collection = (collection.ancestors.include?(ActiveRecord::Base) rescue false)
39
- @active_record_array_collection = collection.kind_of?(Array) && collection.present? && collection.first.kind_of?(ActiveRecord::Base)
40
- @array_collection = collection.kind_of?(Array) && (collection.blank? || collection.first.kind_of?(Array))
25
+ @array_collection = (collection.kind_of?(Array) && (collection.length == 0 || collection.first.kind_of?(Array)))
41
26
 
42
- unless active_record_collection? || active_record_array_collection? || array_collection?
43
- raise "Unsupported collection. Expecting an ActiveRecord relation, an Array of ActiveRecord objects, or an Array of Arrays [[1, 'foo'], [2, 'bar']]"
27
+ unless active_record_collection? || array_collection?
28
+ raise "Unsupported collection type. Expecting an ActiveRecord class, ActiveRecord relation, or an Array of Arrays [[1, 'foo'], [2, 'bar']]"
44
29
  end
45
30
 
46
31
  _scopes.each do |scope, _|