effective_datatables 4.7.16 → 4.15.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +278 -24
  4. data/app/assets/javascripts/effective_datatables/bulk_actions.js.coffee +32 -9
  5. data/app/assets/javascripts/effective_datatables/download.js.coffee +10 -0
  6. data/app/assets/javascripts/effective_datatables/flash.js.coffee +1 -1
  7. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +22 -13
  8. data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +42 -13
  9. data/app/assets/javascripts/effective_datatables/reorder.js.coffee +8 -2
  10. data/app/assets/javascripts/effective_datatables/reset.js.coffee +23 -2
  11. data/app/assets/javascripts/vendor/jquery.delayedChange.js +1 -2
  12. data/app/assets/stylesheets/dataTables/dataTables.bootstrap4.scss +1 -3
  13. data/app/controllers/effective/datatables_controller.rb +34 -0
  14. data/app/helpers/effective_datatables_controller_helper.rb +2 -0
  15. data/app/helpers/effective_datatables_helper.rb +22 -6
  16. data/app/helpers/effective_datatables_private_helper.rb +30 -20
  17. data/app/models/effective/datatable.rb +57 -4
  18. data/app/models/effective/datatable_column.rb +2 -0
  19. data/app/models/effective/datatable_column_tool.rb +5 -3
  20. data/app/models/effective/datatable_dsl_tool.rb +7 -5
  21. data/app/models/effective/datatable_value_tool.rb +9 -8
  22. data/app/models/effective/effective_datatable/attributes.rb +21 -0
  23. data/app/models/effective/effective_datatable/collection.rb +3 -1
  24. data/app/models/effective/effective_datatable/compute.rb +11 -7
  25. data/app/models/effective/effective_datatable/cookie.rb +6 -0
  26. data/app/models/effective/effective_datatable/csv.rb +71 -0
  27. data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +3 -1
  28. data/app/models/effective/effective_datatable/dsl/charts.rb +2 -0
  29. data/app/models/effective/effective_datatable/dsl/datatable.rb +20 -6
  30. data/app/models/effective/effective_datatable/dsl/filters.rb +3 -1
  31. data/app/models/effective/effective_datatable/dsl.rb +7 -3
  32. data/app/models/effective/effective_datatable/format.rb +52 -24
  33. data/app/models/effective/effective_datatable/hooks.rb +2 -0
  34. data/app/models/effective/effective_datatable/params.rb +9 -2
  35. data/app/models/effective/effective_datatable/resource.rb +26 -13
  36. data/app/models/effective/effective_datatable/state.rb +4 -2
  37. data/app/views/effective/datatables/_active_storage_column.html.haml +4 -0
  38. data/app/views/effective/datatables/_bulk_actions_dropdown.html.haml +3 -2
  39. data/app/views/effective/datatables/_buttons.html.haml +14 -0
  40. data/config/effective_datatables.rb +8 -1
  41. data/config/locales/en.yml +4 -1
  42. data/config/locales/es.yml +4 -1
  43. data/config/locales/nl.yml +4 -1
  44. data/config/routes.rb +1 -0
  45. data/lib/effective_datatables/engine.rb +6 -4
  46. data/lib/effective_datatables/version.rb +1 -1
  47. data/lib/effective_datatables.rb +5 -0
  48. metadata +11 -10
  49. data/app/datatables/effective_style_guide_datatable.rb +0 -47
  50. data/app/models/effective/access_denied.rb +0 -17
  51. data/app/views/effective/style_guide/_effective_datatables.html.haml +0 -1
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
 
3
5
  class DatatableDslTool
@@ -16,7 +18,7 @@ module Effective
16
18
  @view = datatable.view
17
19
  end
18
20
 
19
- def method_missing(method, *args, &block)
21
+ def method_missing(method, *args, **kwargs, &block)
20
22
  # Catch a common error
21
23
  if [:bulk_actions, :charts, :collection, :filters].include?(method) && in_datatables_do_block
22
24
  raise "#{method} block must be declared outside the datatable do ... end block"
