active_scaffold 3.0.12 → 3.0.21

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 (142) hide show
  1. data/README +21 -11
  2. data/frontends/default/images/close_touch.png +0 -0
  3. data/frontends/default/javascripts/jquery/active_scaffold.js +187 -99
  4. data/frontends/default/javascripts/prototype/active_scaffold.js +105 -33
  5. data/frontends/default/javascripts/prototype/dhtml_history.js +80 -77
  6. data/frontends/default/stylesheets/stylesheet.css +121 -2
  7. data/frontends/default/views/_action_group.html.erb +6 -2
  8. data/frontends/default/views/_base_form.html.erb +11 -5
  9. data/frontends/default/views/_base_form.html.erb~ +42 -0
  10. data/frontends/default/views/_field_search.html.erb +1 -1
  11. data/frontends/default/views/_form.html.erb +9 -7
  12. data/frontends/default/views/_form_association.html.erb +8 -3
  13. data/frontends/default/views/_form_association_footer.html.erb +10 -3
  14. data/frontends/default/views/_form_attribute.html.erb +8 -3
  15. data/frontends/default/views/_horizontal_subform.html.erb +12 -2
  16. data/frontends/default/views/_horizontal_subform_header.html.erb +1 -1
  17. data/frontends/default/views/_horizontal_subform_record.html.erb +5 -4
  18. data/frontends/default/views/_list_messages.html.erb +1 -1
  19. data/frontends/default/views/_list_with_header.html.erb +1 -1
  20. data/frontends/default/views/_render_field.js.rjs +4 -6
  21. data/frontends/default/views/_vertical_subform.html.erb +1 -1
  22. data/frontends/default/views/_vertical_subform_record.html.erb +2 -2
  23. data/frontends/default/views/on_action_update.js.rjs +3 -1
  24. data/frontends/default/views/on_mark_all.js.rjs +12 -0
  25. data/frontends/default/views/on_update.js.rjs +1 -1
  26. data/frontends/default/views/render_field.js.rjs +1 -0
  27. data/frontends/default/views/update_column.js.rjs +1 -1
  28. data/lib/active_scaffold.rb +60 -21
  29. data/lib/active_scaffold/actions/common_search.rb +2 -2
  30. data/lib/active_scaffold/actions/core.rb +30 -9
  31. data/lib/active_scaffold/actions/create.rb +14 -10
  32. data/lib/active_scaffold/actions/field_search.rb +6 -6
  33. data/lib/active_scaffold/actions/list.rb +22 -12
  34. data/lib/active_scaffold/actions/mark.rb +34 -9
  35. data/lib/active_scaffold/actions/nested.rb +12 -16
  36. data/lib/active_scaffold/actions/show.rb +2 -2
  37. data/lib/active_scaffold/actions/subform.rb +15 -8
  38. data/lib/active_scaffold/actions/update.rb +14 -4
  39. data/lib/active_scaffold/attribute_params.rb +15 -10
  40. data/lib/active_scaffold/bridges/bridge.rb +21 -12
  41. data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +3 -3
  42. data/lib/active_scaffold/bridges/cancan/bridge.rb +12 -0
  43. data/lib/active_scaffold/bridges/cancan/lib/cancan_bridge.rb +107 -0
  44. data/lib/active_scaffold/bridges/carrierwave/bridge.rb +1 -1
  45. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +3 -8
  46. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +1 -15
  47. data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +23 -13
  48. data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +1 -1
  49. data/lib/active_scaffold/bridges/country_helper/bridge.rb +9 -0
  50. data/lib/active_scaffold/bridges/country_helper/lib/country_helper_bridge.rb +358 -0
  51. data/lib/active_scaffold/bridges/date_picker/bridge.rb +5 -3
  52. data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +9 -0
  53. data/lib/active_scaffold/bridges/dragonfly/bridge.rb +9 -0
  54. data/lib/active_scaffold/bridges/dragonfly/bridge.rb~ +12 -0
  55. data/lib/active_scaffold/bridges/dragonfly/lib/dragonfly_bridge.rb +36 -0
  56. data/lib/active_scaffold/bridges/dragonfly/lib/dragonfly_bridge.rb~ +36 -0
  57. data/lib/active_scaffold/bridges/dragonfly/lib/dragonfly_bridge_helpers.rb +12 -0
  58. data/lib/active_scaffold/bridges/dragonfly/lib/dragonfly_bridge_helpers.rb~ +12 -0
  59. data/lib/active_scaffold/bridges/dragonfly/lib/form_ui.rb +27 -0
  60. data/lib/active_scaffold/bridges/dragonfly/lib/form_ui.rb~ +27 -0
  61. data/lib/active_scaffold/bridges/dragonfly/lib/list_ui.rb +16 -0
  62. data/lib/active_scaffold/bridges/dragonfly/lib/list_ui.rb~ +16 -0
  63. data/lib/active_scaffold/bridges/paperclip/bridge.rb +1 -1
  64. data/lib/active_scaffold/bridges/record_select/bridge.rb +5 -0
  65. data/lib/active_scaffold/bridges/record_select/lib/record_select_bridge.rb +87 -0
  66. data/lib/active_scaffold/bridges/record_select/lib/record_select_bridge.rb~ +84 -0
  67. data/lib/active_scaffold/bridges/shared/date_bridge.rb +56 -34
  68. data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +19 -3
  69. data/lib/active_scaffold/config/base.rb +4 -4
  70. data/lib/active_scaffold/config/core.rb +4 -0
  71. data/lib/active_scaffold/config/create.rb +1 -1
  72. data/lib/active_scaffold/config/field_search.rb +7 -7
  73. data/lib/active_scaffold/config/form.rb +8 -2
  74. data/lib/active_scaffold/config/list.rb +22 -8
  75. data/lib/active_scaffold/config/mark.rb +18 -5
  76. data/lib/active_scaffold/config/nested.rb +3 -3
  77. data/lib/active_scaffold/config/search.rb +1 -1
  78. data/lib/active_scaffold/config/show.rb +1 -1
  79. data/lib/active_scaffold/data_structures/action_columns.rb +10 -6
  80. data/lib/active_scaffold/data_structures/action_link.rb +14 -10
  81. data/lib/active_scaffold/data_structures/action_links.rb +2 -2
  82. data/lib/active_scaffold/data_structures/column.rb +25 -11
  83. data/lib/active_scaffold/data_structures/nested_info.rb +21 -21
  84. data/lib/active_scaffold/data_structures/set.rb +2 -3
  85. data/lib/active_scaffold/data_structures/sorting.rb +8 -8
  86. data/lib/{extensions → active_scaffold/extensions}/action_controller_rendering.rb +3 -1
  87. data/lib/{extensions → active_scaffold/extensions}/action_view_rendering.rb +31 -33
  88. data/lib/{extensions → active_scaffold/extensions}/action_view_resolver.rb +0 -0
  89. data/lib/{extensions → active_scaffold/extensions}/active_association_reflection.rb +0 -0
  90. data/lib/active_scaffold/extensions/active_record_offset.rb +12 -0
  91. data/lib/{extensions → active_scaffold/extensions}/array.rb +0 -0
  92. data/lib/{extensions → active_scaffold/extensions}/localize.rb +1 -1
  93. data/lib/{extensions → active_scaffold/extensions}/name_option_for_datetime.rb +1 -1
  94. data/lib/{extensions → active_scaffold/extensions}/nil_id_in_url_params.rb +0 -0
  95. data/lib/{extensions → active_scaffold/extensions}/paginator_extensions.rb +2 -2
  96. data/lib/{extensions → active_scaffold/extensions}/reverse_associations.rb +1 -1
  97. data/lib/{extensions → active_scaffold/extensions}/routing_mapper.rb +2 -2
  98. data/lib/{extensions → active_scaffold/extensions}/to_label.rb +0 -0
  99. data/lib/{extensions → active_scaffold/extensions}/unsaved_associated.rb +0 -0
  100. data/lib/{extensions → active_scaffold/extensions}/unsaved_record.rb +0 -0
  101. data/lib/active_scaffold/extensions/usa_state.rb +46 -0
  102. data/lib/active_scaffold/finder.rb +30 -19
  103. data/lib/active_scaffold/helpers/controller_helpers.rb +3 -5
  104. data/lib/active_scaffold/helpers/form_column_helpers.rb +19 -45
  105. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  106. data/lib/active_scaffold/helpers/id_helpers.rb +2 -2
  107. data/lib/active_scaffold/helpers/list_column_helpers.rb +28 -17
  108. data/lib/active_scaffold/helpers/search_column_helpers.rb +51 -40
  109. data/lib/active_scaffold/helpers/search_column_helpers.rb~ +215 -0
  110. data/lib/active_scaffold/helpers/show_column_helpers.rb +8 -4
  111. data/lib/active_scaffold/helpers/view_helpers.rb +50 -27
  112. data/lib/active_scaffold/locale/de.yml +111 -0
  113. data/lib/active_scaffold/locale/en.yml +115 -0
  114. data/lib/active_scaffold/locale/es.yml +32 -32
  115. data/lib/active_scaffold/locale/fr.yml +118 -0
  116. data/lib/active_scaffold/marked_model.rb +6 -6
  117. data/lib/active_scaffold/version.rb +1 -1
  118. data/lib/active_scaffold_assets.rb +1 -3
  119. data/lib/active_scaffold_env.rb +1 -2
  120. data/lib/generators/active_scaffold/active_scaffold_generator.rb +5 -5
  121. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +3 -2
  122. data/lib/generators/active_scaffold_controller/templates/helper.rb +2 -0
  123. data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +17 -19
  124. data/shoulda_macros/macros.rb +4 -4
  125. data/test/misc/finder_test.rb +2 -2
  126. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +4 -1
  127. metadata +144 -126
  128. data/.autotest +0 -27
  129. data/.document +0 -5
  130. data/Gemfile +0 -13
  131. data/Gemfile.lock +0 -20
  132. data/Rakefile +0 -53
  133. data/active_scaffold.gemspec +0 -385
  134. data/init.rb +0 -2
  135. data/lib/active_scaffold/helpers/country_helpers.rb +0 -358
  136. data/lib/active_scaffold/locale/de.rb +0 -120
  137. data/lib/active_scaffold/locale/en.rb +0 -119
  138. data/lib/active_scaffold/locale/fr.rb +0 -116
  139. data/lib/extensions/active_record_offset.rb +0 -12
  140. data/lib/extensions/usa_state.rb +0 -50
  141. data/test/mock_app/.gitignore +0 -2
  142. data/uninstall.rb +0 -13
