active_scaffold 4.2.3 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +16 -1
  3. data/README.md +108 -7
  4. data/app/assets/javascripts/{jquery → active_scaffold}/active_scaffold.js +759 -762
  5. data/app/assets/javascripts/{jquery/date_picker_bridge.js.erb → active_scaffold/date_picker_bridge.js} +0 -3
  6. data/app/assets/javascripts/active_scaffold/load.js +102 -0
  7. data/app/assets/javascripts/active_scaffold.js.erb +3 -27
  8. data/app/assets/stylesheets/active_scaffold/_colours.scss +330 -0
  9. data/app/assets/stylesheets/active_scaffold/_images.scss +65 -0
  10. data/app/assets/stylesheets/{active_scaffold_layout.scss → active_scaffold/_layout.scss} +14 -0
  11. data/app/assets/stylesheets/active_scaffold/_variables.scss +194 -0
  12. data/app/assets/stylesheets/active_scaffold/core.scss +15 -0
  13. data/app/assets/stylesheets/active_scaffold.scss.erb +16 -0
  14. data/app/views/active_scaffold_overrides/_field_search_columns.html.erb +8 -0
  15. data/app/views/active_scaffold_overrides/_form.html.erb +8 -0
  16. data/app/views/active_scaffold_overrides/_form_association.html.erb +3 -1
  17. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +4 -2
  18. data/app/views/active_scaffold_overrides/_show_association.html.erb +2 -1
  19. data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -2
  20. data/app/views/active_scaffold_overrides/_show_association_vertical.html.erb +1 -1
  21. data/app/views/active_scaffold_overrides/edit_associated.js.erb +10 -8
  22. data/lib/active_scaffold/actions/core.rb +34 -3
  23. data/lib/active_scaffold/assets/css_deps_generator.rb +42 -0
  24. data/lib/active_scaffold/assets/jquery_ui_manifest.rb +77 -0
  25. data/lib/active_scaffold/assets/jquery_ui_theme_generator.rb +102 -0
  26. data/lib/active_scaffold/assets.rb +109 -0
  27. data/lib/active_scaffold/attribute_params.rb +11 -2
  28. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +1 -1
  29. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +1 -1
  30. data/lib/active_scaffold/bridges/chosen.rb +1 -1
  31. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +1 -1
  32. data/lib/active_scaffold/bridges/file_column/form_ui.rb +1 -1
  33. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +1 -1
  34. data/lib/active_scaffold/bridges/record_select/helpers.rb +1 -1
  35. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +1 -0
  36. data/lib/active_scaffold/bridges/tiny_mce.rb +6 -1
  37. data/lib/active_scaffold/bridges.rb +7 -0
  38. data/lib/active_scaffold/config/core.rb +7 -3
  39. data/lib/active_scaffold/constraints.rb +1 -1
  40. data/lib/active_scaffold/data_structures/action_columns.rb +66 -0
  41. data/lib/active_scaffold/data_structures/bridge.rb +2 -0
  42. data/lib/active_scaffold/data_structures/column.rb +3 -0
  43. data/lib/active_scaffold/engine.rb +40 -0
  44. data/lib/active_scaffold/finder.rb +1 -1
  45. data/lib/active_scaffold/helpers/assets_helpers.rb +39 -0
  46. data/lib/active_scaffold/helpers/controller_helpers.rb +1 -1
  47. data/lib/active_scaffold/helpers/form_column_helpers.rb +57 -532
  48. data/lib/active_scaffold/helpers/form_ui_helpers.rb +530 -0
  49. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -0
  50. data/lib/active_scaffold/helpers/list_column_helpers.rb +31 -11
  51. data/lib/active_scaffold/helpers/search_column_helpers.rb +5 -12
  52. data/lib/active_scaffold/helpers/show_column_helpers.rb +4 -2
  53. data/lib/active_scaffold/helpers/view_helpers.rb +12 -0
  54. data/lib/active_scaffold/railties/tasks.rake +10 -0
  55. data/lib/active_scaffold/testing/assert_embedded_load.rb +33 -0
  56. data/lib/active_scaffold/version.rb +2 -2
  57. data/lib/active_scaffold.rb +7 -2
  58. data/lib/tasks/active_scaffold/assets.rake +42 -0
  59. data/lib/tasks/bundle.rake +25 -0
  60. data/vendor/assets/stylesheets/{jquery-ui-theme.css.erb → jquery-ui-theme.css} +17 -17
  61. metadata +26 -28
  62. data/app/assets/stylesheets/active_scaffold.scss +0 -424
  63. data/app/assets/stylesheets/active_scaffold_extensions.css.erb +0 -2
  64. data/app/assets/stylesheets/active_scaffold_images.scss +0 -65
  65. data/app/assets/stylesheets/active_scaffold_jquery_ui.css.erb +0 -13
  66. /data/app/assets/javascripts/{jquery → active_scaffold}/active_scaffold_chosen.js +0 -0
  67. /data/app/assets/javascripts/{jquery → active_scaffold}/draggable_lists.js +0 -0
  68. /data/app/assets/javascripts/{jquery → active_scaffold}/jquery.editinplace.js +0 -0
  69. /data/app/assets/javascripts/{jquery → active_scaffold}/tiny_mce_bridge.js +0 -0
