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
@@ -10,7 +10,7 @@ module ActiveScaffold
10
10
  value = ' '.html_safe if value.nil? or value.blank? # fix for IE 6
11
11
  return value
12
12
  rescue Exception => e
13
- logger.error "#{Time.now.to_s} #{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
13
+ logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}, record: #{record.inspect}"
14
14
  raise e
15
15
  end
16
16
  end
@@ -41,16 +41,21 @@ module ActiveScaffold
41
41
  # TODO: move empty_field_text and   logic in here?
42
42
  # TODO: we need to distinguish between the automatic links *we* create and the ones that the dev specified. some logic may not apply if the dev specified the link.
43
43
  def render_list_column(text, column, record)
44
- if column.link && !skip_action_link?(column.link, record)
45
- link = column.link
46
- associated = record.send(column.association.name) if column.association
47
- render_action_link(link, record, :link => text, :authorized => link.action.nil? || column_link_authorized?(link, column, record, associated))
48
- elsif inplace_edit?(record, column)
49
- active_scaffold_inplace_edit(record, column, {:formatted_column => text})
50
- elsif active_scaffold_config.list.wrap_tag
51
- content_tag active_scaffold_config.list.wrap_tag, text
52
- else
53
- text
44
+ begin
45
+ if column.link && !skip_action_link?(column.link, record)
46
+ link = column.link
47
+ associated = record.send(column.association.name) if column.association
48
+ render_action_link(link, record, :link => text, :authorized => link.action.nil? || column_link_authorized?(link, column, record, associated))
49
+ elsif inplace_edit?(record, column)
50
+ active_scaffold_inplace_edit(record, column, {:formatted_column => text})
51
+ elsif active_scaffold_config.list.wrap_tag
52
+ content_tag active_scaffold_config.list.wrap_tag, text
53
+ else
54
+ text
55
+ end
56
+ rescue Exception => e
57
+ logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
58
+ raise e
54
59
  end
55
60
  end
56
61
 
@@ -78,7 +83,7 @@ module ActiveScaffold
78
83
 
79
84
  def active_scaffold_column_marked(record, column)
80
85
  options = {:id => nil, :object => record}
81
- content_tag(:span, check_box(:record, column.name, options), :class => 'in_place_editor_field', :data => {:ie_id => record.id.to_s})
86
+ content_tag(:span, check_box(:record, column.name, options), :class => 'in_place_editor_field', :data => {:ie_id => record.to_param})
82
87
  end
83
88
 
84
89
  def active_scaffold_column_checkbox(record, column)
@@ -106,11 +111,7 @@ module ActiveScaffold
106
111
  ##
107
112
  def format_column_value(record, column, value = nil)
108
113
  value ||= record.send(column.name) unless record.nil?
109
- if value && column.association # cache association size before calling column_empty?
110
- associated_size = value.size if column.plural_association? and column.associated_number? # get count before cache association
111
- cache_association(value, column, associated_size) if column.plural_association?
112
- end
113
- if column.association.nil? or column_empty?(value)
114
+ if column.association.nil?
114
115
  if column.form_ui == :select && column.options[:options]
115
116
  text, val = column.options[:options].find {|text, val| (val.nil? ? text : val).to_s == value.to_s}
116
117
  value = active_scaffold_translated_option(column, text, val).first if text
@@ -121,6 +122,10 @@ module ActiveScaffold
121
122
  format_value(value, column.options)
122
123
  end
123
124
  else
125
+ if column.plural_association?
126
+ associated_size = value.size if column.associated_number? # get count before cache association
127
+ cache_association(record.association(column.name), column, associated_size) unless value.loaded?
128
+ end
124
129
  format_association_value(value, column, associated_size)
125
130
  end
126
131
  end
@@ -142,29 +147,30 @@ module ActiveScaffold
142
147
  end
143
148
 
144
149
  def format_association_value(value, column, size)