@@ -26,7 +26,7 @@ module ActiveScaffold
26
26
  when :select, :multi_select, :record_select
27
27
  associated = value
28
28
  associated = [associated].compact unless associated.is_a? Array
29
- associated = column.association.klass.find(associated.map(&:to_i)).collect(&:to_label) if column.association
29
+ associated = column.association.klass.where(["id in (?)", associated.map(&:to_i)]).collect(&:to_label) if column.association
30
30
  "#{column.active_record_class.human_attribute_name(column.name)} = #{associated.join(', ')}"
31
31
  when :boolean, :checkbox
32
32
  label = column.column.type_cast(value) ? as_(:true) : as_(:false)
@@ -86,7 +86,7 @@ module ActiveScaffold
86
86
  options[:action] ||= params[:action]
87
87
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-loading-indicator"
88
88
  end
89
-
89
+
90
90
  def sub_section_id(options = {})
91
91
  options[:id] ||= params[:id]
92
92
  options[:id] ||= params[:parent_id]
@@ -98,7 +98,7 @@ module ActiveScaffold
98
98
  options[:id] ||= params[:parent_id]
99
99
  clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform"
100
100
  end
101
-
101
+
102
102
  def sub_form_list_id(options = {})
103
103
  options[:id] ||= params[:id]