@@ -6,9 +6,9 @@ module ActiveScaffold
6
6
  module FormColumnHelpers
7
7
  # This method decides which input to use for the given column.
8
8
  # It does not do any rendering. It only decides which method is responsible for rendering.
9
- def active_scaffold_input_for(column, scope = nil, options = nil)
9
+ def active_scaffold_input_for(column, scope = nil, options = nil, form_columns: nil)
10
10
  options ||= active_scaffold_input_options(column, scope)
11
- options = update_columns_options(column, scope, options)
11
+ options = update_columns_options(column, scope, options, form_columns: form_columns)
12
12
  active_scaffold_render_input(column, options)
13
13
  end
14
14
 
@@ -49,12 +49,10 @@ module ActiveScaffold
49
49
  text_field(:record, column.name, options.merge(column.options).except(:format))
50
50
  end
51
51
  rescue StandardError => e
52
- message = "on the ActiveScaffold column = :#{column.name} in #{controller.class}"
53
- ActiveScaffold.log_exception(e, message)
54
- raise e.class, "#{e.message} -- #{message}", e.backtrace
52
+ handle_exception_on_column(e, column, record)
55
53
  end
56
54
 
57
- def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil) # rubocop:disable Metrics/ParameterLists
55
+ def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil, form_columns: nil) # rubocop:disable Metrics/ParameterLists
58
56
  if add_class
59
57
  col_class = []
60
58
  col_class << 'required' if column.required?(action_for_validation(record))
@@ -67,7 +65,7 @@ module ActiveScaffold
67
65
  form_attribute(column, record, scope, true, col_class)
68
66
  else
69
67
  renders_as = column_renders_as(column)
70
- html = render_column(column, record, renders_as, scope, only_value: false, col_class: col_class)
68
+ html = render_column(column, record, renders_as, scope, only_value: false, col_class: col_class, form_columns: form_columns)
71
69
  html = content_tag(:div, html, active_scaffold_subform_attributes(column)) if renders_as == :subform
72
70
  html
73
71
  end
@@ -195,18 +193,23 @@ module ActiveScaffold
195
193
  end
196
194
  end
197
195
 
198
- def render_column(column, record, renders_as, scope = nil, only_value: false, col_class: nil, **subform_locals)
199
- if form_column_is_hidden?(column, record, scope)
200
- # creates an element that can be replaced by the update_columns routine,
201
- # but will not affect the value of the submitted form in this state:
202
- # <dl><input type="hidden" class="<%= column.name %>-input"></dl>
203
- content_tag :dl, style: 'display: none' do
204
- hidden_field_tag(nil, nil, class: "#{column.name}-input")
196
+ def render_column(column, record, renders_as, scope = nil, only_value: false, col_class: nil, form_columns: nil, **subform_locals)
197
+ hide_column, clear = form_column_is_hidden?(column, record, scope)
198
+ if hide_column
199
+ if clear
200
+ form_hidden_attribute(column, record, scope, true)
201
+ else
202
+ # creates an element that can be replaced by the update_columns routine,
203
+ # but will not affect the value of the submitted form in this state:
204
+ # <dl><input type="hidden" class="<%= column.name %>-input"></dl>
205
+ content_tag :dl, style: 'display: none' do
206
+ hidden_field_tag(nil, nil, class: "#{column.name}-input")
207
+ end
205
208
  end
206
209
  elsif (partial = override_form_field_partial(column))
207
- render partial, column: column, only_value: only_value, scope: scope, col_class: col_class, record: record
210
+ render partial, column: column, only_value: only_value, scope: scope, col_class: col_class, record: record, form_columns: form_columns
208
211
  elsif renders_as == :field || override_form_field?(column)
209
- form_attribute(column, record, scope, only_value, col_class)
212
+ form_attribute(column, record, scope, only_value, col_class, form_columns: form_columns)
210
213
  elsif renders_as == :subform
211
214
  render 'form_association', subform_locals.slice(:tabbed_by, :tab_value, :tab_id).merge(column: column, scope: scope, parent_record: record)
212
215
  else
@@ -214,14 +217,23 @@ module ActiveScaffold
214
217
  end
215
218
  end
216
219
 