145
- format_value case column.association.macro
146
- when :has_one, :belongs_to
147
- if column.polymorphic_association?
148
- "#{value.class.model_name.human}: #{value.to_label}"
149
- else
150
- value.to_label
151
- end
152
- when :has_many, :has_and_belongs_to_many
153
- if column.associated_limit.nil?
154
- firsts = value.collect { |v| v.to_label }
155
- else
156
- firsts = value.first(column.associated_limit)
157
- firsts.collect! { |v| v.to_label }
158
- firsts[column.associated_limit] = '…' if value.size > column.associated_limit
159
- end
160
- if column.associated_limit == 0
161
- size if column.associated_number?
162
- else
163
- joined_associated = firsts.join(h(active_scaffold_config.list.association_join_text)).html_safe
164
- joined_associated << " (#{size})" if column.associated_number? and column.associated_limit and value.size > column.associated_limit
165
- joined_associated
166
- end
150
+ method = column.options[:label_method] || :to_label
151
+ value = if column.association.collection?
152
+ if column.associated_limit.nil?
153
+ firsts = value.collect(&method)
154
+ else
155
+ firsts = value.first(column.associated_limit)
156
+ firsts.collect!(&method)
157
+ firsts[column.associated_limit] = '…' if value.size > column.associated_limit
158
+ end
159
+ if column.associated_limit == 0
160
+ size if column.associated_number?
161
+ else
162
+ joined_associated = firsts.join(h(active_scaffold_config.list.association_join_text)).html_safe
163
+ joined_associated << " (#{size})" if column.associated_number? and column.associated_limit and value.size > column.associated_limit
164
+ joined_associated
165
+ end
166
+ elsif value
167
+ if column.polymorphic_association?
168
+ "#{value.class.model_name.human}: #{value.send(method)}"
169
+ else
170
+ value.send(method)
171
+ end
167
172
  end
173
+ format_value value
168
174
  end
169
175
 
170
176
  def format_value(column_value, options = {})
@@ -180,17 +186,15 @@ module ActiveScaffold
180
186
  clean_column_value(value)
181
187
  end
182
188
 
183
- def cache_association(value, column, size)
184
- # we are not using eager loading, cache firsts records in order not to query the database in a future
185
- unless value.loaded?
186
- # load at least one record, is needed to display '...'
187
- if column.associated_limit.nil?
188
- Rails.logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
189
- elsif column.associated_limit > 0
190
- value.target = value.find(:all, :limit => column.associated_limit + 1, :select => column.select_associated_columns)
191
- elsif @cache_associations
192
- value.target = size.to_i.zero? ? [] : [nil]
193
- end
189
+ def cache_association(association, column, size)
190
+ # we are not using eager loading, cache firsts records in order not to query the database for whole association in a future
191
+ if column.associated_limit.nil?
192
+ logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
193
+ elsif column.associated_limit > 0
194
+ # load at least one record more, is needed to display '...'
195
+ association.target = association.reader.limit(column.associated_limit + 1).select(column.select_associated_columns || '*').to_a
196
+ elsif @cache_associations
197
+ association.target = []
194
198
  end
195
199
  end
196
200
 
@@ -209,15 +213,18 @@ module ActiveScaffold
209
213
  column.inplace_edit != :ajax and (override_form_field?(column) or column.form_ui or (column.column and override_input?(column.column.type)))
210
214
  end
211
215
 
212
- def active_scaffold_inplace_edit(record, column, options = {})
213
- formatted_column = options[:formatted_column] || format_column_value(record, column)
216
+ def active_scaffold_inplace_edit_tag_options(record, column)
214
217
  id_options = {:id => record.id.to_s, :action => 'update_column', :name => column.name.to_s}
215
218
  tag_options = {:id => element_cell_id(id_options), :class => "in_place_editor_field",
216
- :title => as_(:click_to_edit), :data => {:ie_id => record.id.to_s}}
219
+ :title => as_(:click_to_edit), :data => {:ie_id => record.to_param}}
217
220
  tag_options[:data][:ie_update] = column.inplace_edit if column.inplace_edit != true
221
+ tag_options
222
+ end
218
223
 
224
+ def active_scaffold_inplace_edit(record, column, options = {})
225
+ formatted_column = options[:formatted_column] || format_column_value(record, column)
219
226
  content_tag(:span, as_(:inplace_edit_handle), :class => 'handle') <<
220
- content_tag(:span, formatted_column, tag_options)
227
+ content_tag(:span, formatted_column, active_scaffold_inplace_edit_tag_options(record, column))
221
228
  end
222
229
 
223
230
  def inplace_edit_control(column)
@@ -228,8 +235,10 @@ module ActiveScaffold
228
235
  column.form_ui = :select if (column.association && column.form_ui.nil?)
229
236
  options = active_scaffold_input_options(column).merge(:object => new_model)
