active_scaffold 3.7.0 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +24 -0
  3. data/README.md +2 -0
  4. data/app/assets/javascripts/jquery/active_scaffold.js +68 -62
  5. data/app/assets/stylesheets/active_scaffold_layout.css +1 -1
  6. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +2 -1
  7. data/app/views/active_scaffold_overrides/_render_field.js.erb +9 -6
  8. data/config/locales/de.yml +6 -3
  9. data/config/locales/en.yml +3 -0
  10. data/config/locales/es.yml +3 -0
  11. data/config/locales/fr.yml +9 -6
  12. data/config/locales/hu.yml +20 -17
  13. data/config/locales/ja.yml +25 -22
  14. data/config/locales/ru.yml +17 -14
  15. data/lib/active_scaffold/actions/update.rb +3 -3
  16. data/lib/active_scaffold/attribute_params.rb +7 -17
  17. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +6 -6
  18. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +7 -7
  19. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +2 -2
  20. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +12 -14
  21. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +2 -2
  22. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +1 -1
  23. data/lib/active_scaffold/bridges/chosen/helpers.rb +10 -10
  24. data/lib/active_scaffold/bridges/country_select/country_select_bridge_helper.rb +7 -7
  25. data/lib/active_scaffold/bridges/date_picker/ext.rb +20 -9
  26. data/lib/active_scaffold/bridges/date_picker/helper.rb +5 -5
  27. data/lib/active_scaffold/bridges/date_picker.rb +2 -0
  28. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +3 -3
  29. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +5 -5
  30. data/lib/active_scaffold/bridges/file_column/form_ui.rb +1 -1
  31. data/lib/active_scaffold/bridges/file_column/list_ui.rb +3 -3
  32. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +1 -1
  33. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +3 -3
  34. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  35. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -15
  36. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +6 -6
  37. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +5 -5
  38. data/lib/active_scaffold/bridges.rb +0 -3
  39. data/lib/active_scaffold/constraints.rb +22 -7
  40. data/lib/active_scaffold/core.rb +5 -3
  41. data/lib/active_scaffold/data_structures/column.rb +108 -23
  42. data/lib/active_scaffold/engine.rb +19 -1
  43. data/lib/active_scaffold/extensions/routing_mapper.rb +1 -0
  44. data/lib/active_scaffold/finder.rb +142 -27
  45. data/lib/active_scaffold/helpers/controller_helpers.rb +9 -4
  46. data/lib/active_scaffold/helpers/form_column_helpers.rb +114 -94
  47. data/lib/active_scaffold/helpers/human_condition_helpers.rb +48 -14
  48. data/lib/active_scaffold/helpers/list_column_helpers.rb +34 -18
  49. data/lib/active_scaffold/helpers/search_column_helpers.rb +131 -55
  50. data/lib/active_scaffold/helpers/show_column_helpers.rb +6 -6
  51. data/lib/active_scaffold/orm_checks.rb +21 -1
  52. data/lib/active_scaffold/version.rb +1 -1
  53. data/lib/active_scaffold.rb +4 -2
  54. data/test/bridges/date_picker_test.rb +3 -2
  55. data/test/bridges/paperclip_test.rb +3 -2
  56. data/test/bridges/tiny_mce_test.rb +4 -2
  57. data/test/helpers/form_column_helpers_test.rb +7 -5
  58. data/test/helpers/search_column_helpers_test.rb +2 -1
  59. data/test/misc/constraints_test.rb +1 -0
  60. data/test/misc/finder_test.rb +38 -0
  61. metadata +2 -6
  62. data/config/brakeman.ignore +0 -26
  63. data/config/brakeman.yml +0 -3
  64. data/config/i18n-tasks.yml +0 -121
  65. data/lib/active_scaffold/bridges/shared/date_bridge.rb +0 -221
@@ -5,8 +5,13 @@ module ActiveScaffold
5
5
  def get_column_value(record, column)
6
6
  record = record.send(column.delegated_association.name) if column.delegated_association
7
7
  if record
8
- method = get_column_method(record, column)
9
- value = send(method, record, column)
8
+ method, list_ui = get_column_method(record, column)
9
+ value =
10
+ if list_ui
11
+ send(method, record, column, ui_options: column.list_ui_options || column.options)
12
+ else
13
+ send(method, record, column)
14
+ end
10
15
  else
11
16
  value = nil
12
17
  end
@@ -27,8 +32,8 @@ module ActiveScaffold
27
32
  method
28
33
  # second, check if the dev has specified a valid list_ui for this column
29
34
  elsif column.list_ui && (method = override_column_ui(column.list_ui))
30
- method
31
- elsif column.column && (method = override_column_ui(column.column.type))
35
+ [method, true]
36
+ elsif column.column && (method = override_column_ui(column.column_type))
32
37
  method
33
38
  else
34
39
  :format_column_value
@@ -76,39 +81,49 @@ module ActiveScaffold
76
81
  ##
77
82
  ## Overrides
78
83
  ##
79
- def active_scaffold_column_text(record, column)
84
+ def active_scaffold_column_text(record, column, ui_options: column.options)
80
85
  # `to_s` is necessary to convert objects in serialized columns to string before truncation.
