active_scaffold 3.5.3 → 3.6.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +73 -0
  3. data/README.md +17 -7
  4. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  5. data/app/assets/javascripts/jquery/active_scaffold.js +97 -6
  6. data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
  7. data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
  8. data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -2
  9. data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_form_association.html.erb +2 -1
  11. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
  12. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +9 -7
  13. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +4 -4
  14. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +2 -1
  15. data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
  16. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  17. data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
  18. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  19. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  20. data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
  21. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  22. data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
  23. data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
  24. data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
  25. data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
  26. data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
  27. data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
  28. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +2 -2
  29. data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
  30. data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
  31. data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
  32. data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
  33. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  34. data/app/views/active_scaffold_overrides/update_column.js.erb +2 -2
  35. data/config/locales/de.yml +2 -1
  36. data/config/locales/en.yml +1 -0
  37. data/config/locales/es.yml +1 -0
  38. data/config/locales/fr.yml +2 -1
  39. data/config/locales/hu.yml +1 -0
  40. data/config/locales/ja.yml +1 -0
  41. data/config/locales/ru.yml +1 -0
  42. data/lib/active_scaffold.rb +19 -16
  43. data/lib/active_scaffold/actions/common_search.rb +11 -8
  44. data/lib/active_scaffold/actions/core.rb +91 -70
  45. data/lib/active_scaffold/actions/create.rb +28 -28
  46. data/lib/active_scaffold/actions/delete.rb +3 -3
  47. data/lib/active_scaffold/actions/field_search.rb +53 -43
  48. data/lib/active_scaffold/actions/list.rb +111 -27
  49. data/lib/active_scaffold/actions/nested.rb +65 -48
  50. data/lib/active_scaffold/actions/search.rb +1 -1
  51. data/lib/active_scaffold/actions/show.rb +4 -4
  52. data/lib/active_scaffold/actions/subform.rb +23 -22
  53. data/lib/active_scaffold/actions/update.rb +96 -77
  54. data/lib/active_scaffold/active_record_permissions.rb +2 -11
  55. data/lib/active_scaffold/attribute_params.rb +102 -94
  56. data/lib/active_scaffold/bridges.rb +8 -8
  57. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  58. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +34 -0
  59. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  60. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  61. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  62. data/lib/active_scaffold/bridges/bitfields.rb +1 -0
  63. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  64. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
  65. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -12
  66. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
  67. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  68. data/lib/active_scaffold/bridges/chosen/helpers.rb +11 -9
  69. data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
  70. data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
  71. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  72. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  73. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
  74. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  75. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
  76. data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
  77. data/lib/active_scaffold/bridges/paper_trail/actions.rb +3 -1
  78. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  79. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
  80. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  81. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -17
  82. data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
  83. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  84. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
  85. data/lib/active_scaffold/config/base.rb +133 -41
  86. data/lib/active_scaffold/config/core.rb +146 -18
  87. data/lib/active_scaffold/config/delete.rb +14 -1
  88. data/lib/active_scaffold/config/field_search.rb +7 -1
  89. data/lib/active_scaffold/config/form.rb +10 -1
  90. data/lib/active_scaffold/config/list.rb +39 -13
  91. data/lib/active_scaffold/config/mark.rb +4 -2
  92. data/lib/active_scaffold/config/nested.rb +16 -17
  93. data/lib/active_scaffold/config/search.rb +9 -0
  94. data/lib/active_scaffold/config/show.rb +4 -0
  95. data/lib/active_scaffold/config/update.rb +4 -0
  96. data/lib/active_scaffold/configurable.rb +14 -7
  97. data/lib/active_scaffold/constraints.rb +22 -20
  98. data/lib/active_scaffold/core.rb +67 -28
  99. data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
  100. data/lib/active_scaffold/data_structures/action_link.rb +50 -20
  101. data/lib/active_scaffold/data_structures/action_links.rb +15 -13
  102. data/lib/active_scaffold/data_structures/association/abstract.rb +38 -15
  103. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  104. data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
  105. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  106. data/lib/active_scaffold/data_structures/column.rb +75 -66
  107. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  108. data/lib/active_scaffold/data_structures/nested_info.rb +33 -19
  109. data/lib/active_scaffold/data_structures/set.rb +8 -0
  110. data/lib/active_scaffold/data_structures/sorting.rb +10 -2
  111. data/lib/active_scaffold/delayed_setup.rb +16 -5
  112. data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
  113. data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
  114. data/lib/active_scaffold/extensions/cow_proxy.rb +95 -0
  115. data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
  116. data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
  117. data/lib/active_scaffold/extensions/localize.rb +3 -1
  118. data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
  119. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  120. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
  121. data/lib/active_scaffold/finder.rb +110 -77
  122. data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
  123. data/lib/active_scaffold/helpers/association_helpers.rb +21 -19
  124. data/lib/active_scaffold/helpers/controller_helpers.rb +34 -10
  125. data/lib/active_scaffold/helpers/form_column_helpers.rb +196 -124
  126. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  127. data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
  128. data/lib/active_scaffold/helpers/list_column_helpers.rb +86 -57
  129. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  130. data/lib/active_scaffold/helpers/search_column_helpers.rb +29 -34
  131. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  132. data/lib/active_scaffold/helpers/view_helpers.rb +38 -35
  133. data/lib/active_scaffold/marked_model.rb +2 -2
  134. data/lib/active_scaffold/orm_checks.rb +3 -7
  135. data/lib/active_scaffold/paginator.rb +7 -7
  136. data/lib/active_scaffold/registry.rb +33 -0
  137. data/lib/active_scaffold/responds_to_parent.rb +8 -11
  138. data/lib/active_scaffold/tableless.rb +67 -65
  139. data/lib/active_scaffold/version.rb +2 -2
  140. data/lib/generators/active_scaffold/controller_generator.rb +2 -2
  141. data/lib/generators/active_scaffold/install_generator.rb +1 -1
  142. data/lib/generators/active_scaffold/resource_generator.rb +2 -2
  143. data/shoulda_macros/macros.rb +3 -1
  144. data/test/bridges/date_picker_test.rb +1 -2
  145. data/test/bridges/paperclip_test.rb +6 -6
  146. data/test/class_with_finder.rb +2 -2
  147. data/test/company.rb +4 -4
  148. data/test/config/create_test.rb +4 -2
  149. data/test/config/nested_test.rb +1 -1
  150. data/test/config/show_test.rb +1 -1
  151. data/test/config/update_test.rb +7 -6
  152. data/test/data_structures/action_columns_test.rb +2 -2
  153. data/test/data_structures/action_links_test.rb +1 -1
  154. data/test/data_structures/column_test.rb +3 -6
  155. data/test/data_structures/columns_test.rb +2 -2
  156. data/test/data_structures/sorting_test.rb +7 -0
  157. data/test/extensions/active_record_test.rb +4 -4
  158. data/test/extensions/routing_mapper_test.rb +2 -2
  159. data/test/helpers/list_column_helpers_test.rb +3 -1
  160. data/test/misc/active_record_permissions_test.rb +3 -11
  161. data/test/misc/attribute_params_test.rb +12 -8
  162. data/test/misc/calculation_test.rb +1 -1
  163. data/test/misc/configurable_test.rb +10 -10
  164. data/test/misc/constraints_test.rb +2 -2
  165. data/test/misc/convert_numbers_format_test.rb +7 -3
  166. data/test/misc/lang_test.rb +1 -1
  167. data/test/misc/parse_datetime_test.rb +3 -4
  168. data/test/misc/tableless_test.rb +6 -0
  169. data/test/mock_app/Rakefile +1 -1
  170. data/test/mock_app/app/assets/config/manifest.js +0 -0
  171. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  172. data/test/mock_app/app/controllers/people_controller.rb +3 -1
  173. data/test/mock_app/config/application.rb +2 -1
  174. data/test/mock_app/config/boot.rb +1 -1
  175. data/test/mock_app/config/environment.rb +2 -2
  176. data/test/mock_app/config/routes.rb +4 -1
  177. data/test/mock_app/db/schema.rb +2 -0
  178. data/test/performance/list_cars_performance_test.rb +34 -0
  179. data/test/performance/list_people_performance_test.rb +31 -0
  180. data/test/performance_test_help.rb +3 -0
  181. data/test/test_helper.rb +10 -2
  182. metadata +55 -20
  183. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  184. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -10,7 +10,7 @@ module ActiveScaffold
