active_scaffold 3.3.3 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +39 -0
  3. data/README.md +5 -3
  4. data/app/assets/images/active_scaffold/refresh.png +0 -0
  5. data/app/assets/javascripts/jquery/active_scaffold.js +182 -91
  6. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +14 -16
  7. data/app/assets/javascripts/jquery/draggable_lists.js +33 -26
  8. data/app/assets/javascripts/jquery/jquery.editinplace.js +3 -3
  9. data/app/assets/javascripts/prototype/active_scaffold.js +61 -19
  10. data/app/assets/stylesheets/active_scaffold_colors.css.scss +4 -0
  11. data/app/assets/stylesheets/active_scaffold_images.css.scss +3 -0
  12. data/app/assets/stylesheets/active_scaffold_layout.css +23 -2
  13. data/app/views/active_scaffold_overrides/_add_existing_form.html.erb +1 -3
  14. data/app/views/active_scaffold_overrides/_base_form.html.erb +7 -5
  15. data/app/views/active_scaffold_overrides/_field_search.html.erb +1 -2
  16. data/app/views/active_scaffold_overrides/_form.html.erb +6 -4
  17. data/app/views/active_scaffold_overrides/_form_association.html.erb +4 -3
  18. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +5 -5
  19. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +8 -6
  20. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +3 -2
  21. data/app/views/active_scaffold_overrides/_list.html.erb +8 -6
  22. data/app/views/active_scaffold_overrides/_list_column_headings.html.erb +1 -4
  23. data/app/views/active_scaffold_overrides/_list_pagination.html.erb +4 -4
  24. data/app/views/active_scaffold_overrides/_list_pagination_links.html.erb +1 -1
  25. data/app/views/active_scaffold_overrides/_list_record.html.erb +3 -3
  26. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +8 -1
  27. data/app/views/active_scaffold_overrides/_search.html.erb +7 -13
  28. data/app/views/active_scaffold_overrides/_show_columns.html.erb +1 -1
  29. data/app/views/active_scaffold_overrides/on_create.js.erb +4 -4
  30. data/app/views/active_scaffold_overrides/render_field_inplace.html.erb +1 -1
  31. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  32. data/config/locales/de.yml +106 -95
  33. data/config/locales/en.yml +108 -97
  34. data/config/locales/es.yml +109 -98
  35. data/config/locales/fr.yml +108 -97
  36. data/config/locales/hu.yml +109 -98
  37. data/config/locales/ja.yml +100 -89
  38. data/config/locales/ru.yml +115 -104
  39. data/lib/active_scaffold.rb +18 -294
  40. data/lib/active_scaffold/actions/common_search.rb +50 -17
  41. data/lib/active_scaffold/actions/core.rb +93 -22
  42. data/lib/active_scaffold/actions/create.rb +15 -6
  43. data/lib/active_scaffold/actions/field_search.rb +68 -60
  44. data/lib/active_scaffold/actions/list.rb +49 -28
  45. data/lib/active_scaffold/actions/nested.rb +14 -6
  46. data/lib/active_scaffold/actions/search.rb +36 -35
  47. data/lib/active_scaffold/actions/show.rb +9 -4
  48. data/lib/active_scaffold/actions/subform.rb +1 -1
  49. data/lib/active_scaffold/actions/update.rb +22 -7
  50. data/lib/active_scaffold/active_record_permissions.rb +125 -118
  51. data/lib/active_scaffold/attribute_params.rb +84 -66
  52. data/lib/active_scaffold/bridges.rb +3 -3
  53. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +10 -5
  54. data/lib/active_scaffold/bridges/cancan.rb +2 -1
  55. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +13 -2
  56. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +11 -6
  57. data/lib/active_scaffold/bridges/chosen/helpers.rb +2 -2
  58. data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +45 -29
  59. data/lib/active_scaffold/bridges/date_picker/ext.rb +11 -6
  60. data/lib/active_scaffold/bridges/date_picker/helper.rb +5 -1
  61. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +10 -5
  62. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +6 -1
  63. data/lib/active_scaffold/bridges/file_column/form_ui.rb +12 -11
  64. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +14 -6
  65. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  66. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -12
  67. data/lib/active_scaffold/bridges/shared/date_bridge.rb +7 -8
  68. data/lib/active_scaffold/bridges/tiny_mce.rb +5 -3
  69. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +4 -5
  70. data/lib/active_scaffold/config/base.rb +4 -0
  71. data/lib/active_scaffold/config/core.rb +12 -5
  72. data/lib/active_scaffold/config/delete.rb +0 -2
  73. data/lib/active_scaffold/config/field_search.rb +1 -4
  74. data/lib/active_scaffold/config/form.rb +0 -2
  75. data/lib/active_scaffold/config/list.rb +31 -1
  76. data/lib/active_scaffold/config/search.rb +0 -3
  77. data/lib/active_scaffold/config/show.rb +0 -6
  78. data/lib/active_scaffold/config/subform.rb +1 -0
  79. data/lib/active_scaffold/configurable.rb +2 -2
  80. data/lib/active_scaffold/constraints.rb +11 -14
  81. data/lib/active_scaffold/core.rb +277 -0
  82. data/lib/active_scaffold/data_structures/action_columns.rb +18 -2
  83. data/lib/active_scaffold/data_structures/action_link.rb +25 -6
  84. data/lib/active_scaffold/data_structures/action_links.rb +9 -4
  85. data/lib/active_scaffold/data_structures/actions.rb +1 -1
  86. data/lib/active_scaffold/data_structures/column.rb +6 -6
  87. data/lib/active_scaffold/data_structures/columns.rb +2 -2
  88. data/lib/active_scaffold/data_structures/nested_info.rb +5 -1
  89. data/lib/active_scaffold/data_structures/sorting.rb +15 -5
  90. data/lib/active_scaffold/delayed_setup.rb +30 -0
  91. data/lib/active_scaffold/engine.rb +25 -0
  92. data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
  93. data/lib/active_scaffold/extensions/left_outer_joins.rb +61 -21
  94. data/lib/active_scaffold/extensions/localize.rb +1 -1
  95. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +13 -8
  96. data/lib/active_scaffold/extensions/paginator_extensions.rb +5 -1
  97. data/lib/active_scaffold/extensions/reverse_associations.rb +1 -0
  98. data/lib/active_scaffold/extensions/routing_mapper.rb +1 -1
  99. data/lib/active_scaffold/extensions/unsaved_record.rb +4 -6
  100. data/lib/active_scaffold/finder.rb +79 -27
  101. data/lib/active_scaffold/helpers/association_helpers.rb +48 -18
  102. data/lib/active_scaffold/helpers/controller_helpers.rb +19 -10
  103. data/lib/active_scaffold/helpers/form_column_helpers.rb +185 -87
  104. data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -1
  105. data/lib/active_scaffold/helpers/id_helpers.rb +14 -8
  106. data/lib/active_scaffold/helpers/list_column_helpers.rb +65 -56
  107. data/lib/active_scaffold/helpers/pagination_helpers.rb +5 -1
  108. data/lib/active_scaffold/helpers/search_column_helpers.rb +21 -18
  109. data/lib/active_scaffold/helpers/view_helpers.rb +102 -64
  110. data/lib/active_scaffold/responds_to_parent.rb +39 -64
  111. data/lib/active_scaffold/tableless.rb +129 -10
  112. data/lib/active_scaffold/version.rb +2 -2
  113. data/test/bridges/bridge_test.rb +1 -1
  114. data/test/bridges/date_picker_test.rb +2 -2
  115. data/test/bridges/paperclip_test.rb +10 -8
  116. data/test/bridges/tiny_mce_test.rb +2 -2
  117. data/test/company.rb +22 -10
  118. data/test/config/base_test.rb +1 -1
  119. data/test/config/core_test.rb +8 -6
  120. data/test/config/create_test.rb +6 -6
  121. data/test/config/delete_test.rb +4 -4
  122. data/test/config/field_search_test.rb +6 -6
  123. data/test/config/list_test.rb +7 -7
  124. data/test/config/nested_test.rb +8 -7
  125. data/test/config/search_test.rb +7 -7
  126. data/test/config/show_test.rb +5 -5
  127. data/test/config/subform_test.rb +1 -1
  128. data/test/config/update_test.rb +5 -4
  129. data/test/data_structures/action_columns_test.rb +15 -16
  130. data/test/data_structures/action_link_test.rb +10 -10
  131. data/test/data_structures/action_links_test.rb +6 -6
  132. data/test/data_structures/actions_test.rb +4 -4
  133. data/test/data_structures/association_column_test.rb +4 -4
  134. data/test/data_structures/column_test.rb +9 -9
  135. data/test/data_structures/columns_test.rb +7 -7
  136. data/test/data_structures/error_message_test.rb +2 -4
  137. data/test/data_structures/set_test.rb +13 -13
  138. data/test/data_structures/sorting_test.rb +8 -8
  139. data/test/data_structures/standard_column_test.rb +2 -2
  140. data/test/data_structures/validation_reflection_test.rb +8 -8
  141. data/test/data_structures/virtual_column_test.rb +5 -5
  142. data/test/extensions/active_record_test.rb +1 -1
  143. data/test/helpers/form_column_helpers_test.rb +5 -5
  144. data/test/helpers/list_column_helpers_test.rb +2 -1
  145. data/test/helpers/pagination_helpers_test.rb +1 -1
  146. data/test/misc/active_record_permissions_test.rb +23 -4
  147. data/test/misc/attribute_params_test.rb +304 -136
  148. data/test/misc/calculation_test.rb +55 -0
  149. data/test/misc/configurable_test.rb +22 -21
  150. data/test/misc/constraints_test.rb +10 -7
  151. data/test/misc/convert_numbers_format_test.rb +149 -0
  152. data/test/misc/finder_test.rb +17 -13
  153. data/test/misc/lang_test.rb +1 -1
  154. data/test/misc/tableless_test.rb +18 -0
  155. data/test/mock_app/app/controllers/addresses_controller.rb +4 -0
  156. data/test/mock_app/app/controllers/buildings_controller.rb +4 -0
  157. data/test/mock_app/app/controllers/cars_controller.rb +4 -0
  158. data/test/mock_app/app/controllers/contacts_controller.rb +4 -0
  159. data/test/mock_app/app/controllers/floors_controller.rb +6 -0
  160. data/test/mock_app/app/controllers/people_controller.rb +4 -0
  161. data/test/mock_app/app/models/address.rb +3 -0
  162. data/test/mock_app/app/models/building.rb +8 -0
  163. data/test/mock_app/app/models/car.rb +3 -0
  164. data/test/mock_app/app/models/contact.rb +3 -0
  165. data/test/mock_app/app/models/file_model.rb +19 -0
  166. data/test/mock_app/app/models/floor.rb +8 -0
  167. data/test/mock_app/app/models/person.rb +11 -0
  168. data/test/mock_app/config/application.rb +2 -0
  169. data/test/mock_app/config/environments/test.rb +1 -1
  170. data/test/mock_app/config/initializers/secret_token.rb +5 -1
  171. data/test/mock_app/config/routes.rb +1 -1
  172. data/test/mock_app/db/schema.rb +51 -0
  173. data/test/model_stub.rb +3 -3
  174. data/test/test_helper.rb +15 -12
  175. metadata +51 -50
  176. data/lib/active_scaffold/extensions/array.rb +0 -7
  177. data/lib/active_scaffold/extensions/cache_association.rb +0 -16
  178. data/lib/active_scaffold/extensions/usa_state.rb +0 -46
  179. data/lib/active_scaffold_env.rb +0 -13
  180. data/test/extensions/array_test.rb +0 -12
  181. data/test/mock_app/public/blank.html +0 -33
  182. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +0 -2
  183. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  184. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  185. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  186. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  187. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  188. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  189. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  190. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  191. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +0 -2
  192. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +0 -532
  193. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +0 -867
  194. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +0 -117
  195. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +0 -370
  196. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +0 -2
  197. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +0 -35
  198. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +0 -848