230
237
  options[:class] = "#{options[:class]} inplace_field"
238
+ options[:"data-id"] = options[:id]
239
+ options[:id] = nil
231
240
  content_tag(:div, active_scaffold_input_for(column, nil, options), :style => "display:none;", :class => inplace_edit_control_css_class).tap do
232
- @record = old_record
241
+ @record = old_record # TODO remove when relying on @record is removed
233
242
  end
234
243
  end
235
244
  end
@@ -280,7 +289,7 @@ module ActiveScaffold
280
289
  end
281
290
 
282
291
  def column_heading_attributes(column, sorting, sort_direction)
283
- tag_options = {:id => active_scaffold_column_header_id(column), :class => column_heading_class(column, sorting), :title => strip_tags(column.description)}
292
+ tag_options = {:id => active_scaffold_column_header_id(column), :class => column_heading_class(column, sorting), :title => strip_tags(column.description).presence}
284
293
  end
285
294
 
286
295
  def render_column_heading(column, sorting, sort_direction)
@@ -5,7 +5,8 @@ module ActiveScaffold
5
5
  link_to page_number, url_options.merge(:page => page_number), options.merge(:class => "as_paginate")
6
6
  end
7
7
 
8
- def pagination_ajax_links(current_page, url_options, options, inner_window, outer_window)
8
+ def pagination_url_options(url_options = nil)
9
+ url_options ||= params_for(:action => :index)
9
10
  unless active_scaffold_config.store_user_settings
10
11
  url_options.merge!(:search => search_params) if search_params.present?
11
12
  if active_scaffold_config.list.user.user_sorting?
@@ -13,7 +14,10 @@ module ActiveScaffold
13
14
  url_options.merge!(:sort => column.name, :sort_direction => direction)
14
15
  end
15
16
  end
17
+ url_options
18
+ end
16
19
 
20
+ def pagination_ajax_links(current_page, url_options, options, inner_window, outer_window)
17
21
  start_number = current_page.number - inner_window
18
22
  end_number = current_page.number + inner_window
19
23
  start_number = 1 if start_number <= 0
@@ -6,10 +6,13 @@ module ActiveScaffold
6
6
  # It does not do any rendering. It only decides which method is responsible for rendering.
7
7
  def active_scaffold_search_for(column, options = nil)
8
8
  options ||= active_scaffold_search_options(column)
9
+ record = options[:object]
10
+ 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
11
+ record ||= @record # TODO Remove when relying on @record is removed
9
12
 
10
13
  # first, check if the dev has created an override for this specific field for search
11
14
  if (method = override_search_field(column))
12
- send(method, options[:object] || @record, options)
15
+ send(method, record, options)
13
16
 
14
17
  # second, check if the dev has specified a valid search_ui for this column, using specific ui for searches
15
18
  elsif column.search_ui and (method = override_search(column.search_ui))
@@ -21,7 +24,7 @@ module ActiveScaffold
21
24
 
22
25
  # fourth, check if the dev has created an override for this specific field
23
26
  elsif (method = override_form_field(column))
24
- send(method, options[:object] || @record, options)
27
+ send(method, record, options)
25
28
 
26
29
  # fallback: we get to make the decision
27
30
  else
@@ -44,6 +47,9 @@ module ActiveScaffold
44
47
  end
45
48
  end
46
49
  end
50
+ rescue Exception => e
51
+ logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
52
+ raise e
47
53
  end
48
54
 
49
55
  # the standard active scaffold options used for class, name and scope
@@ -66,12 +72,16 @@ module ActiveScaffold
66
72
  ##
67
73
 
68
74
  def active_scaffold_search_multi_select(column, options)
75
+ record = options.delete(:object)
76
+ 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
77
+ record ||= @record # TODO Remove when relying on @record is removed
69
78
  associated = options.delete :value
70
79
  associated = [associated].compact unless associated.is_a? Array
71
80
  associated.collect!(&:to_i)
72
81
 
73
82
  if column.association
74
- select_options = sorted_association_options_find(column.association).collect {|r| [r.to_label, r.id]}
83
+ method = column.options[:label_method] || :to_label
84
+ select_options = sorted_association_options_find(column.association, nil, record).collect {|r| [r.send(method), r.id]}
75
85
  else
76
86
  select_options = column.options[:options].collect do |text, value|
77
87
  active_scaffold_translated_option(column, text, value)