81
- clean_column_value(truncate(record.send(column.name).to_s, :length => column.options[:truncate] || 50))
86
+ clean_column_value(truncate(record.send(column.name).to_s, length: ui_options[:truncate] || 50))
82
87
  end
83
88
 
84
- def active_scaffold_column_fulltext(record, column)
89
+ def active_scaffold_column_fulltext(record, column, ui_options: column.options)
85
90
  clean_column_value(record.send(column.name))
86
91
  end
87
92
 
88
- def active_scaffold_column_marked(record, column)
93
+ def active_scaffold_column_marked(record, column, ui_options: column.options)
89
94
  options = {:id => nil, :object => record}
90
95
  content_tag(:span, check_box(:record, column.name, options), :class => 'in_place_editor_field', :data => {:ie_id => record.to_param})
91
96
  end
92
97
 
93
- def active_scaffold_column_checkbox(record, column)
98
+ def active_scaffold_column_checkbox(record, column, ui_options: column.options)
94
99
  options = {:disabled => true, :id => nil, :object => record}
95
100
  options.delete(:disabled) if inplace_edit?(record, column)
96
101
  check_box(:record, column.name, options)
97
102
  end
98
103
 
99
- def active_scaffold_column_percentage(record, column)
100
- options = column.options[:slider] || {}
104
+ def active_scaffold_column_boolean(record, column, ui_options: column.options)
105
+ value = record.send(column.name)
106
+ if value.nil? && ui_options[:include_blank]
107
+ value = ui_options[:include_blank]
108
+ value.is_a?(Symbol) ? as_(value) : value
109
+ else
110
+ format_column_value(record, column, value)
111
+ end
112
+ end
113
+
114
+ def active_scaffold_column_percentage(record, column, ui_options: column.options)
115
+ options = ui_options[:slider] || {}
101
116
  options = options.merge(min: record.send(options[:min_method])) if options[:min_method]
102
117
  options = options.merge(max: record.send(options[:max_method])) if options[:max_method]
103
118
  value = record.send(options[:value_method]) if options[:value_method]
104
119
  as_slider options.merge(value: value || record.send(column.name))
105
120
  end
106
121
 
107
- def active_scaffold_column_month(record, column)
122
+ def active_scaffold_column_month(record, column, ui_options: column.options)
108
123
  l record.send(column.name), format: :year_month
109
124
  end
110
125
 
111
- def active_scaffold_column_week(record, column)
126
+ def active_scaffold_column_week(record, column, ui_options: column.options)
112
127
  l record.send(column.name), format: :week
113
128
  end
114
129
 
@@ -119,10 +134,10 @@ module ActiveScaffold
119
134
  link_to text, "tel:#{[groups.join('-'), extension].compact.join(',')}"
120
135
  end
121
136
 
122
- def active_scaffold_column_telephone(record, column)
137
+ def active_scaffold_column_telephone(record, column, ui_options: column.options)
123
138
  phone = record.send column.name
124
139
  return if phone.blank?
125
- phone = number_to_phone(phone) unless column.options[:format] == false
140
+ phone = number_to_phone(phone) unless ui_options[:format] == false
126
141
  tel_to phone
127
142
  end
128
143
 
@@ -147,8 +162,9 @@ module ActiveScaffold
147
162
  def format_column_value(record, column, value = nil)
148
163
  value ||= record.send(column.name) unless record.nil?
149
164
  if column.association.nil?
150
- if FORM_UI_WITH_OPTIONS.include?(column.form_ui) && column.options[:options]
151
- text, val = column.options[:options].find { |t, v| (v.nil? ? t : v).to_s == value.to_s }
165
+ form_ui_options = column.form_ui_options || column.options if FORM_UI_WITH_OPTIONS.include?(column.form_ui)
166
+ if form_ui_options&.dig(:options)
167
+ text, val = form_ui_options[:options].find { |t, v| (v.nil? ? t : v).to_s == value.to_s }
152
168
  value = active_scaffold_translated_option(column, text, val).first if text
153
169
  end
154
170
  if grouped_search? && column == search_group_column && search_group_function
@@ -303,7 +319,7 @@ module ActiveScaffold
303
319
  end
304
320
 
305
321
  def inplace_edit_cloning?(column)
306
- column.inplace_edit != :ajax && (override_form_field?(column) || column.form_ui || (column.column && override_input?(column.column.type)))
322
+ column.inplace_edit != :ajax && (override_form_field?(column) || column.form_ui || (column.column && override_input?(column.column_type)))
307
323
  end
308
324
 
309
325
  def active_scaffold_inplace_edit_tag_options(record, column)
@@ -20,11 +20,11 @@ module ActiveScaffold
20
20
 
21
21
  # second, check if the dev has specified a valid search_ui for this column, using specific ui for searches
22
22
  elsif column.search_ui && (method = override_search(column.search_ui))
23
- send(method, column, options)
23
+ send(method, column, options, ui_options: column.search_ui_options || column.options)
24
24
 
25
25
  # third, check if the dev has specified a valid search_ui for this column, using generic ui for forms
26
26
  elsif column.search_ui && (method = override_input(column.search_ui))
