active_scaffold 3.5.5 → 3.6.1

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 (192) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +75 -0
  3. data/README.md +21 -10
  4. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  5. data/app/assets/javascripts/jquery/active_scaffold.js +98 -7
  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 +26 -10
  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 +2 -1
  63. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  64. data/lib/active_scaffold/bridges/bitfields/list_ui.rb +19 -0
  65. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
  66. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +3 -12
  67. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
  68. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  69. data/lib/active_scaffold/bridges/chosen/helpers.rb +7 -6
  70. data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
  71. data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
  72. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  73. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  74. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
  75. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  76. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
  77. data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
  78. data/lib/active_scaffold/bridges/paper_trail/actions.rb +3 -1
  79. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  80. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
  81. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  82. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -17
  83. data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
  84. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  85. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
  86. data/lib/active_scaffold/config/base.rb +133 -41
  87. data/lib/active_scaffold/config/core.rb +146 -18
  88. data/lib/active_scaffold/config/delete.rb +14 -1
  89. data/lib/active_scaffold/config/field_search.rb +7 -1
  90. data/lib/active_scaffold/config/form.rb +10 -1
  91. data/lib/active_scaffold/config/list.rb +39 -13
  92. data/lib/active_scaffold/config/mark.rb +4 -2
  93. data/lib/active_scaffold/config/nested.rb +16 -17
  94. data/lib/active_scaffold/config/search.rb +9 -0
  95. data/lib/active_scaffold/config/show.rb +4 -0
  96. data/lib/active_scaffold/config/update.rb +4 -0
  97. data/lib/active_scaffold/configurable.rb +14 -7
  98. data/lib/active_scaffold/constraints.rb +22 -20
  99. data/lib/active_scaffold/core.rb +67 -28
  100. data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
  101. data/lib/active_scaffold/data_structures/action_link.rb +50 -20
  102. data/lib/active_scaffold/data_structures/action_links.rb +15 -13
  103. data/lib/active_scaffold/data_structures/association/abstract.rb +38 -15
  104. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  105. data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
  106. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  107. data/lib/active_scaffold/data_structures/column.rb +75 -66
  108. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  109. data/lib/active_scaffold/data_structures/nested_info.rb +33 -19
  110. data/lib/active_scaffold/data_structures/set.rb +8 -0
  111. data/lib/active_scaffold/data_structures/sorting.rb +10 -2
  112. data/lib/active_scaffold/delayed_setup.rb +16 -5
  113. data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
  114. data/lib/active_scaffold/extensions/action_view_rendering.rb +93 -32
  115. data/lib/active_scaffold/extensions/cow_proxy.rb +95 -0
  116. data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
  117. data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
  118. data/lib/active_scaffold/extensions/localize.rb +3 -1
  119. data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
  120. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  121. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
  122. data/lib/active_scaffold/finder.rb +110 -77
  123. data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
  124. data/lib/active_scaffold/helpers/association_helpers.rb +18 -16
  125. data/lib/active_scaffold/helpers/controller_helpers.rb +34 -10
  126. data/lib/active_scaffold/helpers/form_column_helpers.rb +196 -124
  127. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  128. data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
  129. data/lib/active_scaffold/helpers/list_column_helpers.rb +90 -57
  130. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  131. data/lib/active_scaffold/helpers/search_column_helpers.rb +43 -41
  132. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  133. data/lib/active_scaffold/helpers/view_helpers.rb +39 -36
  134. data/lib/active_scaffold/marked_model.rb +2 -2
  135. data/lib/active_scaffold/orm_checks.rb +3 -7
  136. data/lib/active_scaffold/paginator.rb +7 -7
  137. data/lib/active_scaffold/registry.rb +33 -0
  138. data/lib/active_scaffold/responds_to_parent.rb +8 -11
  139. data/lib/active_scaffold/tableless.rb +83 -67
  140. data/lib/active_scaffold/version.rb +2 -2
  141. data/lib/generators/active_scaffold/controller_generator.rb +2 -2
  142. data/lib/generators/active_scaffold/install_generator.rb +52 -4
  143. data/lib/generators/active_scaffold/resource_generator.rb +2 -2
  144. data/shoulda_macros/macros.rb +3 -1
  145. data/test/bridges/date_picker_test.rb +1 -2
  146. data/test/bridges/paperclip_test.rb +6 -6
  147. data/test/class_with_finder.rb +2 -2
  148. data/test/company.rb +4 -4
  149. data/test/config/create_test.rb +4 -2
  150. data/test/config/nested_test.rb +1 -1
  151. data/test/config/show_test.rb +1 -1
  152. data/test/config/update_test.rb +7 -6
  153. data/test/data_structures/action_columns_test.rb +2 -2
  154. data/test/data_structures/action_links_test.rb +1 -1
  155. data/test/data_structures/column_test.rb +3 -6
  156. data/test/data_structures/columns_test.rb +2 -2
  157. data/test/data_structures/sorting_test.rb +7 -0
  158. data/test/extensions/action_view_rendering_test.rb +20 -0
  159. data/test/extensions/active_record_test.rb +4 -4
  160. data/test/extensions/routing_mapper_test.rb +2 -2
  161. data/test/helpers/list_column_helpers_test.rb +3 -1
  162. data/test/misc/active_record_permissions_test.rb +3 -11
  163. data/test/misc/attribute_params_test.rb +12 -8
  164. data/test/misc/calculation_test.rb +1 -1
  165. data/test/misc/configurable_test.rb +10 -10
  166. data/test/misc/constraints_test.rb +3 -3
  167. data/test/misc/convert_numbers_format_test.rb +7 -3
  168. data/test/misc/lang_test.rb +1 -1
  169. data/test/misc/parse_datetime_test.rb +3 -4
  170. data/test/misc/tableless_test.rb +14 -0
  171. data/test/mock_app/Rakefile +1 -1
  172. data/test/mock_app/app/assets/config/manifest.js +0 -0
  173. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  174. data/test/mock_app/app/controllers/people_controller.rb +5 -1
  175. data/test/mock_app/app/controllers/roles_controller.rb +4 -0
  176. data/test/mock_app/app/views/active_scaffold_overrides/_form.html.erb +2 -0
  177. data/test/mock_app/app/views/active_scaffold_overrides/list.html.erb +2 -0
  178. data/test/mock_app/app/views/people/_first_name_form_column.html.erb +2 -0
  179. data/test/mock_app/app/views/people/_form.html.erb +2 -0
  180. data/test/mock_app/app/views/people/list.html.erb +2 -0
  181. data/test/mock_app/config/application.rb +2 -1
  182. data/test/mock_app/config/boot.rb +1 -1
  183. data/test/mock_app/config/environment.rb +2 -2
  184. data/test/mock_app/config/routes.rb +4 -1
  185. data/test/mock_app/db/schema.rb +2 -0
  186. data/test/performance/list_cars_performance_test.rb +34 -0
  187. data/test/performance/list_people_performance_test.rb +31 -0
  188. data/test/performance_test_help.rb +3 -0
  189. data/test/test_helper.rb +12 -4
  190. metadata +71 -15
  191. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  192. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -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