104
104
  options[:id] ||= params[:parent_id]
@@ -86,7 +86,7 @@ module ActiveScaffold
86
86
 
87
87
  def column_link_authorized?(link, column, record, associated)
88
88
  if column.association
89
- associated_for_authorized = if associated.nil? || (associated.respond_to?(:empty?) && associated.empty?)
89
+ associated_for_authorized = if associated.nil? || (associated.respond_to?(:blank?) && associated.blank?)
90
90
  column.association.klass
91
91
  elsif [:has_many, :has_and_belongs_to_many].include? column.association.macro
92
92
  associated.first
@@ -136,13 +136,17 @@ module ActiveScaffold
136
136
  check_box(:record, column.name, options)
137
137
  end
138
138
 
139
- def column_override(column)
140
- "#{column.name.to_s.gsub('?', '')}_column" # parse out any question marks (see issue 227)
139
+ def column_override_name(column, class_prefix = false)
140
+ "#{clean_class_name(column.active_record_class.name) + '_' if class_prefix}#{clean_column_name(column.name)}_column"
141
141
  end
142
142
 
143
- def column_override?(column)
144
- respond_to?(column_override(column))
143
+ def column_override(column)
144
+ method_with_class = column_override_name(column, true)
145
+ return method_with_class if respond_to?(method_with_class)
146
+ method = column_override_name(column)
147
+ method if respond_to?(method)
145
148
  end