@@ -24,15 +26,15 @@ module Effective
24
26
 
25
27
  if datatable.respond_to?(method)
26
28
  if block_given?
27
- datatable.send(method, *args) { yield }
29
+ datatable.send(method, *args, **kwargs) { yield }
28
30
  else
29
- datatable.send(method, *args)
31
+ datatable.send(method, *args, **kwargs)
30
32
  end
31
33
  elsif view.respond_to?(method)
32
34
  if block_given?
33
- view.send(method, *args) { yield }
35
+ view.send(method, *args, **kwargs) { yield }
34
36
  else
35
- view.send(method, *args)
37
+ view.send(method, *args, **kwargs)
36
38
  end
37
39
  else
38
40
  super
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  # The collection is an Array of Arrays
3
5
  class DatatableValueTool
@@ -77,7 +79,7 @@ module Effective
77
79
  def search_column(collection, original, column, index)
78
80
  Rails.logger.info "VALUE TOOL: search_column #{column.to_s} #{original} #{index}" if EffectiveDatatables.debug
79
81
 
80
- fuzzy = column[:search][:fuzzy]
82
+ fuzzy = (column[:search][:operation] == :matches)
81
83
 
82
84
  term = Effective::Attribute.new(column[:as]).parse(original, name: column[:name])
83
85
  term_downcased = term.to_s.downcase
@@ -91,8 +93,11 @@ module Effective
91
93
  collection.select! do |row|
92
94
  obj = row[index]
93
95
  value = obj_to_value(row[index], column, row)
96
+ next if value.nil? || value == ''
97
+
98
+ obj_equals = obj.respond_to?(column[:name]) && obj.send(column[:name]).to_s.downcase == term_downcased
94
99
 
95
- case column[:as]
100
+ obj_equals || case column[:as]
96
101
  when :boolean
97
102
  if fuzzy
98
103
  term ? (obj == true) : (obj != true)
@@ -174,6 +179,8 @@ module Effective
174
179
 
175
180
  if column[:format]
176
181
  datatable.dsl_tool.instance_exec(obj, row, &column[:format])
182
+ elsif column[:as] == :belongs_to_polymorphic
183
+ obj.send(column[:name]).to_s
177
184
  elsif column[:partial]
178
185
  obj.to_s
179
186
  elsif obj.respond_to?(column[:name])
@@ -187,9 +194,3 @@ module Effective
187
194
 
188
195
  end
189
196
  end
190
-
191
- # [
192
- # [1, 'title 1'],
193
- # [2, 'title 2'],
194
- # [3, 'title 3']
195
- # ]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Attributes
@@ -11,9 +13,28 @@ module Effective
11
13
  end
12
14
 
13
15
  def load_attributes!
16
+ return unless view.respond_to?(:controller_path)
14
17
  @attributes[:namespace] ||= view.controller_path.split('/')[0...-1].join('/')
15
18
  end
16
19
 
20
+ # Polymorphic shorthand attributes.
21
+ # If you pass resource: User(1), it sets resource_id: 1, resource_type: 'User'
22
+ def initial_attributes(attributes)
23
+ return {} if attributes.blank?
24
+
25
+ resources = attributes.select { |k, v| v.kind_of?(ActiveRecord::Base) }
26
+ return attributes if resources.blank?
27
+
28
+ retval = attributes.except(*resources.keys)
29
+
30
+ resources.each do |k, resource|
31
+ retval["#{k}_id".to_sym] = resource.id
32
+ retval["#{k}_type".to_sym] = resource.class.name
33
+ end
34
+
35
+ retval
36
+ end
37
+
17
38
  end
18
39
  end
19
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Collection
@@ -34,7 +36,7 @@ module Effective
34
36
  raise 'No collection defined. Please add a collection with collection do ... end' if collection.nil?
35
37
 
36
38
  @collection_class = (collection.respond_to?(:klass) ? collection.klass : self.class)
37
-
39
+
38
40
  @active_record_collection = (collection.ancestors.include?(ActiveRecord::Base) rescue false)