10
10
  else
11
11
  attachment.name
12
12
  end
13
- link_to(content, dragonfly_url_for_attachment(attachment, record, column), :target => '_blank')
13
+ link_to(content, dragonfly_url_for_attachment(attachment, record, column), :target => '_blank', rel: 'noopener noreferrer')
14
14
  end
15
15
 
16
16
  def dragonfly_url_for_attachment(attachment, record, column)
@@ -33,7 +33,7 @@ class ActiveScaffold::Bridges::FileColumn
33
33
  # set null to false so active_scaffold wont set it to null
34
34
  # delete_file_column will take care of deleting a file or not.
35
35
  _columns_hash[field.to_s].instance_variable_set('@null', false)
36
- rescue
36
+ rescue StandardError
37
37
  false
38
38
  end
39
39
  end
@@ -9,7 +9,7 @@ module ActiveScaffold
9
9
 
10
10
  def generate_delete_helpers(klass)
11
11
  file_column_fields(klass).each do |field|
12
- klass.send :class_eval, <<-EOF, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"#{field}_with_delete=")
12
+ klass.send :class_eval, <<-CODE, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"#{field}_with_delete=")
13
13
  attr_reader :delete_#{field}
14
14
 
15
15
  def delete_#{field}=(value)
@@ -19,7 +19,7 @@ module ActiveScaffold
19
19
  # passing nil to the file column causes the file to be deleted. Don't delete if we just uploaded a file!