149
+ alias_method :column_override?, :column_override
146
150
 
147
151
  def override_column_ui?(list_ui)
148
152
  respond_to?(override_column_ui(list_ui))
@@ -208,7 +212,7 @@ module ActiveScaffold
208
212
  if column.associated_limit == 0
209
213
  size if column.associated_number?
210
214
  else
211
- joined_associated = format_value(firsts.join(', '))
215
+ joined_associated = format_value(firsts.join(active_scaffold_config.list.association_join_text))
212
216
  joined_associated << " (#{size})" if column.associated_number? and column.associated_limit and value.size > column.associated_limit
213
217
  joined_associated
214
218
  end
@@ -247,7 +251,7 @@ module ActiveScaffold
247
251
  def inplace_edit?(record, column)
248
252
  if column.inplace_edit
249
253
  editable = controller.send(:update_authorized?, record) if controller.respond_to?(:update_authorized?)
250
- editable = record.authorized_for?(:action => :update, :column => column.name) if editable.nil? || editable == true
254
+ editable = record.authorized_for?(:crud_type => :update, :column => column.name) if editable.nil? || editable == true
251
255
  editable
252
256
  end
253
257
  end
@@ -275,7 +279,7 @@ module ActiveScaffold
275
279
 
276
280
  def inplace_edit_control(column)
277
281
  if inplace_edit?(active_scaffold_config.model, column) and inplace_edit_cloning?(column)
278
- @record = active_scaffold_config.model.new
282
+ @record = new_model
279
283
  column = column.clone
280
284
  column.options = column.options.clone
281
285
  column.form_ui = :select if (column.association && column.form_ui.nil?)
@@ -313,10 +317,17 @@ module ActiveScaffold
313
317
  end
314
318
 
315
319
  def mark_column_heading
316
- all_marked = (marked_records.length >= @page.pager.count)
320
+ if active_scaffold_config.mark.mark_all_mode == :page then
321
+ all_marked = true
322
+ @page.items.each do |record|
323
+ all_marked = false if !marked_records.entries.include?(record.id)
324
+ end
325
+ else
326
+ all_marked = (marked_records.length >= @page.pager.count)
327
+ end
317
328
  tag_options = {:id => "#{controller_id}_mark_heading", :class => "mark_heading in_place_editor_field"}
318
329
  tag_options['data-ie_url'] = url_for({:controller => params_for[:controller], :action => 'mark_all', :eid => params[:eid]})
319
- content_tag(:span, check_box_tag(nil, !all_marked, all_marked), tag_options)
330
+ content_tag(:span, check_box_tag("#{controller_id}_mark_heading_span_input", !all_marked, all_marked), tag_options)
320
331
  end
321
332
 
322
333
  def render_column_heading(column, sorting, sort_direction)
@@ -342,19 +353,19 @@ module ActiveScaffold
342
353
  end
343
354
  end
344
355
  end
345
-
356
+
346
357
  def render_nested_view(action_links, url_options, record)
347
358
  rendered = []
348
359
  action_links.member.each do |link|
349
- if link.nested_link? && link.column && @nested_auto_open[link.column.name] && @records.length <= @nested_auto_open[link.column.name] && respond_to?(:render_component)
350
- link_url_options = {:adapter => '_list_inline_adapter', :format => :js}.merge(action_link_url_options(link, url_options, record, options = {:reuse_eid => true}))
360
+ if link.nested_link? && link.column && @nested_auto_open[link.column.name] && @records.length <= @nested_auto_open[link.column.name] && controller.respond_to?(:render_component_into_view)
361
+ link_url_options = {:adapter => '_list_inline_adapter', :format => :js}.merge(action_link_url_options(link, url_options, record, options = {:reuse_eid => true}))
351
362
  link_id = get_action_link_id(link_url_options, record, link.column)
352
- rendered << (render_component(link_url_options) + javascript_tag("ActiveScaffold.ActionLink.get('#{link_id}').set_opened();"))
353
- end
363
+ rendered << (controller.send(:render_component_into_view, link_url_options) + javascript_tag("ActiveScaffold.ActionLink.get('#{link_id}').set_opened();"))
364
+ end
354
365
  end
355
366
  rendered.join(' ').html_safe
356
- end
357
-
367
+ end
368
+
358
369
  end
359
370
  end
360
371
  end
@@ -59,7 +59,7 @@ module ActiveScaffold
59
59
  associated = options.delete :value
60
60
  associated = [associated].compact unless associated.is_a? Array