@@ -11,54 +11,56 @@ module ActiveScaffold
11
11
  end
12
12
 
13
13
  def active_scaffold_render_input(column, options)
14
- begin
15
- # first, check if the dev has created an override for this specific field
16
- if (method = override_form_field(column))
17
- send(method, options[:object] || @record, options)
18
- # second, check if the dev has specified a valid form_ui for this column
19
- elsif column.form_ui and (method = override_input(column.form_ui))
20
- send(method, column, options)
21
- # fallback: we get to make the decision
22
- else
23
- if column.association
24
- if column.form_ui.nil?
25
- # its an association and nothing is specified, we will assume form_ui :select
26
- active_scaffold_input_select(column, options)
27
- else
28
- # if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
29
- raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'"
30
- end
31
- elsif column.virtual?
32
- options[:value] = format_number_value((options[:object] || @record).send(column.name), column.options) if column.number?
33
- active_scaffold_input_virtual(column, options)
34
-
35
- else # regular model attribute column
36
- # if we (or someone else) have created a custom render option for the column type, use that
37
- if (method = override_input(column.column.type))
38
- send(method, column, options)
39
- # final ultimate fallback: use rails' generic input method
40
- else
41
- # for textual fields we pass different options
42
- text_types = [:text, :string, :integer, :float, :decimal, :date, :time, :datetime]
43
- options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
44
- if column.column.type == :string && options[:maxlength].blank?
45
- options[:maxlength] = column.column.limit
46
- options[:size] ||= ActionView::Helpers::InstanceTag::DEFAULT_FIELD_OPTIONS["size"]
47
- end
48
- options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
49
- options[:value] = format_number_value((options[:object] || @record).send(column.name), column.options) if column.number?
50
- text_field(:record, column.name, options.merge(column.options))
14
+ record = options[:object]
15
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
16
+ record ||= @record # TODO Remove when relying on @record is removed
17
+
18
+ # first, check if the dev has created an override for this specific field
19
+ if (method = override_form_field(column))
20
+ send(method, record, options)
21
+ # second, check if the dev has specified a valid form_ui for this column
22
+ elsif column.form_ui and (method = override_input(column.form_ui))
23
+ send(method, column, options)
24
+ # fallback: we get to make the decision
25
+ else
26
+ if column.association
27
+ if column.form_ui.nil?
28
+ # its an association and nothing is specified, we will assume form_ui :select
29
+ active_scaffold_input_select(column, options)
30
+ else
31
+ # if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
32
+ raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'"
33
+ end
34
+ elsif column.virtual?
35
+ options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
36
+ active_scaffold_input_virtual(column, options)
37
+
38
+ else # regular model attribute column
39
+ # if we (or someone else) have created a custom render option for the column type, use that
40
+ if (method = override_input(column.column.type))
41
+ send(method, column, options)
42
+ # final ultimate fallback: use rails' generic input method
43
+ else
44
+ # for textual fields we pass different options
45
+ text_types = [:text, :string, :integer, :float, :decimal, :date, :time, :datetime]
46
+ options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
47
+ if column.column.type == :string && options[:maxlength].blank?
48
+ options[:maxlength] = column.column.limit
49
+ options[:size] ||= options[:maxlength].to_i > 30 ? 30 : options[:maxlength]
51
50
  end
