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
@@ -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