effective_datatables 4.7.16 → 4.15.1

Sign up to get free protection for your applications and to get access to all the features.
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 }