20
20
  self.#{field} = nil unless self.#{field}_just_uploaded?
21
21
  end
22
- EOF
22
+ CODE
23
23
  end
24
24
  end
25
25
 
@@ -41,7 +41,7 @@ module ActiveScaffold
41
41
  versions = options[:magick][:versions]
42
42
  raise unless versions.stringify_keys[version]
43
43
  true
44
- rescue
44
+ rescue StandardError
45
45
  false
46
46
  end
47
47
 
@@ -18,9 +18,9 @@ module ActiveScaffold
18
18
 
19
19
  content_tag(:div) do
20
20
  content_tag(:div) do
21
- get_column_value(record, column) + " #{custom_hidden_field_tag} | ".html_safe <<
22
- content_tag(:a, as_(:remove_file), :href => '#', :onclick => remove_file_js) <<
23
- content_tag(:div, file_column_field('record', column.name, options), :style => 'display: none')
21
+ safe_join [get_column_value(record, column), custom_hidden_field_tag, '|',
22
+ content_tag(:a, as_(:remove_file), :href => '#', :onclick => remove_file_js),
23
+ content_tag(:div, 'test', :style => 'display: none')], ' '
24
24
  end
25
25
  end
26
26
  else
@@ -1,14 +1,17 @@
1
- require File.join(File.dirname(__FILE__), '../test_helper.rb')
1
+ require 'test_helper'
2
+ require File.expand_path('../mock_model.rb', __dir__)
3
+ require File.expand_path('../../file_column_helpers.rb', __dir__)
2
4
 
3
- class DeleteFileColumnTest < Test::Unit::TestCase
5
+ class DeleteFileColumnTest < MiniTest::Test
4
6
  def setup
5
- DeleteFileColumn.generate_delete_helpers(MockModel)
7
+ MockModel.extend ActiveScaffold::Bridges::FileColumn::FileColumnHelpers
8
+ ActiveScaffold::Bridges::FileColumn::FileColumnHelpers.generate_delete_helpers(MockModel)
6
9
  @model = MockModel.new
7
10
  @model.band_image = 'coolio.jpg'
8
11
  end
9
12
 
10
13
  def test__file_column_fields
11
- assert_equal(1, @model.file_column_fields.length)
14
+ assert_equal(1, @model.class.file_column_fields.length)
12
15
  end
13
16
 
14
17
  def test__delete_band_image__boolean__should_delete
@@ -23,17 +26,17 @@ class DeleteFileColumnTest < Test::Unit::TestCase
23
26
 
24
27
  def test__delete_band_image__boolean_false__shouldnt_delete
25
28
  @model.delete_band_image = false
26
- assert_not_nil @model.band_image
29
+ refute_nil @model.band_image
27
30
  end
28
31
 
29
32
  def test__delete_band_image__string_false__shouldnt_delete
30
33
  @model.delete_band_image = 'false'
31
- assert_not_nil @model.band_image
34
+ refute_nil @model.band_image
32
35
  end
33
36
 
34
37
  def test__just_uploaded__shouldnt_delete
35
38
  @model.band_image_just_uploaded = true
36
39
  @model.delete_band_image = 'true'
37
- assert_not_nil(@model.band_image)
40
+ refute_nil(@model.band_image)
38
41
  end
39
42
  end
@@ -7,6 +7,6 @@ class ActiveScaffold::Bridges::PaperTrail < ActiveScaffold::DataStructures::Brid
7
7
  end
8
8
 
9
9
  def self.prepare
10
- ActionDispatch::Routing::ACTIVE_SCAFFOLD_CORE_ROUTING[:collection][:deleted] = :get
10
+ ActiveScaffold::Routing::ACTIVE_SCAFFOLD_CORE_ROUTING[:collection][:deleted] = :get
11
11
  end
12
12
  end
@@ -11,7 +11,9 @@ module ActiveScaffold::Actions
11
11
 
12
12
  def deleted
13
13
  query = PaperTrail::Version.destroys.where(:item_type => active_scaffold_config.model)
14
- query = query.where_object(nested.child_association.foreign_key => nested.parent_id) if nested? && nested.child_association.belongs_to? && PaperTrail::Version.respond_to?(:where_object)
14
+ if nested? && nested.child_association&.belongs_to? && PaperTrail::Version.respond_to?(:where_object)
15
+ query = query.where_object(nested.child_association.foreign_key => nested.parent_id)
16
+ end
15
17
  pager = Paginator.new(query.count, active_scaffold_config.list.per_page) do |offset, per_page|