51
+ options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
52
+ options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
53
+ text_field(:record, column.name, options.merge(column.options))
52
54
  end
53
55
  end
54
- rescue Exception => e
55
- logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
56
- raise e
57
56
  end
57
+ rescue Exception => e
58
+ logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
59
+ raise e
58
60
  end
59
61
 
60
62
  def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil)
61
- Rails.logger.warn "Relying on @record is deprecated, call active_scaffold_render_subform_column with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
63
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
62
64
  record ||= @record # TODO Remove when relying on @record is removed
63
65
  if add_class
64
66
  col_class = []
@@ -69,7 +71,10 @@ module ActiveScaffold
69
71
  col_class = col_class.join(' ')
70
72
  end
71
73
  unless readonly and not record.new_record? or not record.authorized_for?(:crud_type => crud_type, :column => column.name)
72
- render_column(column, record, column_renders_as(column), scope, false, col_class)
74
+ renders_as = column_renders_as(column)
75
+ html = render_column(column, record, renders_as, scope, false, col_class)
76
+ html = content_tag(:div, html, active_scaffold_subform_attributes(column)) if renders_as == :subform
77
+ html
73
78
  else
74
79
  options = active_scaffold_input_options(column, scope).except(:name)
75
80
  options[:class] = "#{options[:class]} #{col_class}" if col_class