217
- def form_column_is_hidden?(column, record, scope = nil)
218
- if column.hide_form_column_if.respond_to?(:call)
219
- column.hide_form_column_if.call(record, column, scope)
220
- elsif column.hide_form_column_if.is_a?(Symbol)
221
- record.send(column.hide_form_column_if)
220
+ def form_column_is_hidden?(column, record, scope = nil) # rubocop:disable Naming/PredicateMethod
221
+ if column.clear_form_column_if.nil?
222
+ condition_to_hide = column.hide_form_column_if
223
+ clear = false
222
224
  else
223
- column.hide_form_column_if
224
- end
225
+ condition_to_hide = column.clear_form_column_if
226
+ clear = true
227
+ end
228
+ hide =
229
+ if condition_to_hide.respond_to?(:call)
230
+ condition_to_hide.call(record, column, scope)
231
+ elsif condition_to_hide.is_a?(Symbol)
232
+ record.send(condition_to_hide)
233
+ else
234
+ condition_to_hide
235
+ end
236
+ [hide, clear]
225
237
  end
226
238
 
227
239
  def column_description(column, record, scope = nil)
@@ -229,7 +241,7 @@ module ActiveScaffold
229
241
  content_tag(:span, h(desc) + content_tag(:span, nil, class: 'close'), class: 'description') if desc.present?
230
242
  end
231
243
 
232
- def form_attribute(column, record, scope = nil, only_value = false, col_class = nil)
244
+ def form_attribute(column, record, scope = nil, only_value = false, col_class = nil, form_columns: nil)
233
245
  column_options = active_scaffold_input_options(column, scope, object: record)
234
246
  collapsible_id = column_options.delete :collapsible_id
235
247
  attributes = field_attributes(column, record)
@@ -243,7 +255,7 @@ module ActiveScaffold
243
255
  field << hidden_field(:record, method, column_options)
244
256
  end
245
257
  else
246
- field = active_scaffold_input_for column, scope, column_options
258
+ field = active_scaffold_input_for column, scope, column_options, form_columns: form_columns
247
259
  end
248
260
  if field
249
261
  field << loading_indicator_tag(action: :render_field, id: params[:id]) if column.update_columns
@@ -270,30 +282,41 @@ module ActiveScaffold
270
282
  column.label unless hidden
271
283
  end
272
284
 
273
- def form_hidden_attribute(column, record, scope = nil)
285
+ def form_hidden_attribute(column, record, scope = nil, clear = false)
274
286
  content_tag :dl, style: 'display: none' do
275
287
  content_tag(:dt, '') <<
276
- content_tag(:dd, form_hidden_field(column, record, scope))
288
+ content_tag(:dd, form_hidden_field(column, record, scope, clear))
277
289
  end
278
290
  end
279
291
 
280
- def form_hidden_field(column, record, scope)
292
+ def form_hidden_field(column, record, scope, clear = false)
281
293
  options = active_scaffold_input_options(column, scope)
294
+ value = record.send(column.name) unless clear
282
295
  if column.association&.collection?
283
- associated = record.send(column.name)
284
- if associated.blank?
296
+ options[:name] += '[]'
297
+ if value.blank?
285
298
  hidden_field_tag options[:name], '', options
286
299
  else
287
- options[:name] += '[]'
288
- fields = associated.map do |r|
300
+ fields = value.map do |r|
289
301
  hidden_field_tag options[:name], r.id, options.merge(id: options[:id] + "_#{r.id}")
290
302
  end
291
303
  safe_join fields, ''
292
304
  end
293
305
  elsif column.association
294
- hidden_field_tag options[:name], record.send(column.name)&.id, options
306
+ hidden_field_tag options[:name], value&.id, options
295
307
  else
296
- hidden_field :record, column.name, options.merge(object: record)
308
+ options[:name] += '[]' if active_scaffold_column_expect_array?(column)
309
+ hidden_field_tag options[:name], value, options
310
+ end
311
+ end
312
+
313
+ def active_scaffold_column_expect_array?(column)
314
+ ui_options = column.form_ui_options || column.options
315
+ case column.form_ui
316
+ when :select
317
+ column.association&.collection? || ui_options[:multiple]
318
+ when :select_multiple, :checkboxes, :draggable
319
+ true
297
320
  end
298
321
  end
299
322
 
@@ -330,504 +353,6 @@ module ActiveScaffold
330
353
  value
331
354
  end
332
355
 