27
- send(method, column, options)
27
+ send(method, column, options, ui_options: column.search_ui_options || column.options)
28
28
 
29
29
  # fourth, check if the dev has created an override for this specific field
30
30
  elsif (method = override_form_field(column))
@@ -34,11 +34,11 @@ module ActiveScaffold
34
34
  elsif column.association || column.virtual?
35
35
  active_scaffold_search_text(column, options)
36
36
 
37
- elsif (method = override_search(column.column.type))
37
+ elsif (method = override_search(column.column_type))
38
38
  # if we (or someone else) have created a custom render option for the column type, use that
39
39
  send(method, column, options)
40
40
 
41
- elsif (method = override_input(column.column.type))
41
+ elsif (method = override_input(column.column_type))
42
42
  # if we (or someone else) have created a custom render option for the column type, use that
43
43
  send(method, column, options)
44
44
 
@@ -73,28 +73,28 @@ module ActiveScaffold
73
73
  ## Search input methods
74
74
  ##
75
75
 
76
- def active_scaffold_search_multi_select(column, options)
76
+ def active_scaffold_search_multi_select(column, options, ui_options: column.options)
77
77
  record = options.delete(:object)
78
78
  associated = options.delete :value
79
79
  associated = [associated].compact unless associated.is_a? Array
80
80
 
81
81
  if column.association
82
82
  associated.collect!(&:to_i)
83
- method = column.options[:label_method] || :to_label
83
+ method = ui_options[:label_method] || :to_label
84
84
  select_options = sorted_association_options_find(column.association, nil, record).collect do |r|
85
85
  [r.send(method), r.id]
86
86
  end
87
87
  else
88
- select_options = column.options[:options].collect do |text, value|
88
+ select_options = active_scaffold_enum_options(column, record, ui_options: ui_options).collect do |text, value|
89
89
  active_scaffold_translated_option(column, text, value)
90
90
  end
91
91
  end
92
92
  return as_(:no_options) if select_options.empty?
93
93
 
94
- active_scaffold_checkbox_list(column, select_options, associated, options)
94
+ active_scaffold_checkbox_list(column, select_options, associated, options, ui_options: ui_options)
95
95
  end
96
96
 
97
- def active_scaffold_search_select(column, html_options, options = {})
97
+ def active_scaffold_search_select(column, html_options, options = {}, ui_options: column.options)
98
98
  record = html_options.delete(:object)
99
99
  associated = html_options.delete :value
100
100
  if column.association
@@ -103,13 +103,13 @@ module ActiveScaffold
103
103
  select_options = sorted_association_options_find(column.association, false, record)
104
104
  else
105
105
  method = column.name
106
- select_options = active_scaffold_enum_options(column, record).collect do |text, value|
106
+ select_options = active_scaffold_enum_options(column, record, ui_options: ui_options).collect do |text, value|
107
107
  active_scaffold_translated_option(column, text, value)
108
108
  end
109
109
  end
110
110
 
111
- options = options.merge(:selected => associated).merge column.options
112
- html_options.merge! column.options[:html_options] || {}
111
+ options = options.merge(selected: associated).merge ui_options
112
+ html_options.merge! ui_options[:html_options] || {}
113
113
  if html_options[:multiple]
114
114
  active_scaffold_select_name_with_multiple html_options
115
115
  else
@@ -120,23 +120,31 @@ module ActiveScaffold
120
120
  if (optgroup = options.delete(:optgroup))
121
121
  select(:record, method, active_scaffold_grouped_options(column, select_options, optgroup), options, html_options)
122
122
  elsif column.association
123
- collection_select(:record, method, select_options, :id, column.options[:label_method] || :to_label, options, html_options)
123
+ collection_select(:record, method, select_options, :id, ui_options[:label_method] || :to_label, options, html_options)
124
124
  else
125
125
  select(:record, method, select_options, options, html_options)
126
126
  end
127
127
  end
128
128
 
129
- def active_scaffold_search_text(column, options)
129
+ def active_scaffold_search_select_multiple(column, options, ui_options: column.options)
130
+ active_scaffold_search_select(column, options.merge(multiple: true), ui_options: ui_options)
131
+ end
132
+
133
+ def active_scaffold_search_draggable(column, options, ui_options: column.options)
134
+ active_scaffold_search_multi_select(column, options.merge(draggable_lists: true), ui_options: ui_options)
135
+ end
136
+
137
+ def active_scaffold_search_text(column, options, ui_options: column.options)
130
138
  text_field :record, column.name, active_scaffold_input_text_options(options)
131
139
  end
132
140
 
133
141
  # we can't use active_scaffold_input_boolean because we need to have a nil value even when column can't be null
134
142
  # to decide whether search for this field or not
135
- def active_scaffold_search_boolean(column, options)
143
+ def active_scaffold_search_boolean(column, options, ui_options: column.options)
136
144
  select_options = []
137
145
  select_options << [as_(:_select_), nil]
138
- if column.column&.null
139
- null_label = column.options[:include_blank] || :null
146
+ if column.null?
147
+ null_label = ui_options[:include_blank] || :null
140
148
  null_label = as_(null_label) if null_label.is_a?(Symbol)
141
149
  select_options << [null_label, 'null']