39
41
  @active_record_array_collection = collection.kind_of?(Array) && collection.present? && collection.first.kind_of?(ActiveRecord::Base)
40
42
  @array_collection = collection.kind_of?(Array) && (collection.blank? || collection.first.kind_of?(Array))
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Compute
@@ -36,6 +38,9 @@ module Effective
36
38
  # Apply value ordering
37
39
  col = value_tool.order(col)
38
40
 
41
+ # Charts too
42
+ @charts_data = chart(collection, col) if _charts.present?
43
+
39
44
  # Apply pagination
40
45
  col = col.kind_of?(Array) ? value_tool.paginate(col) : column_tool.paginate(col)
41
46
 
@@ -48,9 +53,6 @@ module Effective
48
53
  # Compute aggregate data
49
54
  @aggregates_data = aggregate(col) if _aggregates.present?
50
55
 
51
- # Charts too
52
- @charts_data = chart(col) if _charts.present?
53
-
54
56
  # Format all results
55
57
  format(col)
56
58
 
@@ -58,10 +60,12 @@ module Effective
58
60
  finalize(col)
59
61
  end
60
62
 
61
- def arrayize(collection)
63
+ def arrayize(collection, csv: false)
62
64
  collection.map do |obj|
63
65
  columns.map do |name, opts|
64
- if state[:visible][name] == false && (name != order_name) # Sort by invisible array column
66
+ if state[:visible][name] == false && !csv && (name != order_name) # Sort by invisible array column
67
+ BLANK
68
+ elsif csv && !opts[:csv]
65
69
  BLANK
66
70
  elsif opts[:compute]
67
71
  if array_collection?
@@ -161,11 +165,11 @@ module Effective
161
165
  end || BLANK
162
166
  end
163
167
 
164
- def chart(collection)
168
+ def chart(collection, searched_collection)
165
169
  _charts.inject({}) do |retval, (name, chart)|
166
170
  retval[name] = {
167
171
  as: chart[:as],
168
- data: dsl_tool.instance_exec(collection, &chart[:compute]),
172
+ data: dsl_tool.instance_exec(collection, searched_collection, &chart[:compute]),
169
173
  name: chart[:name],
170
174
  options: chart[:options]
171
175
  }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Cookie
@@ -10,6 +12,8 @@ module Effective
10
12
 
11
13
  def load_cookie!
12
14
  return unless EffectiveDatatables.save_state
15
+ return if skip_save_state?
16
+ return unless (view.cookies rescue false) # Rails 6.1 view doesn't respond_to?(:cookies)
13
17
 
14
18
  @dt_cookie = view.cookies.signed['_effective_dt']
15
19
 
@@ -33,6 +37,8 @@ module Effective
33
37
 
34
38
  def save_cookie!
35
39
  return unless EffectiveDatatables.save_state
40
+ return if skip_save_state?
41
+ return unless (view.cookies rescue false)
36
42
 
37
43
  @dt_cookie ||= []
38
44
  @dt_cookie << [cookie_key, cookie_payload]
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module Effective
6
+ module EffectiveDatatable
7
+ module Csv
8
+
9
+ def csv_filename
10
+ self.class.name.underscore.parameterize + '.csv'
11
+ end
12
+
13
+ def csv_content_type
14
+ 'text/csv; charset=utf-8'
15
+ end
16
+
17
+ def csv_header
18
+ columns.map do |name, opts|
19
+ opts[:label].presence || csv_human_attribute_name(name)
20
+ end
21
+ end
22
+
23
+ def csv_human_attribute_name(name)
24
+ if active_record_collection?
25
+ collection_class.human_attribute_name(name)
26
+ else
27
+ (name.to_s.split('.').last || '')
28
+ end
29
+ end
30
+
31
+ def csv_file
32
+ CSV.generate do |csv|
33
+ csv << csv_header()
34
+
35
+ collection.find_in_batches do |resources|
36
+ resources = arrayize(resources, csv: true)
37
+ format(resources, csv: true)
38
+ finalize(resources)
39
+
40
+ resources.each { |resource| csv << resource }
41
+ end
42
+ end
43
+ end
44
+
45
+ def csv_stream
46
+ EffectiveResources.with_resource_enumerator do |lines|
47
+ lines << CSV.generate_line(csv_header)
48
+
49
+ if active_record_collection?
50
+ collection.find_in_batches do |resources|
51
+ resources = arrayize(resources, csv: true)
52
+ format(resources, csv: true)
53
+ finalize(resources)
54
+
55
+ resources.each { |resource| lines << CSV.generate_line(resource) }
56
+ end
57
+ else
58
+ resources = collection
59
+
60
+ format(resources, csv: true)
61
+ finalize(resources)
62
+
63
+ resources.each { |resource| lines << CSV.generate_line(resource) }
64
+ end
65
+
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Dsl
@@ -34,7 +36,7 @@ module Effective
34
36
 