61
61
  associated.collect!(&:to_i)
62
-
62
+
63
63
  if column.association
64
64
  select_options = options_for_association(column.association, false)
65
65
  else
@@ -86,7 +86,7 @@ module ActiveScaffold
86
86
  if html_options[:multiple]
87
87
  html_options[:name] += '[]'
88
88
  else
89
- options[:include_blank] ||= as_(:_select_)
89
+ options[:include_blank] ||= as_(:_select_)
90
90
  end
91
91
  select(:record, method, select_options, options, html_options)
92
92
  end
@@ -107,7 +107,7 @@ module ActiveScaffold
107
107
  end
108
108
  # we can't use checkbox ui because it's not possible to decide whether search for this field or not
109
109
  alias_method :active_scaffold_search_checkbox, :active_scaffold_search_boolean
110
-
110
+
111
111
  def active_scaffold_search_null(column, options)
112
112
  select_options = []
113
113
  select_options << [as_(:_select_), nil]
@@ -118,18 +118,46 @@ module ActiveScaffold
118
118
  def field_search_params_range_values(column)
119
119
  values = field_search_params[column.name]
120
120
  return nil if values.nil?
121
- return values[:opt], values[:from], values[:to]
121
+ return values[:opt], (values[:from].blank? ? nil : values[:from]), (values[:to].blank? ? nil : values[:to])
122
+
122
123
  end
123
124
 
124
- def active_scaffold_search_range(column, options)
125
- opt_value, from_value, to_value = field_search_params_range_values(column)
125
+ def active_scaffold_search_range_string?(column)
126
+ (column.column && column.column.text?) || column.search_ui == :string
127
+ end
128
+
129
+ def include_null_comparators?(column)
130
+ return column.options[:null_comparators] if column.options.has_key? :null_comparators
131
+ if column.association
132
+ column.association.macro != :belongs_to || active_scaffold_config.columns[column.association.primary_key_name].column.try(:null)
133
+ else
134
+ column.column.try(:null)
135
+ end
136
+ end
126
137
 
127
- text_field_size = 10
138
+ def active_scaffold_search_range_comparator_options(column)
128
139
  select_options = ActiveScaffold::Finder::NumericComparators.collect {|comp| [as_(comp.downcase.to_sym), comp]}
129
- if column.column && column.column.text?
140
+ if active_scaffold_search_range_string?(column)
130
141
  select_options.unshift *ActiveScaffold::Finder::StringComparators.collect {|title, comp| [as_(title), comp]}
142
+ end
143
+ if include_null_comparators? column
144
+ select_options += ActiveScaffold::Finder::NullComparators.collect {|comp| [as_(comp), comp]}
145
+ end
146
+ select_options
147
+ end
148
+
149
+ def active_scaffold_search_range(column, options)
150
+ opt_value, from_value, to_value = field_search_params_range_values(column)
151
+
152
+ select_options = active_scaffold_search_range_comparator_options(column)
153
+ if active_scaffold_search_range_string?(column)
131
154
  text_field_size = 15
155
+ opt_value ||= '%?%'
156
+ else
157
+ text_field_size = 10
158
+ opt_value ||= '='
132
159
  end
160
+
133
161
  from_value = controller.class.condition_value_for_numeric(column, from_value)
134
162
  to_value = controller.class.condition_value_for_numeric(column, to_value)
135
163
  from_value = format_number_value(from_value, column.options) if from_value.is_a?(Numeric)
@@ -142,44 +170,23 @@ module ActiveScaffold
142
170
  html << ' ' << content_tag(:span, (' - ' + text_field_tag("#{options[:name]}[to]", to_value,
143
171
  active_scaffold_input_text_options(:id => "#{options[:id]}_to", :size => text_field_size))).html_safe,
144
172
  :id => "#{options[:id]}_between", :class => "as_search_range_between", :style => "display:#{(opt_value == 'BETWEEN') ? '' : 'none'}")
145
- html
173
+ content_tag :span, html, :class => 'search_range'
146
174
  end
147
175
  alias_method :active_scaffold_search_integer, :active_scaffold_search_range
148
176
  alias_method :active_scaffold_search_decimal, :active_scaffold_search_range
149
177
  alias_method :active_scaffold_search_float, :active_scaffold_search_range
150
178
  alias_method :active_scaffold_search_string, :active_scaffold_search_range
151
179
 