@@ -77,6 +82,13 @@ module ActiveScaffold
77
82
  end
78
83
  end
79
84
 
85
+ def active_scaffold_subform_attributes(column, column_css_class = nil)
86
+ {
87
+ :class => "sub-form #{active_scaffold_config_for(column.association.klass).subform.layout}-sub-form #{column_css_class} #{column.name}-sub-form",
88
+ :id => sub_form_id(:association => column.name)
89
+ }
90
+ end
91
+
80
92
  # the standard active scaffold options used for textual inputs
81
93
  def active_scaffold_input_text_options(options = {})
82
94
  options[:autocomplete] = 'off'
@@ -87,9 +99,10 @@ module ActiveScaffold
87
99
  # the standard active scaffold options used for class, name and scope
88
100
  def active_scaffold_input_options(column, scope = nil, options = {})
89
101
  name = scope ? "record#{scope}[#{column.name}]" : "record[#{column.name}]"
102
+ record = options[:object]
90
103
 
91
104
  # Add some HTML5 attributes for in-browser validation and better user experience
92
- if column.required? && (!@disable_required_for_new || scope.nil? || @record.persisted?)
105
+ if column.required? && (!@disable_required_for_new || scope.nil? || record.try(:persisted?))
93
106
  options[:required] = true
94
107
  end
95
108
  options[:placeholder] = column.placeholder if column.placeholder.present?
@@ -104,29 +117,34 @@ module ActiveScaffold
104
117
  { :name => name, :class => classes, :id => id_control}.merge(options)
105
118
  end
106
119
 
107
- def update_columns_options(column, scope, options)
120
+ def current_form_columns(record, scope, subform_controller = nil)
121
+ if scope
122
+ subform_controller.active_scaffold_config.subform.columns.names
123
+ elsif [:new, :create, :edit, :update, :render_field].include? action_name.to_sym
124
+ active_scaffold_config.send(record.new_record? ? :create : :update).columns.names
125
+ end
126
+ end
127
+
128
+ def update_columns_options(column, scope, options, force = false)
108
129
  record = options[:object]
109
- Rails.logger.warn "Relying on @record is deprecated, call update_columns_options with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
130
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
110
131
  record ||= @record # TODO Remove when relying on @record is removed