35
37
  opts[:class] = [opts[:class], 'dropdown-item'].compact.join(' ')
36
38
 
37
- link_to(title, url, opts)
39
+ link_to(title, url, **opts)
38
40
  end
39
41
 
40
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Dsl
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Dsl
@@ -24,11 +26,19 @@ module Effective
24
26
  reorder_col(name)
25
27
  end
26
28
 
29
+ def download(bool)
30
+ datatable.attributes[:downloadable] = bool
31
+ end
32
+
33
+ def skip_save_state!
34
+ datatable.attributes[:skip_save_state] = true
35
+ end
36
+
27
37
  # A col has its internal values sorted/searched before the block is run
28
38
  # Anything done in the block, is purely a format on the after sorted/ordered value
29
39
  # the original object == the computed value, which is yielded to the format block
30
40
  # You can't do compute with .col
31
- def col(name, action: nil, as: nil, col_class: nil, label: nil, partial: nil, partial_as: nil, responsive: 10000, search: {}, sort: true, sql_column: nil, th: nil, th_append: nil, visible: true, &format)
41
+ def col(name, action: nil, as: nil, col_class: nil, csv: true, label: nil, partial: nil, partial_as: nil, responsive: 10000, search: {}, sort: true, sql_column: nil, th: nil, th_append: nil, visible: true, &format)
32
42
  raise 'You cannot use partial: ... with the block syntax' if partial && block_given?
33
43
 
34
44
  name = name.to_sym unless name.to_s.include?('.')
@@ -38,9 +48,10 @@ module Effective
38
48
  as: as,
39
49
  compute: nil,
40
50
  col_class: col_class,
51
+ csv: csv,
41
52
  format: (format if block_given?),
42
53
  index: nil,
43
- label: (label.nil? ? name.to_s.split('.').last.titleize : label),
54
+ label: label,
44
55
  name: name,
45
56
  partial: partial,
46
57
  partial_as: partial_as,
@@ -56,7 +67,7 @@ module Effective
56
67
 
57
68
  # A val is a computed value that is then sorted/searched after the block is run
58
69
  # You can have another block by calling .format afterwards to work on the computed value itself
59
- def val(name, action: nil, as: nil, col_class: nil, label: nil, partial: nil, partial_as: nil, responsive: 10000, search: {}, sort: true, sql_column: false, th: nil, th_append: nil, visible: true, &compute)
70
+ def val(name, action: nil, as: nil, col_class: nil, csv: true, label: nil, partial: nil, partial_as: nil, responsive: 10000, search: {}, sort: true, sql_column: false, th: nil, th_append: nil, visible: true, &compute)
60
71
  raise 'You cannot use partial: ... with the block syntax' if partial && block_given?
61
72
 
62
73
  name = name.to_sym unless name.to_s.include?('.')
@@ -66,9 +77,10 @@ module Effective
66
77
  as: as,
67
78
  compute: (compute if block_given?),
68
79
  col_class: col_class,
80
+ csv: csv,
69
81
  format: nil,
70
82
  index: nil,
