active_scaffold_vho 3.0.6

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 (279) hide show
  1. data/.autotest +27 -0
  2. data/.document +5 -0
  3. data/CHANGELOG +179 -0
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +20 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README +63 -0
  8. data/Rakefile +53 -0
  9. data/frontends/default/images/add.gif +0 -0
  10. data/frontends/default/images/arrow_down.gif +0 -0
  11. data/frontends/default/images/arrow_up.gif +0 -0
  12. data/frontends/default/images/close.gif +0 -0
  13. data/frontends/default/images/config.png +0 -0
  14. data/frontends/default/images/cross.png +0 -0
  15. data/frontends/default/images/gears.png +0 -0
  16. data/frontends/default/images/indicator-small.gif +0 -0
  17. data/frontends/default/images/indicator.gif +0 -0
  18. data/frontends/default/images/magnifier.png +0 -0
  19. data/frontends/default/javascripts/jquery/active_scaffold.js +957 -0
  20. data/frontends/default/javascripts/jquery/jquery.editinplace.js +743 -0
  21. data/frontends/default/javascripts/prototype/active_scaffold.js +957 -0
  22. data/frontends/default/javascripts/prototype/dhtml_history.js +867 -0
  23. data/frontends/default/javascripts/prototype/form_enhancements.js +117 -0
  24. data/frontends/default/javascripts/prototype/rico_corner.js +370 -0
  25. data/frontends/default/stylesheets/stylesheet-ie.css +35 -0
  26. data/frontends/default/stylesheets/stylesheet.css +964 -0
  27. data/frontends/default/views/_action_group.html.erb +20 -0
  28. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  29. data/frontends/default/views/_base_form.html.erb +45 -0
  30. data/frontends/default/views/_create_form.html.erb +8 -0
  31. data/frontends/default/views/_create_form_on_list.html.erb +6 -0
  32. data/frontends/default/views/_field_search.html.erb +32 -0
  33. data/frontends/default/views/_form.html.erb +24 -0
  34. data/frontends/default/views/_form_association.html.erb +14 -0
  35. data/frontends/default/views/_form_association_footer.html.erb +40 -0
  36. data/frontends/default/views/_form_attribute.html.erb +15 -0
  37. data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
  38. data/frontends/default/views/_form_messages.html.erb +5 -0
  39. data/frontends/default/views/_horizontal_subform.html.erb +19 -0
  40. data/frontends/default/views/_horizontal_subform_header.html.erb +10 -0
  41. data/frontends/default/views/_horizontal_subform_record.html.erb +37 -0
  42. data/frontends/default/views/_human_conditions.html.erb +1 -0
  43. data/frontends/default/views/_list.html.erb +18 -0
  44. data/frontends/default/views/_list_actions.html.erb +15 -0
  45. data/frontends/default/views/_list_calculations.html.erb +16 -0
  46. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  47. data/frontends/default/views/_list_header.html.erb +10 -0
  48. data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
  49. data/frontends/default/views/_list_messages.html.erb +32 -0
  50. data/frontends/default/views/_list_pagination.html.erb +11 -0
  51. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  52. data/frontends/default/views/_list_record.html.erb +14 -0
  53. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  54. data/frontends/default/views/_list_with_header.html.erb +32 -0
  55. data/frontends/default/views/_messages.html.erb +10 -0
  56. data/frontends/default/views/_render_field.js.rjs +13 -0
  57. data/frontends/default/views/_row.html.erb +12 -0
  58. data/frontends/default/views/_search.html.erb +34 -0
  59. data/frontends/default/views/_search_attribute.html.erb +10 -0
  60. data/frontends/default/views/_show.html.erb +8 -0
  61. data/frontends/default/views/_show_columns.html.erb +15 -0
  62. data/frontends/default/views/_update_actions.html.erb +9 -0
  63. data/frontends/default/views/_update_form.html.erb +6 -0
  64. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  65. data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
  66. data/frontends/default/views/action_confirmation.html.erb +13 -0
  67. data/frontends/default/views/add_existing.js.rjs +17 -0
  68. data/frontends/default/views/add_existing_form.html.erb +5 -0
  69. data/frontends/default/views/create.html.erb +5 -0
  70. data/frontends/default/views/delete.html.erb +13 -0
  71. data/frontends/default/views/destroy.js.rjs +11 -0
  72. data/frontends/default/views/edit_associated.js.rjs +11 -0
  73. data/frontends/default/views/field_search.html.erb +5 -0
  74. data/frontends/default/views/form_messages.js.rjs +1 -0
  75. data/frontends/default/views/list.html.erb +1 -0
  76. data/frontends/default/views/list.js.rjs +1 -0
  77. data/frontends/default/views/on_action_update.js.rjs +8 -0
  78. data/frontends/default/views/on_create.js.rjs +41 -0
  79. data/frontends/default/views/on_update.js.rjs +28 -0
  80. data/frontends/default/views/search.html.erb +5 -0
  81. data/frontends/default/views/show.html.erb +5 -0
  82. data/frontends/default/views/update.html.erb +8 -0
  83. data/frontends/default/views/update_column.js.rjs +13 -0
  84. data/frontends/default/views/update_row.js.rjs +1 -0
  85. data/init.rb +9 -0
  86. data/lib/active_record_permissions.rb +134 -0
  87. data/lib/active_scaffold/actions/common_search.rb +22 -0
  88. data/lib/active_scaffold/actions/core.rb +170 -0
  89. data/lib/active_scaffold/actions/create.rb +145 -0
  90. data/lib/active_scaffold/actions/delete.rb +75 -0
  91. data/lib/active_scaffold/actions/field_search.rb +82 -0
  92. data/lib/active_scaffold/actions/list.rb +184 -0
  93. data/lib/active_scaffold/actions/mark.rb +50 -0
  94. data/lib/active_scaffold/actions/nested.rb +250 -0
  95. data/lib/active_scaffold/actions/search.rb +47 -0
  96. data/lib/active_scaffold/actions/show.rb +61 -0
  97. data/lib/active_scaffold/actions/subform.rb +17 -0
  98. data/lib/active_scaffold/actions/update.rb +141 -0
  99. data/lib/active_scaffold/attribute_params.rb +207 -0
  100. data/lib/active_scaffold/bridges/ancestry/bridge.rb +5 -0
  101. data/lib/active_scaffold/bridges/ancestry/lib/ancestry_bridge.rb +39 -0
  102. data/lib/active_scaffold/bridges/bridge.rb +52 -0
  103. data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +16 -0
  104. data/lib/active_scaffold/bridges/calendar_date_select/lib/as_cds_bridge.rb +79 -0
  105. data/lib/active_scaffold/bridges/carrierwave/bridge.rb +7 -0
  106. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +38 -0
  107. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +26 -0
  108. data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +35 -0
  109. data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +17 -0
  110. data/lib/active_scaffold/bridges/date_picker/bridge.rb +22 -0
  111. data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +225 -0
  112. data/lib/active_scaffold/bridges/date_picker/public/javascripts/date_picker_bridge.js +22 -0
  113. data/lib/active_scaffold/bridges/file_column/bridge.rb +11 -0
  114. data/lib/active_scaffold/bridges/file_column/lib/as_file_column_bridge.rb +46 -0
  115. data/lib/active_scaffold/bridges/file_column/lib/file_column_helpers.rb +59 -0
  116. data/lib/active_scaffold/bridges/file_column/lib/form_ui.rb +37 -0
  117. data/lib/active_scaffold/bridges/file_column/lib/list_ui.rb +26 -0
  118. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  119. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  120. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  121. data/lib/active_scaffold/bridges/paperclip/bridge.rb +10 -0
  122. data/lib/active_scaffold/bridges/paperclip/lib/form_ui.rb +27 -0
  123. data/lib/active_scaffold/bridges/paperclip/lib/list_ui.rb +16 -0
  124. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge.rb +38 -0
  125. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge_helpers.rb +26 -0
  126. data/lib/active_scaffold/bridges/semantic_attributes/bridge.rb +5 -0
  127. data/lib/active_scaffold/bridges/semantic_attributes/lib/semantic_attributes_bridge.rb +20 -0
  128. data/lib/active_scaffold/bridges/shared/date_bridge.rb +187 -0
  129. data/lib/active_scaffold/bridges/tiny_mce/bridge.rb +5 -0
  130. data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +45 -0
  131. data/lib/active_scaffold/bridges/validation_reflection/bridge.rb +8 -0
  132. data/lib/active_scaffold/bridges/validation_reflection/lib/validation_reflection_bridge.rb +21 -0
  133. data/lib/active_scaffold/config/base.rb +62 -0
  134. data/lib/active_scaffold/config/core.rb +220 -0
  135. data/lib/active_scaffold/config/create.rb +51 -0
  136. data/lib/active_scaffold/config/delete.rb +34 -0
  137. data/lib/active_scaffold/config/field_search.rb +75 -0
  138. data/lib/active_scaffold/config/form.rb +47 -0
  139. data/lib/active_scaffold/config/list.rb +174 -0
  140. data/lib/active_scaffold/config/mark.rb +22 -0
  141. data/lib/active_scaffold/config/nested.rb +44 -0
  142. data/lib/active_scaffold/config/search.rb +69 -0
  143. data/lib/active_scaffold/config/show.rb +35 -0
  144. data/lib/active_scaffold/config/subform.rb +35 -0
  145. data/lib/active_scaffold/config/update.rb +46 -0
  146. data/lib/active_scaffold/configurable.rb +29 -0
  147. data/lib/active_scaffold/constraints.rb +184 -0
  148. data/lib/active_scaffold/data_structures/action_columns.rb +133 -0
  149. data/lib/active_scaffold/data_structures/action_link.rb +171 -0
  150. data/lib/active_scaffold/data_structures/action_links.rb +175 -0
  151. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  152. data/lib/active_scaffold/data_structures/column.rb +351 -0
  153. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  154. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  155. data/lib/active_scaffold/data_structures/nested_info.rb +123 -0
  156. data/lib/active_scaffold/data_structures/set.rb +62 -0
  157. data/lib/active_scaffold/data_structures/sorting.rb +168 -0
  158. data/lib/active_scaffold/finder.rb +333 -0
  159. data/lib/active_scaffold/helpers/association_helpers.rb +40 -0
  160. data/lib/active_scaffold/helpers/controller_helpers.rb +82 -0
  161. data/lib/active_scaffold/helpers/country_helpers.rb +352 -0
  162. data/lib/active_scaffold/helpers/form_column_helpers.rb +347 -0
  163. data/lib/active_scaffold/helpers/human_condition_helpers.rb +59 -0
  164. data/lib/active_scaffold/helpers/id_helpers.rb +127 -0
  165. data/lib/active_scaffold/helpers/list_column_helpers.rb +361 -0
  166. data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
  167. data/lib/active_scaffold/helpers/search_column_helpers.rb +243 -0
  168. data/lib/active_scaffold/helpers/show_column_helpers.rb +46 -0
  169. data/lib/active_scaffold/helpers/view_helpers.rb +356 -0
  170. data/lib/active_scaffold/locale/de.rb +120 -0
  171. data/lib/active_scaffold/locale/en.rb +119 -0
  172. data/lib/active_scaffold/locale/es.yml +115 -0
  173. data/lib/active_scaffold/locale/fr.rb +116 -0
  174. data/lib/active_scaffold/locale/hu.yml +63 -0
  175. data/lib/active_scaffold/locale/ja.yml +64 -0
  176. data/lib/active_scaffold/locale/ru.yml +119 -0
  177. data/lib/active_scaffold/marked_model.rb +38 -0
  178. data/lib/active_scaffold/version.rb +9 -0
  179. data/lib/active_scaffold.rb +345 -0
  180. data/lib/active_scaffold_assets.rb +45 -0
  181. data/lib/dhtml_confirm.rb +54 -0
  182. data/lib/environment.rb +14 -0
  183. data/lib/extensions/action_controller_rendering.rb +20 -0
  184. data/lib/extensions/action_view_rendering.rb +113 -0
  185. data/lib/extensions/action_view_resolver.rb +7 -0
  186. data/lib/extensions/active_association_reflection.rb +13 -0
  187. data/lib/extensions/active_record_offset.rb +12 -0
  188. data/lib/extensions/array.rb +7 -0
  189. data/lib/extensions/localize.rb +10 -0
  190. data/lib/extensions/name_option_for_datetime.rb +12 -0
  191. data/lib/extensions/nil_id_in_url_params.rb +7 -0
  192. data/lib/extensions/paginator_extensions.rb +26 -0
  193. data/lib/extensions/reverse_associations.rb +62 -0
  194. data/lib/extensions/routing_mapper.rb +34 -0
  195. data/lib/extensions/to_label.rb +8 -0
  196. data/lib/extensions/unsaved_associated.rb +61 -0
  197. data/lib/extensions/unsaved_record.rb +20 -0
  198. data/lib/extensions/usa_state.rb +46 -0
  199. data/lib/generators/active_scaffold/USAGE +29 -0
  200. data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
  201. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  202. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +28 -0
  203. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  204. data/lib/generators/active_scaffold_setup/USAGE +10 -0
  205. data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +53 -0
  206. data/lib/paginator.rb +136 -0
  207. data/lib/responds_to_parent.rb +70 -0
  208. data/public/blank.html +33 -0
  209. data/shoulda_macros/macros.rb +136 -0
  210. data/test/bridges/bridge_test.rb +47 -0
  211. data/test/config/base_test.rb +15 -0
  212. data/test/config/create_test.rb +55 -0
  213. data/test/config/list_test.rb +74 -0
  214. data/test/config/show_test.rb +43 -0
  215. data/test/config/update_test.rb +17 -0
  216. data/test/const_mocker.rb +36 -0
  217. data/test/data_structures/action_columns_test.rb +113 -0
  218. data/test/data_structures/action_link_test.rb +78 -0
  219. data/test/data_structures/action_links_test.rb +78 -0
  220. data/test/data_structures/actions_test.rb +25 -0
  221. data/test/data_structures/association_column_test.rb +42 -0
  222. data/test/data_structures/column_test.rb +185 -0
  223. data/test/data_structures/columns_test.rb +69 -0
  224. data/test/data_structures/error_message_test.rb +28 -0
  225. data/test/data_structures/set_test.rb +86 -0
  226. data/test/data_structures/sorting_test.rb +126 -0
  227. data/test/data_structures/standard_column_test.rb +24 -0
  228. data/test/data_structures/virtual_column_test.rb +23 -0
  229. data/test/extensions/active_record_test.rb +45 -0
  230. data/test/extensions/array_test.rb +12 -0
  231. data/test/helpers/form_column_helpers_test.rb +31 -0
  232. data/test/helpers/list_column_helpers_test.rb +31 -0
  233. data/test/helpers/pagination_helpers_test.rb +55 -0
  234. data/test/misc/active_record_permissions_test.rb +154 -0
  235. data/test/misc/attribute_params_test.rb +110 -0
  236. data/test/misc/configurable_test.rb +96 -0
  237. data/test/misc/constraints_test.rb +193 -0
  238. data/test/misc/finder_test.rb +93 -0
  239. data/test/misc/lang_test.rb +12 -0
  240. data/test/mock_app/.gitignore +2 -0
  241. data/test/mock_app/app/controllers/application_controller.rb +10 -0
  242. data/test/mock_app/app/helpers/application_helper.rb +3 -0
  243. data/test/mock_app/config/boot.rb +110 -0
  244. data/test/mock_app/config/database.yml +16 -0
  245. data/test/mock_app/config/environment.rb +43 -0
  246. data/test/mock_app/config/environments/development.rb +17 -0
  247. data/test/mock_app/config/environments/production.rb +28 -0
  248. data/test/mock_app/config/environments/test.rb +28 -0
  249. data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
  250. data/test/mock_app/config/initializers/inflections.rb +10 -0
  251. data/test/mock_app/config/initializers/mime_types.rb +5 -0
  252. data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  253. data/test/mock_app/config/initializers/session_store.rb +15 -0
  254. data/test/mock_app/config/locales/en.yml +5 -0
  255. data/test/mock_app/config/routes.rb +43 -0
  256. data/test/mock_app/db/test.sqlite3 +1 -0
  257. data/test/mock_app/public/blank.html +33 -0
  258. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
  259. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  260. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  261. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  262. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  263. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  264. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  265. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  266. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  267. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
  268. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
  269. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
  270. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
  271. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
  272. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
  273. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
  274. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +839 -0
  275. data/test/model_stub.rb +55 -0
  276. data/test/run_all.rb +8 -0
  277. data/test/test_helper.rb +39 -0
  278. data/uninstall.rb +13 -0
  279. metadata +492 -0