333
- ##
334
- ## Form input methods
335
- ##
336
-
337
- def active_scaffold_grouped_options(column, select_options, optgroup)
338
- group_column = active_scaffold_config_for(column.association.klass).columns[optgroup]
339
- group_label = group_column.options[:label_method] if group_column
340
- group_label ||= group_column&.association ? :to_label : :to_s
341
- select_options.group_by(&optgroup.to_sym).collect do |group, options|
342
- [group.send(group_label), options.collect { |r| [r.send(column.options[:label_method] || :to_label), r.id] }]
343
- end
344
- end
345
-
346
- def active_scaffold_translate_select_options(options)
347
- options[:include_blank] = as_(options[:include_blank].to_s) if options[:include_blank].is_a? Symbol
348
- options[:prompt] = as_(options[:prompt].to_s) if options[:prompt].is_a? Symbol
349
- options
350
- end
351
-
352
- def active_scaffold_select_name_with_multiple(options)
353
- return if !options[:multiple] || options[:name].to_s.ends_with?('[]')
354
-
355
- options[:name] = "#{options[:name]}[]"
356
- end
357
-
358
- def active_scaffold_input_singular_association(column, html_options, options = {}, ui_options: column.options)
359
- record = html_options.delete(:object)
360
- associated = html_options.include?(:associated) ? html_options.delete(:associated) : record.send(column.association.name)
361
-
362
- helper_method = association_helper_method(column.association, :sorted_association_options_find)
363
- select_options = send(helper_method, column.association, nil, record)
364
- select_options.unshift(associated) if associated&.persisted? && select_options.exclude?(associated)
365
-
366
- method = column.name
367
- options.merge! selected: associated&.id, include_blank: as_(:_select_), object: record
368
-
369
- html_options.merge!(ui_options[:html_options] || {})
370
- options.merge!(ui_options)
371
- html_options.delete(:multiple) # no point using multiple in a form for singular assoc, but may be set for field search
372
- active_scaffold_translate_select_options(options)
373
-
374
- html =
375
- if (optgroup = options.delete(:optgroup))
376
- select(:record, method, active_scaffold_grouped_options(column, select_options, optgroup), options, html_options)
377
- else
378
- collection_select(:record, method, select_options, :id, ui_options[:label_method] || :to_label, options, html_options)
379
- end
380
- html << active_scaffold_refresh_link(column, html_options, record, ui_options) if ui_options[:refresh_link]
381
- html
382
- end
383
-
384
- def active_scaffold_new_record_klass(column, record, **options)
385
- if column.association.polymorphic? && column.association.belongs_to?
386
- type = record.send(column.association.foreign_type)
387
- type_options = options[:types]
388
- column.association.klass(record) if type.present? && (type_options.nil? || type_options.include?(type))
389
- else
390
- column.association.klass
391
- end
392
- end
393
-
394
- def active_scaffold_add_new(column, record, html_options, ui_options: column.options, skip_link: false)
395
- options = ui_options[:add_new] == true ? {} : ui_options[:add_new]
396
- options[:mode] = :popup if column.association&.collection?
397
- case options[:mode]
398
- when nil, :subform
399
- active_scaffold_new_record_subform(column, record, html_options, options: options, skip_link: skip_link)
400
- when :popup
401
- active_scaffold_new_record_popup(column, record, html_options, options: options) unless skip_link
402
- else
403
- raise ArgumentError, "unsupported mode for add_new: #{options[:mode].inspect}"
404
- end
405
- end
406
-
407
- def active_scaffold_new_record_url_options(column, record)
408
- if column.association.reverse
409
- constraint = [record.id]
410
- constraint.unshift record.class.name if column.association.reverse_association.polymorphic?
411
- {embedded: {constraints: {column.association.reverse => constraint}}}
412
- else
413
- raise "can't add constraint to create new record with :popup, no reverse association for " \
414
- "\"#{column.name}\" in #{column.association.klass}, add the reverse association " \
415
- 'or override active_scaffold_new_record_url_options helper.'
416
- end
417
- end
418
-
419
- def active_scaffold_new_record_popup(column, record, html_options, options: {})
420
- klass = send(override_helper_per_model(:active_scaffold_new_record_klass, record.class), column, record, **options)
421
- klass = nil if options[:security_method] && !controller.send(options[:security_method])
422
- klass = nil if klass && options[:security_method].nil? && !klass.authorized_for?(crud_type: :create)
423
- return h('') unless klass
424
-
425
- link_text = active_scaffold_add_new_text(options, :add_new_text, :add)
426
- url_options_helper = override_helper_per_model(:active_scaffold_new_record_url_options, record.class)
427
- url_options = send(url_options_helper, column, record)
428
- url_options[:controller] ||= active_scaffold_controller_for(klass).controller_path
429
- url_options[:action] ||= :new
430
- url_options[:from_field] ||= html_options[:id]
431
- url_options[:parent_model] ||= record.class.name
432
- url_options[:parent_column] ||= column.name
433
- url_options.reverse_merge! options[:url_options] if options[:url_options]
434
- link_to(link_text, url_options, remote: true, data: {position: :popup}, class: 'as_action')
435
- end
436
-
437
- def active_scaffold_new_record_subform(column, record, html_options, options: {}, new_record_attributes: nil, locals: {}, skip_link: false)
438
- klass = send(override_helper_per_model(:active_scaffold_new_record_klass, record.class), column, record, **options)
439
- return content_tag(:div, '') unless klass
440
-
441
- subform_attrs = active_scaffold_subform_attributes(column, nil, klass, ui_options: options)
442
- if record.send(column.name)&.new_record?
443
- new_record = record.send(column.name)
444
- else
445
- subform_attrs[:style] = 'display: none'
446
- end
447
- subform_attrs[:class] << ' optional'
448
- scope = html_options[:name].scan(/record(.*)\[#{column.name}\]/).dig(0, 0)
449
- new_record ||= klass.new(new_record_attributes)
450
- locals = locals.reverse_merge(column: column, parent_record: record, associated: [], show_blank_record: new_record, scope: scope)
451
- subform = render(partial: subform_partial_for_column(column, klass, ui_options: options), locals: locals)
452
- if options[:hide_subgroups]
453
- toggable_id = "#{sub_form_id(association: column.name, id: record.id || generated_id(record) || 99_999_999_999)}-div"
454
- subform << link_to_visibility_toggle(toggable_id, default_visible: false)
455
- end
456
- html = content_tag(:div, subform, subform_attrs)
457
- return html if skip_link
458
-
459
- html << active_scaffold_show_new_subform_link(column, record, html_options[:id], subform_attrs[:id], options: options)
460
- end
461
-
462
- def active_scaffold_add_new_text(options, key, default)
463
- text = options[key] unless options == true
464
- return text if text.is_a? String
465
-
466
- as_(text || default)
467
- end
468
-
469
- def active_scaffold_show_new_subform_link(column, record, select_id, subform_id, options: {})
470
- add_existing = active_scaffold_add_new_text(options, :add_existing_text, :add_existing)
471
- create_new = active_scaffold_add_new_text(options, :add_new_text, :create_new)
472
- data = {select_id: select_id, subform_id: subform_id, subform_text: add_existing, select_text: create_new}
473
- label = data[record.send(column.name)&.new_record? ? :subform_text : :select_text]
474
- link_to(label, '#', data: data, class: 'show-new-subform')
475
- end
476
-
477
- def active_scaffold_file_with_content(column, options, content, remove_file_prefix, controls_class, ui_options: column.options)
478
- options = active_scaffold_input_text_options(options.merge(ui_options))
479
- options[:style] = 'display: none' if content
480
- field = file_field(:record, column.name, options)
481
-
482
- if content
483
- content = [content, ' | ']
484
- content << yield if block_given?
485
- object_name, method = options[:name].split(/\[(#{column.name})\]/)
486
- method.sub!(/#{column.name}/, "#{remove_file_prefix}\\0")
487
- content << hidden_field(object_name, method, value: 'false', class: 'remove_file')
488
- active_scaffold_file_with_remove_link(safe_join(content), options, controls_class) { field }
489
- else
490
- field
491
- end
492
- end
493
-
494
- def active_scaffold_file_with_remove_link(content, options, controls_class, link_key = nil)
495
- required = options.delete(:required)
496
- link_key ||= options[:multiple] ? :remove_files : :remove_file
497
- content_tag(:div, class: "#{controls_class} file-input-controls", data: {required: required}) do
498
- content_line = content_tag(:div) do
499
- safe_join [content, content_tag(:a, as_(link_key), href: '#', class: 'remove-file-btn')]
500
- end
501
- content_line << yield if block_given?
502
- content_line
503
- end
504
- end
505
-
506
- def active_scaffold_refresh_link(column, html_options, record, ui_options = {})
507
- link_options = {object: record, data: {field_selector: ui_options[:field_selector] || "##{html_options[:id]}"}}
508
- if html_options['data-update_url']
509
- link_options['data-update_send_form'] = html_options['data-update_send_form']
510
- link_options['data-update_send_form_selector'] = html_options['data-update_send_form_selector']
511
- else
512
- scope = html_options[:name].scan(/^record((\[[^\]]*\])*)\[#{column.name}\]/).dig(0, 0) if html_options[:name]
513
- link_options = update_columns_options(column, scope.presence, link_options, true)
514
- end
515
- link_options[:class] = 'refresh-link'
516
- if ui_options[:refresh_link].is_a?(Hash)
517
- text = ui_options.dig(:refresh_link, :text)
518
- text = as_(text) if text.is_a?(Symbol)
519
- link_options.merge! ui_options[:refresh_link].except(:text)
520
- end
521
- link_to(text || as_(:refresh), link_options.delete('data-update_url') || html_options['data-update_url'], link_options.except(:object))
522
- end
523
-
524
- def active_scaffold_plural_association_options(column, record = nil)
525
- associated_options = record.send(column.association.name)
526
- helper_method = association_helper_method(column.association, :sorted_association_options_find)
527
- [associated_options, associated_options | send(helper_method, column.association, nil, record)]
528
- end
529
-
530
- def active_scaffold_input_plural_association(column, options, ui_options: column.options)
531
- record = options.delete(:object)
532
- associated_options, select_options = active_scaffold_plural_association_options(column, record)
533
-
534
- html =
535
- if options[:multiple] || ui_options.dig(:html_options, :multiple)
536
- html_options = options.merge(ui_options[:html_options] || {})
537
- active_scaffold_select_name_with_multiple html_options
538
- collection_select(:record, column.name, select_options, :id, ui_options[:label_method] || :to_label, ui_options.merge(object: record), html_options)
539
- elsif select_options.empty?
540
- content_tag(:span, as_(:no_options), class: "#{options[:class]} no-options", id: options[:id]) <<
541
- hidden_field_tag("#{options[:name]}[]", '', id: nil)
542
- else
543
- active_scaffold_checkbox_list(column, select_options, associated_options.collect(&:id), options, ui_options: ui_options)
544
- end
545
- html << active_scaffold_refresh_link(column, options, record, ui_options) if ui_options[:refresh_link]
546
- html
547
- end
548
-
549
- def active_scaffold_input_draggable(column, options, ui_options: column.options)
550
- active_scaffold_input_select(column, options.merge(draggable_lists: true), ui_options: ui_options)
551
- end
552
-
553
- def active_scaffold_checkbox_option(option, label_method, associated_ids, checkbox_options, li_options = {})
554
- content_tag(:li, li_options) do
555
- option_id = option.is_a?(Array) ? option[1] : option.id
556
- label = option.is_a?(Array) ? option[0] : option.send(label_method)
557
- check_box_tag(checkbox_options[:name], option_id, associated_ids.include?(option_id), checkbox_options) <<
558
- content_tag(:label, label, for: checkbox_options[:id])
559
- end
560
- end
561
-
562
- def active_scaffold_check_all_buttons(column, options, ui_options: column.options)
563
- content_tag(:div, class: 'check-buttons') do
564
- link_to(as_(:check_all), '#', class: 'check-all') <<
565
- link_to(as_(:uncheck_all), '#', class: 'uncheck-all')
566
- end
567
- end
568
-
569
- def active_scaffold_checkbox_list(column, select_options, associated_ids, options, ui_options: column.options)
570
- label_method = ui_options[:label_method] || :to_label
571
- html = active_scaffold_check_all_buttons(column, options, ui_options: ui_options)
572
- html << hidden_field_tag("#{options[:name]}[]", '', id: nil)
573
- draggable = options.delete(:draggable_lists) || ui_options[:draggable_lists]
574
- html << content_tag(:ul, options.merge(class: "#{options[:class]} checkbox-list#{' draggable-lists' if draggable}")) do
575
- content = []
576
- select_options.each_with_index do |option, i|
577
- content << active_scaffold_checkbox_option(option, label_method, associated_ids, name: "#{options[:name]}[]", id: "#{options[:id]}_#{i}_id")
578
- end
579
- safe_join content
580
- end
581
- html
582
- end
583
-
584
- def active_scaffold_translated_option(column, text, value = nil)
585
- value = text if value.nil?
586
- [(text.is_a?(Symbol) ? column.active_record_class.human_attribute_name(text) : text), value]
587
- end
588
-
589
- def active_scaffold_enum_options(column, record = nil, ui_options: column.options)
590
- ui_options[:options]
591
- end
592
-
593
- def active_scaffold_input_enum(column, html_options, options = {}, ui_options: column.options)
594
- record = html_options.delete(:object)
595
- options[:selected] = record.send(column.name)
596
- options[:object] = record
597
- enum_options_method = override_helper_per_model(:active_scaffold_enum_options, record.class)
598
- options_for_select = send(enum_options_method, column, record, ui_options: ui_options).collect do |text, value|
599
- active_scaffold_translated_option(column, text, value)
600
- end
601
- html_options.merge!(ui_options[:html_options] || {})
602
- options.merge!(ui_options)
603
- active_scaffold_select_name_with_multiple html_options
604
- active_scaffold_translate_select_options(options)
605
- html = select(:record, column.name, options_for_select, options, html_options)
606
- html << active_scaffold_refresh_link(column, html_options, record, ui_options) if ui_options[:refresh_link]
607
- html
608
- end
609
-
610
- def active_scaffold_input_select(column, html_options, ui_options: column.options)
611
- record = html_options[:object]
612
- html =
613
- if column.association&.singular?
614
- active_scaffold_input_singular_association(column, html_options, ui_options: ui_options)
615
- elsif column.association&.collection?
616
- active_scaffold_input_plural_association(column, html_options, ui_options: ui_options)
617
- else
618
- active_scaffold_input_enum(column, html_options, ui_options: ui_options)
619
- end
620
- if ui_options[:add_new]
621
- html = content_tag(:div, html, class: 'select-field') <<
622
- active_scaffold_add_new(column, record, html_options, ui_options: ui_options)
623
- end
624
- html
625
- end
626
-
627
- def active_scaffold_input_select_multiple(column, options, ui_options: column.options)
628
- active_scaffold_input_select(column, options.merge(multiple: true), ui_options: ui_options)
629
- end
630
-
631
- def active_scaffold_radio_option(option, selected, column, radio_options, ui_options: column.options)
632
- if column.association
633
- label_method = ui_options[:label_method] || :to_label
634
- text = option.send(label_method)
635
- value = option.id
636
- checked = {checked: selected == value}
637
- else
638
- text, value = active_scaffold_translated_option(column, *option)
639
- end
640
-
641
- id_key = radio_options[:'data-id'] ? :'data-id' : :id
642
- radio_options = radio_options.merge(id_key => "#{radio_options[id_key]}-#{value.to_s.parameterize}")
643
- radio_options.merge!(checked) if checked
644
- content_tag(:label, radio_button(:record, column.name, value, radio_options) + text)
645
- end
646
-
647
- def active_scaffold_input_radio_content(column, record, options, html_options, ui_options)
648
- if ui_options[:add_new]
649
- add_new_subform = ui_options[:add_new] == true || ui_options[:add_new][:mode].in?([nil, :subform])
650
- if add_new_subform
651
- html_options[:data] ||= {}
652
- html_options[:data][:subform_id] = active_scaffold_subform_attributes(column, ui_options: ui_options)[:id]
653
- end
654
- radio_html_options = html_options.merge(class: "#{html_options[:class]} hide-new-subform")
655
- else
656
- radio_html_options = html_options
657
- end
658
-
659
- selected = record.send(column.association.name) if column.association
660
- radios = options.map do |option|
661
- active_scaffold_radio_option(option, selected&.id, column, radio_html_options, ui_options: ui_options)
662
- end
663
-
664
- if ui_options[:include_blank]
665
- label = ui_options[:include_blank]
666
- label = as_(ui_options[:include_blank]) if ui_options[:include_blank].is_a?(Symbol)
667
- radio_id = "#{html_options[:id]}-"
668
- radios.prepend content_tag(:label, radio_button(:record, column.name, '', html_options.merge(id: radio_id)) + label)
669
- end
670
- if ui_options[:add_new]
671
- if add_new_subform
672
- create_new = content_tag(:label) do
673
- radio_button_tag(html_options[:name], '', selected&.new_record?, html_options.merge(
674
- id: "#{html_options[:id]}-create_new", class: "#{html_options[:class]} show-new-subform"
675
- ).except(:object)) <<
676
- active_scaffold_add_new_text(ui_options[:add_new], :add_new_text, :create_new)
677
- end
678
- radios << create_new
679
- skip_link = true
680
- else
681
- ui_options = ui_options.merge(add_new: ui_options[:add_new].merge(
682
- url_options: {
683
- parent_scope: html_options[:name].gsub(/^record|\[[^\]]*\]$/, '').presence,
684
- radio_data: html_options.slice(*html_options.keys.grep(/^data-update_/))
685
- }
686
- ))
687
- radios << content_tag(:span, '', class: 'new-radio-container', id: html_options[:id])
688
- end
689
- radios << active_scaffold_add_new(column, record, html_options, ui_options: ui_options, skip_link: skip_link)
690
- end
691
-
692
- safe_join radios
693
- end
694
-
695
- def active_scaffold_input_radio(column, html_options, ui_options: column.options)
696
- record = html_options[:object]
697
- html_options.merge!(ui_options[:html_options] || {})
698
- options =
699
- if column.association
700
- helper_method = association_helper_method(column.association, :sorted_association_options_find)
701
- send(helper_method, column.association, nil, record)
702
- else
703
- enum_options_method = override_helper_per_model(:active_scaffold_enum_options, record.class)
704
- send(enum_options_method, column, record, ui_options: ui_options)
705
- end
706
-
707
- if options.present?
708
- html = active_scaffold_input_radio_content(column, record, options, html_options, ui_options)
709
- else
710
- html = content_tag(:span, as_(:no_options), class: "#{html_options[:class]} no-options")
711
- html << hidden_field_tag(html_options[:name], '', id: html_options[:id])
712
- if ui_options[:add_new]
713
- html = content_tag(:div, html, class: 'select-field') <<
714
- active_scaffold_add_new(column, record, html_options, ui_options: ui_options)
715
- end
716
- html
717
- end
718
- html << active_scaffold_refresh_link(column, html_options, record, ui_options.merge(field_selector: "[name=\"#{html_options[:name]}\"]")) if ui_options[:refresh_link]
719
- html
720
- end
721
-
722
- def active_scaffold_input_checkbox(column, options, ui_options: column.options)
723
- check_box(:record, column.name, options.merge(ui_options))
724
- end
725
-
726
- def active_scaffold_input_password(column, options, ui_options: column.options)
727
- active_scaffold_text_input :password_field, column, options.reverse_merge(autocomplete: 'new-password'), ui_options: ui_options
728
- end
729
-
730
- def active_scaffold_input_textarea(column, options, ui_options: column.options)
731
- text_area(:record, column.name, options.merge(cols: ui_options[:cols], rows: ui_options[:rows], size: ui_options[:size]))
732
- end
733
-
734
- def active_scaffold_input_virtual(column, options)
735
- active_scaffold_text_input :text_field, column, options
736
- end
737
-
738
- # Some fields from HTML5 (primarily for using in-browser validation)
739
- # Sadly, many of them lacks browser support
740
-
741
- # A text box, that accepts only valid email address (in-browser validation)
742
- def active_scaffold_input_email(column, options, ui_options: column.options)
743
- active_scaffold_text_input :email_field, column, options, ui_options: ui_options
744
- end
745
-
746
- # A text box, that accepts only valid URI (in-browser validation)
747
- def active_scaffold_input_url(column, options, ui_options: column.options)
748
- active_scaffold_text_input :url_field, column, options, ui_options: ui_options
749
- end
750
-
751
- # A text box, that accepts only valid phone-number (in-browser validation)
752
- def active_scaffold_input_telephone(column, options, ui_options: column.options)
753
- active_scaffold_text_input :telephone_field, column, options, :format, ui_options: ui_options
754
- end
755
-
756
- # A spinbox control for number values (in-browser validation)
757
- def active_scaffold_input_number(column, options, ui_options: column.options)
758
- active_scaffold_number_input :number_field, column, options, :format, ui_options: ui_options
759
- end
760
-
761
- # A slider control for number values (in-browser validation)
762
- def active_scaffold_input_range(column, options, ui_options: column.options)
763
- active_scaffold_number_input :range_field, column, options, :format, ui_options: ui_options
764
- end
765
-
766
- # A slider control for number values (in-browser validation)
767
- def active_scaffold_number_input(method, column, options, remove_options = nil, ui_options: column.options)
768
- options = numerical_constraints_for_column(column, options)
769
- active_scaffold_text_input method, column, options, remove_options, ui_options: ui_options
770
- end
771
-
772
- def active_scaffold_text_input(method, column, options, remove_options = nil, ui_options: column.options)
773
- options = active_scaffold_input_text_options(options)
774
- options = options.merge(ui_options)
775
- options = options.except(*remove_options) if remove_options.present?
776
- send method, :record, column.name, options
777
- end
778
-
779
- # A color picker
780
- def active_scaffold_input_color(column, options, ui_options: column.options)
781
- html = []
782
- options = active_scaffold_input_text_options(options)
783
- if column.null?
784
- no_color = options[:object].send(column.name).nil?
785
- method = no_color ? :hidden_field : :color_field
786
- html << content_tag(:label, check_box_tag('disable', '1', no_color, id: nil, name: nil, class: 'no-color') << " #{as_ ui_options[:no_color] || :no_color}")
787
- else
788
- method = :color_field
789
- end
790
- html << send(method, :record, column.name, options.merge(ui_options).except(:format, :no_color))
791
- safe_join html
792
- end
793
-
794
- #
795
- # Column.type-based inputs
796
- #
797
-
798
- def active_scaffold_input_boolean(column, html_options, ui_options: column.options)
799
- record = html_options.delete(:object)
800
- html_options.merge!(ui_options[:html_options] || {})
801
-
802
- options = {selected: record.send(column.name), object: record}
803
- options[:include_blank] = :_select_ if column.null?
804
- options.merge!(ui_options)
805
- active_scaffold_translate_select_options(options)
806
-
807
- options_for_select = [[as_(:true), true], [as_(:false), false]] # rubocop:disable Lint/BooleanSymbol
808
- select(:record, column.name, options_for_select, options, html_options)
809
- end
810
-
811
- def active_scaffold_input_date(column, options, ui_options: column.options)
812
- active_scaffold_text_input :date_field, column, options, ui_options: ui_options
813
- end
814
-
815
- def active_scaffold_input_time(column, options, ui_options: column.options)
816
- active_scaffold_text_input :time_field, column, options, ui_options: ui_options
817
- end
818
-
819
- def active_scaffold_input_datetime(column, options, ui_options: column.options)
820
- active_scaffold_text_input :datetime_local_field, column, options, ui_options: ui_options
821
- end
822
-
823
- def active_scaffold_input_month(column, options, ui_options: column.options)
824
- active_scaffold_text_input :month_field, column, options, ui_options: ui_options
825
- end
826
-
827
- def active_scaffold_input_week(column, options, ui_options: column.options)
828
- active_scaffold_text_input :week_field, column, options, ui_options: ui_options
829
- end
830
-
831
356
  ##
832
357
  ## Form column override signatures
833
358
  ##