71
- label: (label.nil? ? name.to_s.split('.').last.titleize : label),
83
+ label: label,
72
84
  name: name,
73
85
  partial: partial,
74
86
  partial_as: partial_as,
@@ -82,7 +94,7 @@ module Effective
82
94
  )
83
95
  end
84
96
 
85
- def actions_col(btn_class: nil, col_class: nil, inline: nil, partial: nil, partial_as: nil, actions_partial: nil, responsive: 5000, visible: true, **actions, &format)
97
+ def actions_col(btn_class: nil, col_class: nil, partial: nil, partial_as: nil, actions_partial: nil, responsive: 5000, visible: true, **actions, &format)
86
98
  raise 'You can only have one actions column' if datatable.columns[:_actions].present?
87
99
 
88
100
  datatable._columns[:_actions] = Effective::DatatableColumn.new(
@@ -91,9 +103,9 @@ module Effective
91
103
  compute: nil,
92
104
  btn_class: (btn_class || 'btn-sm btn-outline-primary'),
93
105
  col_class: col_class,
106
+ csv: false,
94
107
  format: (format if block_given?),
95
108
  index: nil,
96
- inline: (inline.nil? ? datatable.inline? : inline),
97
109
  label: false,
98
110
  name: :actions,
99
111
  partial: partial,
@@ -130,6 +142,7 @@ module Effective
130
142
  as: :bulk_actions,
131
143
  compute: nil,
132
144
  col_class: col_class,
145
+ csv: false,
133
146
  format: nil,
134
147
  index: nil,
135
148
  input_name: (input_name || 'bulk_actions_resources'),
@@ -157,6 +170,7 @@ module Effective
157
170
  as: :reorder,
158
171
  compute: nil,
159
172
  col_class: col_class,
173
+ csv: false,
160
174
  format: nil,
161
175
  index: nil,
162
176
  label: false,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Dsl
@@ -20,7 +22,7 @@ module Effective
20
22
  elsif value != nil
21
23
  Effective::Attribute.new(value).type
22
24
  end
23
- ) || :text
25
+ ) || :string
24
26
 
