active_scaffold 4.0.13 → 4.1.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 +4 -4
- data/CHANGELOG.rdoc +19 -0
- data/README.md +11 -5
- data/app/assets/javascripts/active_scaffold.js.erb +1 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +67 -20
- data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +1 -1
- data/app/assets/javascripts/jquery/draggable_lists.js +1 -1
- data/app/assets/javascripts/jquery/tiny_mce_bridge.js +1 -0
- data/app/assets/stylesheets/active_scaffold.scss +415 -6
- data/app/assets/stylesheets/active_scaffold_layout.css +11 -1
- data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +2 -1
- data/app/views/active_scaffold_overrides/_form_association_record.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_human_filters.html.erb +1 -0
- data/app/views/active_scaffold_overrides/_list_header.html.erb +2 -0
- data/app/views/active_scaffold_overrides/_list_messages.html.erb +11 -0
- data/app/views/active_scaffold_overrides/_render_field.js.erb +1 -1
- data/app/views/active_scaffold_overrides/_show_association.html.erb +1 -0
- data/app/views/active_scaffold_overrides/_show_columns.html.erb +17 -2
- data/app/views/active_scaffold_overrides/_update_field_on_create.js.erb +20 -0
- data/app/views/active_scaffold_overrides/add_tab.js.erb +3 -3
- data/app/views/active_scaffold_overrides/edit_associated.js.erb +1 -1
- data/app/views/active_scaffold_overrides/on_create.js.erb +21 -17
- data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
- data/lib/active_scaffold/actions/core.rb +34 -16
- data/lib/active_scaffold/actions/field_search.rb +21 -8
- data/lib/active_scaffold/actions/list.rb +40 -5
- data/lib/active_scaffold/actions/nested.rb +1 -1
- data/lib/active_scaffold/actions/subform.rb +2 -1
- data/lib/active_scaffold/attribute_params.rb +12 -2
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +1 -1
- data/lib/active_scaffold/bridges/paper_trail/helper.rb +1 -1
- data/lib/active_scaffold/bridges/record_select/helpers.rb +1 -1
- data/lib/active_scaffold/config/core.rb +5 -1
- data/lib/active_scaffold/config/list.rb +35 -1
- data/lib/active_scaffold/constraints.rb +4 -2
- data/lib/active_scaffold/data_structures/action_columns.rb +2 -2
- data/lib/active_scaffold/data_structures/action_link.rb +16 -11
- data/lib/active_scaffold/data_structures/action_links.rb +3 -3
- data/lib/active_scaffold/data_structures/actions.rb +2 -2
- data/lib/active_scaffold/data_structures/column.rb +21 -0
- data/lib/active_scaffold/data_structures/columns.rb +2 -2
- data/lib/active_scaffold/data_structures/filter.rb +85 -0
- data/lib/active_scaffold/data_structures/filter_option.rb +32 -0
- data/lib/active_scaffold/data_structures/filters.rb +51 -0
- data/lib/active_scaffold/data_structures/set.rb +2 -2
- data/lib/active_scaffold/data_structures/sorting.rb +2 -2
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +2 -2
- data/lib/active_scaffold/extensions/action_view_rendering.rb +3 -3
- data/lib/active_scaffold/finder.rb +16 -6
- data/lib/active_scaffold/helpers/action_link_helpers.rb +21 -17
- data/lib/active_scaffold/helpers/filter_helpers.rb +36 -0
- data/lib/active_scaffold/helpers/form_column_helpers.rb +116 -26
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +4 -0
- data/lib/active_scaffold/helpers/list_column_helpers.rb +26 -12
- data/lib/active_scaffold/helpers/search_column_helpers.rb +4 -2
- data/lib/active_scaffold/helpers/show_column_helpers.rb +4 -3
- data/lib/active_scaffold/helpers/tabs_helpers.rb +4 -3
- data/lib/active_scaffold/helpers/view_helpers.rb +7 -1
- data/lib/active_scaffold/registry.rb +1 -1
- data/lib/active_scaffold/responds_to_parent.rb +3 -3
- data/lib/active_scaffold/tableless.rb +2 -2
- data/lib/active_scaffold/version.rb +2 -2
- data/lib/active_scaffold.rb +3 -7
- metadata +22 -17
- data/app/assets/stylesheets/active_scaffold_colors.scss +0 -414
@@ -88,14 +88,13 @@ module ActiveScaffold::Actions
|
|
88
88
|
@columns += [@column.name] if @column.options[:refresh_link] && @columns.exclude?(@column.name)
|
89
89
|
process_render_field_params
|
90
90
|
|
91
|
-
@record =
|
91
|
+
@record = find_from_scope(setup_parent, @scope) if main_form_controller && @scope
|
92
|
+
@record ||=
|
92
93
|
if @column.send_form_on_update_column
|
93
94
|
updated_record_with_form(@main_columns, params[:record] || params[:search], @scope)
|
94
95
|
else
|
95
96
|
updated_record_with_column(@column, params.delete(:value), @scope)
|
96
97
|
end
|
97
|
-
# if @scope has more than 2 ] then it's subform inside subform, and assign parent would fail (found associotion may be through association)
|
98
|
-
setup_parent(@record) if main_form_controller && @scope && @scope.scan(']').size == 2
|
99
98
|
after_render_field(@record, @column)
|
100
99
|
end
|
101
100
|
|
@@ -146,21 +145,15 @@ module ActiveScaffold::Actions
|
|
146
145
|
"#{params[:parent_controller].camelize}Controller"
|
147
146
|
end
|
148
147
|
|
149
|
-
def setup_parent
|
148
|
+
def setup_parent
|
150
149
|
cfg = main_form_controller.active_scaffold_config
|
151
|
-
association = cfg.columns[subform_child_association]&.association&.reverse_association
|
152
|
-
return if association.nil?
|
153
|
-
|
154
150
|
parent_model = cfg.model
|
155
151
|
parent = parent_model.new
|
156
152
|
copy_attributes(find_if_allowed(params[:parent_id], :read, parent_model), parent) if params[:parent_id]
|
157
153
|
parent.id = params[:parent_id]
|
158
154
|
apply_constraints_to_record(parent) unless params[:parent_id]
|
159
|
-
|
160
|
-
|
161
|
-
record.send(association.name) << parent
|
162
|
-
else
|
163
|
-
record.send(:"#{association.name}=", parent)
|
155
|
+
if @column.send_form_on_update_column
|
156
|
+
parent = update_record_from_params(parent, cfg.send(params[:parent_id] ? :update : :create).columns, params[:record], true)
|
164
157
|
end
|
165
158
|
|
166
159
|
if params[:nested] # form in nested scaffold, set nested parent_record to parent
|
@@ -172,6 +165,27 @@ module ActiveScaffold::Actions
|
|
172
165
|
parent
|
173
166
|
end
|
174
167
|
|
168
|
+
def find_from_scope(parent, scope)
|
169
|
+
parts = scope[1..-2].split('][')
|
170
|
+
record = parent
|
171
|
+
|
172
|
+
while parts.present?
|
173
|
+
part = parts.shift
|
174
|
+
return unless record.respond_to?(part)
|
175
|
+
|
176
|
+
association = record.class.reflect_on_association(part)
|
177
|
+
id = parts.shift.to_i if association&.collection?
|
178
|
+
record = record.send(part)
|
179
|
+
if id
|
180
|
+
record = record.find { |child| child.id == id }
|
181
|
+
record ||= @new_records&.dig(association.klass, id.to_s)
|
182
|
+
end
|
183
|
+
return if record.nil?
|
184
|
+
end
|
185
|
+
|
186
|
+
record
|
187
|
+
end
|
188
|
+
|
175
189
|
def copy_attributes(orig, dst = nil)
|
176
190
|
dst ||= orig.class.new
|
177
191
|
orig.attributes.each { |attr, value| dst.send :write_attribute, attr, value }
|
@@ -203,8 +217,8 @@ module ActiveScaffold::Actions
|
|
203
217
|
cookies[params[:_dl_cookie]] = {value: Time.now.to_i, expires: 1.day.since} if params[:_dl_cookie]
|
204
218
|
end
|
205
219
|
|
206
|
-
def each_marked_record(&
|
207
|
-
active_scaffold_config.model.as_marked.each(&
|
220
|
+
def each_marked_record(&)
|
221
|
+
active_scaffold_config.model.as_marked.each(&)
|
208
222
|
end
|
209
223
|
|
210
224
|
def marked_records
|
@@ -276,6 +290,10 @@ module ActiveScaffold::Actions
|
|
276
290
|
redirect_to options.is_a?(Hash) ? url_for(options) : options
|
277
291
|
end
|
278
292
|
|
293
|
+
def filtered_query
|
294
|
+
beginning_of_chain
|
295
|
+
end
|
296
|
+
|
279
297
|
# Overide this method on your controller to provide model with named scopes
|
280
298
|
def beginning_of_chain
|
281
299
|
active_scaffold_config.model
|
@@ -352,7 +370,7 @@ module ActiveScaffold::Actions
|
|
352
370
|
end
|
353
371
|
|
354
372
|
def get_row(crud_type_or_security_options = :read)
|
355
|
-
klass =
|
373
|
+
klass = filtered_query
|
356
374
|
klass = klass.preload(active_scaffold_preload) unless active_scaffold_config.mongoid?
|
357
375
|
@record = find_if_allowed(params[:id], crud_type_or_security_options, klass)
|
358
376
|
end
|
@@ -369,7 +387,7 @@ module ActiveScaffold::Actions
|
|
369
387
|
end
|
370
388
|
|
371
389
|
def set_vary_accept_header
|
372
|
-
response.
|
390
|
+
response.set_header 'vary', 'Accept'
|
373
391
|
end
|
374
392
|
|
375
393
|
def check_input_device
|
@@ -65,16 +65,22 @@ module ActiveScaffold::Actions
|
|
65
65
|
|
66
66
|
def grouped_search_finder_options
|
67
67
|
select_query = grouped_search_select
|
68
|
+
group_by = calculation_for_group_by(search_group_column&.group_by || [search_group_name], search_group_function)
|
69
|
+
|
68
70
|
if search_group_function
|
69
|
-
|
70
|
-
group_by =
|
71
|
-
select_query += [group_sql.as(search_group_column.name.to_s)]
|
71
|
+
select_query += [group_by.as(search_group_name)]
|
72
|
+
group_by = group_by.to_sql
|
72
73
|
order = grouped_sorting(group_by)
|
73
74
|
else
|
74
|
-
|
75
|
-
|
75
|
+
if search_group_column&.group_by
|
76
|
+
sql_with_names = search_group_column.group_by.map.with_index { |part, i| [part, "#{search_group_name}_#{i}"] }
|
77
|
+
select_query += quoted_select_columns(sql_with_names)
|
78
|
+
else
|
79
|
+
select_query += group_by
|
80
|
+
end
|
76
81
|
order = grouped_sorting
|
77
82
|
end
|
83
|
+
|
78
84
|
{group: group_by, select: select_query, reorder: order}
|
79
85
|
end
|
80
86
|
|
@@ -103,11 +109,13 @@ module ActiveScaffold::Actions
|
|
103
109
|
end
|
104
110
|
|
105
111
|
def calculation_for_group_search(column)
|
106
|
-
sql_function column.calculate.to_s, column.
|
112
|
+
sql_function column.calculate.to_s, column.grouped_select
|
107
113
|
end
|
108
114
|
|
109
115
|
def calculation_for_group_by(group_sql, group_function)
|
110
|
-
|
116
|
+
return quoted_select_columns(group_sql) unless group_function
|
117
|
+
|
118
|
+
group_sql = Arel.sql(group_sql.join(', '))
|
111
119
|
case group_function
|
112
120
|
when 'year', 'month', 'quarter'
|
113
121
|
extract_sql_fn(group_function, group_sql)
|
@@ -121,7 +129,7 @@ module ActiveScaffold::Actions
|
|
121
129
|
end
|
122
130
|
|
123
131
|
def extract_sql_fn(part, column)
|
124
|
-
sql_function('extract', sql_operator(Arel
|
132
|
+
sql_function('extract', sql_operator(Arel.sql(part), 'FROM', column))
|
125
133
|
end
|
126
134
|
|
127
135
|
def sql_function(function, *args)
|
@@ -206,11 +214,16 @@ module ActiveScaffold::Actions
|
|
206
214
|
def setup_joins_for_filtered_columns(filtered_columns)
|
207
215
|
if grouped_search? || active_scaffold_config.list.user.count_includes.present?
|
208
216
|
active_scaffold_outer_joins.concat filtered_columns.map(&:search_joins).flatten.uniq.compact
|
217
|
+
active_scaffold_joins << search_group_column.search_joins if grouped_column_needs_joins?(filtered_columns)
|
209
218
|
else
|
210
219
|
set_outer_joins_for_search filtered_columns
|
211
220
|
end
|
212
221
|
end
|
213
222
|
|
223
|
+
def grouped_column_needs_joins?(filtered_columns)
|
224
|
+
grouped_search? && search_group_column&.search_joins.present? && filtered_columns.exclude?(search_group_column)
|
225
|
+
end
|
226
|
+
|
214
227
|
def field_search_formats
|
215
228
|
(default_formats + active_scaffold_config.formats + active_scaffold_config.field_search.formats).uniq
|
216
229
|
end
|
@@ -215,7 +215,10 @@ module ActiveScaffold::Actions
|
|
215
215
|
end
|
216
216
|
|
217
217
|
def quoted_select_columns(columns)
|
218
|
-
columns&.map
|
218
|
+
columns&.map do |col, name|
|
219
|
+
sql_column = active_scaffold_config.columns[col]&.field || col
|
220
|
+
name ? Arel.sql(sql_column).as(name) : sql_column
|
221
|
+
end
|
219
222
|
end
|
220
223
|
|
221
224
|
def do_refresh_list
|
@@ -227,12 +230,12 @@ module ActiveScaffold::Actions
|
|
227
230
|
do_list
|
228
231
|
end
|
229
232
|
|
230
|
-
def each_record_in_page(&
|
231
|
-
page_items.each(&
|
233
|
+
def each_record_in_page(&)
|
234
|
+
page_items.each(&)
|
232
235
|
end
|
233
236
|
|
234
|
-
def each_record_in_scope(&
|
235
|
-
scoped_query.each(&
|
237
|
+
def each_record_in_scope(&)
|
238
|
+
scoped_query.each(&)
|
236
239
|
end
|
237
240
|
|
238
241
|
def page_items
|
@@ -245,6 +248,38 @@ module ActiveScaffold::Actions
|
|
245
248
|
end
|
246
249
|
end
|
247
250
|
|
251
|
+
def filtered_query
|
252
|
+
apply_filters beginning_of_chain
|
253
|
+
end
|
254
|
+
|
255
|
+
def filters_enabled?
|
256
|
+
active_scaffold_config.list.filters.present? && params[:id].nil?
|
257
|
+
end
|
258
|
+
|
259
|
+
def apply_filters(query)
|
260
|
+
return query unless filters_enabled?
|
261
|
+
|
262
|
+
active_scaffold_config.list.refresh_with_header = true
|
263
|
+
|
264
|
+
active_scaffold_config.list.filters.inject(query) do |q, filter|
|
265
|
+
next q unless filter.security_method.nil? || send(filter.security_method)
|
266
|
+
|
267
|
+
default_option = filter[filter.default_option]
|
268
|
+
apply_filter q, params[filter.name] ? filter[params[filter.name]] : default_option, default_option
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def apply_filter(query, filter_option, default_option)
|
273
|
+
return query if filter_option.nil? || (filter_option.security_method_set? && !send(filter_option.security_method))
|
274
|
+
|
275
|
+
@applied_filters ||= []
|
276
|
+
@applied_filters << filter_option unless filter_option == default_option
|
277
|
+
case filter_option.conditions
|
278
|
+
when Proc then instance_exec query, &filter_option.conditions
|
279
|
+
else query.where(filter_option.conditions)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
248
283
|
def scoped_query
|
249
284
|
@scoped_query ||= begin
|
250
285
|
do_search if respond_to? :do_search, true
|
@@ -147,7 +147,7 @@ module ActiveScaffold::Actions::Nested
|
|
147
147
|
security_method: :delete_existing_authorized?,
|
148
148
|
ignore_method: :delete_existing_ignore?)
|
149
149
|
end
|
150
|
-
config.action_links['destroy']
|
150
|
+
config.action_links['destroy']&.ignore_method = :habtm_delete_ignore? if config.actions.include?(:delete)
|
151
151
|
end
|
152
152
|
|
153
153
|
def new_existing
|
@@ -26,7 +26,8 @@ module ActiveScaffold::Actions
|
|
26
26
|
@record = (find_associated_record if params[:associated_id]) ||
|
27
27
|
build_associated(@column.association, @parent_record) do |blank_record|
|
28
28
|
if params[:tabbed_by] && params[:value]
|
29
|
-
|
29
|
+
@tab_id = params.delete(:value)
|
30
|
+
assign_tabbed_by(blank_record, @column, params.delete(:tabbed_by), @tab_id, params.delete(:value_type))
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
@@ -195,13 +195,23 @@ module ActiveScaffold
|
|
195
195
|
manage_nested_record_from_params(parent_record, column, value, avoid_changes)
|
196
196
|
elsif column.association&.collection?
|
197
197
|
# HACK: to be able to delete all associated records, hash will include "0" => ""
|
198
|
-
value.
|
199
|
-
|
198
|
+
value.compact_blank.filter_map do |id, attributes|
|
199
|
+
manage_nested_record_from_params(parent_record, column, attributes, avoid_changes).tap do |record|
|
200
|
+
track_new_record(record, id)
|
201
|
+
end
|
202
|
+
end
|
200
203
|
else
|
201
204
|
value
|
202
205
|
end
|
203
206
|
end
|
204
207
|
|
208
|
+
def track_new_record(record, id)
|
209
|
+
return unless record&.new_record?
|
210
|
+
|
211
|
+
@new_records ||= Hash.new { |h, k| h[k] = {} }
|
212
|
+
@new_records[record.class][id] = record
|
213
|
+
end
|
214
|
+
|
205
215
|
def manage_nested_record_from_params(parent_record, column, attributes, avoid_changes = false)
|
206
216
|
return nil unless build_record_from_params?(attributes, column, parent_record)
|
207
217
|
|
@@ -23,7 +23,7 @@ module ActiveScaffold::Bridges
|
|
23
23
|
# As already has callbacks to ensure authorization at controller method via "authorization_method"
|
24
24
|
# but let's include this too, just in case, no sure how performance is affected tough :TODO benchmark
|
25
25
|
module ClassMethods
|
26
|
-
def active_scaffold(model_id = nil, &
|
26
|
+
def active_scaffold(model_id = nil, &)
|
27
27
|
super
|
28
28
|
authorize_resource(
|
29
29
|
class: active_scaffold_config.model,
|
@@ -3,7 +3,7 @@ module ActiveScaffold::Bridges
|
|
3
3
|
module Helper
|
4
4
|
def filter_action_links_for_deleted(action_links, record, options); end
|
5
5
|
|
6
|
-
def display_action_links(action_links, record, options, &
|
6
|
+
def display_action_links(action_links, record, options, &)
|
7
7
|
if action_name == 'deleted'
|
8
8
|
action_links = filter_action_links_for_deleted(action_links, record, options)
|
9
9
|
return unless action_links
|
@@ -15,7 +15,7 @@ class ActiveScaffold::Bridges::RecordSelect
|
|
15
15
|
if column.association&.singular?
|
16
16
|
multiple = ui_options.dig(:html_options, :multiple)
|
17
17
|
html = active_scaffold_record_select(record, column, options, record.send(column.name), multiple, ui_options: ui_options)
|
18
|
-
html <<
|
18
|
+
html << active_scaffold_add_new(column, record, options, ui_options: ui_options) if ui_options[:add_new]
|
19
19
|
html
|
20
20
|
elsif column.association&.collection?
|
21
21
|
active_scaffold_record_select(record, column, options, record.send(column.name), true, ui_options: ui_options)
|
@@ -197,9 +197,13 @@ module ActiveScaffold::Config
|
|
197
197
|
def _cache_lazy_values
|
198
198
|
action_links.collection # ensure the collection group exist although it's empty
|
199
199
|
action_links.member # ensure the collection group exist although it's empty
|
200
|
-
|
200
|
+
if cache_action_link_urls
|
201
|
+
action_links.each(&:name_to_cache)
|
202
|
+
list.filters.each { |filter| filter.each(&:name_to_cache) } if actions.include?(:list)
|
203
|
+
end
|
201
204
|
columns.select(&:sortable?).each(&:sort)
|
202
205
|
columns.select(&:searchable?).each(&:search_sql)
|
206
|
+
columns.each(&:field)
|
203
207
|
actions.each do |action_name|
|
204
208
|
action = send(action_name)
|
205
209
|
Array(action.class.columns_collections).each { |method| action.send(method) }
|
@@ -7,6 +7,7 @@ module ActiveScaffold::Config
|
|
7
7
|
# inherit from global scope
|
8
8
|
# full configuration path is: defaults => global table => local table
|
9
9
|
@per_page = self.class.per_page
|
10
|
+
@filters = ActiveScaffold::DataStructures::Filters.new
|
10
11
|
@page_links_inner_window = self.class.page_links_inner_window
|
11
12
|
@page_links_outer_window = self.class.page_links_outer_window
|
12
13
|
|
@@ -20,7 +21,10 @@ module ActiveScaffold::Config
|
|
20
21
|
@pagination = self.class.pagination
|
21
22
|
@auto_pagination = self.class.auto_pagination
|
22
23
|
@show_search_reset = self.class.show_search_reset
|
24
|
+
@show_filter_reset = self.class.show_filter_reset
|
25
|
+
@filter_human_message = self.class.filter_human_message
|
23
26
|
@reset_link = self.class.reset_link.clone
|
27
|
+
@reset_filter_link = self.class.reset_filter_link.clone
|
24
28
|
@wrap_tag = self.class.wrap_tag
|
25
29
|
@always_show_search = self.class.always_show_search
|
26
30
|
@always_show_create = self.class.always_show_create
|
@@ -77,10 +81,23 @@ module ActiveScaffold::Config
|
|
77
81
|
cattr_accessor :show_search_reset, instance_accessor: false
|
78
82
|
@@show_search_reset = true
|
79
83
|
|
84
|
+
# show a link to reset the filter next to filter human message
|
85
|
+
cattr_accessor :show_filter_reset, instance_accessor: false
|
86
|
+
@@show_filter_reset = true
|
87
|
+
|
88
|
+
# filter human message
|
89
|
+
# you may show the user a humanized applied filters, not the default ones
|
90
|
+
cattr_accessor :filter_human_message, instance_accessor: false
|
91
|
+
@@filter_human_message = false
|
92
|
+
|
80
93
|
# the ActionLink to reset search
|
81
94
|
cattr_reader :reset_link, instance_reader: false
|
82
95
|
@@reset_link = ActiveScaffold::DataStructures::ActionLink.new('index', label: :click_to_reset, type: :collection, position: false, parameters: {search: ''})
|
83
96
|
|
97
|
+
# the ActionLink to reset the filters
|
98
|
+
cattr_reader :reset_filter_link, instance_reader: false
|
99
|
+
@@reset_filter_link = ActiveScaffold::DataStructures::ActionLink.new('index', label: :click_to_reset, type: :collection, position: false, dynamic_parameters: -> { clear_filters_params })
|
100
|
+
|
84
101
|
# wrap normal cells (not inplace editable columns or with link) with a tag
|
85
102
|
# it allows for more css styling
|
86
103
|
cattr_accessor :wrap_tag, instance_accessor: false
|
@@ -103,6 +120,10 @@ module ActiveScaffold::Config
|
|
103
120
|
cattr_accessor :calculate_etag, instance_accessor: false
|
104
121
|
@@calculate_etag = false
|
105
122
|
|
123
|
+
def self.filters
|
124
|
+
ActiveScaffold::DataStructures::Filters
|
125
|
+
end
|
126
|
+
|
106
127
|
# instance-level configuration
|
107
128
|
# ----------------------------
|
108
129
|
|
@@ -143,9 +164,22 @@ module ActiveScaffold::Config
|
|
143
164
|
# show a link to reset the search next to filtered message
|
144
165
|
attr_accessor :show_search_reset
|
145
166
|
|
167
|
+
# show a link to reset the filter next to filter human message
|
168
|
+
attr_accessor :show_filter_reset
|
169
|
+
|
170
|
+
# filter human message
|
171
|
+
# you may show the user a humanized applied filters, not the default ones
|
172
|
+
attr_accessor :filter_human_message
|
173
|
+
|
146
174
|
# the ActionLink to reset search
|
147
175
|
attr_reader :reset_link
|
148
176
|
|
177
|
+
# the ActionLink to reset the filters
|
178
|
+
attr_reader :reset_filter_link
|
179
|
+
|
180
|
+
# the filters for this controller
|
181
|
+
attr_reader :filters
|
182
|
+
|
149
183
|
# the default sorting.
|
150
184
|
# should be a hash of {column_name => direction}, e.g. {a: 'desc', b: 'asc'}.
|
151
185
|
# for backwards compatibility, it may be an array of hashes of {column_name => direction}, e.g. [{a: 'desc'}, {b: 'asc'}].
|
@@ -229,7 +263,7 @@ module ActiveScaffold::Config
|
|
229
263
|
user_attr :page_links_inner_window, :page_links_outer_window, :refresh_with_header, :empty_field_text,
|
230
264
|
:association_join_text, :messages_above_header, :wrap_tag, :auto_select_columns, :calculate_etag,
|
231
265
|
:no_entries_message, :filtered_message, :show_search_reset, :always_show_create, :always_show_search,
|
232
|
-
:hide_nested_column, :pagination, :auto_pagination
|
266
|
+
:hide_nested_column, :pagination, :auto_pagination, :filter_human_message, :show_filter_reset
|
233
267
|
|
234
268
|
def initialize(conf, storage, params)
|
235
269
|
super(conf, storage, params, :list)
|
@@ -87,7 +87,9 @@ module ActiveScaffold
|
|
87
87
|
# regular column constraints
|
88
88
|
elsif column.searchable? && params[column.name] != v
|
89
89
|
active_scaffold_references.concat column.references if column.includes.present?
|
90
|
-
|
90
|
+
condition = column.search_sql.collect { |search_sql| "#{search_sql} = ?" }.join(' OR ')
|
91
|
+
condition = ([condition] * v.size).join(' OR ') if Array(v).many?
|
92
|
+
conditions << [condition, *(Array(v) * column.search_sql.size)]
|
91
93
|
end
|
92
94
|
# unknown-to-activescaffold-but-real-database-column constraint
|
93
95
|
elsif active_scaffold_config._columns_hash[k.to_s] && params[column.name] != v
|
@@ -101,7 +103,7 @@ module ActiveScaffold
|
|
101
103
|
|
102
104
|
def join_from_association_constraint(column)
|
103
105
|
if column.association.habtm?
|
104
|
-
|
106
|
+
active_scaffold_joins.concat column.includes
|
105
107
|
elsif !column.association.polymorphic?
|
106
108
|
if column.association.belongs_to?
|
107
109
|
active_scaffold_preload.concat column.includes
|
@@ -40,11 +40,11 @@ module ActiveScaffold::DataStructures
|
|
40
40
|
attr_accessor :collapsed
|
41
41
|
|
42
42
|
# nests a subgroup in the column set
|
43
|
-
def add_subgroup(label, &
|
43
|
+
def add_subgroup(label, &)
|
44
44
|
columns = ActiveScaffold::DataStructures::ActionColumns.new
|
45
45
|
columns.label = label
|
46
46
|
columns.action = action
|
47
|
-
columns.configure(&
|
47
|
+
columns.configure(&)
|
48
48
|
exclude columns.collect_columns
|
49
49
|
add columns
|
50
50
|
end
|
@@ -95,10 +95,7 @@ module ActiveScaffold::DataStructures
|
|
95
95
|
attr_accessor :image
|
96
96
|
|
97
97
|
# if the action requires confirmation
|
98
|
-
|
99
|
-
@dhtml_confirm = nil if value
|
100
|
-
@confirm = value
|
101
|
-
end
|
98
|
+
attr_writer :confirm
|
102
99
|
|
103
100
|
def confirm(label = '')
|
104
101
|
return @confirm if !confirm? || @confirm.is_a?(String)
|
@@ -110,16 +107,24 @@ module ActiveScaffold::DataStructures
|
|
110
107
|
@confirm.present?
|
111
108
|
end
|
112
109
|
|
113
|
-
# if the action
|
114
|
-
|
110
|
+
# if the action requires prompting a value, only for inline links
|
111
|
+
attr_writer :prompt
|
112
|
+
|
113
|
+
def prompt(label = '')
|
114
|
+
return @prompt if !prompt? || @prompt.is_a?(String)
|
115
115
|
|
116
|
-
|
117
|
-
@confirm = nil if value
|
118
|
-
@dhtml_confirm = value
|
116
|
+
ActiveScaffold::Registry.cache(:translations, @prompt) { as_(@prompt) } % {label: label}
|
119
117
|
end
|
120
118
|
|
121
|
-
def
|
122
|
-
@
|
119
|
+
def prompt?
|
120
|
+
@prompt.present?
|
121
|
+
end
|
122
|
+
|
123
|
+
# if the prompt is required, empty value or cancel will prevent running the action
|
124
|
+
attr_writer :prompt_required
|
125
|
+
|
126
|
+
def prompt_required?
|
127
|
+
@prompt_required
|
123
128
|
end
|
124
129
|
|
125
130
|
# what method to call on the controller to see if this action_link should be visible
|
@@ -160,9 +160,9 @@ module ActiveScaffold::DataStructures
|
|
160
160
|
end
|
161
161
|
end
|
162
162
|
|
163
|
-
def method_missing(name, *args, &
|
163
|
+
def method_missing(name, *args, &)
|
164
164
|
return super if name.match?(/[=!?]$/)
|
165
|
-
return subgroup(name.to_sym, args.first, &
|
165
|
+
return subgroup(name.to_sym, args.first, &) if frozen?
|
166
166
|
|
167
167
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
168
168
|
def #{name}(label = nil) # def group_name(label = nil)
|
@@ -171,7 +171,7 @@ module ActiveScaffold::DataStructures
|
|
171
171
|
@#{name} # @group_name
|
172
172
|
end # end
|
173
173
|
METHOD
|
174
|
-
send(name, args.first, &
|
174
|
+
send(name, args.first, &)
|
175
175
|
end
|
176
176
|
|
177
177
|
def respond_to_missing?(name, *)
|
@@ -44,6 +44,9 @@ module ActiveScaffold::DataStructures
|
|
44
44
|
# send all the form instead of only new value when this column changes
|
45
45
|
attr_accessor :send_form_on_update_column
|
46
46
|
|
47
|
+
# disable the form while the request to refresh other columns is sent
|
48
|
+
attr_accessor :disable_on_update_column
|
49
|
+
|
47
50
|
# add a custom attr_accessor that can contain a Proc (or boolean or symbol)
|
48
51
|
# that will be called when the column renders, such that we can dynamically
|
49
52
|
# hide or show the column with an element that can be replaced by
|
@@ -57,6 +60,9 @@ module ActiveScaffold::DataStructures
|
|
57
60
|
# config.columns[:my_column].hide_form_column_if = :hide_tractor_fields?
|
58
61
|
attr_accessor :hide_form_column_if
|
59
62
|
|
63
|
+
# text to display when the column is empty, defaults nil, so list.empty_field_text is used
|
64
|
+
attr_accessor :empty_field_text
|
65
|
+
|
60
66
|
# a collection of columns to load from the association when eager loading is disabled, if it's nil all columns will be loaded
|
61
67
|
attr_accessor :select_associated_columns
|
62
68
|
|
@@ -480,6 +486,7 @@ module ActiveScaffold::DataStructures
|
|
480
486
|
if @column.nil? && active_record? && active_record_class._default_attributes.key?(name.to_s)
|
481
487
|
@column = active_record_class._default_attributes[name.to_s]
|
482
488
|
end
|
489
|
+
@disable_on_update_column = true
|
483
490
|
@db_default_value = ActiveScaffold::OrmChecks.default_value active_record_class, name if @column
|
484
491
|
@delegated_association = delegated_association
|
485
492
|
@cache_key = [@active_record_class.name, name].compact.map(&:to_s).join('#')
|
@@ -551,6 +558,20 @@ module ActiveScaffold::DataStructures
|
|
551
558
|
@field ||= quoted_field(field_name)
|
552
559
|
end
|
553
560
|
|
561
|
+
def group_by=(value)
|
562
|
+
@group_by = value ? Array(value) : nil
|
563
|
+
end
|
564
|
+
|
565
|
+
def group_by
|
566
|
+
@group_by || select_columns || [field]
|
567
|
+
end
|
568
|
+
|
569
|
+
attr_writer :grouped_select
|
570
|
+
|
571
|
+
def grouped_select
|
572
|
+
Arel.sql(@grouped_select&.to_s || field)
|
573
|
+
end
|
574
|
+
|
554
575
|
def quoted_foreign_type
|
555
576
|
quoted_field(quoted_field_name(association.foreign_type))
|
556
577
|
end
|