@@ -83,11 +93,14 @@ module ActiveScaffold
83
93
  end
84
94
 
85
95
  def active_scaffold_search_select(column, html_options, options = {})
96
+ record = html_options.delete(:object)
97
+ 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
98
+ record ||= @record # TODO Remove when relying on @record is removed
86
99
  associated = html_options.delete :value
87
100
  if column.association
88
101
  associated = associated.is_a?(Array) ? associated.map(&:to_i) : associated.to_i unless associated.nil?
89
102
  method = column.association.macro == :belongs_to ? column.association.foreign_key : column.name
90
- select_options = sorted_association_options_find(column.association, false)
103
+ select_options = sorted_association_options_find(column.association, false, record)
91
104
  else
92
105
  method = column.name
93
106
  select_options = column.options[:options].collect do |text, value|
@@ -106,7 +119,7 @@ module ActiveScaffold
106
119
  if optgroup = options.delete(:optgroup)
107
120
  select(:record, method, active_scaffold_grouped_options(column, select_options, optgroup), options, html_options)
108
121
  elsif column.association
109
- collection_select(:record, method, select_options, :id, :to_label, options, html_options)
122
+ collection_select(:record, method, select_options, :id, column.options[:label_method] || :to_label, options, html_options)
110
123
  else
111
124
  select(:record, method, select_options, options, html_options)
112
125
  end
@@ -124,7 +137,7 @@ module ActiveScaffold
124
137
  select_options << [as_(:true), true]
125
138
  select_options << [as_(:false), false]
126
139
 
127
- select_tag(options[:name], options_for_select(select_options, column.column.type_cast(field_search_params[column.name])), :id => options[:id])
140
+ select_tag(options[:name], options_for_select(select_options, column.column.type_cast(options[:value])), :id => options[:id])
128
141
  end
129
142
  # we can't use checkbox ui because it's not possible to decide whether search for this field or not
130
143
  alias_method :active_scaffold_search_checkbox, :active_scaffold_search_boolean
@@ -133,29 +146,19 @@ module ActiveScaffold
133
146
  select_options = []
134
147
  select_options << [as_(:_select_), nil]
135
148
  select_options.concat ActiveScaffold::Finder::NullComparators.collect {|comp| [as_(comp), comp]}
136
- select_tag(options[:name], options_for_select(select_options, field_search_params[column.name]), :id => options[:id])
149
+ select_tag(options[:name], options_for_select(select_options, options[:value]), :id => options[:id])
137
150
  end
138
151
 
139
152
  def field_search_params_range_values(column)
140
153
  values = field_search_params[column.name]
141
- return nil if values.nil?
154
+ return nil unless values.is_a? Hash
142
155
  return values[:opt], (values[:from].blank? ? nil : values[:from]), (values[:to].blank? ? nil : values[:to])
143
-
144
156
  end
145
157
 
146
158
  def active_scaffold_search_range_string?(column)
147
159
  (column.column && column.column.text?) || column.search_ui == :string
148
160
  end
149
161
 
150
- def include_null_comparators?(column)
151
- return column.options[:null_comparators] if column.options.has_key? :null_comparators
152
- if column.association
153
- column.association.macro != :belongs_to || active_scaffold_config.columns[column.association.foreign_key].column.try(:null)
154
- else
155
- column.column.try(:null)
156
- end
157
- end
158
-
159
162
  def active_scaffold_search_range_comparator_options(column)
160
163
  select_options = ActiveScaffold::Finder::NumericComparators.collect {|comp| [as_(comp.downcase.to_sym), comp]}
161
164
  if active_scaffold_search_range_string?(column)
@@ -59,19 +59,6 @@ module ActiveScaffold
59
59
  end
60
60
  end
61
61
 
62
- # Should this column be displayed in the subform?
63
- def in_subform?(column, parent_record)
64
- return true unless column.association
65
-
66
- # 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.
67
- return false if column.polymorphic_association?
68
-
69
- # A column shouldn't be in the subform if it's the reverse association to the parent
70
- return false if column.association.inverse_for?(parent_record.class)
71
-
72
- return true
73
- end
74
-
75
62
  def form_remote_upload_tag(url_for_options = {}, options = {})
76
63
  options[:target] = action_iframe_id(url_for_options)
77
64
  options[:multipart] ||= true
@@ -91,8 +78,8 @@ module ActiveScaffold
91
78
  # You may also flag whether the other element is visible by default or not, and the initial text will adjust accordingly.