111
- form_action = if scope
112
- subform_controller = controller.class.active_scaffold_controller_for(record.class)
113
- subform_controller.active_scaffold_config.subform
114
- elsif [:new, :create, :edit, :update, :render_field].include? params[:action].to_sym
115
- active_scaffold_config.send(record.new_record? ? :create : :update)
116
- end
117
- if form_action && column.update_columns && (column.update_columns & form_action.columns.names).present?
118
- url_params = params_for(:action => 'render_field', :column => column.name, :id => record.id)
132
+ subform_controller = controller.class.active_scaffold_controller_for(record.class) if scope
133
+ form_columns = @main_columns.try(:names)
134
+ form_columns ||= current_form_columns(record, scope, subform_controller)
135
+ if force || (form_columns && column.update_columns && (column.update_columns & form_columns).present?)
136
+ url_params = params_for(:action => 'render_field', :column => column.name, :id => record.to_param)
119
137
  url_params = url_params.except(:parent_scaffold, :association, nested.param_name) if nested? && scope
120
138
  url_params[:eid] = params[:eid] if params[:eid]
121
139
  if scope
122
- url_params[:parent_controller] ||= url_params[:controller]
140
+ url_params[:parent_controller] ||= url_params[:controller].gsub(/^\//, '')
123
141
  url_params[:controller] = subform_controller.controller_path
124
142
  url_params[:scope] = scope
125
143
  url_params[:parent_id] = params[:parent_id] || params[:id]
126
144
  end
127
145
 
128
146
  options[:class] = "#{options[:class]} update_form".strip
129
- options['data-update_url'] = url_for(url_params)
147
+ options['data-update_url'] = url_for(url_params.merge(:_added => nil, :_removed => nil))
130
148
  options['data-update_send_form'] = column.send_form_on_update_column
131
149
  options['data-update_send_form_selector'] = column.options[:send_form_selector] if column.options[:send_form_selector]
132
150
  end
@@ -171,6 +189,10 @@ module ActiveScaffold
171
189
  def label_for(column, options)
172
190
  options[:id] unless column.form_ui == :select && column.plural_association?
173
191
  end
192
+
193
+ def subform_label(column, hidden)
194
+ column.label unless hidden
195
+ end
174
196
 
175
197
  def form_hidden_attribute(column, record, scope = nil)
176
198
  %|<dl style="display: none;"><dt></dt><dd>
@@ -178,14 +200,41 @@ module ActiveScaffold
178
200
  </dd></dl>|.html_safe
179
201
  end
180
202
 
203
+ # Should this column be displayed in the subform?
204
+ def in_subform?(column, parent_record)
205
+ return true unless column.association
206
+
207
+ # Polymorphic associations can't appear because they *might* be the reverse association, and because you generally don't assign an association from the polymorphic side ... I think.
208
+ return false if column.polymorphic_association?
209
+
210
+ # A column shouldn't be in the subform if it's the reverse association to the parent
211
+ return false if column.association.inverse_for?(parent_record.class)
212
+
213
+ return true
214
+ end
215
+
216
+ def column_show_add_existing(column, record = nil)
217
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
218
+ record ||= @record # TODO Remove when relying on @record is removed
219
+ (column.allow_add_existing and options_for_association_count(column.association, record) > 0)
220
+ end
221
+
222
+ def column_show_add_new(column, associated, record)
223
+ value = (column.plural_association? && !column.readonly_association?) || column.singular_association?
224
+ value &&= false unless column.association.klass.authorized_for?(:crud_type => :create)
225
+ value
226
+ end
227
+
181
228
  ##
182
229
  ## Form input methods
183
230
  ##
184
231
 
185
232
  def active_scaffold_grouped_options(column, select_options, optgroup)
186
- group_label = active_scaffold_config_for(column.association.klass).columns[optgroup].try(:association) ? :to_label : :to_s
233
+ group_column = active_scaffold_config_for(column.association.klass).columns[optgroup]
234
+ group_label = group_column.options[:label_method] if group_column
235
+ group_label ||= group_column.try(:association) ? :to_label : :to_s
187
236
  select_options.group_by(&optgroup.to_sym).collect do |group, options|
188
- [group.send(group_label), options.collect {|r| [r.to_label, r.id]}]
237
+ [group.send(group_label), options.collect {|r| [r.send(column.options[:label_method] || :to_label), r.id]}]
189
238
  end
190
239
  end
191
240
 
@@ -196,41 +245,70 @@ module ActiveScaffold
196
245
  end
197
246
 
198
247
  def active_scaffold_input_singular_association(column, html_options)
199
- associated = @record.send(column.association.name)
248
+ record = html_options.delete(:object)
249
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in html_options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
250
+ record ||= @record # TODO Remove when relying on @record is removed
251
+ associated = record.send(column.association.name)
200
252
 
201
- select_options = sorted_association_options_find(column.association)
253
+ select_options = sorted_association_options_find(column.association, nil, record)
202
254
  select_options.unshift(associated) unless associated.nil? || select_options.include?(associated)
203
255
 
204
256
  method = column.name
205
- options = {:selected => associated.try(:id), :include_blank => as_(:_select_), :object => html_options.delete(:object)}
257
+ options = {:selected => associated.try(:id), :include_blank => as_(:_select_), :object => record}
206
258
 
207
- html_options.update(column.options[:html_options] || {})
208
- options.update(column.options)
259
+ html_options.merge!(column.options[:html_options] || {})
260
+ options.merge!(column.options)
209
261
  html_options[:name] = "#{html_options[:name]}[]" if html_options[:multiple] == true && !html_options[:name].to_s.ends_with?("[]")
210
262
  active_scaffold_translate_select_options(options)
211
263
 
212
- if optgroup = options.delete(:optgroup)
264
+ html = if optgroup = options.delete(:optgroup)
213
265
  select(:record, method, active_scaffold_grouped_options(column, select_options, optgroup), options, html_options)
214
266
  else
215
- collection_select(:record, method, select_options, :id, :to_label, options, html_options)
267
+ collection_select(:record, method, select_options, :id, column.options[:label_method] || :to_label, options, html_options)
216
268
  end
269
+ html << active_scaffold_refresh_link(column, html_options, record) if column.options[:refresh_link]
270
+ html
217
271
  end
218
272
 
219
- def active_scaffold_plural_association_options(column)
220
- associated_options = @record.send(column.association.name)
221
- [associated_options, associated_options | sorted_association_options_find(column.association)]
273
+ def active_scaffold_refresh_link(column, html_options, record)
274
+ link_options = {:object => record}
275
+ if html_options['data-update_url']
276
+ link_options['data-update_send_form'] = html_options['data-update_send_form']
277
+ link_options['data-update_send_form_selector'] = html_options['data-update_send_form_selector']
278
+ else
279
+ scope = html_options[:name].scan(/^record((\[[^\]]*\])*)\[#{column.name}\]/)[0].try(:first) if html_options[:name]
280
+ link_options = update_columns_options(column, scope, link_options, true)
281
+ end
282
+ link_options[:class] = 'refresh-link'
283
+ link_to(as_(:refresh), link_options.delete('data-update_url') || html_options['data-update_url'], link_options)
222
284
  end
223
285
 
224
- def active_scaffold_input_plural_association(column, options)
225
- associated_options, select_options = active_scaffold_plural_association_options(column)
226
- return content_tag(:span, as_(:no_options), :class => options[:class], :id => options[:id]) if select_options.empty?
286
+ def active_scaffold_plural_association_options(column, record = nil)
287
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
288
+ record ||= @record # TODO Remove when relying on @record is removed
289
+ associated_options = record.send(column.association.name)
290
+ [associated_options, associated_options | sorted_association_options_find(column.association, nil, record)]
291
+ end
227
292
 
228
- active_scaffold_checkbox_list(column, select_options.collect {|r| [r.to_label, r.id]}, associated_options.collect(&:id), options)
293
+ def active_scaffold_input_plural_association(column, options)
294
+ record = options.delete(:object)
295
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
296
+ record ||= @record # TODO Remove when relying on @record is removed
297
+ associated_options, select_options = active_scaffold_plural_association_options(column, record)
298
+
299
+ html = if select_options.empty?
300
+ content_tag(:span, as_(:no_options), :class => "#{options[:class]} no-options", :id => options[:id])
301
+ else
302
+ method = column.options[:label_method] || :to_label
303
+ active_scaffold_checkbox_list(column, select_options.collect {|r| [r.send(method), r.id]}, associated_options.collect(&:id), options)
304
+ end
305
+ html << active_scaffold_refresh_link(column, options, record) if column.options[:refresh_link]
306
+ html
229
307
  end
230
308
 
231
309
  def active_scaffold_checkbox_list(column, select_options, associated_ids, options)
232
310
  html = hidden_field_tag("#{options[:name]}[]", '', :id => nil)
233
- html << content_tag(:ul, :class => "#{options[:class]} checkbox-list", :id => options[:id]) do
311
+ html << content_tag(:ul, options.merge(:class => "#{options[:class]} checkbox-list#{' draggable-lists' if column.options[:draggable_lists]}")) do
234
312
  content = ''.html_safe
235
313
  select_options.each_with_index do |option, i|
236
314
  label, id = option
@@ -242,7 +320,7 @@ module ActiveScaffold
242
320
  end
243
321
  content
244
322
  end
245
- html << javascript_tag("ActiveScaffold.draggable_lists('#{options[:id]}')") if column.options[:draggable_lists]
323
+ html << javascript_tag("ActiveScaffold.draggable_lists('#{options[:id]}')") if column.options[:draggable_lists] && ActiveScaffold.js_framework == :prototype
246
324
  html
247
325
  end
248
326
 
@@ -251,17 +329,20 @@ module ActiveScaffold
251
329
  [(text.is_a?(Symbol) ? column.active_record_class.human_attribute_name(text) : text), value]
252
330
  end
253
331
 
254
- def active_scaffold_enum_options(column)
332
+ def active_scaffold_enum_options(column, record = nil)
255
333
  column.options[:options]
256
334
  end
257
335
 
258
336
  def active_scaffold_input_enum(column, html_options)
259
- options = { :selected => @record.send(column.name), :object => html_options.delete(:object) }
260
- options_for_select = active_scaffold_enum_options(column).collect do |text, value|
337
+ record = html_options.delete(:object)
338
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in html_options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
339
+ record ||= @record # TODO Remove when relying on @record is removed
340
+ options = { :selected => record.send(column.name), :object => record }
341
+ options_for_select = active_scaffold_enum_options(column, record).collect do |text, value|
261
342
  active_scaffold_translated_option(column, text, value)
262
343
  end
263
- html_options.update(column.options[:html_options] || {})
264
- options.update(column.options)
344
+ html_options.merge!(column.options[:html_options] || {})
345
+ options.merge!(column.options)
265
346
  active_scaffold_translate_select_options(options)
266
347
  select(:record, column.name, options_for_select, options, html_options)
267
348
  end
@@ -277,10 +358,21 @@ module ActiveScaffold
277
358
  end
278
359
 
279
360
  def active_scaffold_input_radio(column, html_options)
280
- html_options.update(column.options[:html_options] || {})
281
- column.options[:options].inject('') do |html, (text, value)|
282
- text, value = active_scaffold_translated_option(column, text, value)
283
- html << content_tag(:label, radio_button(:record, column.name, value, html_options.merge(:id => html_options[:id] + '-' + value.to_s)) + text)
361
+ record = html_options[:object]
362
+ html_options.merge!(column.options[:html_options] || {})
363
+ options = if column.association
364
+ sorted_association_options_find(column.association, nil, record)
365
+ else
366
+ active_scaffold_enum_options(column, record)
367
+ end
368
+ id_key = html_options[:"data-id"] ? :"data-id" : :id
369
+ options.inject('') do |html, (text, value)|
370
+ method = column.options[:label_method] || :to_label if column.association
371
+ text, value = column.association ? [text.send(method), text.id] : active_scaffold_translated_option(column, text, value)
372
+ checked = {:checked => html_options[:object].send(column.association.name).try(:id) == value} if column.association
373
+ radio_options = html_options.merge(id_key => html_options[id_key] + '-' + value.to_s)
374
+ radio_options.merge!(checked) if checked
375
+ html << content_tag(:label, radio_button(:record, column.name, value, radio_options) + text)
284
376
  end.html_safe
285
377
  end
286
378
 
@@ -342,12 +434,15 @@ module ActiveScaffold
342
434
  #
343
435
 
344
436
  def active_scaffold_input_boolean(column, options)
437
+ record = options.delete(:object)
438
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
439
+ record ||= @record # TODO Remove when relying on @record is removed
345
440
  select_options = []
346
441
  select_options << [as_(:_select_), nil] if !column.virtual? && column.column.null
347
442
  select_options << [as_(:true), true]
348
443
  select_options << [as_(:false), false]
349
444
 
350
- select_tag(options[:name], options_for_select(select_options, @record.send(column.name)), options)
445
+ select_tag(options[:name], options_for_select(select_options, record.send(column.name)), options)
351
446
  end
352
447
 
353
448
  def onsubmit
@@ -402,7 +497,7 @@ module ActiveScaffold
402
497
  ##
403
498
 
404
499
  def column_renders_as(column)
405
- if column.is_a? ActiveScaffold::DataStructures::ActionColumns
500
+ if column.respond_to? :each
406
501
  return :subsection
407
502
  elsif column.active_record_class.locking_column.to_s == column.name.to_s or column.form_ui == :hidden
408
503
  return :hidden
@@ -414,7 +509,7 @@ module ActiveScaffold
414
509
  end
415
510
 
416
511
  def column_scope(column, scope = nil, record = nil)
417
- Rails.logger.warn "Relying on @record is deprecated, call column_scope with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
512
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
418
513
  if column.plural_association?
419
514
  "#{scope}[#{column.name}][#{record.id || generate_temporary_id(record)}]"
420
515
  else
@@ -423,13 +518,16 @@ module ActiveScaffold
423
518
  end
424
519
 
425
520
  def active_scaffold_add_existing_input(options)
521
+ record = options.delete(:object)
522
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
523
+ record ||= @record # TODO Remove when relying on @record is removed
426
524
  if ActiveScaffold.js_framework == :prototype && controller.respond_to?(:record_select_config, true)
427
525
  remote_controller = active_scaffold_controller_for(record_select_config.model).controller_path
428
526
  options.merge!(:controller => remote_controller)
429
527
  options.merge!(active_scaffold_input_text_options)
430
- record_select_field(options[:name], @record, options)
528
+ record_select_field(options[:name], record, options)
431
529
  else
432
- select_options = sorted_association_options_find(nested.association)
530
+ select_options = sorted_association_options_find(nested.association, nil, record)
433
531
  select_options ||= active_scaffold_config.model.all
434
532
  select_options = options_from_collection_for_select(select_options, :id, :to_label)
435
533
  select_tag 'associated_id', ('<option value="">' + as_(:_select_) + '</option>' + select_options).html_safe unless select_options.empty?
@@ -27,7 +27,8 @@ module ActiveScaffold
27
27
  associated = value
28
28
  associated = [associated].compact unless associated.is_a? Array
29
29
  if column.association
30
- associated = column.association.klass.where(:id => associated.map(&:to_i)).collect(&:to_label)
30
+ method = column.options[:label_method] || :to_label
31
+ associated = column.association.klass.where(:id => associated.map(&:to_i)).collect(&method)
31
32
  elsif column.options[:options]
32
33
  associated = associated.collect do |value|
33
34
  text, val = column.options[:options].find {|text, val| (val.nil? ? text : val).to_s == value.to_s}
@@ -10,8 +10,12 @@ module ActiveScaffold
10
10
  controller_id ||= 'as_' + id_from_controller(controller)
11
11
  end
12
12
 
13
+ def nested_parent_id
14
+ nested_parent_record.id
15
+ end
16
+
13
17
  def nested_id
14
- "#{nested.parent_scaffold.controller_path}-#{nested.parent_id}-#{params[:controller]}" if nested?
18
+ "#{nested.parent_scaffold.controller_path}-#{nested_parent_id}-#{params[:controller]}" if nested?
15
19
  end
16
20
 
17
21
  def active_scaffold_id
@@ -58,14 +62,14 @@ module ActiveScaffold
58
62
  def element_row_id(options = {})
59
63
  options[:action] ||= params[:action]
60
64
  options[:id] ||= params[:id]
61
- options[:id] ||= nested.parent_id if nested?
65
+ options[:id] ||= nested_parent_id if nested?
62
66
  clean_id "#{options[:controller_id] || controller_id}-#{options[:action]}-#{options[:id]}-row"
63
67
  end
64
68
 
65
69
  def element_cell_id(options = {})
66
70
  options[:action] ||= params[:action]
67
71
  options[:id] ||= params[:id]
68
- options[:id] ||= nested.parent_id if nested?
72
+ options[:id] ||= nested_parent_id if nested?
69
73
  options[:name] ||= params[:name]
70
74
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-#{options[:name]}-cell"
71
75
  end
@@ -73,7 +77,7 @@ module ActiveScaffold
73
77
  def element_form_id(options = {})
74
78
  options[:action] ||= params[:action]
75
79
  options[:id] ||= params[:id]
76
- options[:id] ||= nested.parent_id if nested?
80
+ options[:id] ||= nested_parent_id if nested?
77
81
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-form"
78
82
  end
79
83
 
@@ -84,31 +88,33 @@ module ActiveScaffold
84
88
 
85
89
  def loading_indicator_id(options = {})
86
90
  options[:action] ||= params[:action]
91
+ options[:id] ||= params[:id]
92
+ options[:id] ||= nested_parent_id if nested?
87
93
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-loading-indicator"
88
94
  end
89
95
 
90
96
  def sub_section_id(options = {})
91
97
  options[:id] ||= params[:id]
92
- options[:id] ||= nested.parent_id if nested?
98
+ options[:id] ||= nested_parent_id if nested?
93
99
  clean_id "#{controller_id}-#{options[:id]}-#{options[:sub_section]}-subsection"
94
100
  end
95
101
 
96
102
  def sub_form_id(options = {})
97
103
  options[:id] ||= params[:id]
98
- options[:id] ||= nested.parent_id if nested?
104
+ options[:id] ||= nested_parent_id if nested?
99
105
  clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform"
100
106
  end
101
107
 
102
108
  def sub_form_list_id(options = {})
103
109
  options[:id] ||= params[:id]
104
- options[:id] ||= nested.parent_id if nested?
110
+ options[:id] ||= nested_parent_id if nested?
105
111
  clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform-list"
106
112
  end
107
113
 
108
114
  def element_messages_id(options = {})
109
115
  options[:action] ||= params[:action]
110
116
  options[:id] ||= params[:id]
111
- options[:id] ||= nested.parent_id if nested?
117
+ options[:id] ||= nested_parent_id if nested?
112
118
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-messages"
113
119
  end
114
120