16
18
  query.offset(offset).limit(per_page).map(&:reify)
17
19
  end
@@ -6,7 +6,7 @@ module ActiveScaffold
6
6
  return nil unless paperclip.file?
7
7
  content =
8
8
  if paperclip.styles.include?(ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.thumbnail_style)
9
- image_tag(paperclip.url(ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.thumbnail_style), :border => 0)
9
+ image_tag(paperclip.url(ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.thumbnail_style), :border => 0, :alt => nil)
10
10
  else
11
11
  paperclip.original_filename
12
12
  end
@@ -9,7 +9,7 @@ module ActiveScaffold
9
9
  update.multipart = true
10
10
  create.multipart = true
11
11
 
12
- model.attachment_definitions.keys.each do |field|
12
+ model.attachment_definitions.each_key do |field|
13
13
  configure_paperclip_field(field.to_sym)
14
14
  # define the "delete" helper for use with active scaffold, unless it's already defined
15
15
  ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.generate_delete_helper(model, field)
@@ -6,7 +6,7 @@ module ActiveScaffold
6
6
  self.thumbnail_style = :thumbnail
7
7
 
8
8
  def self.generate_delete_helper(klass, field)
9
- klass.class_eval <<-EOF, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"delete_#{field}=")
9
+ klass.class_eval <<-CODE, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"delete_#{field}=")
10
10
  attr_reader :delete_#{field}
11
11
 
12
12
  def delete_#{field}=(value)
@@ -16,7 +16,7 @@ module ActiveScaffold
16
16
  # passing nil to the file column causes the file to be deleted. Don't delete if we just uploaded a file!
17
17
  self.#{field} = nil unless self.#{field}.dirty?
18
18
  end
19
- EOF
19
+ CODE
20
20
  end
21
21
  end
22
22
  end
@@ -1,21 +1,23 @@
1
+ require 'active_support/concern'
2
+
1
3
  class ActiveScaffold::Bridges::RecordSelect
2
4
  module Helpers
3
- def self.included(base)
4
- base.class_eval do
5
- include FormColumnHelpers
6
- include SearchColumnHelpers
7
- end
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ include FormColumnHelpers
8
+ include SearchColumnHelpers
8
9
  end
9
10
 
10
11
  module FormColumnHelpers
11
12
  # requires RecordSelect plugin to be installed and configured.
12
13
  def active_scaffold_input_record_select(column, options)
13
14
  record = options.delete(:object)
14
- if column.association.try(:singular?)
15
- multiple = false
16
- multiple = column.options[:html_options][:multiple] if column.options[:html_options] && column.options[:html_options][:multiple]
17
- active_scaffold_record_select(record, column, options, record.send(column.name), multiple)
18
- elsif column.association.try(:collection?)
15
+ if column.association&.singular?
16
+ multiple = column.options.dig(:html_options, :multiple)
17
+ html = active_scaffold_record_select(record, column, options, record.send(column.name), multiple)
18
+ html << active_scaffold_new_record_subform(column, record, options) if column.options[:add_new]
19
+ html
20
+ elsif column.association&.collection?
19
21
  active_scaffold_record_select(record, column, options, record.send(column.name), true)
20
22
  else
21
23
  active_scaffold_record_select_autocomplete(record, column, options)
@@ -24,14 +26,10 @@ class ActiveScaffold::Bridges::RecordSelect
24
26
 
25
27
  def active_scaffold_record_select(record, column, options, value, multiple)
26
28
  unless column.association
27
- raise ArgumentError, "record_select can only work against associations (and #{column.name} is not). A common mistake is to specify the foreign key field (like :user_id), instead of the association (:user)."
29
+ raise ArgumentError, "record_select can only work against associations (and #{column.name} is not). "\
30
+ 'A common mistake is to specify the foreign key field (like :user_id), instead of the association (:user).'
28
31
  end
29
- klass =
30
- if column.association.polymorphic?
31
- record.send(column.association.foreign_type).constantize rescue nil
32
- else
33
- column.association.klass
34
- end
32
+ klass = column.association.klass(record)
35
33
  return content_tag :span, '', :class => options[:class] unless klass
36
34
 
37
35
  remote_controller = active_scaffold_controller_for(klass).controller_path
@@ -12,7 +12,7 @@ module ActiveScaffold
12
12
  tags << active_scaffold_search_date_bridge_trend_tag(column, options, current_search)
13
13
  tags << active_scaffold_search_date_bridge_numeric_tag(column, options, current_search)
14
14
  tags << active_scaffold_search_date_bridge_range_tag(column, options, current_search)
15
- safe_join tags, '&nbsp;'.html_safe
15
+ safe_join tags, '&nbsp;'.html_safe # rubocop:disable Rails/OutputSafety
16
16
  end