142
150
  end
@@ -168,7 +176,7 @@ module ActiveScaffold
168
176
  end
169
177
  end
170
178
 
171
- def active_scaffold_search_null(column, options)
179
+ def active_scaffold_search_null(column, options, ui_options: column.options)
172
180
  select_options = []
173
181
  select_options << [as_(:_select_), nil]
174
182
  select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
@@ -185,38 +193,38 @@ module ActiveScaffold
185
193
  column.text? || column.search_ui == :string
186
194
  end
187
195
 
188
- def active_scaffold_search_range_comparator_options(column)
196
+ def active_scaffold_search_range_comparator_options(column, ui_options: column.options)
189
197
  select_options = ActiveScaffold::Finder::NUMERIC_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] }
190
198
  if active_scaffold_search_range_string?(column)
191
199
  comparators = ActiveScaffold::Finder::STRING_COMPARATORS.collect { |title, comp| [as_(title), comp] }
192
200
  select_options.unshift(*comparators)
193
201
  end
194
- if include_null_comparators? column
202
+ if include_null_comparators? column, ui_options: ui_options
195
203
  select_options.concat(ActiveScaffold::Finder::NULL_COMPARATORS.collect { |comp| [as_(comp), comp] })
196
204
  end
197
205
  select_options
198
206
  end
199
207
 
200
- def include_null_comparators?(column)
201
- return column.options[:null_comparators] if column.options.key? :null_comparators
208
+ def include_null_comparators?(column, ui_options: column.options)
209
+ return ui_options[:null_comparators] if ui_options.key? :null_comparators
202
210
  if column.association
203
- !column.association.belongs_to? || active_scaffold_config.columns[column.association.foreign_key].column&.null
211
+ !column.association.belongs_to? || active_scaffold_config.columns[column.association.foreign_key].null?
204
212
  else
205
- column.column&.null
213
+ column.null?
206
214
  end
207
215
  end
208
216
 
209
- def active_scaffold_search_range(column, options, input_method = :text_field_tag, input_options = {})
217
+ def active_scaffold_search_range(column, options, input_method = :text_field_tag, input_options = {}, ui_options: column.options)
210
218
  opt_value, from_value, to_value = field_search_params_range_values(column)
211
219
 
212
- select_options = active_scaffold_search_range_comparator_options(column)
220
+ select_options = active_scaffold_search_range_comparator_options(column, ui_options: ui_options)
213
221
  text_field_size = active_scaffold_search_range_string?(column) ? 15 : 10
214
222
  opt_value ||= select_options[0][1]
215
223
 
216
224
  from_value = controller.class.condition_value_for_numeric(column, from_value)
217
225
  to_value = controller.class.condition_value_for_numeric(column, to_value)
218
- from_value = format_number_value(from_value, column.options) if from_value.is_a?(Numeric)
219
- to_value = format_number_value(to_value, column.options) if to_value.is_a?(Numeric)
226
+ from_value = format_number_value(from_value, ui_options) if from_value.is_a?(Numeric)
227
+ to_value = format_number_value(to_value, ui_options) if to_value.is_a?(Numeric)
220
228
  html = select_tag("#{options[:name]}[opt]", options_for_select(select_options, opt_value),
221
229
  :id => "#{options[:id]}_opt", :class => 'as_search_range_option')
222
230
  from_options = active_scaffold_input_text_options(input_options.merge(:id => options[:id], :size => text_field_size))
@@ -233,51 +241,119 @@ module ActiveScaffold
233
241
  end
234
242
  alias active_scaffold_search_string active_scaffold_search_range
235
243
 
236
- def active_scaffold_search_integer(column, options)
237
- active_scaffold_search_range(column, options, :number_field_tag, step: '1')
244
+ def active_scaffold_search_integer(column, options, ui_options: column.options)
245
+ active_scaffold_search_range(column, options, :number_field_tag, {step: '1'}, ui_options: ui_options) # rubocop:disable Style/BracesAroundHashParameters
238
246
  end
239
247
 
240
- def active_scaffold_search_decimal(column, options)
241
- active_scaffold_search_range(column, options, :number_field_tag, step: :any)
248
+ def active_scaffold_search_decimal(column, options, ui_options: column.options)
249
+ active_scaffold_search_range(column, options, :number_field_tag, {step: :any}, ui_options: ui_options) # rubocop:disable Style/BracesAroundHashParameters
242
250
  end
243
251
  alias active_scaffold_search_float active_scaffold_search_decimal
244
252
 