92
79
  def link_to_visibility_toggle(id, options = {})
93
80
  options[:default_visible] = true if options[:default_visible].nil?
94
- options[:hide_label] = as_(:hide)
95
- options[:show_label] = as_(:show)
81
+ options[:hide_label] ||= as_(:hide)
82
+ options[:show_label] ||= as_(:show_block)
96
83
  javascript_tag("ActiveScaffold.create_visibility_toggle('#{id}', #{options.to_json});")
97
84
  end
98
85
 
@@ -148,7 +135,7 @@ module ActiveScaffold
148
135
  group_tag = :li
149
136
  end
150
137
  content = content_tag(group_tag, :class => (html_classes if html_classes.present?), :onclick => ('' if hover_via_click?)) do
151
- content_tag(:div, as_(link.name), :class => link.name.to_s.downcase) << content_tag(:ul, content)
138
+ content_tag(:div, as_(link.label), :class => link.name.to_s.downcase) << content_tag(:ul, content)
152
139
  end
153
140
  else
154
141
  content = render_action_link(link, record, options)
@@ -229,42 +216,61 @@ module ActiveScaffold
229
216
  end
230
217
  end
231
218
 
232
- def action_link_url(link, record)
233
- url = (@action_links_urls ||= {})[link.name_to_cache_link_url]
219
+ def is_sti_record?(record)
220
+ model = active_scaffold_config.model
221
+ is_sti_record = record && model.columns_hash.include?(model.inheritance_column) &&
222
+ record[model.inheritance_column].present? && !record.instance_of?(model)
223
+ end
224
+
225
+ def cache_action_link_url?(link, record)
226
+ active_scaffold_config.cache_action_link_urls && link.type == :member && !link.dynamic_parameters.is_a?(Proc) && !is_sti_record?(record)
227
+ end
228
+
229
+ def cached_action_link_url(link, record)
230
+ url = (@action_links_urls ||= {})[link.name_to_cache]
234
231
  url ||= begin
235
232
  url_options = action_link_url_options(link, record)
236
- if active_scaffold_config.cache_action_link_urls
237
- url = url_for(url_options)
238
- model = active_scaffold_config.model
239
- is_sti_record = record && model.columns_hash.include?(model.inheritance_column) &&
240
- record[model.inheritance_column].present?
241
- unless link.dynamic_parameters.is_a?(Proc) || is_sti_record
242
- @action_links_urls[link.name_to_cache_link_url] = url
243
- end
244
- url
233
+ if cache_action_link_url?(link, record)
234
+ @action_links_urls[link.name_to_cache] = url_for(url_options)
245
235
  else
246
236
  url_for(params_for(url_options))
247
237
  end
248
238
  end
249
-
250
- url = record ? url.sub('--ID--', record.id.to_s) : url.clone
239
+ end
240
+
241
+ def replace_id_params_in_action_link_url(link, record, url)
242
+ url = record ? url.sub('--ID--', record.to_param) : url.clone
251
243
  if link.column.try(:singular_association?)
252
- url = url.sub('--CHILD_ID--', record.send(link.column.association.name).try(:id).to_s)
244
+ child_id = record.send(link.column.association.name).try(:to_param)
245
+ if child_id.present?
246
+ url.sub!('--CHILD_ID--', child_id)
247
+ else
248
+ url.sub!(/\w+=--CHILD_ID--&?/,'')
249
+ url.sub!(/\?$/, '')
250
+ end
253
251
  elsif nested?
254
- url = url.sub('--CHILD_ID--', params[nested.param_name].to_s)
252
+ url.sub!('--CHILD_ID--', params[nested.param_name].to_s)
255
253
  end
256
-
257
- if active_scaffold_config.cache_action_link_urls
258
- query_string, non_nested_query_string = query_string_for_action_links(link)
259
- if query_string || (!link.nested_link? && non_nested_query_string)
260
- url << (url.include?('?') ? '&' : '?')
261
- url << query_string if query_string
262
- url << non_nested_query_string if !link.nested_link? && non_nested_query_string
263
- end
254
+ url
255
+ end
256
+
257
+ def add_query_string_to_cached_url(link, url)
258
+ query_string, non_nested_query_string = query_string_for_action_links(link)
259
+ nested_params = (!link.nested_link? && non_nested_query_string)
260
+ if query_string || nested_params
261
+ url << (url.include?('?') ? '&' : '?')
262
+ url << query_string if query_string
263
+ url << non_nested_query_string if nested_params
264
264
  end