17
17
 
18
18
  def active_scaffold_search_date_bridge_comparator_options(column)
@@ -21,17 +21,18 @@ module ActiveScaffold
21
21
  end
22
22
 
23
23
  def active_scaffold_search_date_bridge_comparator_tag(column, options, current_search)
24
- select_tag("#{options[:name]}[opt]", options_for_select(active_scaffold_search_date_bridge_comparator_options(column), current_search['opt']), :id => "#{options[:id]}_opt", :class => 'as_search_range_option as_search_date_time_option')
24
+ choices = options_for_select(active_scaffold_search_date_bridge_comparator_options(column), current_search['opt'])
25
+ select_tag("#{options[:name]}[opt]", choices, :id => "#{options[:id]}_opt", :class => 'as_search_range_option as_search_date_time_option')
25
26
  end
26
27
 
27
28
  def active_scaffold_search_date_bridge_numeric_tag(column, options, current_search)
28
- numeric_controls =
29
- '' <<
30
- active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'from') <<
31
- content_tag(:span, (' - ' + active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'to')).html_safe,
29
+ numeric_controls = [
30
+ active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'from'),
31
+ content_tag(:span, safe_join([' - ', active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'to')]),
32
32
  :id => "#{options[:id]}_between", :class => 'as_search_range_between',
33
33
  :style => current_search['opt'] == 'BETWEEN' ? nil : 'display: none')
34
- content_tag('span', numeric_controls.html_safe,
34
+ ]
35
+ content_tag('span', safe_join(numeric_controls),
35
36
  :id => "#{options[:id]}_numeric", :class => 'search-date-numeric',
36
37
  :style => ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(current_search['opt']) ? nil : 'display: none')
37
38
  end
@@ -44,12 +45,13 @@ module ActiveScaffold
44
45
  end
45
46
 
46
47
  def active_scaffold_date_bridge_trend_tag(column, options, trend_options)
