effective_datatables 3.7.10 → 4.0.0

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 (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
@@ -8,148 +8,108 @@ module Effective
8
8
  end
9
9
 
10
10
  def controller_namespace
11
- @attributes[:namespace]
12
- end
13
-
14
- def association_macros
15
- [:belongs_to, :belongs_to_polymorphic, :has_many, :has_and_belongs_to_many, :has_one]
11
+ @attributes[:_n]
16
12
  end
17
13
 
18
14
  private
19
15
 
20
- def load_effective_resource!
21
- @effective_resource = if active_record_collection?
22
- Effective::Resource.new(collection_class, namespace: controller_namespace)
23
- end
24
- end
25
-
26
16
  # This looks at all the columns and figures out the as:
27
17
  def load_resource!
28
- load_effective_resource!
18
+ @resource = Effective::Resource.new(collection_class, namespace: controller_namespace)
29
19
 
30
- load_active_record_collection!
31
- load_active_record_array_collection!
32
- load_array_collection!
20
+ if active_record_collection?
21
+ columns.each do |name, opts|
33
22
 
34
- load_resource_columns!
35
- load_resource_belongs_tos!
36
- load_resource_search!
37
- end
23
+ # col 'comments.title'
24
+ if name.kind_of?(String) && name.include?('.')
25
+ raise "invalid datatables column '#{name}'. the joined syntax only supports one dot." if name.scan(/\./).count > 1
38
26
 
39
- def load_effective_resource!
40
- @effective_resource = if active_record_collection?
41
- Effective::Resource.new(collection_class, namespace: controller_namespace)
42
- end
43
- end
44
-
45
- def load_active_record_collection!
46
- return unless active_record_collection?
27
+ (associated, field) = name.split('.').first(2)
47
28
 
48
- columns.each do |name, opts|
49
- # col 'comments.title'
50
- if name.kind_of?(String) && name.include?('.')
51
- raise "invalid datatables column '#{name}'. the joined syntax only supports one dot." if name.scan(/\./).count > 1
29
+ unless resource.macros.include?(resource.sql_type(associated))
30
+ raise "invalid datatables column '#{name}'. unable to find '#{name.split('.').first}' association on '#{resource}'."
31
+ end
52
32
 
53
- (associated, field) = name.split('.').first(2)
33
+ joins_values = (collection.joins_values + collection.left_outer_joins_values)
54
34
 
55
- unless association_macros.include?(effective_resource.sql_type(associated))
56
- raise "invalid datatables column '#{name}'. unable to find '#{name.split('.').first}' association on '#{effective_resource}'."
57
- end
35
+ unless joins_values.include?(associated.to_sym)
36
+ raise "your datatables collection must .joins(:#{associated}) or .left_outer_joins(:#{associated}) to work with the joined syntax"
37
+ end
58
38
 
59
- joins_values = (collection.joins_values + collection.left_outer_joins_values)
39
+ opts[:resource] = Effective::Resource.new(resource.associated(associated), namespace: controller_namespace)
60
40
 
61
- unless joins_values.include?(associated.to_sym)
62
- raise "your datatables collection must .joins(:#{associated}) or .left_outer_joins(:#{associated}) to work with the joined syntax"
63
- end
41
+ if opts[:resource].column(field)
42
+ opts[:as] ||= opts[:resource].sql_type(field)
43
+ opts[:as] = :integer if opts[:resource].sql_type(field) == :belongs_to && field.end_with?('_id')
44
+ opts[:sql_column] = opts[:resource].sql_column(field) if opts[:sql_column].nil?
64
45
 
65
- opts[:resource] = Effective::Resource.new(effective_resource.associated(associated), namespace: controller_namespace)
46
+ opts[:resource].sort_column = field
47
+ opts[:resource].search_columns = field
48
+ end
66
49
 
67
- if opts[:resource].column(field)
68
- opts[:as] ||= opts[:resource].sql_type(field)
69
- opts[:as] = :integer if opts[:resource].sql_type(field) == :belongs_to && field.end_with?('_id')
70
- opts[:sql_column] = opts[:resource].sql_column(field) if opts[:sql_column].nil?
50
+ opts[:resource_field] = field
71
51
 
72
- opts[:resource].sort_column = field
73
- opts[:resource].search_columns = field
52
+ next
74
53
  end
75
54
 
76
- opts[:resource_field] = field
77
-
78
- next
79
- end
80
-
81
- # Regular fields
82
- opts[:as] ||= effective_resource.sql_type(name)
83
- opts[:sql_column] = effective_resource.sql_column(name) if opts[:sql_column].nil?
55
+ # Regular fields
56
+ opts[:as] ||= resource.sql_type(name)
57
+ opts[:sql_column] = resource.sql_column(name) if opts[:sql_column].nil?
84
58
 
85
- case opts[:as]
86
- when *association_macros
87
- opts[:resource] ||= Effective::Resource.new(effective_resource.associated(name), namespace: controller_namespace)
88
- opts[:sql_column] = name if opts[:sql_column].nil?
89
- when Class
90
- if opts[:as].ancestors.include?(ActiveRecord::Base)
91
- opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
92
- opts[:as] = :resource
59
+ case opts[:as]
60
+ when *resource.macros
61
+ opts[:resource] ||= Effective::Resource.new(resource.associated(name), namespace: controller_namespace)
93
62
  opts[:sql_column] = name if opts[:sql_column].nil?
63
+ when Class
64
+ if opts[:as].ancestors.include?(ActiveRecord::Base)
65
+ opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
66
+ opts[:as] = :resource
67
+ opts[:sql_column] = name if opts[:sql_column].nil?
68
+ end
69
+ when :effective_addresses
70
+ opts[:resource] = Effective::Resource.new(resource.associated(name), namespace: controller_namespace)
71
+ opts[:sql_column] = :effective_addresses
72
+ when :effective_roles
73
+ opts[:sql_column] = :effective_roles
74
+ when :string # This is the fallback
75
+ # Anything that doesn't belong to the model or the sql table, we assume is a SELECT SUM|AVG|RANK() as fancy
76
+ opts[:sql_as_column] = true if (resource.table && resource.column(name).blank?)
94
77
  end
95
- when :effective_addresses
96
- opts[:resource] = Effective::Resource.new(effective_resource.associated(name), namespace: controller_namespace)
97
- opts[:sql_column] = :effective_addresses
98
- when :effective_roles
99
- opts[:sql_column] = :effective_roles
100
- when :string # This is the fallback
101
- # Anything that doesn't belong to the model or the sql table, we assume is a SELECT SUM|AVG|RANK() as fancy
102
- opts[:sql_as_column] = true if (effective_resource.table && effective_resource.column(name).blank?)
103
- end
104
78
 
105
- if opts[:sql_column].present? && AGGREGATE_SQL_FUNCTIONS.any? { |str| opts[:sql_column].to_s.start_with?(str) }
106
- opts[:sql_as_column] = true
79
+ if opts[:sql_column].present? && AGGREGATE_SQL_FUNCTIONS.any? { |str| opts[:sql_column].to_s.start_with?(str) }
80
+ opts[:sql_as_column] = true
81
+ end
107
82
  end
108
83
  end
109
- end
110
-
111
- def load_active_record_array_collection!
112
- return unless active_record_array_collection?
113
- end
114
-
115
- def load_array_collection!
116
- return unless array_collection?
117
84
 
118
- row = collection.first
85
+ if array_collection?
86
+ row = collection.first
119
87
 
120
- columns.each do |name, opts|
121
- if opts[:as].kind_of?(Class) && opts[:as].ancestors.include?(ActiveRecord::Base)
122
- opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
123
- opts[:as] = :resource
124
- elsif opts[:as] == nil && row.present?
125
- if (value = Array(row[opts[:index]]).first).kind_of?(ActiveRecord::Base)
126
- opts[:resource] = Effective::Resource.new(value, namespace: controller_namespace)
88
+ columns.each do |name, opts|
89
+ if opts[:as].kind_of?(Class) && opts[:as].ancestors.include?(ActiveRecord::Base)
90
+ opts[:resource] = Effective::Resource.new(opts[:as], namespace: controller_namespace)
127
91
  opts[:as] = :resource
92
+ elsif opts[:as] == nil
93
+ if (value = Array(row[opts[:index]]).first).kind_of?(ActiveRecord::Base)
94
+ opts[:resource] = Effective::Resource.new(value, namespace: controller_namespace)
95
+ opts[:as] = :resource
96
+ end
128
97
  end
129
98
  end
130
99
  end
131
- end
132
100
 
133
- def load_resource_columns!
134
101
  columns.each do |name, opts|
135
102
  opts[:as] ||= :string
136
103
  opts[:as] = :email if (opts[:as] == :string && name.to_s.end_with?('email'))
137
104
 
138
- if opts[:action]
139
- opts[:resource] ||= effective_resource
140
- end
141
-
142
105
  if opts[:resource] && !opts[:resource_field] && opts[:as] != :effective_addresses
143
106
  opts[:partial] ||= '/effective/datatables/resource_column'
144
107
  end
145
108
 
146
- opts[:col_class] = [
147
- "col-#{opts[:as]}",
148
- "col-#{name.to_s.parameterize}",
149
- ('colvis-default' if opts[:visible]),
150
- opts[:col_class].presence
151
- ].compact.join(' ')
109
+ opts[:col_class] = "col-#{opts[:as]} col-#{name.to_s.parameterize} #{opts[:col_class]}".strip
152
110
  end
111
+
112
+ load_resource_search!
153
113
  end
154
114
 
155
115
  def load_resource_search!
@@ -161,7 +121,7 @@ module Effective
161
121
  when Symbol
162
122
  opts[:search] = { as: opts[:search] }
163
123
  when Array, ActiveRecord::Relation
164
- opts[:search] = { as: :select, collection: opts[:search] }
124
+ opts[:search] = { collection: opts[:search] }
165
125
  when Hash
166
126
  # Nothing
167
127
  else
@@ -170,35 +130,31 @@ module Effective
170
130
 
171
131
  search = opts[:search]
172
132
 
173
- # Parameterize collection
174
133
  if search[:collection].kind_of?(ActiveRecord::Relation)
175
134
  search[:collection] = search[:collection].map { |obj| [obj.to_s, obj.to_param] }
176
135
  elsif search[:collection].kind_of?(Array) && search[:collection].first.kind_of?(ActiveRecord::Base)
177
136
  search[:collection] = search[:collection].map { |obj| [obj.to_s, obj.to_param] }
137
+ elsif search[:collection].kind_of?(Array)
138
+ search[:collection].each { |obj| obj[1] = 'nil' if obj[1] == nil }
139
+ elsif search[:collection].kind_of?(Hash)
140
+ search[:collection].each { |k, v| search[:collection][k] = 'nil' if v == nil }
178
141
  end
179
142
 
180
- search[:as] ||= :select if search.key?(:collection)
181
- search[:fuzzy] ||= true unless search.key?(:fuzzy)
182
143
  search[:value] ||= search.delete(:selected) if search.key?(:selected)
183
144
 
184
- # Merge with defaults
185
- search_resource = [opts[:resource], effective_resource, fallback_effective_resource].compact
186
- search_resource = search_resource.find { |res| res.klass.present? } || search_resource.first
145
+ search[:as] ||= :select if (search.key?(:collection) && opts[:as] != :belongs_to_polymorphic)
187
146
 
188
- if array_collection? && opts[:resource].present?
189
- search.reverse_merge!(search_resource.search_form_field(name, collection.first[opts[:index]]))
190
- elsif search[:as] != :string
191
- search.reverse_merge!(search_resource.search_form_field(name, opts[:as]))
192
- end
147
+ search[:fuzzy] = true unless search.key?(:fuzzy)
193
148
 
194
- # Assign default include_null
195
- if search[:as] == :select && !search.key?(:include_null)
196
- search[:include_null] = true
149
+ if array_collection? && opts[:resource].present?
150
+ search.reverse_merge!(resource.search_form_field(name, collection.first[opts[:index]]))
151
+ else
152
+ search.reverse_merge!(resource.search_form_field(name, opts[:as]))
197
153
  end
198
154
  end
199
155
  end
200
156
 
201
- def load_resource_belongs_tos!
157
+ def apply_belongs_to_attributes!
202
158
  return unless active_record_collection?
203
159
 
204
160
  changed = attributes.select do |attribute, value|
@@ -206,27 +162,10 @@ module Effective
206
162
  next unless attribute.ends_with?('_id')
207
163
 
208
164
  associated = attribute.gsub(/_id\z/, '').to_sym # Replace last _id
165
+ next unless columns[associated] && columns[associated][:as] == :belongs_to
209
166
 
210
- next unless columns[associated]
211
-
212
- if columns[associated][:as] == :belongs_to
213
- if @_collection_apply_belongs_to && !@_collection.where_values_hash.include?(attribute)
214
- @_collection = @_collection.where(attribute => value)
215
- end
216
-
217
- columns.delete(associated)
218
- elsif columns[associated][:as] == :belongs_to_polymorphic
219
- associated_type = attributes["#{associated}_type".to_sym] || raise("Expected #{associated}_type attribute to be present when #{associated}_id is present on a polymorphic belongs to")
220
-
221
- if @_collection_apply_belongs_to
222
- if !@_collection.where_values_hash.include?(attribute) && !@_collection.where_values_hash.include?("#{associated}_type")
223
- @_collection = @_collection.where(attribute => value).where("#{associated}_type" => associated_type)
224
- end
225
- end
226
-
227
- columns.delete(associated)
228
- end
229
-
167
+ @_collection = @_collection.where(attribute => value)
168
+ columns.delete(associated)
230
169
  end.present?
231
170
 
232
171
  load_columns! if changed
@@ -55,6 +55,7 @@ module Effective
55
55
  # This is called first. Our initial state is set.
56
56
  def initial_state
57
57
  {
58
+ attributes: {},
58
59
  filter: {},
59
60
  length: nil,
60
61
  order_name: nil,
@@ -88,27 +89,23 @@ module Effective
88
89
 
89
90
  def load_state!
90
91
  if datatables_ajax_request?
91
- load_cookie! # but not state.
92
92
  load_filter_params!
93
93
  load_ajax_state!
94
- elsif datatables_inline_request?
95
- load_filter_params!
94
+ elsif cookie.present? && cookie[:params] == params.length
95
+ load_cookie_state!
96
96
  else
97
- load_cookie!
98
- load_cookie_state! if cookie.present? && cookie[:params] == cookie_state_params
99
- load_filter_params!
97
+ # Nothing to do for default state
100
98
  end
101
99
 
100
+ load_filter_params! unless datatables_ajax_request?
102
101
  fill_empty_filters!
103
102
  end
104
103
 
105
104
  def load_ajax_state!
106
105
  state[:length] = params[:length].to_i
107
106
 
108
- if params[:order]
109
- state[:order_dir] = (params[:order]['0'][:dir] == 'desc' ? :desc : :asc)
110
- state[:order_index] = params[:order]['0'][:column].to_i
111
- end
107
+ state[:order_dir] = (params[:order]['0'][:dir] == 'desc' ? :desc : :asc)
108
+ state[:order_index] = params[:order]['0'][:column].to_i
112
109
 
113
110
  state[:scope] = _scopes.keys.find { |name| params[:scope] == name.to_s }
114
111
  state[:start] = params[:start].to_i
@@ -133,7 +130,7 @@ module Effective
133
130
  state[:filter][name] = parse_filter_value(_filters[name], value)
134
131
  end
135
132
 
136
- state[:params] = cookie[:params] if cookie.present?
133
+ state[:params] = cookie[:params]
137
134
  end
138
135
 
139
136
  def load_cookie_state!
@@ -143,21 +140,14 @@ module Effective
143
140
  def load_columns!
144
141
  state[:length] ||= EffectiveDatatables.default_length
145
142
 
146
- (columns || {}).each_with_index { |(_, column), index| column[:index] = index }
147
-
148
143
  if columns.present?
149
- state[:order_name] = (
150
- if columns.key?(:_reorder)
151
- :_reorder
152
- elsif order_index.present?
153
- columns.keys[order_index]
154
- elsif state[:order_name].present?
155
- state[:order_name]
156
- else
157
- columns.find { |name, opts| opts[:sort] }.first
158
- end
159
- )
144
+ columns.each_with_index { |(_, column), index| column[:index] = index }
160
145
 
146
+ if order_index.present?
147
+ state[:order_name] = columns.keys[order_index]
148
+ end
149
+
150
+ state[:order_name] ||= columns.find { |name, opts| opts[:sort] }.first
161
151
  raise "order column :#{order_name} must exist as a col or val" unless columns[order_name]
162
152
 
163
153
  state[:order_index] = columns[order_name][:index]
@@ -186,7 +176,7 @@ module Effective
186
176
 
187
177
  unless datatables_ajax_request?
188
178
  search_params.each { |name, value| state[:search][name] = value }
189
- state[:params] = cookie_state_params
179
+ state[:params] = params.length
190
180
  end
191
181
 
192
182
  state[:visible].delete_if { |name, _| columns.key?(name) == false }
@@ -197,14 +187,9 @@ module Effective
197
187
  # When we parse an incoming filter term for this filter.
198
188
  def parse_filter_value(filter, value)
199
189
  return filter[:parse].call(value) if filter[:parse]
200
- return nil if value.blank? && !filter[:required]
201
190
  Effective::Attribute.new(filter[:value]).parse(value, name: filter[:name])
202
191
  end
203
192
 
204
- def cookie_state_params
205
- params.hash.abs.to_s.last(12)
206
- end
207
-
208
193
  end
209
194
  end
210
195
  end
@@ -1 +1,8 @@
1
- = render_resource_actions(resource, **actions_col_locals)
1
+ - if show_action && EffectiveDatatables.authorized?(self, :show, resource)
2
+ = show_icon_to effective_resource.action_path(:show, resource)
3
+
4
+ - if edit_action && EffectiveDatatables.authorized?(self, :edit, resource)
5
+ = edit_icon_to effective_resource.action_path(:edit, resource)
6
+
7
+ - if destroy_action && EffectiveDatatables.authorized?(self, :destroy, resource)
8
+ = destroy_icon_to effective_resource.action_path(:destroy, resource), data: { method: :delete, confirm: "Delete #{resource}?" }
@@ -1,2 +1,2 @@
1
1
  - id = (resource.try(:to_param) || resource.try(:id) || resource.object_id)
2
- = check_box_tag 'bulk_actions_resources[]', id, false, autocomplete: 'off', id: "datatable_bulk_actions_resource_#{id}", data: { role: 'bulk-action' }, onClick: 'event.stopPropagation();'
2
+ = check_box_tag 'bulk_actions_resources[]', id, false, autocomplete: 'off', id: "datatable_bulk_actions_resource_#{id}", data: { role: 'bulk-actions-resource' }, onClick: 'event.stopPropagation();'
@@ -1,17 +1,16 @@
1
1
  .effective-datatables-filters{'aria-controls': datatable.to_param}
2
- = simple_form_for :filters, url: (datatable._form[:url] || '#'), method: datatable._form[:verb], html: { class: 'form-inline' } do |form|
3
- - if datatable._scopes.present?
4
- .effective-datatables-filters-scopes
5
- = datatable_scope_tag(form, datatable)
2
+ = effective_form_with(scope: :filters, url: (datatable._form[:url] || '#'), method: datatable._form[:verb]) do |form|
3
+ .form-row.align-items-center
4
+ - if datatable._scopes.present?
5
+ = form.radios :scope, datatable._scopes.map { |name, opts| [opts[:label], name] },
6
+ label: false, required: false, checked: datatable.state[:scope], buttons: true,
7
+ wrapper: { class: 'form-group col-auto' }
6
8
 
7
- - if datatable._filters.present?
8
- .effective-datatables-filters-inputs
9
- - datatable._filters.each do |name, opts|
10
- = datatable_filter_tag(form, datatable, name, opts)
9
+ - datatable._filters.each do |name, opts|
10
+ = datatable_filter_tag(form, datatable, name, opts)
11
11
 
12
- - if datatable._scopes.present? || datatable._filters.present?
13
- .effective-datatables-filters-btn
12
+ .form-group.col-auto
14
13
  - if datatable._filters_form_required?
15
- = form.button :submit, t('effective_datatables.apply'), 'data-disable-with': t('effective_datatables.applying')
14
+ = form.save 'Apply', 'data-disable-with': 'Applying...'
16
15
  - else
17
- = link_to t('effective_datatables.apply'), '#', class: 'btn btn-primary btn-sm btn-effective-datatables-filters', 'data-apply-effective-datatables-filters': true
16
+ = link_to 'Apply', '#', class: 'btn btn-primary btn-effective-datatables-filters', 'data-apply-effective-datatables-filters': true
@@ -1,11 +1,8 @@
1
- - Array(local_assigns[:resource_name] ? resource.public_send(resource_name) : resource).each do |resource|
2
- - resource_to_s = ((local_assigns[:resource_to_s] && resource) ? resource.public_send(resource_to_s) : resource.to_s)
3
-
4
- - if resource_to_s.present?
5
- .col-resource_item
6
- - if edit_action && EffectiveDatatables.authorized?(controller, :edit, resource) && (path = effective_resource.action_path(:edit, resource)).present?
7
- = link_to resource_to_s, path, title: resource_to_s
8
- - elsif show_action && EffectiveDatatables.authorized?(controller, :show, resource) && (path = effective_resource.action_path(:show, resource)).present?
9
- = link_to resource_to_s, path, title: resource_to_s
10
- - else
11
- = resource_to_s.to_s.html_safe
1
+ - Array(datatable.array_collection? ? resource : resource.send(name)).each do |resource|
2
+ .col-resource_item
3
+ - if show_action
4
+ = link_to resource.to_s, effective_resource.action_path(:show, resource), title: resource.to_s
5
+ - elsif edit_action
6
+ = link_to resource.to_s, effective_resource.action_path(:edit, resource), title: resource.to_s
7
+ - else
8
+ = resource.to_s.html_safe
@@ -28,19 +28,21 @@ EffectiveDatatables.setup do |config|
28
28
  # Default class used on the <table> tag
29
29
  config.html_class = 'table table-hover'
30
30
 
31
+ # When using the actions_column DSL method, apply the following behavior
32
+ # Valid values for each action are:
33
+ # true - display this action if authorized?(:show, Post)
34
+ # false - do not display this action
35
+ # :authorize - display this action if authorized?(:show, Post<3>) (every instance is checked)
36
+ #
37
+ # You can override these defaults on a per-table basis
38
+ # by calling `actions_column(show: false, edit: true, destroy: :authorize)`
39
+ config.actions_column = {
40
+ show: true,
41
+ edit: true,
42
+ destroy: true
43
+ }
44
+
31
45
  # Log search/sort information to the console
32
46
  config.debug = true
33
47
 
34
- # Use a cookie to save and restore state from previous page visits.
35
- config.save_state = true
36
-
37
- # Configure the _effective_dt cookie.
38
- config.cookie_max_size = 2000 # String size. Final byte size is about 1.5 times bigger, after rails signs it
39
- config.cookie_domain = :all # Should usually be :all
40
- config.cookie_tld_length = nil # Leave nil to autodetect, or set to probably 2
41
-
42
- # Date formatting
43
- config.format_datetime = '%F %H:%M'
44
- config.format_date = '%F'
45
- config.format_time = '%H:%M'
46
48
  end
data/config/routes.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  EffectiveDatatables::Engine.routes.draw do
2
2
  scope :module => 'effective' do
3
3
  match 'datatables/:id(.:format)', to: 'datatables#show', via: [:get, :post], as: :datatable
4
- match 'datatables/:id/reorder(.:format)', to: 'datatables#reorder', via: [:post], as: :reorder_datatable
5
4
  end
6
5
  end
7
6
 
@@ -1,26 +1,16 @@
1
- require_relative '../../app/helpers/effective_datatables_controller_helper'
2
- require_relative '../../app/helpers/effective_datatables_helper'
3
- require_relative '../../app/helpers/effective_datatables_private_helper'
4
-
5
1
  module EffectiveDatatables
6
2
  class Engine < ::Rails::Engine
7
3
  engine_name 'effective_datatables'
8
4
 
9
5
  config.autoload_paths += Dir["#{config.root}/app/models/concerns", '/app/datatables/**/']
10
6
 
11
- initializer 'effective_datatables.assets' do |app|
12
- app.config.assets.precompile += ['effective_datatables_manifest.js', 'images/*']
13
- end
14
-
15
7
  # Include Helpers to base application
16
8
  initializer 'effective_datatables.action_controller' do |app|
17
- app.config.to_prepare do
18
- ActiveSupport.on_load :action_controller_base do
19
- helper EffectiveDatatablesHelper
20
- helper EffectiveDatatablesPrivateHelper
9
+ ActiveSupport.on_load :action_controller do
10
+ helper EffectiveDatatablesHelper
11
+ helper EffectiveDatatablesPrivateHelper
21
12
 
22
- ActionController::Base.send :include, ::EffectiveDatatablesControllerHelper
23
- end
13
+ ActionController::Base.send :include, ::EffectiveDatatablesControllerHelper
24
14
  end
25
15
  end
26
16
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveDatatables
2
- VERSION = '3.7.10'.freeze
2
+ VERSION = '4.0.0'.freeze
3
3
  end
@@ -1,30 +1,17 @@
1
- require 'simple_form'
1
+ require 'effective_bootstrap'
2
2
  require 'effective_resources'
3
3
  require 'effective_datatables/engine'
4
4
  require 'effective_datatables/version'
5
5
 
6
6
  module EffectiveDatatables
7
- AVAILABLE_LOCALES = %w(en es nl)
8
-
9
7
  mattr_accessor :authorization_method
10
8
 
11
9
  mattr_accessor :default_length
12
10
  mattr_accessor :html_class
13
- mattr_accessor :save_state
14
-
15
- mattr_accessor :cookie_max_size
16
- mattr_accessor :cookie_domain
17
- mattr_accessor :cookie_tld_length
18
-
19
- mattr_accessor :format_datetime
20
- mattr_accessor :format_date
21
- mattr_accessor :format_time
22
11
 
12
+ mattr_accessor :actions_column # A Hash
23
13
  mattr_accessor :debug
24
14
 
25
- alias_method :max_cookie_size, :cookie_max_size
26
- alias_method :max_cookie_size=, :cookie_max_size=
27
-
28
15
  def self.setup
29
16
  yield self
30
17
  end
@@ -33,7 +20,7 @@ module EffectiveDatatables
33
20
  @_exceptions ||= [Effective::AccessDenied, (CanCan::AccessDenied if defined?(CanCan)), (Pundit::NotAuthorizedError if defined?(Pundit))].compact
34
21
 
35
22
  return !!authorization_method unless authorization_method.respond_to?(:call)
36
- controller = controller.controller if controller.respond_to?(:controller)
23
+ controller = controller.controller if controller.respond_to?(:controller) # Do the right thing with a view
37
24
 
38
25
  begin
39
26
  !!(controller || self).instance_exec((controller || self), action, resource, &authorization_method)
@@ -43,47 +30,7 @@ module EffectiveDatatables
43
30
  end
44
31
 
45
32
  def self.authorize!(controller, action, resource)
46
- raise Effective::AccessDenied.new('Access Denied', action, resource) unless authorized?(controller, action, resource)
47
- end
48
-
49
- def self.find(id, attributes = nil)
50
- id = id.to_s.gsub(/-\d+\z/, '').gsub('-', '/')
51
- klass = (id.classify.safe_constantize || id.classify.pluralize.safe_constantize)
52
- attributes = decrypt(attributes) || {}
53
-
54
- klass.try(:new, **attributes) || raise('unable to find datatable')
55
- end
56
-
57
- # Locale is coming from view. I think it can be dynamic.
58
- # We currently support: en, es, nl
59
- def self.language(locale)
60
- @_languages ||= {}
61
-
62
- locale = :en unless AVAILABLE_LOCALES.include?(locale.to_s)
63
-
64
- @_languages[locale] ||= begin
65
- path = Gem::Specification.find_by_name('effective_datatables').gem_dir + "/app/assets/javascripts/dataTables/locales/#{locale}.lang"
66
- JSON.parse(File.read(path)).to_json
67
- end
68
- end
69
-
70
- def self.encrypt(attributes)
71
- payload = message_encrypter.encrypt_and_sign(attributes)
72
- end
73
-
74
- def self.decrypt(payload)
75
- return unless payload.present?
76
- return payload if payload.kind_of?(Hash)
77
-
78
- attributes = message_encrypter.decrypt_and_verify(payload)
79
-
80
- raise 'invalid decoded inline payload' unless attributes.kind_of?(Hash)
81
-
82
- attributes
83
- end
84
-
85
- def self.message_encrypter
86
- ActiveSupport::MessageEncryptor.new(Rails.application.secret_key_base.to_s.first(32))
33
+ raise Effective::AccessDenied unless authorized?(controller, action, resource)
87
34
  end
88
35
 
89
36
  end