25
27
  datatable._filters[name.to_sym] = {
26
28
  value: value,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Dsl
@@ -11,11 +13,11 @@ module Effective
11
13
  end
12
14
 
13
15
  def collection(apply_belongs_to: true, apply_scope: true, &block)
14
- define_method('initialize_collection') {
16
+ define_method('initialize_collection') {
15
17
  self._collection_apply_belongs_to = apply_belongs_to
16
18
  self._collection_apply_scope = apply_scope
17
-
18
- self._collection = dsl_tool.instance_exec(&block)
19
+
20
+ self._collection = dsl_tool.instance_exec(&block)
19
21
  }
20
22
  end
21
23
 
@@ -24,6 +26,8 @@ module Effective
24
26
  dsl_tool.in_datatables_do_block = true
25
27
  dsl_tool.instance_exec(&block)
26
28
  dsl_tool.in_datatables_do_block = false
29
+
30
+ self.source_location = block.source_location.first if block.respond_to?(:source_location)
27
31
  end
28
32
  end
29
33
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Format
@@ -8,15 +10,17 @@ module Effective
8
10
 
9
11
  private
10
12
 
11
- def format(collection)
13
+ def format(collection, csv: false)
12
14
  # We want to use the render :collection for each column that renders partials
13
15
  rendered = {}
14
16
 
15
17
  columns.each do |name, opts|
16
- next unless state[:visible][name]
17
-
18
- if opts[:partial]
19
- locals = { datatable: self, column: opts }.merge(resource_col_locals(opts))
18
+ if state[:visible][name] == false && !csv
19
+ # Nothing to do
20
+ elsif csv && !opts[:csv]
21
+ # Nothing to do
22
+ elsif opts[:partial]
23
+ locals = { datatable: self, column: opts }.merge!(resource_col_locals(opts))
20
24
 
21
25
  rendered[name] = (view.render(
22
26
  partial: opts[:partial],
@@ -26,8 +30,8 @@ module Effective
26
30
  locals: locals,
27
31
  spacer_template: SPACER_TEMPLATE
28
32
  ) || '').split(SPACER)
33
+
29
34
  elsif opts[:as] == :actions # This is actions_col and actions_col do .. end, but not actions_col partial: 'something'
30
- resources = collection.map { |row| row[opts[:index]] }
31
35
  locals = { datatable: self, column: opts, spacer_template: SPACER_TEMPLATE }
32
36
 
33
37
  atts = {
@@ -36,15 +40,15 @@ module Effective
36
40
  effective_resource: effective_resource,
37
41
  locals: locals,
38
42
  partial: opts[:actions_partial],
39
- }.compact.merge(opts[:actions])
43
+ }.merge!(opts[:actions]).tap(&:compact!)
40
44
 
41
45
  rendered[name] = if effective_resource.blank?
42
- resources.map do |resource|
46
+ collection.map { |row| row[opts[:index]] }.map do |resource|
43
47
  polymorphic_resource = Effective::Resource.new(resource, namespace: controller_namespace)
44
48
  (view.render_resource_actions(resource, atts.merge(effective_resource: polymorphic_resource), &opts[:format]) || '')
45
49
  end
46
50
  else
47
- (view.render_resource_actions(resources, atts, &opts[:format]) || '').split(SPACER)
51
+ (view.render_resource_actions(collection.map { |row| row[opts[:index]] }, atts, &opts[:format]) || '').split(SPACER)
48
52
  end
49
53
  end
50
54
  end
@@ -54,32 +58,52 @@ module Effective
54
58
  index = opts[:index]
55
59
  value = row[index]
56
60
 
57
- row[index] = (
58
- if state[:visible][name] == false
61
+ formatted = (
62
+ if state[:visible][name] == false && !csv
59
63
  NONVISIBLE
64
+ elsif csv && !opts[:csv]
65
+ BLANK
60
66
  elsif opts[:as] == :actions
61
67
  rendered[name][row_index]
62
68
  elsif opts[:format] && rendered.key?(name)
63
69
  dsl_tool.instance_exec(value, row, rendered[name][row_index], &opts[:format])
64
70
  elsif opts[:format]
65
- dsl_tool.instance_exec(value, row, &opts[:format])
71
+ dsl_tool.instance_exec(value, row, &opts[:format]).to_s
66
72
  elsif opts[:partial]
67
73
  rendered[name][row_index]
68
74
  else
69
- format_column(value, opts)
75
+ format_column(value, opts, csv: csv)
70
76
  end
71
77
  )
78
+
79
+ if csv && (opts[:format] || opts[:partial])
80
+ formatted = view.strip_tags(formatted)
81
+
82
+ formatted.gsub!("\n\n", ' ') unless formatted.frozen?
83
+ formatted.gsub!("\n", '') unless formatted.frozen?
84
+ end
85
+
86
+ row[index] = formatted
72
87
  end
73
88
  end
74
89
  end
75
90
 
76
- def format_column(value, column)
91
+ # Must return a string
92
+ def format_column(value, column, csv: false)
77
93
  return if value.nil? || (column[:resource] && value.blank?)
78
94
 
79
95
  unless column[:as] == :email
80
96
  return value if value.kind_of?(String)
81
97
  end
82
98
 
99
+ if value.kind_of?(Array) && column[:as] == :string
100
+ if csv
101
+ return value.map { |v| format_column(v, column, csv: csv) }.join("\n")
102
+ else
103
+ return value.map { |v| view.content_tag(:div, format_column(v, column, csv: csv), class: 'col-resource_item') }.join.html_safe
104
+ end
105
+ end
106
+
83
107
  case column[:as]
84
108
  when :actions
85
109
  raise("please use actions_col instead of col(#{name}, as: :actions)")
@@ -88,23 +112,27 @@ module Effective
88
112
  when :currency
89
113
  view.number_to_currency(value)
90
114
  when :date
91
- (value.strftime('%F') rescue BLANK)
115
+ value.respond_to?(:strftime) ? value.strftime(EffectiveDatatables.format_date) : BLANK
92
116
  when :datetime
93
- (value.strftime('%F %H:%M') rescue BLANK)
117
+ if csv
118
+ value.to_s
119
+ else
120
+ value.respond_to?(:strftime) ? value.strftime(EffectiveDatatables.format_datetime) : BLANK
121
+ end
94
122
  when :decimal
95
- value
123
+ value.to_s
96
124
  when :duration
97
125
  view.number_to_duration(value)
98
126
  when :effective_addresses
99
- value.to_html
127
+ csv ? value.to_html.gsub('<br>', "\n") : value.to_html
100
128
  when :effective_obfuscation
101
- value
129
+ value.to_s
102
130
  when :effective_roles
103
131
  value.join(', ')
104
132
  when :email
105
- view.mail_to(value)
133
+ csv ? value : view.mail_to(value)
106
134
  when :integer
107
- value
135
+ value.to_s
108
136
  when :percent
109
137
  case value
110
138
  when Integer ; view.number_to_percentage(value / 1000.0, precision: 3).gsub('.000%', '%')
@@ -116,7 +144,7 @@ module Effective
116
144
  when Numeric ; view.number_to_currency(value)
117
145
  end
118
146
  when :time
119
- (value.strftime('%H:%M') rescue BLANK)
147
+ value.respond_to?(:strftime) ? value.strftime(EffectiveDatatables.format_time) : BLANK
120
148
  else
121
149
  value.to_s
122
150
  end
@@ -128,14 +156,14 @@ module Effective
128
156
  def actions_col_actions(column)
129
157
  resource_actions = (effective_resource&.resource_actions || fallback_effective_resource.fallback_resource_actions)
130
158
 
131
- actions = if column[:inline]
159
+ actions = if inline?
132
160
  resource_actions.transform_values { |opts| opts['data-remote'] = true; opts }
133
161
  else
134
162
  resource_actions.transform_values { |opts| opts['data-remote'] = true if opts['data-method']; opts }
135
163
  end
136
164
 
137
165
  # Merge local options. Special behaviour for remote: false
138
- if column[:actions].kind_of?(Hash)
166
+ if column[:actions].present? && column[:actions].kind_of?(Hash)
139
167
  column[:actions].each do |action, opts|
140
168
  next unless opts.kind_of?(Hash)
141
169
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Hooks
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Effective
2
4
  module EffectiveDatatable
3
5
  module Params
@@ -6,18 +8,23 @@ module Effective
6
8
 
7
9
  def datatables_ajax_request?
8
10
  return @_datatables_ajax_request unless @_datatables_ajax_request.nil?
11
+ return unless view.respond_to?(:params)
9
12
 
10
- @_datatables_ajax_request = (view.present? && view.params.key?(:draw) && view.params.key?(:columns))
13
+ @_datatables_ajax_request = (view.params.key?(:draw) && view.params.key?(:columns))
11
14
  end
12
15
 
13
16
  def datatables_inline_request?
14
17
  return @_datatables_inline_request unless @_datatables_inline_request.nil?
18
+ return unless view.respond_to?(:params)
15
19
 
16
- @_datatables_inline_request = (view.present? && view.params[:_datatable_id].to_s.split('-')[0...-1] == to_param.split('-')[0...-1])
20
+ @_datatables_inline_request = (view.params[:_datatable_id].to_s.split('-')[0...-1] == to_param.split('-')[0...-1])
17
21
  end
18
22
 
19
23
  def params
20
24
  return {} unless view.present?
25
+ return view.rendered_params if view.respond_to?(:rendered_params)
26
+ return {} unless view.respond_to?(:request)
27
+
21
28
  @params ||= {}.tap do |params|
22
29
  Rack::Utils.parse_query(URI(view.request.referer.presence || '/').query).each { |k, v| params[k.to_sym] = v }
23
30
  view.params.each { |k, v| params[k.to_sym] = v }