265
265
  url
266
266
  end
267
267
 
268
+ def action_link_url(link, record)
269
+ url = replace_id_params_in_action_link_url(link, record, cached_action_link_url(link, record))
270
+ url = add_query_string_to_cached_url(link, url) if @action_links_urls[link.name_to_cache]
271
+ url
272
+ end
273
+
268
274
  def query_string_for_action_links(link)
269
275
  if defined?(@query_string) && link.parameters.none? { |k, v| @query_string_params.include? k }
270
276
  return [@query_string, @non_nested_query_string]
@@ -272,8 +278,8 @@ module ActiveScaffold
272
278
  keep = true
273
279
  @query_string_params ||= Set.new
274
280
  query_string_for_all = nil
275
- query_string_options = []
276
- non_nested_query_string_options = []
281
+ query_string_options = {}
282
+ non_nested_query_string_options = {}
277
283
 
278
284
  params_for.except(:controller, :action, :id).each do |key, value|
279
285
  @query_string_params << key
@@ -281,17 +287,16 @@ module ActiveScaffold
281
287
  keep = false
282
288
  next
283
289
  end
284
- qs = "#{key}=#{value}"
285
290
  if NESTED_PARAMS.include?(key) || conditions_from_params.include?(key) || (nested? && nested.param_name == key)
286
- non_nested_query_string_options << qs
291
+ non_nested_query_string_options[key] = value
287
292
  else
288
- query_string_options << qs
293
+ query_string_options[key] = value
289
294
  end
290
295
  end
291
296
 
292
- query_string = URI.escape(query_string_options.join('&')) if query_string_options.present?
297
+ query_string = query_string_options.to_query if query_string_options.present?
293
298
  if non_nested_query_string_options.present?
294
- non_nested_query_string = "#{'&' if query_string}#{URI.escape(non_nested_query_string_options.join('&'))}"
299
+ non_nested_query_string = "#{'&' if query_string}#{non_nested_query_string_options.to_query}"
295
300
  end
296
301
  if keep
297
302
  @query_string = query_string
@@ -299,8 +304,23 @@ module ActiveScaffold
299
304
  end
300
305
  [query_string, non_nested_query_string]
301
306
  end
307
+
308
+ def cache_action_link_url_options?(link, record)
309
+ active_scaffold_config.cache_action_link_urls && (link.type == :collection || !link.dynamic_parameters.is_a?(Proc)) && !is_sti_record?(record)
310
+ end
302
311
 
303
312
  def action_link_url_options(link, record)
313
+ options = (@action_links_url_options ||= {})[link.name_to_cache]
314
+ options ||= begin
315
+ options = generate_action_link_url_options(link, record)
316
+ if cache_action_link_url_options?(link, record)
317
+ @action_links_url_options[link.name_to_cache] = options
318
+ end
319
+ options
320
+ end
321
+ end
322
+
323
+ def generate_action_link_url_options(link, record)
304
324
  url_options = {:action => link.action}
305
325
  url_options[:id] = '--ID--' unless record.nil?
306
326
  url_options[:controller] = link.controller.to_s if link.controller
@@ -327,6 +347,28 @@ module ActiveScaffold
327
347
  text || options[:link]
328
348
  end
329
349
 
350
+ def replaced_action_link_url_options(link, record)
351
+ url = action_link_url_options(link, record)
352
+ url[:controller] ||= params[:controller]
353
+ missing_options, url_options = url.partition{|k,v| v.nil?}
354
+ replacements = {}
355
+ replacements['--ID--'] = record.id.to_s if record
356
+ if link.column.try(:singular_association?)
357
+ replacements['--CHILD_ID--'] = record.send(link.column.association.name).try(:id).to_s
358
+ elsif nested?
359
+ replacements['--CHILD_ID--'] = params[nested.param_name].to_s
360
+ end
361
+ url_options.collect! do |k,v|
362
+ [k.to_s, replacements[v] || v]
363
+ end
364
+ [missing_options, url_options]
365
+ end
366
+
367
+ def action_link_selected?(link, record)
368
+ missing_options, url_options = replaced_action_link_url_options(link, record)
369
+ (url_options - params.to_a).blank? && missing_options.all? {|k,v| params[k].nil?}
370
+ end
371
+
330
372
  def action_link_html_options(link, record, options)