253
+ def active_scaffold_search_datetime(column, options, ui_options: column.options, field_ui: column.search_ui || :datetime)
254
+ current_search = {'from' => nil, 'to' => nil, 'opt' => 'BETWEEN',
255
+ 'number' => 1, 'unit' => 'DAYS', 'range' => nil}
256
+ current_search.merge!(options[:value]) unless options[:value].nil?
257
+ tags = [
258
+ active_scaffold_search_datetime_comparator_tag(column, options, current_search),
259
+ active_scaffold_search_datetime_trend_tag(column, options, current_search),
260
+ active_scaffold_search_datetime_numeric_tag(column, options, current_search, ui_options: ui_options, field_ui: field_ui),
261
+ active_scaffold_search_datetime_range_tag(column, options, current_search)
262
+ ]
263
+ safe_join tags, '&nbsp;'.html_safe # rubocop:disable Rails/OutputSafety
264
+ end
265
+
266
+ def active_scaffold_search_timestamp(column, options, ui_options: column.options)
267
+ active_scaffold_search_datetime(column, options, ui_options: ui_options, field_ui: :datetime)
268
+ end
269
+
270
+ def active_scaffold_search_time(column, options, ui_options: column.options)
271
+ active_scaffold_search_datetime(column, options, ui_options: ui_options, field_ui: :time)
272
+ end
273
+
274
+ def active_scaffold_search_date(column, options, ui_options: column.options)
275
+ active_scaffold_search_datetime(column, options, ui_options: ui_options, field_ui: :date)
276
+ end
277
+
278
+ def active_scaffold_search_datetime_comparator_options(column)
279
+ select_options = ActiveScaffold::Finder::DATE_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] }
280
+ select_options + ActiveScaffold::Finder::NUMERIC_COMPARATORS.collect { |comp| [as_(comp.downcase.to_sym), comp] }
281
+ end
282
+
283
+ def active_scaffold_search_datetime_comparator_tag(column, options, current_search)
284
+ choices = options_for_select(active_scaffold_search_datetime_comparator_options(column), current_search['opt'])
285
+ select_tag("#{options[:name]}[opt]", choices, id: "#{options[:id]}_opt", class: 'as_search_range_option as_search_date_time_option')
286
+ end
287
+
288
+ def active_scaffold_search_datetime_numeric_tag(column, options, current_search, ui_options: column.options, field_ui: column.search_ui)
289
+ helper = "active_scaffold_search_#{field_ui}_field"
290
+ numeric_controls = [
291
+ send(helper, column, options, current_search, 'from', ui_options: ui_options),
292
+ content_tag(:span, id: "#{options[:id]}_between", class: 'as_search_range_between',
293
+ style: ('display: none' unless current_search['opt'] == 'BETWEEN')) do
294
+ safe_join([' - ', send(helper, column, options, current_search, 'to', ui_options: ui_options)])
295
+ end
296
+ ]
297
+ content_tag('span', safe_join(numeric_controls),
298
+ :id => "#{options[:id]}_numeric", :class => 'search-date-numeric',
299
+ :style => ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(current_search['opt']) ? nil : 'display: none')
300
+ end
301
+
302
+ def active_scaffold_search_datetime_trend_tag(column, options, current_search)
303
+ trend_controls = [
304
+ text_field_tag("#{options[:name]}[number]", current_search['number'], class: 'text-input', size: 10, autocomplete: 'off'),
305
+ select_tag("#{options[:name]}[unit]",
306
+ options_for_select(active_scaffold_search_datetime_trend_units(column), current_search['unit']),
307
+ class: 'text-input')
308
+ ]
309
+ content_tag('span', safe_join(trend_controls, ' '),
310
+ id: "#{options[:id]}_trend", class: 'search-date-trend',
311
+ style: ('display: none' unless current_search['opt'] == 'PAST' || current_search['opt'] == 'FUTURE'))
312
+ end
313
+
314
+ def active_scaffold_search_datetime_trend_units(column)
315
+ options = ActiveScaffold::Finder::DATE_UNITS.collect { |unit| [as_(unit.downcase.to_sym), unit] }
316
+ options = ActiveScaffold::Finder::TIME_UNITS.collect { |unit| [as_(unit.downcase.to_sym), unit] } + options if column_datetime?(column)
317
+ options
318
+ end
319
+
320
+ def active_scaffold_search_datetime_range_tag(column, options, current_search)
321
+ values = ActiveScaffold::Finder::DATE_RANGES.collect { |range| [as_(range.downcase.to_sym), range] }
322
+ range_controls = select_tag("#{options[:name]}[range]",
323
+ options_for_select(values, current_search['range']),
324
+ class: 'text-input', id: nil)
325
+ content_tag('span', range_controls,
326
+ id: "#{options[:id]}_range", class: 'search-date-range',
327
+ style: ('display: none' unless current_search['opt'] == 'RANGE'))
328
+ end
329
+
330
+ def column_datetime?(column)
331
+ (!column.column.nil? && %i[datetime time].include?(column.column_type))
332
+ end
333
+
245
334
  def field_search_datetime_value(value)
246
335
  Time.zone.local(value[:year].to_i, value[:month].to_i, value[:day].to_i, value[:hour].to_i, value[:minute].to_i, value[:second].to_i) unless value.nil? || value[:year].blank?
247
336
  end
248
337
 
249
- def active_scaffold_search_datetime(column, options)
250
- _, from_value, to_value = field_search_params_range_values(column)
251
- options = column.options.merge(options)
338
+ def active_scaffold_search_datetime_field(column, options, current_search, name, ui_options: column.options)
339
+ options = ui_options.merge(options)
252
340
  type = "#{'date' unless options[:discard_date]}#{'time' unless options[:discard_time]}"