47
- trend_controls =
48
- text_field_tag("#{options[:name]}[number]", trend_options[:number_value], :class => 'text-input', :size => 10, :autocomplete => 'off') << ' ' <<
48
+ trend_controls = [
49
+ text_field_tag("#{options[:name]}[number]", trend_options[:number_value], :class => 'text-input', :size => 10, :autocomplete => 'off'),
49
50
  select_tag("#{options[:name]}[unit]",
50
51
  options_for_select(active_scaffold_search_date_bridge_trend_units(column), trend_options[:unit_value]),
51
52
  :class => 'text-input')
52
- content_tag('span', trend_controls.html_safe,
53
+ ]
54
+ content_tag('span', safe_join(trend_controls, ' '),
53
55
  :id => "#{options[:id]}_trend", :class => 'search-date-trend',
54
56
  :style => trend_options[:show] ? nil : 'display: none')
55
57
  end
@@ -61,12 +63,13 @@ module ActiveScaffold
61
63
  end
62
64
 
63
65
  def active_scaffold_search_date_bridge_range_tag(column, options, current_search)
66
+ values = ActiveScaffold::Finder::DATE_RANGES.collect { |range| [as_(range.downcase.to_sym), range] }
64
67
  range_controls = select_tag("#{options[:name]}[range]",
65
- options_for_select(ActiveScaffold::Finder::DATE_RANGES.collect { |range| [as_(range.downcase.to_sym), range] }, current_search['range']),
68
+ options_for_select(values, current_search['range']),
66
69
  :class => 'text-input', :id => nil)
67
- content_tag('span', range_controls.html_safe,
70
+ content_tag('span', range_controls,
68
71
  :id => "#{options[:id]}_range", :class => 'search-date-range',
69
- :style => (current_search['opt'] == 'RANGE') ? nil : 'display: none')
72
+ :style => ('display: none' unless current_search['opt'] == 'RANGE'))
70
73
  end
71
74
 
72
75
  def column_datetime?(column)
@@ -80,7 +83,7 @@ module ActiveScaffold
80
83
  when 'RANGE'
81
84
  range_type, range = value['range'].downcase.split('_')
82
85
  format = active_scaffold_human_condition_date_bridge_range_format(range_type, range)
83
- from, to = controller.class.date_bridge_from_to(column, value)
86
+ from, = controller.class.date_bridge_from_to(column, value)
84
87
  "#{column.active_record_class.human_attribute_name(column.name)} = #{as_(value['range'].downcase).downcase} (#{I18n.l(from, :format => format)})"
85
88
  when 'PAST', 'FUTURE'
86
89
  from, to = controller.class.date_bridge_from_to(column, value)
@@ -118,12 +121,10 @@ module ActiveScaffold
118
121
 
119
122
  if column.search_sql.is_a? Proc
120
123
  column.search_sql.call(from_value, to_value, operator)
124
+ elsif operator.nil?
125
+ ['%<search_sql>s BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)] unless from_value.nil? || to_value.nil?
121
126
  else
122
- if operator.nil?
123
- ['%{search_sql} BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)] unless from_value.nil? || to_value.nil?
124
- else
125
- ["%{search_sql} #{value['opt']} ?", from_value.to_s(:db)] unless from_value.nil?
126
- end
127
+ ["%<search_sql>s #{value['opt']} ?", from_value.to_s(:db)] unless from_value.nil?
127
128
  end
128
129
  end
129
130
 
@@ -24,7 +24,9 @@ class ActiveScaffold::Bridges::TinyMce
24
24
 
25
25
  html = []
26
26
  html << send(override_input(:textarea), column, options)
27
- html << javascript_tag("tinyMCE.settings = #{settings.to_json}; tinyMCE.execCommand('mceAddEditor', false, '#{options[:id]}');") if ActiveScaffold.js_framework == :prototype && (request.xhr? || params[:iframe])
27
+ if ActiveScaffold.js_framework == :prototype && (request.xhr? || params[:iframe])
28
+ html << javascript_tag("tinyMCE.settings = #{settings.to_json}; tinyMCE.execCommand('mceAddEditor', false, '#{options[:id]}');")
29
+ end
28
30
  safe_join html
29
31
  end
30
32
 
@@ -23,7 +23,7 @@ module ActiveScaffold::Bridges
23
23
  options_for_select([])
24
24
  end
25
25
 
26
- state_options += if priority_states && priority_states.include?(selected)
26
+ state_options += if priority_states&.include?(selected)
27
27
  options_for_select(USASTATES - priority_states, :selected => selected)
28
28
  else
29
29
  options_for_select(USASTATES, :selected => selected)
@@ -32,15 +32,32 @@ module ActiveScaffold::Bridges
32
32
  state_options
33
33
  end
34
34
 
35
- USASTATES = [%w[Alabama AL], %w[Alaska AK], %w[Arizona AZ], %w[Arkansas AR], %w[California CA], %w[Colorado CO], %w[Connecticut CT], %w[Delaware DE], ['District of Columbia', 'DC'], %w[Florida FL], %w[Georgia GA], %w[Hawaii HI], %w[Idaho ID], %w[Illinois IL], %w[Indiana IN], %w[Iowa IA], %w[Kansas KS], %w[Kentucky KY], %w[Louisiana LA], %w[Maine ME], %w[Maryland MD], %w[Massachusetts MA], %w[Michigan MI], %w[Minnesota MN], %w[Mississippi MS], %w[Missouri MO], %w[Montana MT], %w[Nebraska NE], %w[Nevada NV], ['New Hampshire', 'NH'], ['New Jersey', 'NJ'], ['New Mexico', 'NM'], ['New York', 'NY'], ['North Carolina', 'NC'], ['North Dakota', 'ND'], %w[Ohio OH], %w[Oklahoma OK], %w[Oregon OR], %w[Pennsylvania PA], ['Rhode Island', 'RI'], ['South Carolina', 'SC'], ['South Dakota', 'SD'], %w[Tennessee TN], %w[Texas TX], %w[Utah UT], %w[Vermont VT], %w[Virginia VA], %w[Washington WA], %w[Wisconsin WI], ['West Virginia', 'WV'], %w[Wyoming WY]].freeze unless const_defined?('USASTATES')
35
+ unless const_defined?('USASTATES')
36
+ USASTATES = [
37
+ %w[Alabama AL], %w[Alaska AK], %w[Arizona AZ], %w[Arkansas AR], %w[California CA], %w[Colorado CO],
38
+ %w[Connecticut CT], %w[Delaware DE], ['District of Columbia', 'DC'], %w[Florida FL], %w[Georgia GA],
39
+ %w[Hawaii HI], %w[Idaho ID], %w[Illinois IL], %w[Indiana IN], %w[Iowa IA], %w[Kansas KS], %w[Kentucky KY],
40
+ %w[Louisiana LA], %w[Maine ME], %w[Maryland MD], %w[Massachusetts MA], %w[Michigan MI], %w[Minnesota MN],
41
+ %w[Mississippi MS], %w[Missouri MO], %w[Montana MT], %w[Nebraska NE], %w[Nevada NV],
42
+ ['New Hampshire', 'NH'], ['New Jersey', 'NJ'], ['New Mexico', 'NM'], ['New York', 'NY'],
43
+ ['North Carolina', 'NC'], ['North Dakota', 'ND'], %w[Ohio OH], %w[Oklahoma OK], %w[Oregon OR],
44
+ %w[Pennsylvania PA], ['Rhode Island', 'RI'], ['South Carolina', 'SC'], ['South Dakota', 'SD'],
45
+ %w[Tennessee TN], %w[Texas TX], %w[Utah UT], %w[Vermont VT], %w[Virginia VA], %w[Washington WA],
46
+ %w[Wisconsin WI], ['West Virginia', 'WV'], %w[Wyoming WY]
47
+ ].freeze
48
+ end
36
49
  end
37
50
 
38
51
  module InstanceTagMethods
39
52
  def to_usa_state_select_tag(priority_states, options, html_options)
40
53
  html_options = html_options.stringify_keys
41
54
  add_default_name_and_id(html_options)
42
- value = value(object)
43
- selected_value = options.key?(:selected) ? options[:selected] : value
55
+ selected_value =
56
+ if options.key?(:selected)
57
+ options[:selected]
58
+ else
59
+ method(:value).parameters.any? ? value(object) : value
60
+ end
44
61
  content_tag('select', add_options(usa_state_options_for_select(selected_value, priority_states), options, selected_value), html_options)
45
62
  end
46
63
  end
@@ -2,6 +2,7 @@ module ActiveScaffold::Config
2
2
  class Base
3
3
  include ActiveScaffold::Configurable
4
4
  extend ActiveScaffold::Configurable
5
+ NO_FORMATS = [].freeze
5
6
 
6
7
  def initialize(core_config)
7
8
  @core = core_config
@@ -9,7 +10,13 @@ module ActiveScaffold::Config
9
10
 
10
11
  # start with the ActionLink defined globally
11
12
  @link = self.class.link.clone if self.class.respond_to?(:link) && self.class.link
13
+ setup_user_setting_key
12
14
  end
15
+
16
+ def setup_user_setting_key
17
+ @user_settings_key = :"#{model_id}_#{self.class.name.underscore}"
18
+ end
19
+
13
20
  attr_reader :core
14
21
 
15
22
  def self.inherited(subclass)
@@ -37,8 +44,20 @@ module ActiveScaffold::Config
37
44
  @label.nil? ? model : as_(@label, :model => model)
38
45
  end
39
46
 
47
+ def model_id
48
+ (core || self).model_id
49
+ end
50
+
51
+ attr_reader :user_settings_key
52
+
40
53
  # the user property gets set to the instantiation of the local UserSettings class during the automatic instantiation of this class.
41
- attr_accessor :user
54
+ def user
55
+ ActiveScaffold::Registry.user_settings[user_settings_key]
56
+ end
57
+
58
+ def new_user_settings(storage, params)
59
+ ActiveScaffold::Registry.user_settings[user_settings_key] = self.class::UserSettings.new(self, storage, params)
60
+ end
42
61
 
43
62
  # define a default action_group for this action
44
63
  # e.g. 'members.crud'
@@ -47,10 +66,39 @@ module ActiveScaffold::Config
47
66
  # action_group this action should belong to
48
67
  attr_accessor :action_group
49
68
 
69
+ def formats
70
+ return @formats || NO_FORMATS if frozen?
71
+ @formats ||= NO_FORMATS.dup
72
+ end
73
+ attr_writer :formats
74
+
50
75
  class UserSettings
76
+ # define setter and getter for names
77
+ # values will be saved for current request only
78
+ # getter will return value set with setter, or value from conf
79
+ def self.user_attr(*names)
80
+ attr_writer(*names)
81
+ names.each do |name|
82
+ define_method(name) do
83
+ instance_variable_defined?("@#{name}") ? instance_variable_get("@#{name}") : @conf.send(name)
84
+ end
85
+ end
86
+ end
87
+
88
+ # define setter and getter for names
89
+ # values will be saved in session if store_user_settings is enabled,
90
+ # in other case for current request only
91
+ # getter will return value set with setter, or value from conf
92
+ def self.session_attr(*names)
93
+ names.each do |name|
94
+ define_method(name) { |value| self[name] = value }
95
+ define_method(name) { key?(name) ? self[name] : @conf.send(name) }
96
+ end
97
+ end
98
+
51
99
  def initialize(conf, storage, params, action = :base)
52
100
  # the session hash relevant to this action
53
- @session = storage
101
+ @storage = storage
54
102
  # all the request params
55
103
  @params = params
56
104
  # the configuration object for this action
@@ -58,71 +106,115 @@ module ActiveScaffold::Config
58
106
  @action = action.to_s
59
107
  end
60
108
 
109
+ def user
110
+ self
111
+ end
112
+
113
+ def core
114
+ @conf.core.user
115
+ end
116
+
61
117
  def [](key)
62
- @session[@action][key] if @action && @session[@action]
118
+ @storage[@action][key.to_s] if @action && @storage[@action]
63
119
  end
64
120
 
65
121
  def []=(key, value)
66
- @session[@action] ||= {}
67
- if value
68
- @session[@action][key] = value
122
+ @storage[@action] ||= {}
123
+ if value.present?
124
+ @storage[@action][key.to_s] = value
69
125
  else
70
- @session[@action].delete key
71
- @session.delete @action if @session[@action].empty?
126
+ @storage[@action].delete key.to_s
127
+ @storage.delete @action if @storage[@action].empty?
72
128
  end
73
129
  end
74
- end
75
130
 
76
- def formats
77
- @formats ||= []
131
+ def key?(key)
132
+ @storage[@action].key? key.to_s if @action && @storage[@action]
133
+ end
134
+
135
+ def method_missing(name, *args)
136
+ proxy_to_conf?(name, true) ? @conf.send(name, *args) : super
137
+ end
138
+
139
+ def respond_to_missing?(name, include_all = false)
140
+ proxy_to_conf?(name, include_all) || super
141
+ end
142
+
143
+ def proxy_to_conf?(name, include_all)
144
+ name !~ /=$/ && @conf.respond_to?(name, include_all)
145
+ end
146
+
147
+ private
148
+
149
+ def proxy_columns(columns)
150
+ proxy = ::CowProxy.wrap(columns)
151
+ proxy.action = self
152
+ proxy
153
+ end
78
154
  end
79
- attr_writer :formats
80
155
 
81
156
  private
82
157
 
83
158
  def build_action_columns(val)
84
- columns =
85
- if val.is_a?(ActiveScaffold::DataStructures::ActionColumns)
86
- val.dup
159
+ @core.build_action_columns self, val
160
+ end
161
+
162
+ class_attribute :columns_collections
163
+
164
+ def self.columns_writer(name)
165
+ var = "@#{name}"
166
+ define_method "#{name}=" do |val|
167
+ if instance_variable_defined?(var)
168
+ instance_variable_get(var).set_values(*val)
169
+ instance_variable_get(var)
87
170
  else
88
- ActiveScaffold::DataStructures::ActionColumns.new(*val)
171
+ instance_variable_set(var, build_action_columns(val))
172
+ end
173
+ end
174
+ end
175
+
176
+ def self.columns_reader(name, options, &block)
177
+ var = "@#{name}"
178
+ define_method name do
179
+ unless instance_variable_defined?(var) # lazy evaluation
180
+ action, columns = options[:copy] if options[:copy]
181
+ if action && @core.actions.include?(action)
182
+ action_columns = @core.send(action).send(columns || :columns).clone
183
+ action_columns.action = self
184
+ instance_variable_set(var, action_columns)
185
+ else
186
+ send("#{name}=", @core.columns._inheritable)
187
+ end
188
+ instance_exec(&block) if block
89
189
  end
90
- columns.action = self
91
- columns.set_columns(@core.columns)
92
- columns
190
+ instance_variable_get(var)
191
+ end
93
192
  end
94
193
 
95
194
  def self.columns_accessor(*names, &block)
96
195
  options = names.extract_options!
196
+ self.columns_collections = ((columns_collections || []) + names).uniq
97
197
  names.each do |name|
98
- var = "@#{name}"
99
- define_method "#{name}=" do |val|
100
- if instance_variable_defined?(var)
101
- instance_variable_get(var).set_values(*val)
102
- else
103
- instance_variable_set(var, build_action_columns(val))
104
- end
105
- instance_variable_get(var)
198
+ columns_writer name
199
+ columns_reader name, options, &block unless method_defined? name
200
+
201
+ if self::UserSettings == ActiveScaffold::Config::Base::UserSettings
202
+ const_set 'UserSettings', Class.new(ActiveScaffold::Config::Base::UserSettings)
106
203
  end
107
204
 
108
- return if method_defined? name
109
- define_method name do
110
- unless instance_variable_defined?(var) # lazy evaluation
111
- action, columns = options[:copy] if options[:copy]
112
- if action && @core.actions.include?(action)
113
- action_columns = @core.send(action).send(columns || :columns).clone
114
- action_columns.action = self
115
- instance_variable_set(var, action_columns)
116
- else
117
- send("#{name}=", @core.columns._inheritable)
118
- end
119
- instance_exec(&block) if block
205
+ var = "@#{name}"
206
+ self::UserSettings.class_eval do
207
+ define_method "#{name}=" do |val|
208
+ instance_variable_set var, proxy_columns(build_action_columns(val))
209
+ end
210
+ define_method name do
211
+ instance_variable_get(var) ||
212
+ instance_variable_set(var, proxy_columns(@conf.send(name)))
120
213
  end
121
- instance_variable_get(var)
122
214
  end
123
215
  end
124
216
  end
125
217
 
126
- private_class_method :columns_accessor
218
+ private_class_method :columns_accessor, :columns_reader, :columns_writer
127
219
  end
128
220
  end