152
- def active_scaffold_search_record_select(column, options)
153
- value = field_search_record_select_value(column)
154
- active_scaffold_record_select(column, options, value, column.options[:multiple])
155
- end
156
-
157
- def field_search_record_select_value(column)
158
- begin
159
- value = field_search_params[column.name]
160
- unless value.blank?
161
- if column.options[:multiple]
162
- column.association.klass.find value.collect!(&:to_i)
163
- else
164
- column.association.klass.find(value.to_i)
165
- end
166
- end
167
- rescue Exception => e
168
- logger.error Time.now.to_s + "Sorry, we are not that smart yet. Attempted to restore search values to search fields but instead got -- #{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
169
- raise e
170
- end
171
- end
172
-
173
180
  def field_search_datetime_value(value)
174
181
  DateTime.new(value[:year].to_i, value[:month].to_i, value[:day].to_i, value[:hour].to_i, value[:minute].to_i, value[:second].to_i) unless value.nil? || value[:year].blank?
175
182
  end
176
-
183
+
177
184
  def active_scaffold_search_datetime(column, options)
178
185
  opt_value, from_value, to_value = field_search_params_range_values(column)
179
186
  options = column.options.merge(options)
180
187
  helper = "select_#{'date' unless options[:discard_date]}#{'time' unless options[:discard_time]}"
181
-
182
- send(helper, field_search_datetime_value(from_value), {:include_blank => true, :prefix => "#{options[:name]}[from]"}.merge(options)) <<
188
+
189
+ send(helper, field_search_datetime_value(from_value), {:include_blank => true, :prefix => "#{options[:name]}[from]"}.merge(options)) <<
183
190
  ' - '.html_safe << send(helper, field_search_datetime_value(to_value), {:include_blank => true, :prefix => "#{options[:name]}[to]"}.merge(options))
184
191
  end
185
192
 
@@ -195,13 +202,17 @@ module ActiveScaffold
195
202
  ## Search column override signatures
196
203
  ##
197
204
 
198
- def override_search_field?(column)
199
- respond_to?(override_search_field(column))
205
+ def override_search_field(column)
206
+ method_with_class = override_search_field_name(column, true)
207
+ return method_with_class if respond_to?(method_with_class)
208
+ method = override_search_field_name(column)
209
+ method if respond_to?(method)
200
210
  end
211
+ alias_method :override_search_field?, :override_search_field
201
212
 
202
213
  # the naming convention for overriding form fields with helpers
203
- def override_search_field(column)
204
- "#{column.name}_search_column"
214
+ def override_search_field_name(column, class_prefix = false)
215
+ "#{clean_class_name(column.active_record_class.name) + '_' if class_prefix}#{clean_column_name(column.name)}_search_column"
205
216
  end
206
217
 
207
218
  def override_search?(search_ui)
@@ -212,9 +223,9 @@ module ActiveScaffold
212
223
  def override_search(form_ui)
213
224
  "active_scaffold_search_#{form_ui}"
214
225
  end
215
-
226
+
216
227
  def visibles_and_hiddens(search_config)
217
- visibles = []
228
+ visibles = []
218
229
  hiddens = []
219
230
  search_config.columns.each do |column|
220
231
  next unless column.search_sql
@@ -226,7 +237,7 @@ module ActiveScaffold
226
237
  end
227
238
  return visibles, hiddens
228
239
  end
229
-
240
+
230
241
  def searched_by?(column)
231
242
  value = field_search_params[column.name]
232
243
  case value