253
- use_select = options.delete(:use_select)
254
- from_name = "#{options[:name]}[from]"
255
- to_name = "#{options[:name]}[to]"
256
- if use_select
257
- helper = "select_#{type}"
258
- fields = [
259
- send(helper, field_search_datetime_value(from_value), options.reverse_merge(include_blank: true, prefix: from_name)),
260
- send(helper, field_search_datetime_value(to_value), options.reverse_merge(include_blank: true, prefix: to_name))
261
- ]
341
+ field_name = "#{options[:name]}[#{name}]"
342
+ if options[:use_select]
343
+ send("select_#{type}", current_search[name], options.reverse_merge(include_blank: true, prefix: field_name))
262
344
  else
263
345
  helper = "#{type}#{'_local' if type == 'datetime'}_field_tag"
264
- fields = [
265
- send(helper, from_name, field_search_datetime_value(from_value), options.except(:name, :object).merge(id: "#{options[:id]}_from")),
266
- send(helper, to_name, field_search_datetime_value(to_value), options.except(:name, :object).merge(id: "#{options[:id]}_to"))
267
- ]
346
+ send(helper, field_name, current_search[name], options.except(:name, :object, :use_select).merge(id: "#{options[:id]}_#{name}"))
268
347
  end
269
-
270
- safe_join fields, ' - '
271
348
  end
272
349
 
273
- def active_scaffold_search_date(column, options)
274
- active_scaffold_search_datetime(column, options.merge!(:discard_time => true))
350
+ def active_scaffold_search_date_field(column, options, current_search, name, ui_options: column.options)
351
+ active_scaffold_search_datetime_field(column, options.merge!(:discard_time => true), current_search, name, ui_options: ui_options)
275
352
  end
276
353
 
277
- def active_scaffold_search_time(column, options)
278
- active_scaffold_search_datetime(column, options.merge!(:discard_date => true))
354
+ def active_scaffold_search_time_field(column, options, current_search, name, ui_options: column.options)
355
+ active_scaffold_search_datetime_field(column, options.merge!(:discard_date => true), current_search, name, ui_options: ui_options)
279
356
  end
280
- alias active_scaffold_search_timestamp active_scaffold_search_datetime
281
357
 
282
358
  ##
283
359
  ## Search column override signatures
@@ -13,24 +13,24 @@ module ActiveScaffold
13
13
  send(method, value_record, column)
14
14
  # second, check if the dev has specified a valid list_ui for this column
15
15
  elsif column.show_ui && (method = override_show_column_ui(column.show_ui))
16
- send(method, value_record, column)
17
- elsif column.column && (method = override_show_column_ui(column.column.type))
16
+ send(method, value_record, column, ui_options: column.show_ui_options || column.options)
17
+ elsif column.column && (method = override_show_column_ui(column.column_type))
18
18
  send(method, value_record, column)
19
19
  else
20
20
  get_column_value(record, column)
21
21
  end
22
22
  end
23
23
 
24
- def active_scaffold_show_text(record, column)
25
- simple_format(clean_column_value(record.send(column.name)))
24
+ def active_scaffold_show_text(record, column, ui_options: column.options)
25
+ simple_format(clean_column_value(record.send(column.name)), ui_options[:html_options], ui_options)
26
26
  end
27
27
 
28
- def active_scaffold_show_horizontal(record, column)
28
+ def active_scaffold_show_horizontal(record, column, ui_options: column.options)
29
29
  raise ':horizontal show_ui must be used on association column' unless column.association
30
30
  render :partial => 'show_association', :locals => {:column => column, :parent_record => record, :show_partial => :horizontal}
31
31
  end
32
32
 
33
- def active_scaffold_show_vertical(record, column)
33
+ def active_scaffold_show_vertical(record, column, ui_options: column.options)
34
34
  raise ':vertical show_ui must be used on association column' unless column.association
35
35
  render :partial => 'show_association', :locals => {:column => column, :parent_record => record, :show_partial => :vertical}
36
36
  end
@@ -82,6 +82,22 @@ module ActiveScaffold
82
82
  type_for_attribute(klass, column_name)
83
83
  end
84
84
  end
85
+
86
+ def default_value(klass, column_name)
87
+ if ActiveScaffold::OrmChecks.mongoid? klass
88
+ columns_hash(klass)[column_name]&.default_val
89
+ elsif ActiveScaffold::OrmChecks.active_record? klass
90
+ klass._default_attributes[column_name]&.value
91
+ end
92
+ end
93
+
94
+ def cast(klass, column_name, value)
95
+ if active_record? klass
96
+ type_for_attribute(klass, column_name).cast value
97
+ elsif mongoid? klass
98
+ type_for_attribute(klass, column_name)&.evolve value
99
+ end
100
+ end
85
101
  end
86
102
 
87
103
  %i[active_record? mongoid? tableless?].each do |method|
@@ -96,10 +112,14 @@ module ActiveScaffold
96
112
  end
97
113
  end
98
114
 
99
- %i[type_for_attribute column_type].each do |method|
115
+ %i[type_for_attribute column_type default_value].each do |method|
100
116
  define_method method do |column_name|
101
117
  ActiveScaffold::OrmChecks.send method, active_record_class, column_name
102
118
  end
103
119
  end