@@ -0,0 +1,361 @@
1
+ # coding: utf-8
2
+ module ActiveScaffold
3
+ module Helpers
4
+ # Helpers that assist with the rendering of a List Column
5
+ module ListColumnHelpers
6
+ def get_column_value(record, column)
7
+ begin
8
+ # check for an override helper
9
+ value = if column_override? column
10
+ # we only pass the record as the argument. we previously also passed the formatted_value,
11
+ # but mike perham pointed out that prohibited the usage of overrides to improve on the
12
+ # performance of our default formatting. see issue #138.
13
+ send(column_override(column), record)
14
+ # second, check if the dev has specified a valid list_ui for this column
15
+ elsif column.list_ui and override_column_ui?(column.list_ui)
16
+ send(override_column_ui(column.list_ui), column, record)
17
+ elsif column.column and override_column_ui?(column.column.type)
18
+ send(override_column_ui(column.column.type), column, record)
19
+ else
20
+ format_column_value(record, column)
21
+ end
22
+
23
+ value = ' '.html_safe if value.nil? or (value.respond_to?(:empty?) and value.empty?) # fix for IE 6
24
+ return value
25
+ rescue Exception => e
26
+ logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
27
+ raise e
28
+ end
29
+ end
30
+
31
+ # TODO: move empty_field_text and   logic in here?
32
+ # 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.
33
+ def render_list_column(text, column, record)
34
+ if column.link
35
+ link = column.link
36
+ associated = record.send(column.association.name) if column.association
37
+ url_options = params_for(:action => nil, :id => record.id, :link => text)
38
+
39
+ # setup automatic link
40
+ if column.autolink? && column.singular_association? # link to inline form
41
+ link = action_link_to_inline_form(column, record, associated)
42
+ return text if link.crud_type.nil?
43
+ url_options[:link] = as_(:create_new) if link.crud_type == :create
44
+ end
45
+
46
+ if column_link_authorized?(link, column, record, associated)
47
+ render_action_link(link, url_options, record)
48
+ else
49
+ "<a class='disabled'>#{text}</a>".html_safe
50
+ end
51
+ else
52
+ text = active_scaffold_inplace_edit(record, column, {:formatted_column => text}) if inplace_edit?(record, column)
53
+ text
54
+ end
55
+ end
56
+
57
+ # setup the action link to inline form
58
+ def action_link_to_inline_form(column, record, associated)
59
+ link = column.link.clone
60
+ if column.polymorphic_association?
61
+ polymorphic_controller = controller_path_for_activerecord(record.send(column.association.name).class)
62
+ return link if polymorphic_controller.nil?
63
+ link.controller = polymorphic_controller
64
+ end
65
+ configure_column_link(link, associated, column.actions_for_association_links)
66
+ end
67
+
68
+ def configure_column_link(link, associated, actions)
69
+ if column_empty?(associated) # if association is empty, we only can link to create form
70
+ if actions.include?(:new)
71
+ link.action = 'new'
72
+ link.crud_type = :create
73
+ end
74
+ elsif actions.include?(:edit)
75
+ link.action = 'edit'
76
+ link.crud_type = :update
77
+ elsif actions.include?(:show)
78
+ link.action = 'show'
79
+ link.crud_type = :read
80
+ elsif actions.include?(:list)
81
+ link.action = 'index'
82
+ link.crud_type = :read
83
+ end
84
+ link
85
+ end
86
+
87
+ def column_link_authorized?(link, column, record, associated)
88
+ if column.association
89
+ associated_for_authorized = if associated.nil? || (associated.respond_to?(:empty?) && associated.empty?)
90
+ column.association.klass
91
+ elsif [:has_many, :has_and_belongs_to_many].include? column.association.macro
92
+ associated.first
93
+ else
94
+ associated
95
+ end
96
+ authorized = associated_for_authorized.authorized_for?(:crud_type => link.crud_type)
97
+ authorized = authorized and record.authorized_for?(:crud_type => :update, :column => column.name) if link.crud_type == :create
98
+ authorized
99
+ else
100
+ record.authorized_for?(:crud_type => link.crud_type)
101
+ end
102
+ end
103
+
104
+ # There are two basic ways to clean a column's value: h() and sanitize(). The latter is useful
105
+ # when the column contains *valid* html data, and you want to just disable any scripting. People
106
+ # can always use field overrides to clean data one way or the other, but having this override
107
+ # lets people decide which way it should happen by default.
108
+ #
109
+ # Why is it not a configuration option? Because it seems like a somewhat rare request. But it
110
+ # could eventually be an option in config.list (and config.show, I guess).
111
+ def clean_column_value(v)
112
+ h(v)
113
+ end
114
+
115
+ ##
116
+ ## Overrides
117
+ ##
118
+ def active_scaffold_column_text(column, record)
119
+ truncate(clean_column_value(record.send(column.name)), :length => column.options[:truncate] || 50)
120
+ end
121
+
122
+ def active_scaffold_column_select(column, record)
123
+ if column.association
124
+ format_column_value(record, column)
125
+ else
126
+ value = record.send(column.name)
127
+ text, val = column.options[:options].find {|text, val| (val || text).to_s == value}
128
+ value = active_scaffold_translated_option(column, text, val).first if text
129
+ format_column_value(record, column, value)
130
+ end
131
+ end
132
+
133
+ def active_scaffold_column_checkbox(column, record)
134
+ options = {:disabled => true, :id => nil, :object => record}
135
+ options.delete(:disabled) if inplace_edit?(record, column)
136
+ check_box(:record, column.name, options)
137
+ end
138
+
139
+ def column_override(column)
140
+ "#{column.name.to_s.gsub('?', '')}_column" # parse out any question marks (see issue 227)
141
+ end
142
+
143
+ def column_override?(column)
144
+ respond_to?(column_override(column))
145
+ end
146
+
147
+ def override_column_ui?(list_ui)
148
+ respond_to?(override_column_ui(list_ui))
149
+ end
150
+
151
+ # the naming convention for overriding column types with helpers
152
+ def override_column_ui(list_ui)
153
+ "active_scaffold_column_#{list_ui}"
154
+ end
155
+
156
+ ##
157
+ ## Formatting
158
+ ##
159
+ def format_column_value(record, column, value = nil)
160
+ value ||= record.send(column.name) unless record.nil?
161
+ if value && column.association # cache association size before calling column_empty?
162
+ associated_size = value.size if column.plural_association? and column.associated_number? # get count before cache association
163
+ cache_association(value, column)
164
+ end
165
+ if column.association.nil? or column_empty?(value)
166
+ if value.is_a? Numeric
167
+ format_number_value(value, column.options)
168
+ else
169
+ format_value(value, column.options)
170
+ end
171
+ else
172
+ format_association_value(value, column, associated_size)
173
+ end
174
+ end
175
+
176
+ def format_number_value(value, options = {})
177
+ value = case options[:format]
178
+ when :size
179
+ number_to_human_size(value, options[:i18n_options] || {})
180
+ when :percentage
181
+ number_to_percentage(value, options[:i18n_options] || {})
182
+ when :currency
183
+ number_to_currency(value, options[:i18n_options] || {})
184
+ when :i18n_number
185
+ send("number_with_#{value.is_a?(Integer) ? 'delimiter' : 'precision'}", value, options[:i18n_options] || {})
186
+ else
187
+ value
188
+ end
189
+ clean_column_value(value)
190
+ end
191
+
192
+ def format_association_value(value, column, size)
193
+ case column.association.macro
194
+ when :has_one, :belongs_to
195
+ if column.polymorphic_association?
196
+ format_value("#{value.class.model_name.human}: #{value.to_label}")
197
+ else
198
+ format_value(value.to_label)
199
+ end
200
+ when :has_many, :has_and_belongs_to_many
201
+ if column.associated_limit.nil?
202
+ firsts = value.collect { |v| v.to_label }
203
+ else
204
+ firsts = value.first(column.associated_limit)
205
+ firsts.collect! { |v| v.to_label }
206
+ firsts[column.associated_limit] = '…' if value.size > column.associated_limit
207
+ end
208
+ if column.associated_limit == 0
209
+ size if column.associated_number?
210
+ else
211
+ joined_associated = format_value(firsts.join(', '))
212
+ joined_associated << " (#{size})" if column.associated_number? and column.associated_limit and value.size > column.associated_limit
213
+ joined_associated
214
+ end
215
+ end
216
+ end
217
+
218
+ def format_value(column_value, options = {})
219
+ value = if column_empty?(column_value)
220
+ active_scaffold_config.list.empty_field_text
221
+ elsif column_value.is_a?(Time) || column_value.is_a?(Date)
222
+ l(column_value, :format => options[:format] || :default)
223
+ elsif [FalseClass, TrueClass].include?(column_value.class)
224
+ as_(column_value.to_s.to_sym)
225
+ else
226
+ column_value.to_s
227
+ end
228
+ clean_column_value(value)
229
+ end
230
+
231
+ def cache_association(value, column)
232
+ # we are not using eager loading, cache firsts records in order not to query the database in a future
233
+ unless value.loaded?
234
+ # load at least one record, is needed for column_empty? and checking permissions
235
+ if column.associated_limit.nil?
236
+ Rails.logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
237
+ else
238
+ value.target = value.find(:all, :limit => column.associated_limit + 1, :select => column.select_columns)
239
+ end
240
+ end
241
+ end
242
+
243
+ # ==========
244
+ # = Inline Edit =
245
+ # ==========
246
+
247
+ def inplace_edit?(record, column)
248
+ if column.inplace_edit
249
+ 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
251
+ editable
252
+ end
253
+ end
254
+
255
+ def inplace_edit_cloning?(column)
256
+ column.inplace_edit != :ajax and (override_form_field?(column) or column.form_ui or (column.column and override_input?(column.column.type)))
257
+ end
258
+
259
+ def format_inplace_edit_column(record,column)
260
+ if column.list_ui == :checkbox
261
+ active_scaffold_column_checkbox(column, record)
262
+ else
263
+ format_column_value(record, column)
264
+ end
265
+ end
266
+
267
+ def active_scaffold_inplace_edit(record, column, options = {})
268
+ formatted_column = options[:formatted_column] || format_column_value(record, column)
269
+ id_options = {:id => record.id.to_s, :action => 'update_column', :name => column.name.to_s}
270
+ tag_options = {:id => element_cell_id(id_options), :class => "in_place_editor_field",
271
+ :title => as_(:click_to_edit), 'data-ie_id' => record.id.to_s}
272
+
273
+ content_tag(:span, formatted_column, tag_options)
274
+ end
275
+
276
+ def inplace_edit_control(column)
277
+ if inplace_edit?(active_scaffold_config.model, column) and inplace_edit_cloning?(column)
278
+ @record = active_scaffold_config.model.new
279
+ column = column.clone
280
+ column.options = column.options.clone
281
+ column.form_ui = :select if (column.association && column.form_ui.nil?)
282
+ content_tag(:div, active_scaffold_input_for(column), {:style => "display:none;", :class => inplace_edit_control_css_class})
283
+ end
284
+ end
285
+
286
+ def inplace_edit_control_css_class
287
+ "as_inplace_pattern"
288
+ end
289
+
290
+ def inplace_edit_tag_attributes(column)
291
+ tag_options = {}
292
+ tag_options['data-ie_url'] = url_for({:controller => params_for[:controller], :action => "update_column", :column => column.name, :id => '__id__'})
293
+ tag_options['data-ie_cancel_text'] = column.options[:cancel_text] || as_(:cancel)
294
+ tag_options['data-ie_loading_text'] = column.options[:loading_text] || as_(:loading)
295
+ tag_options['data-ie_save_text'] = column.options[:save_text] || as_(:update)
296
+ tag_options['data-ie_saving_text'] = column.options[:saving_text] || as_(:saving)
297
+ tag_options['data-ie_rows'] = column.options[:rows] || 5 if column.column.try(:type) == :text
298
+ tag_options['data-ie_cols'] = column.options[:cols] if column.options[:cols]
299
+ tag_options['data-ie_size'] = column.options[:size] if column.options[:size]
300
+
301
+ if column.list_ui == :checkbox
302
+ tag_options['data-ie_mode'] = :inline_checkbox
303
+ elsif inplace_edit_cloning?(column)
304
+ tag_options['data-ie_mode'] = :clone
305
+ elsif column.inplace_edit == :ajax
306
+ url = url_for(:controller => params_for[:controller], :action => 'render_field', :id => '__id__', :column => column.name, :update_column => column.name, :in_place_editing => true, :escape => false)
307
+ plural = column.plural_association? && !override_form_field?(column) && [:select, :record_select].include?(column.form_ui)
308
+ tag_options['data-ie_render_url'] = url
309
+ tag_options['data-ie_mode'] = :ajax
310
+ tag_options['data-ie_plural'] = plural
311
+ end
312
+ tag_options
313
+ end
314
+
315
+ def mark_column_heading
316
+ all_marked = (marked_records.length >= @page.pager.count)
317
+ tag_options = {:id => "#{controller_id}_mark_heading", :class => "mark_heading in_place_editor_field"}
318
+ 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)
320
+ end
321
+
322
+ def render_column_heading(column, sorting, sort_direction)
323
+ tag_options = {:id => active_scaffold_column_header_id(column), :class => column_heading_class(column, sorting), :title => column.description}
324
+ tag_options.merge!(inplace_edit_tag_attributes(column)) if column.inplace_edit
325
+ content_tag(:th, column_heading_value(column, sorting, sort_direction) + inplace_edit_control(column), tag_options)
326
+ end
327
+
328
+
329
+ def column_heading_value(column, sorting, sort_direction)
330
+ if column.sortable?
331
+ options = {:id => nil, :class => "as_sort",
332
+ 'data-page-history' => controller_id,
333
+ :remote => true, :method => :get}
334
+ url_options = params_for(:action => :index, :page => 1,
335
+ :sort => column.name, :sort_direction => sort_direction)
336
+ link_to column.label, url_options, options
337
+ else
338
+ if column.name != :marked
339
+ content_tag(:p, column.label)
340
+ else
341
+ mark_column_heading
342
+ end
343
+ end
344
+ end
345
+
346
+ def render_nested_view(action_links, url_options, record)
347
+ rendered = []
348
+ 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}))
351
+ 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
354
+ end
355
+ rendered.join(' ').html_safe
356
+ end
357
+
358
+ end
359
+ end
360
+ end
361
+
@@ -0,0 +1,55 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ module PaginationHelpers
4
+ def pagination_ajax_link(page_number, url_options, options)
5
+ link_to page_number, url_options.merge(:page => page_number), options.merge(:class => "as_paginate")
6
+ end
7
+
8
+ def pagination_ajax_links(current_page, url_options, options, window_size)
9
+ start_number = current_page.number - window_size
10
+ end_number = current_page.number + window_size
11
+ start_number = 1 if start_number <= 0
12
+ if current_page.pager.infinite?
13
+ offsets = [20, 100]
14
+ else
15
+ end_number = current_page.pager.last.number if end_number > current_page.pager.last.number
16
+ end
17
+
18
+ html = []
19
+ unless start_number == 1
20
+ last_page = 1
21
+ html << pagination_ajax_link(last_page, url_options, options)
22
+ if current_page.pager.infinite?
23
+ offsets.reverse.each do |offset|
24
+ page = current_page.number - offset
25
+ if page < start_number && page > 1
26
+ html << '..' if page > last_page + 1
27
+ html << pagination_ajax_link(page, params)
28
+ last_page = page
29
+ end
30
+ end
31
+ end
32
+ html << ".." if start_number > last_page + 1
33
+ end
34
+
35
+ start_number.upto(end_number) do |num|
36
+ if current_page.number == num
37
+ html << content_tag(:span, num.to_s, {:class => "as_paginate current"})
38
+ else
39
+ html << pagination_ajax_link(num, url_options, options)
40
+ end
41
+ end
42
+
43
+ if current_page.pager.infinite?
44
+ offsets.each do |offset|
45
+ html << '..' << pagination_ajax_link(current_page.number + offset, url_options, options)
46
+ end
47
+ else
48
+ html << ".." unless end_number >= current_page.pager.last.number - 1
49
+ html << pagination_ajax_link(current_page.pager.last.number, url_options, options) unless end_number == current_page.pager.last.number
50
+ end
51
+ html.join(' ').html_safe
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,243 @@
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
+ text_field(: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
+
63
+ if column.association
64
+ select_options = options_for_association(column.association, false)
65
+ else
66
+ select_options = Array(column.options[:options])
67
+ end
68
+ return as_(:no_options) if select_options.empty?
69
+
70
+ active_scaffold_checkbox_list(column, select_options, associated, options)
71
+ end
72
+
73
+ def active_scaffold_search_select(column, html_options)
74
+ associated = html_options.delete :value
75
+ if column.association
76
+ associated = associated.is_a?(Array) ? associated.map(&:to_i) : associated.to_i unless associated.nil?
77
+ method = column.association.macro == :belongs_to ? column.association.primary_key_name : column.name
78
+ select_options = options_for_association(column.association, true)
79
+ else
80
+ method = column.name
81
+ select_options = Array(column.options[:options])
82
+ end
83
+
84
+ options = { :selected => associated }.merge! column.options
85
+ html_options.merge! column.options[:html_options] || {}
86
+ if html_options[:multiple]
87
+ html_options[:name] += '[]'
88
+ else
89
+ options[:include_blank] ||= as_(:_select_)
90
+ end
91
+ select(:record, method, select_options, options, html_options)
92
+ end
93
+
94
+ def active_scaffold_search_text(column, options)
95
+ text_field :record, column.name, active_scaffold_input_text_options(options)
96
+ end
97
+
98
+ # we can't use active_scaffold_input_boolean because we need to have a nil value even when column can't be null
99
+ # to decide whether search for this field or not
100
+ def active_scaffold_search_boolean(column, options)
101
+ select_options = []
102
+ select_options << [as_(:_select_), nil]
103
+ select_options << [as_(:true), true]
104
+ select_options << [as_(:false), false]
105
+
106
+ select_tag(options[:name], options_for_select(select_options, column.column.type_cast(field_search_params[column.name])))
107
+ end
108
+ # we can't use checkbox ui because it's not possible to decide whether search for this field or not
109
+ alias_method :active_scaffold_search_checkbox, :active_scaffold_search_boolean
110
+
111
+ def active_scaffold_search_null(column, options)
112
+ select_options = []
113
+ select_options << [as_(:_select_), nil]
114
+ select_options.concat ActiveScaffold::Finder::NullComparators.collect {|comp| [as_(comp), comp]}
115
+ select_tag(options[:name], options_for_select(select_options, field_search_params[column.name]))
116
+ end
117
+
118
+ def field_search_params_range_values(column)
119
+ values = field_search_params[column.name]
120
+ return nil if values.nil?
121
+ return values[:opt], values[:from], values[:to]
122
+ end
123
+
124
+ def active_scaffold_search_range(column, options)
125
+ opt_value, from_value, to_value = field_search_params_range_values(column)
126
+
127
+ text_field_size = 10
128
+ select_options = ActiveScaffold::Finder::NumericComparators.collect {|comp| [as_(comp.downcase.to_sym), comp]}
129
+ if column.column && column.column.text?
130
+ select_options.unshift *ActiveScaffold::Finder::StringComparators.collect {|title, comp| [as_(title), comp]}
131
+ text_field_size = 15
132
+ end
133
+ from_value = controller.class.condition_value_for_numeric(column, from_value)
134
+ to_value = controller.class.condition_value_for_numeric(column, to_value)
135
+ from_value = format_number_value(from_value, column.options) if from_value.is_a?(Numeric)
136
+ to_value = format_number_value(to_value, column.options) if to_value.is_a?(Numeric)
137
+ html = select_tag("#{options[:name]}[opt]",
138
+ options_for_select(select_options, opt_value),
139
+ :id => "#{options[:id]}_opt",
140
+ :class => "as_search_range_option")
141
+ html << ' ' << text_field_tag("#{options[:name]}[from]", from_value, active_scaffold_input_text_options(:id => options[:id], :size => text_field_size))
142
+ html << ' ' << content_tag(:span, (' - ' + text_field_tag("#{options[:name]}[to]", to_value,
143
+ active_scaffold_input_text_options(:id => "#{options[:id]}_to", :size => text_field_size))).html_safe,
144
+ :id => "#{options[:id]}_between", :class => "as_search_range_between", :style => "display:#{(opt_value == 'BETWEEN') ? '' : 'none'}")
145
+ html
146
+ end
147
+ alias_method :active_scaffold_search_integer, :active_scaffold_search_range
148
+ alias_method :active_scaffold_search_decimal, :active_scaffold_search_range
149
+ alias_method :active_scaffold_search_float, :active_scaffold_search_range
150
+ alias_method :active_scaffold_search_string, :active_scaffold_search_range
151
+
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
+ def field_search_datetime_value(value)
174
+ 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
+ end
176
+
177
+ def active_scaffold_search_datetime(column, options)
178
+ opt_value, from_value, to_value = field_search_params_range_values(column)
179
+ options = column.options.merge(options)
180
+ 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)) <<
183
+ ' - '.html_safe << send(helper, field_search_datetime_value(to_value), {:include_blank => true, :prefix => "#{options[:name]}[to]"}.merge(options))
184
+ end
185
+
186
+ def active_scaffold_search_date(column, options)
187
+ active_scaffold_search_datetime(column, options.merge!(:discard_time => true))
188
+ end
189
+ def active_scaffold_search_time(column, options)
190
+ active_scaffold_search_datetime(column, options.merge!(:discard_date => true))
191
+ end
192
+ alias_method :active_scaffold_search_timestamp, :active_scaffold_search_datetime
193
+
194
+ ##
195
+ ## Search column override signatures
196
+ ##
197
+
198
+ def override_search_field?(column)
199
+ respond_to?(override_search_field(column))
200
+ end
201
+
202
+ # the naming convention for overriding form fields with helpers
203
+ def override_search_field(column)
204
+ "#{column.name}_search_column"
205
+ end
206
+
207
+ def override_search?(search_ui)
208
+ respond_to?(override_search(search_ui))
209
+ end
210
+
211
+ # the naming convention for overriding search input types with helpers
212
+ def override_search(form_ui)
213
+ "active_scaffold_search_#{form_ui}"
214
+ end
215
+
216
+ def visibles_and_hiddens(search_config)
217
+ visibles = []
218
+ hiddens = []
219
+ search_config.columns.each do |column|
220
+ next unless column.search_sql
221
+ if search_config.optional_columns.include?(column.name) && !searched_by?(column)
222
+ hiddens << column
223
+ else
224
+ visibles << column
225
+ end
226
+ end
227
+ return visibles, hiddens
228
+ end
229
+
230
+ def searched_by?(column)
231
+ value = field_search_params[column.name]
232
+ case value
233
+ when Hash
234
+ !value['from'].blank?
235
+ when String
236
+ !value.blank?
237
+ else
238
+ false
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end