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.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +32 -32
- data/app/assets/images/dataTables/sort-down.svg +1 -0
- data/app/assets/images/dataTables/sort-up.svg +1 -0
- data/app/assets/images/dataTables/sort.svg +1 -0
- data/app/assets/javascripts/dataTables/buttons/{buttons.bootstrap.js → buttons.bootstrap4.js} +7 -15
- data/app/assets/javascripts/dataTables/dataTables.bootstrap4.js +184 -0
- data/app/assets/javascripts/dataTables/responsive/dataTables.responsive.js +30 -11
- data/app/assets/javascripts/dataTables/responsive/{responsive.bootstrap.js → responsive.bootstrap4.js} +6 -6
- data/app/assets/javascripts/effective_datatables/bulk_actions.js.coffee +43 -43
- data/app/assets/javascripts/effective_datatables/events.js.coffee +7 -4
- data/app/assets/javascripts/effective_datatables/filters.js.coffee +0 -1
- data/app/assets/javascripts/effective_datatables/initialize.js.coffee +45 -49
- data/app/assets/javascripts/effective_datatables/overrides.js +12 -0
- data/app/assets/javascripts/effective_datatables/reset.js.coffee +1 -1
- data/app/assets/javascripts/effective_datatables.js +4 -4
- data/app/assets/stylesheets/dataTables/buttons/{buttons.bootstrap.scss → buttons.bootstrap4.css} +68 -1
- data/app/assets/stylesheets/dataTables/{dataTables.bootstrap.scss → dataTables.bootstrap4.css} +44 -29
- data/app/assets/stylesheets/dataTables/responsive/{responsive.bootstrap.scss → responsive.bootstrap4.css} +3 -3
- data/app/assets/stylesheets/effective_datatables/_overrides.scss +72 -152
- data/app/assets/stylesheets/effective_datatables.scss +3 -4
- data/app/controllers/effective/datatables_controller.rb +6 -39
- data/app/helpers/effective_datatables_helper.rb +55 -50
- data/app/helpers/effective_datatables_private_helper.rb +47 -179
- data/app/models/effective/datatable.rb +16 -44
- data/app/models/effective/datatable_column.rb +0 -1
- data/app/models/effective/datatable_column_tool.rb +2 -4
- data/app/models/effective/datatable_dsl_tool.rb +3 -11
- data/app/models/effective/datatable_value_tool.rb +23 -23
- data/app/models/effective/effective_datatable/attributes.rb +13 -5
- data/app/models/effective/effective_datatable/collection.rb +3 -18
- data/app/models/effective/effective_datatable/compute.rb +6 -17
- data/app/models/effective/effective_datatable/cookie.rb +20 -19
- data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +25 -14
- data/app/models/effective/effective_datatable/dsl/datatable.rb +28 -70
- data/app/models/effective/effective_datatable/dsl/filters.rb +5 -5
- data/app/models/effective/effective_datatable/dsl.rb +3 -8
- data/app/models/effective/effective_datatable/format.rb +50 -95
- data/app/models/effective/effective_datatable/params.rb +3 -8
- data/app/models/effective/effective_datatable/resource.rb +76 -137
- data/app/models/effective/effective_datatable/state.rb +15 -30
- data/app/views/effective/datatables/_actions_column.html.haml +8 -1
- data/app/views/effective/datatables/_bulk_actions_column.html.haml +1 -1
- data/app/views/effective/datatables/_filters.html.haml +11 -12
- data/app/views/effective/datatables/_resource_column.html.haml +8 -11
- data/config/effective_datatables.rb +14 -12
- data/config/routes.rb +0 -1
- data/lib/effective_datatables/engine.rb +4 -14
- data/lib/effective_datatables/version.rb +1 -1
- data/lib/effective_datatables.rb +4 -57
- metadata +20 -31
- data/app/assets/config/effective_datatables_manifest.js +0 -3
- data/app/assets/images/dataTables/sort_asc.png +0 -0
- data/app/assets/images/dataTables/sort_both.png +0 -0
- data/app/assets/images/dataTables/sort_desc.png +0 -0
- data/app/assets/javascripts/dataTables/dataTables.bootstrap.js +0 -182
- data/app/assets/javascripts/dataTables/locales/en.lang +0 -33
- data/app/assets/javascripts/dataTables/locales/es.lang +0 -36
- data/app/assets/javascripts/dataTables/locales/nl.lang +0 -30
- data/app/assets/javascripts/effective_datatables/flash.js.coffee +0 -31
- data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +0 -217
- data/app/assets/javascripts/effective_datatables/overrides.js.coffee +0 -7
- data/app/assets/javascripts/effective_datatables/reorder.js.coffee +0 -43
- data/app/assets/stylesheets/effective_datatables/_filters.scss +0 -7
- data/app/views/effective/datatables/_reorder_column.html.haml +0 -5
- data/config/locales/en.yml +0 -12
- data/config/locales/es.yml +0 -12
- 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[:
|
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
|
-
|
18
|
+
@resource = Effective::Resource.new(collection_class, namespace: controller_namespace)
|
29
19
|
|
30
|
-
|
31
|
-
|
32
|
-
load_array_collection!
|
20
|
+
if active_record_collection?
|
21
|
+
columns.each do |name, opts|
|
33
22
|
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
33
|
+
joins_values = (collection.joins_values + collection.left_outer_joins_values)
|
54
34
|
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
39
|
+
opts[:resource] = Effective::Resource.new(resource.associated(associated), namespace: controller_namespace)
|
60
40
|
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
46
|
+
opts[:resource].sort_column = field
|
47
|
+
opts[:resource].search_columns = field
|
48
|
+
end
|
66
49
|
|
67
|
-
|
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
|
-
|
73
|
-
opts[:resource].search_columns = field
|
52
|
+
next
|
74
53
|
end
|
75
54
|
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
106
|
-
|
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
|
-
|
85
|
+
if array_collection?
|
86
|
+
row = collection.first
|
119
87
|
|
120
|
-
|
121
|
-
|
122
|
-
|
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] = {
|
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
|
-
|
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
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
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
|
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
|
-
|
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
|
95
|
-
|
94
|
+
elsif cookie.present? && cookie[:params] == params.length
|
95
|
+
load_cookie_state!
|
96
96
|
else
|
97
|
-
|
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
|
-
|
109
|
-
|
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]
|
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
|
-
|
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] =
|
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
|
-
|
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-
|
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
|
-
=
|
3
|
-
-
|
4
|
-
.
|
5
|
-
=
|
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
|
-
|
8
|
-
|
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
|
-
|
13
|
-
.effective-datatables-filters-btn
|
12
|
+
.form-group.col-auto
|
14
13
|
- if datatable._filters_form_required?
|
15
|
-
= form.
|
14
|
+
= form.save 'Apply', 'data-disable-with': 'Applying...'
|
16
15
|
- else
|
17
|
-
= link_to
|
16
|
+
= link_to 'Apply', '#', class: 'btn btn-primary btn-effective-datatables-filters', 'data-apply-effective-datatables-filters': true
|
@@ -1,11 +1,8 @@
|
|
1
|
-
- Array(
|
2
|
-
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
helper EffectiveDatatablesPrivateHelper
|
9
|
+
ActiveSupport.on_load :action_controller do
|
10
|
+
helper EffectiveDatatablesHelper
|
11
|
+
helper EffectiveDatatablesPrivateHelper
|
21
12
|
|
22
|
-
|
23
|
-
end
|
13
|
+
ActionController::Base.send :include, ::EffectiveDatatablesControllerHelper
|
24
14
|
end
|
25
15
|
end
|
26
16
|
|
data/lib/effective_datatables.rb
CHANGED
@@ -1,30 +1,17 @@
|
|
1
|
-
require '
|
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
|
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
|