120
+
121
+ def cast(column_name, value)
122
+ ActiveScaffold::OrmChecks.cast active_record_class, column_name, value
123
+ end
104
124
  end
105
125
  end
@@ -2,7 +2,7 @@ module ActiveScaffold
2
2
  module Version
3
3
  MAJOR = 3
4
4
  MINOR = 7
5
- PATCH = 0
5
+ PATCH = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
8
  end
@@ -3,6 +3,7 @@ module ActiveScaffold
3
3
  autoload :AttributeParams, 'active_scaffold/attribute_params'
4
4
  autoload :Bridges, 'active_scaffold/bridges'
5
5
  autoload :Configurable, 'active_scaffold/configurable'
6
+ autoload :ConnectionAdapters, 'active_scaffold/extensions/connection_adapter.rb'
6
7
  autoload :Constraints, 'active_scaffold/constraints'
7
8
  autoload :Core, 'active_scaffold/core'
8
9
  autoload :Finder, 'active_scaffold/finder'
@@ -10,6 +11,7 @@ module ActiveScaffold
10
11
  autoload :OrmChecks, 'active_scaffold/orm_checks'
11
12
  autoload :Registry, 'active_scaffold/registry'
12
13
  autoload :RespondsToParent, 'active_scaffold/responds_to_parent'
14
+ autoload :Routing, 'active_scaffold/extensions/routing_mapper'
13
15
  autoload :Tableless, 'active_scaffold/tableless'
14
16
  autoload :Version, 'active_scaffold/version'
15
17
 
@@ -78,6 +80,8 @@ module ActiveScaffold
78
80
  @@exclude_bridges ||= []
79
81
  end
80
82
 
83
+ mattr_accessor :nested_subforms, instance_writer: false
84
+
81
85
  def self.root
82
86
  File.dirname(__FILE__) + '/..'
83
87
  end
@@ -90,5 +94,3 @@ require 'active_scaffold/engine'
90
94
  require 'ice_nine'
91
95
  require 'ice_nine/core_ext/object'
92
96
  require 'request_store'
93
- # TODO: clean up extensions. some could be organized for autoloading, and others could be removed entirely.
94
- Dir["#{File.dirname __FILE__}/active_scaffold/extensions/*.rb"].each { |file| require file }
@@ -24,7 +24,8 @@ class DatePickerTest < ActionView::TestCase
24
24
  def test_form_ui
25
25
  config = ActiveScaffold::Config::Core.new(:company)
26
26
  @record = Company.new
27
- assert active_scaffold_input_date_picker(config.columns[:date], :name => 'record[date]', :id => 'record_date', :object => @record)
28
- assert active_scaffold_input_date_picker(config.columns[:datetime], :name => 'record[datetime]', :id => 'record_datetime', :object => @record)
27
+ opts = {object: @record}
28
+ assert active_scaffold_input_date_picker(config.columns[:date], opts.merge(id: 'record_date', name: 'record[date]'))
29
+ assert active_scaffold_input_date_picker(config.columns[:datetime], opts.merge(id: 'record_date', name: 'record[datetime]'))
29
30
  end
30
31
  end
@@ -58,11 +58,12 @@ class PaperclipTest < ActionView::TestCase
58
58
  with_js_framework :jquery do
59
59
  config = PaperclipCore.new(:company)
60
60
  @record = Company.new
61
+ opts = {name: 'record[logo]', id: 'record_logo', object: @record}
61
62
 
62
63
  @record.stubs(:logo).returns(stub(:file? => true, :original_filename => 'file', :url => '/system/file', :styles => Company.attachment_definitions[:logo]))
63
64
  click_js = "jQuery(this).prev().val('true'); jQuery(this).parent().hide().next().show(); return false;"
64
65
  change_js = "jQuery(this).parents('div.paperclip_controls').find('input.remove_file').val('false'); return false;"
65
- @document = Nokogiri::HTML::Document.parse(active_scaffold_input_paperclip(config.columns[:logo], :name => 'record[logo]', :id => 'record_logo', :object => @record))
66
+ @document = Nokogiri::HTML::Document.parse(active_scaffold_input_paperclip(config.columns[:logo], opts))
66
67
  assert_select 'div.paperclip_controls input[type=file]' do |match|
67
68
  assert_equal match[0]['onchange'], change_js
68
69
  end
@@ -72,7 +73,7 @@ class PaperclipTest < ActionView::TestCase
72
73
  assert_select 'div.paperclip_controls input.remove_file[type=hidden][value=false]'
73
74
 
74
75
  @record.stubs(:logo).returns(stub(:file? => false))
75
- assert_dom_equal '<input name="record[logo]" class="text-input" autocomplete="off" type="file" id="record_logo" />', active_scaffold_input_paperclip(config.columns[:logo], :name => 'record[logo]', :id => 'record_logo', :object => @record)
76
+ assert_dom_equal '<input name="record[logo]" class="text-input" autocomplete="off" type="file" id="record_logo" />', active_scaffold_input_paperclip(config.columns[:logo], opts)
76
77
  end
77
78
  end
78
79
 
@@ -35,16 +35,18 @@ class TinyMceTest < ActionView::TestCase
35
35
  def test_form_ui
36
36
  config = ActiveScaffold::Config::Core.new(:company)