331
373
  link_id = get_action_link_id(link, record)
332
374
  html_options = link.html_options.merge(:class => [link.html_options[:class], link.action.to_s].compact.join(' '))
@@ -344,6 +386,12 @@ module ActiveScaffold
344
386
  html_options[:data][:cancel_refresh] = true if link.refresh_on_close
345
387
  html_options[:data][:keep_open] = true if link.keep_open?
346
388
  end
389
+
390
+ if link.toggle
391
+ html_options[:class] << ' toggle'
392
+ html_options[:class] << ' active' if action_link_selected?(link, record)
393
+ end
394
+
347
395
  html_options[:target] = '_blank' if link.popup?
348
396
  html_options[:id] = link_id
349
397
  html_options[:remote] = true unless link.page? || link.popup?
@@ -360,7 +408,6 @@ module ActiveScaffold
360
408
 
361
409
  def get_action_link_id(link, record = nil, column = nil)
362
410
  column ||= link.column
363
- id = record ? record.id.to_s : (nested? ? nested.parent_id : '')
364
411
  if column && column.plural_association?
365
412
  id = "#{column.association.name}-#{record.id}"
366
413
  elsif column && column.singular_association?
@@ -370,6 +417,7 @@ module ActiveScaffold
370
417
  id = "#{column.association.name}-#{record.id}" unless record.nil?
371
418
  end
372
419
  end
420
+ id ||= record ? record.id : (nested? ? nested_parent_id : '')
373
421
  action_id = "#{id_from_controller("#{link.controller}-") if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)}#{link.action}"
374
422
  action_link_id(action_id, id)
375
423
  end
@@ -416,7 +464,7 @@ module ActiveScaffold
416
464
 
417
465
  def list_row_class_method(record)
418
466
  return @_list_row_class_method if defined? @_list_row_class_method
419
- class_override_helper = :"#{clean_class_name(record.class.name)}_list_row_class"
467
+ class_override_helper = "#{clean_class_name(record.class.name)}_list_row_class"
420
468
  @_list_row_class_method = (class_override_helper if respond_to?(class_override_helper))
421
469
  end
422
470
 
@@ -487,16 +535,6 @@ module ActiveScaffold
487
535
  def format_column_calculation(column, calculation)
488
536
  "#{"#{as_(column.calculate)}: " unless column.calculate.is_a? Proc}#{format_column_value nil, column, calculation}"
489
537
  end
490
-
491
- def column_show_add_existing(column)
492
- (column.allow_add_existing and options_for_association_count(column.association) > 0)
493
- end
494
-
495
- def column_show_add_new(column, associated, record)
496
- value = (column.plural_association? && !column.readonly_association?) || (column.singular_association? and not associated.empty?)
497
- value = false unless column.association.klass.authorized_for?(:crud_type => :create)
498
- value
499
- end
500
538
 
501
539
  def clean_column_name(name)
502
540
  name.to_s.gsub('?', '')
@@ -512,11 +550,11 @@ module ActiveScaffold
512
550
  end
513
551
 
514
552
  def override_helper(column, suffix)
515
- @_override_helpers ||= {}
516
- @_override_helpers[suffix] ||= {}
517
- @_override_helpers[suffix][@record.class.name] ||= {}
518
- return @_override_helpers[suffix][@record.class.name][column.name] if @_override_helpers[suffix][@record.class.name].include? column.name
519
- @_override_helpers[suffix][@record.class.name][column.name] = begin
553
+ hash = @_override_helpers ||= {}
554
+ hash = hash[suffix] ||= {}
555
+ hash = hash[column.active_record_class.name] ||= {}
556
+ return hash[column.name] if hash.include? column.name
557
+ hash[column.name] = begin
520
558
  method_with_class = override_helper_name(column, suffix, true)
521
559
  if respond_to?(method_with_class)
522
560
  method_with_class
@@ -530,7 +568,7 @@ module ActiveScaffold
530
568
  def display_message(message)
531
569
  if (highlights = active_scaffold_config.highlight_messages)
532
570
  message = highlights.inject(message) do |msg, (phrases, highlighter)|
533
- highlight(msg, phrases, highlighter)
571
+ highlight(msg, phrases, highlighter || {})
534
572
  end
535
573
  end
536
574
  if (format = active_scaffold_config.timestamped_messages)