@@ -0,0 +1,215 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ # Helpers that assist with the rendering of a Form Column
4
+ module SearchColumnHelpers
5
+ # This method decides which input to use for the given column.
6
+ # It does not do any rendering. It only decides which method is responsible for rendering.
7
+ def active_scaffold_search_for(column)
8
+ options = active_scaffold_search_options(column)
9
+
10
+ # first, check if the dev has created an override for this specific field for search
11
+ if override_search_field?(column)
12
+ send(override_search_field(column), @record, options)
13
+
14
+ # second, check if the dev has specified a valid search_ui for this column, using specific ui for searches
15
+ elsif column.search_ui and override_search?(column.search_ui)
16
+ send(override_search(column.search_ui), column, options)
17
+
18
+ # third, check if the dev has specified a valid search_ui for this column, using generic ui for forms
19
+ elsif column.search_ui and override_input?(column.search_ui)
20
+ send(override_input(column.search_ui), column, options)
21
+
22
+ # fourth, check if the dev has created an override for this specific field
23
+ elsif override_form_field?(column)
24
+ send(override_form_field(column), @record, options)
25
+
26
+ # fallback: we get to make the decision
27
+ else
28
+ if column.association or column.virtual?
29
+ active_scaffold_search_text(column, options)
30
+
31
+ else # regular model attribute column
32
+ # if we (or someone else) have created a custom render option for the column type, use that
33
+ if override_search?(column.column.type)
34
+ send(override_search(column.column.type), column, options)
35
+ # if we (or someone else) have created a custom render option for the column type, use that
36
+ elsif override_input?(column.column.type)
37
+ send(override_input(column.column.type), column, options)
38
+ # final ultimate fallback: use rails' generic input method
39
+ else
40
+ # for textual fields we pass different options
41
+ text_types = [:text, :string, :integer, :float, :decimal]
42
+ options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
43
+ input(:record, column.name, options.merge(column.options))
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ # the standard active scaffold options used for class, name and scope
50
+ def active_scaffold_search_options(column)
51
+ { :name => "search[#{column.name}]", :class => "#{column.name}-input", :id => "search_#{column.name}", :value => field_search_params[column.name] }
52
+ end
53
+
54
+ ##
55
+ ## Search input methods
56
+ ##
57
+
58
+ def active_scaffold_search_multi_select(column, options)
59
+ associated = options.delete :value
60
+ associated = [associated].compact unless associated.is_a? Array
61
+ associated.collect!(&:to_i)
62
+ select_options = options_for_association(column.association, true)
63
+ return as_(:no_options) if select_options.empty?
64
+
65
+ html = "<ul class=\"checkbox-list\" id=\"#{options[:id]}\">"
66
+
67
+ options[:name] += '[]'
68
+ select_options.each_with_index do |option, i|
69
+ label, id = option
70
+ this_id = "#{options[:id]}_#{i}_id"
71
+ html << "<li>"
72
+ html << check_box_tag(options[:name], id, associated.include?(id), :id => this_id)
73
+ html << "<label for='#{this_id}'>"
74
+ html << label
75
+ html << "</label>"
76
+ html << "</li>"
77
+ end
78
+
79
+ html << '</ul>'
80
+ html << javascript_tag("new DraggableLists('#{options[:id]}')") if column.options[:draggable_lists]
81
+ html
82
+ end
83
+
84
+ def active_scaffold_search_select(column, html_options)
85
+ associated = html_options.delete :value
86
+ if column.association
87
+ associated = associated.is_a?(Array) ? associated.map(&:to_i) : associated.to_i unless associated.nil?
88
+ method = column.association.macro == :belongs_to ? column.association.primary_key_name : column.name
89
+ options_for_select = options_for_association(column.association, true)
90
+ else
91
+ method = column.name
92
+ options_for_select = active_scaffold_translated_options(column)
93
+ end
94
+
95
+ options = { :selected => associated }.merge! column.options
96
+ html_options.merge! column.options[:html_options] || {}
97
+ if html_options[:multiple]
98
+ html_options[:name] += '[]'
99
+ else
100
+ options[:include_blank] ||= as_(:_select_)
101
+ end
102
+ select(:record, method, options_for_select, options, html_options)
103
+ end
104
+
105
+ def active_scaffold_search_text(column, options)
106
+ text_field :record, column.name, active_scaffold_input_text_options(options)
107
+ end
108
+
109
+ # we can't use active_scaffold_input_boolean because we need to have a nil value even when column can't be null
110
+ # to decide whether search for this field or not
111
+ def active_scaffold_search_boolean(column, options)
112
+ select_options = []
113
+ select_options << [as_(:_select_), nil]
114
+ select_options << [as_(:true), true]
115
+ select_options << [as_(:false), false]
116
+
117
+ select_tag(options[:name], options_for_select(select_options, column.column.type_cast(field_search_params[column.name])))
118
+ end
119
+ # we can't use checkbox ui because it's not possible to decide whether search for this field or not
120
+ alias_method :active_scaffold_search_checkbox, :active_scaffold_search_boolean
121
+
122
+ def field_search_params_range_values(column)
123
+ values = field_search_params[column.name]
124
+ return nil if values.nil?
125
+ return values[:opt], values[:from], values[:to]
126
+ end
127
+
128
+ def include_null_comparators?(column)
129
+ return column.options[:null_comparators] if column.options.has_key? :null_comparators
130
+ if column.association
131
+ column.association.macro != :belongs_to || active_scaffold_config.columns[column.association.primary_key_name].column.try(:null)
132
+ else
133
+ column.column.try(:null)
134
+ end
135
+ end
136
+
137
+ def active_scaffold_search_range(column, options)
138
+ opt_value, from_value, to_value = field_search_params_range_values(column)
139
+ select_options = ActiveScaffold::Finder::NumericComparators.collect {|comp| [as_(comp.downcase.to_sym), comp]}
140
+ select_options.unshift *ActiveScaffold::Finder::StringComparators.collect {|title, comp| [as_(title), comp]} if column.options[:string_comparators] || column.column.try(:text?)
141
+ select_options += ActiveScaffold::Finder::NullComparators.collect {|comp| [as_(comp.downcase.to_sym), comp]} if include_null_comparators? column
142
+
143
+ html = []
144
+ html << select_tag("#{options[:name]}[opt]",
145
+ options_for_select(select_options, opt_value),
146
+ :id => "#{options[:id]}_opt",
147
+ :onchange => "Element[this.value == 'BETWEEN' ? 'show' : 'hide']('#{options[:id]}_between');")
148
+ html << text_field_tag("#{options[:name]}[from]", from_value, active_scaffold_input_text_options(:id => options[:id], :size => 10))
149
+ html << content_tag(:span, ' - ' + text_field_tag("#{options[:name]}[to]", to_value,
150
+ active_scaffold_input_text_options(:id => "#{options[:id]}_to", :size => 10)),
151
+ :id => "#{options[:id]}_between", :style => "display:none")
152
+ html * ' '
153
+ end
154
+ alias_method :active_scaffold_search_integer, :active_scaffold_search_range
155
+ alias_method :active_scaffold_search_decimal, :active_scaffold_search_range
156
+ alias_method :active_scaffold_search_float, :active_scaffold_search_range
157
+ alias_method :active_scaffold_search_string, :active_scaffold_search_range
158
+
159
+ def field_search_datetime_value(value)
160
+ DateTime.new(value[:year].to_i, value[:month].to_i, value[:day].to_i, value[:hour].to_i, value[:minute].to_i, value[:second].to_i) unless value.nil? || value[:year].blank?
161
+ end
162
+
163
+ def active_scaffold_search_datetime(column, options)
164
+ opt_value, from_value, to_value = field_search_params_range_values(column)
165
+ options = column.options.merge(options)
166
+ helper = "select_#{'date' unless options[:discard_date]}#{'time' unless options[:discard_time]}"
167
+ html = []
168
+ html << send(helper, field_search_datetime_value(from_value), {:include_blank => true, :prefix => "#{options[:name]}[from]"}.merge(options))
169
+ html << send(helper, field_search_datetime_value(to_value), {:include_blank => true, :prefix => "#{options[:name]}[to]"}.merge(options))
170
+ html * ' - '
171
+ end
172
+
173
+ def active_scaffold_search_date(column, options)
174
+ active_scaffold_search_datetime(column, options.merge!(:discard_time => true))
175
+ end
176
+ def active_scaffold_search_time(column, options)
177
+ active_scaffold_search_datetime(column, options.merge!(:discard_date => true))
178
+ end
179
+ alias_method :active_scaffold_search_timestamp, :active_scaffold_search_datetime
180
+
181
+ ##
182
+ ## Search column override signatures
183
+ ##
184
+
185
+ def override_search_field(column)
186
+ method = override_search_field_name(column)
187
+ return method if respond_to?(method)
188
+ old_method = override_search_field_name(column, true)
189
+ if respond_to?(old_method)
190
+ ActiveSupport::Deprecation.warn("You are using an old naming schema for overrides, you should name the helper #{method} instead of #{old_method}")
191
+ old_method
192
+ end
193
+ method_with_class = override_search_field_name(column, true)
194
+ return method_with_class if respond_to?(method_with_class)
195
+ method = override_form_field_name(column)
196
+ method if respond_to?(method)
197
+ end
198
+ alias_method :override_search_field?, :override_search_field
199
+
200
+ # the naming convention for overriding form fields with helpers
201
+ def override_search_field_name(column, class_prefix = false)
202
+ "#{clean_class_name(column.active_record_class.name) + '_' if class_prefix}#{clean_column_name(column.name)}_search_column"
203
+ end
204
+
205
+ def override_search?(search_ui)
206
+ respond_to?(override_search(search_ui))
207
+ end
208
+
209
+ # the naming convention for overriding search input types with helpers
210
+ def override_search(form_ui)
211
+ "active_scaffold_search_#{form_ui}"
212
+ end
213
+ end
214
+ end
215
+ end