37
37
  record = Company.new
38
+ opts = {name: 'record[name]', id: 'record_name', class: 'name-input', object: record}
38
39
 
39
- assert_dom_equal %(<textarea name=\"record[name]\" class=\"name-input mceEditor\" id=\"record_name\" data-tinymce=\"{&quot;theme&quot;:&quot;modern&quot;}\">\n</textarea>), active_scaffold_input_text_editor(config.columns[:name], :name => 'record[name]', :id => 'record_name', :class => 'name-input', :object => record)
40
+ assert_dom_equal %(<textarea name=\"record[name]\" class=\"name-input mceEditor\" id=\"record_name\" data-tinymce=\"{&quot;theme&quot;:&quot;modern&quot;}\">\n</textarea>), active_scaffold_input_text_editor(config.columns[:name], opts)
40
41
  end
41
42
 
42
43
  def test_form_ui_alternate
43
44
  config = ActiveScaffold::Config::Core.new(:company)
44
45
  record = Company.new
45
46
  config.columns[:name].options[:tinymce_config] = :alternate
47
+ opts = {name: 'record[name]', id: 'record_name', class: 'name-input', object: record}
46
48
 
47
- assert_dom_equal %(<textarea name=\"record[name]\" class=\"name-input mceEditor\" id=\"record_name\" data-tinymce=\"{&quot;theme&quot;:&quot;alternate&quot;,&quot;toolbar&quot;:&quot;undo redo | format&quot;}\">\n</textarea>), active_scaffold_input_tinymce(config.columns[:name], :name => 'record[name]', :id => 'record_name', :class => 'name-input', :object => record)
49
+ assert_dom_equal %(<textarea name=\"record[name]\" class=\"name-input mceEditor\" id=\"record_name\" data-tinymce=\"{&quot;theme&quot;:&quot;alternate&quot;,&quot;toolbar&quot;:&quot;undo redo | format&quot;}\">\n</textarea>), active_scaffold_input_tinymce(config.columns[:name], opts)
48
50
  end
49
51
 
50
52
  protected
@@ -9,23 +9,25 @@ class FormColumnHelpersTest < ActionView::TestCase
9
9
  end
10
10
 
11
11
  def test_choices_for_select_form_ui_for_simple_column
12
+ opts = {object: @record}
12
13
  @column.options[:options] = %i[value_1 value_2 value_3]
13
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Value 1</option>\n<option value=\"value_2\">Value 2</option>\n<option value=\"value_3\">Value 3</option></select>", active_scaffold_input_select(@column, :object => @record)
14
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Value 1</option>\n<option value=\"value_2\">Value 2</option>\n<option value=\"value_3\">Value 3</option></select>", active_scaffold_input_select(@column, opts.dup)
14
15
 
15
16
  @column.options[:options] = %w[value_1 value_2 value_3]
16
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">value_1</option>\n<option value=\"value_2\">value_2</option>\n<option value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, :object => @record)
17
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">value_1</option>\n<option value=\"value_2\">value_2</option>\n<option value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, opts.dup)
17
18
 
18
19
  @column.options[:options] = [%w[text_1 value_1], %w[text_2 value_2], %w[text_3 value_3]]
19
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">text_1</option>\n<option value=\"value_2\">text_2</option>\n<option value=\"value_3\">text_3</option></select>", active_scaffold_input_select(@column, :object => @record)
20
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">text_1</option>\n<option value=\"value_2\">text_2</option>\n<option value=\"value_3\">text_3</option></select>", active_scaffold_input_select(@column, opts.dup)
20
21
 
21
22
  @column.options[:options] = [%i[text_1 value_1], %i[text_2 value_2], %i[text_3 value_3]]
22
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Text 1</option>\n<option value=\"value_2\">Text 2</option>\n<option value=\"value_3\">Text 3</option></select>", active_scaffold_input_select(@column, :object => @record)
23
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Text 1</option>\n<option value=\"value_2\">Text 2</option>\n<option value=\"value_3\">Text 3</option></select>", active_scaffold_input_select(@column, opts.dup)
23
24
  end
24
25
 
25
26
  def test_options_for_select_form_ui_for_simple_column
27
+ opts = {object: @record}
26
28
  @column.options = {:include_blank => 'None', :selected => 'value_2', :disabled => %w[value_1 value_3]}
27
29
  @column.options[:options] = %w[value_1 value_2 value_3]
28
30
  @column.options[:html_options] = {:class => 'big'}
29
- assert_dom_equal "<select name=\"record[a]\" class=\"big\" id=\"record_a\"><option value=\"\">None</option>\n<option disabled=\"disabled\" value=\"value_1\">value_1</option>\n<option selected=\"selected\" value=\"value_2\">value_2</option>\n<option disabled=\"disabled\" value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, :object => @record)
31
+ assert_dom_equal "<select name=\"record[a]\" class=\"big\" id=\"record_a\"><option value=\"\">None</option>\n<option disabled=\"disabled\" value=\"value_1\">value_1</option>\n<option selected=\"selected\" value=\"value_2\">value_2</option>\n<option disabled=\"disabled\" value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, opts)
30
32
  end
31
33
  end