active_scaffold 3.0.0

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 (272) hide show
  1. data/.autotest +27 -0
  2. data/CHANGELOG +152 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README +51 -0
  6. data/Rakefile +24 -0
  7. data/active_scaffold.gemspec +24 -0
  8. data/environment.rb +22 -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/cross.png +0 -0
  14. data/frontends/default/images/indicator-small.gif +0 -0
  15. data/frontends/default/images/indicator.gif +0 -0
  16. data/frontends/default/images/magnifier.png +0 -0
  17. data/frontends/default/javascripts/jquery/active_scaffold.js +957 -0
  18. data/frontends/default/javascripts/jquery/jquery.editinplace.js +726 -0
  19. data/frontends/default/javascripts/prototype/active_scaffold.js +954 -0
  20. data/frontends/default/javascripts/prototype/dhtml_history.js +867 -0
  21. data/frontends/default/javascripts/prototype/form_enhancements.js +117 -0
  22. data/frontends/default/javascripts/prototype/rico_corner.js +370 -0
  23. data/frontends/default/stylesheets/stylesheet-ie.css +35 -0
  24. data/frontends/default/stylesheets/stylesheet.css +858 -0
  25. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  26. data/frontends/default/views/_base_form.html.erb +41 -0
  27. data/frontends/default/views/_create_form.html.erb +6 -0
  28. data/frontends/default/views/_create_form_on_list.html.erb +5 -0
  29. data/frontends/default/views/_field_search.html.erb +32 -0
  30. data/frontends/default/views/_form.html.erb +24 -0
  31. data/frontends/default/views/_form_association.html.erb +14 -0
  32. data/frontends/default/views/_form_association_footer.html.erb +40 -0
  33. data/frontends/default/views/_form_attribute.html.erb +15 -0
  34. data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
  35. data/frontends/default/views/_form_messages.html.erb +5 -0
  36. data/frontends/default/views/_horizontal_subform.html.erb +19 -0
  37. data/frontends/default/views/_horizontal_subform_header.html.erb +10 -0
  38. data/frontends/default/views/_horizontal_subform_record.html.erb +37 -0
  39. data/frontends/default/views/_human_conditions.html.erb +1 -0
  40. data/frontends/default/views/_list.html.erb +18 -0
  41. data/frontends/default/views/_list_actions.html.erb +16 -0
  42. data/frontends/default/views/_list_calculations.html.erb +16 -0
  43. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  44. data/frontends/default/views/_list_header.html.erb +12 -0
  45. data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
  46. data/frontends/default/views/_list_messages.html.erb +32 -0
  47. data/frontends/default/views/_list_pagination.html.erb +11 -0
  48. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  49. data/frontends/default/views/_list_record.html.erb +14 -0
  50. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  51. data/frontends/default/views/_list_with_header.html.erb +32 -0
  52. data/frontends/default/views/_messages.html.erb +10 -0
  53. data/frontends/default/views/_render_field.js.rjs +13 -0
  54. data/frontends/default/views/_row.html.erb +12 -0
  55. data/frontends/default/views/_search.html.erb +34 -0
  56. data/frontends/default/views/_search_attribute.html.erb +10 -0
  57. data/frontends/default/views/_show.html.erb +8 -0
  58. data/frontends/default/views/_show_columns.html.erb +12 -0
  59. data/frontends/default/views/_update_actions.html.erb +9 -0
  60. data/frontends/default/views/_update_form.html.erb +5 -0
  61. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  62. data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
  63. data/frontends/default/views/add_existing.js.rjs +17 -0
  64. data/frontends/default/views/add_existing_form.html.erb +5 -0
  65. data/frontends/default/views/create.html.erb +5 -0
  66. data/frontends/default/views/delete.html.erb +13 -0
  67. data/frontends/default/views/destroy.js.rjs +5 -0
  68. data/frontends/default/views/edit_associated.js.rjs +11 -0
  69. data/frontends/default/views/field_search.html.erb +5 -0
  70. data/frontends/default/views/form_messages.js.rjs +1 -0
  71. data/frontends/default/views/list.html.erb +1 -0
  72. data/frontends/default/views/list.js.rjs +1 -0
  73. data/frontends/default/views/on_action_update.js.rjs +8 -0
  74. data/frontends/default/views/on_create.js.rjs +24 -0
  75. data/frontends/default/views/on_update.js.rjs +15 -0
  76. data/frontends/default/views/search.html.erb +5 -0
  77. data/frontends/default/views/show.html.erb +5 -0
  78. data/frontends/default/views/update.html.erb +8 -0
  79. data/frontends/default/views/update_column.js.rjs +13 -0
  80. data/frontends/default/views/update_row.js.rjs +1 -0
  81. data/init.rb +1 -0
  82. data/install_assets.rb +44 -0
  83. data/lib/active_record_permissions.rb +134 -0
  84. data/lib/active_scaffold.rb +279 -0
  85. data/lib/active_scaffold/actions/common_search.rb +22 -0
  86. data/lib/active_scaffold/actions/core.rb +150 -0
  87. data/lib/active_scaffold/actions/create.rb +152 -0
  88. data/lib/active_scaffold/actions/delete.rb +72 -0
  89. data/lib/active_scaffold/actions/field_search.rb +82 -0
  90. data/lib/active_scaffold/actions/list.rb +128 -0
  91. data/lib/active_scaffold/actions/mark.rb +50 -0
  92. data/lib/active_scaffold/actions/nested.rb +241 -0
  93. data/lib/active_scaffold/actions/search.rb +47 -0
  94. data/lib/active_scaffold/actions/show.rb +54 -0
  95. data/lib/active_scaffold/actions/subform.rb +17 -0
  96. data/lib/active_scaffold/actions/update.rb +134 -0
  97. data/lib/active_scaffold/attribute_params.rb +207 -0
  98. data/lib/active_scaffold/bridges/ancestry/bridge.rb +5 -0
  99. data/lib/active_scaffold/bridges/ancestry/lib/ancestry_bridge.rb +38 -0
  100. data/lib/active_scaffold/bridges/bridge.rb +52 -0
  101. data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +16 -0
  102. data/lib/active_scaffold/bridges/calendar_date_select/lib/as_cds_bridge.rb +79 -0
  103. data/lib/active_scaffold/bridges/carrierwave/bridge.rb +7 -0
  104. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +38 -0
  105. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +26 -0
  106. data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +35 -0
  107. data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +17 -0
  108. data/lib/active_scaffold/bridges/date_picker/bridge.rb +22 -0
  109. data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +225 -0
  110. data/lib/active_scaffold/bridges/date_picker/public/javascripts/date_picker_bridge.js +22 -0
  111. data/lib/active_scaffold/bridges/file_column/bridge.rb +11 -0
  112. data/lib/active_scaffold/bridges/file_column/lib/as_file_column_bridge.rb +46 -0
  113. data/lib/active_scaffold/bridges/file_column/lib/file_column_helpers.rb +59 -0
  114. data/lib/active_scaffold/bridges/file_column/lib/form_ui.rb +37 -0
  115. data/lib/active_scaffold/bridges/file_column/lib/list_ui.rb +26 -0
  116. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  117. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  118. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  119. data/lib/active_scaffold/bridges/paperclip/bridge.rb +12 -0
  120. data/lib/active_scaffold/bridges/paperclip/lib/form_ui.rb +27 -0
  121. data/lib/active_scaffold/bridges/paperclip/lib/list_ui.rb +16 -0
  122. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge.rb +38 -0
  123. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge_helpers.rb +26 -0
  124. data/lib/active_scaffold/bridges/semantic_attributes/bridge.rb +5 -0
  125. data/lib/active_scaffold/bridges/semantic_attributes/lib/semantic_attributes_bridge.rb +20 -0
  126. data/lib/active_scaffold/bridges/shared/date_bridge.rb +187 -0
  127. data/lib/active_scaffold/bridges/tiny_mce/bridge.rb +5 -0
  128. data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +45 -0
  129. data/lib/active_scaffold/bridges/validation_reflection/bridge.rb +8 -0
  130. data/lib/active_scaffold/bridges/validation_reflection/lib/validation_reflection_bridge.rb +21 -0
  131. data/lib/active_scaffold/config/base.rb +54 -0
  132. data/lib/active_scaffold/config/core.rb +229 -0
  133. data/lib/active_scaffold/config/create.rb +43 -0
  134. data/lib/active_scaffold/config/delete.rb +25 -0
  135. data/lib/active_scaffold/config/field_search.rb +74 -0
  136. data/lib/active_scaffold/config/form.rb +46 -0
  137. data/lib/active_scaffold/config/list.rb +174 -0
  138. data/lib/active_scaffold/config/mark.rb +22 -0
  139. data/lib/active_scaffold/config/nested.rb +43 -0
  140. data/lib/active_scaffold/config/search.rb +68 -0
  141. data/lib/active_scaffold/config/show.rb +34 -0
  142. data/lib/active_scaffold/config/subform.rb +35 -0
  143. data/lib/active_scaffold/config/update.rb +38 -0
  144. data/lib/active_scaffold/configurable.rb +29 -0
  145. data/lib/active_scaffold/constraints.rb +179 -0
  146. data/lib/active_scaffold/data_structures/action_columns.rb +133 -0
  147. data/lib/active_scaffold/data_structures/action_link.rb +162 -0
  148. data/lib/active_scaffold/data_structures/action_links.rb +59 -0
  149. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  150. data/lib/active_scaffold/data_structures/column.rb +348 -0
  151. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  152. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  153. data/lib/active_scaffold/data_structures/nested_info.rb +108 -0
  154. data/lib/active_scaffold/data_structures/set.rb +62 -0
  155. data/lib/active_scaffold/data_structures/sorting.rb +168 -0
  156. data/lib/active_scaffold/finder.rb +333 -0
  157. data/lib/active_scaffold/helpers/association_helpers.rb +40 -0
  158. data/lib/active_scaffold/helpers/controller_helpers.rb +40 -0
  159. data/lib/active_scaffold/helpers/country_helpers.rb +352 -0
  160. data/lib/active_scaffold/helpers/form_column_helpers.rb +343 -0
  161. data/lib/active_scaffold/helpers/human_condition_helpers.rb +59 -0
  162. data/lib/active_scaffold/helpers/id_helpers.rb +131 -0
  163. data/lib/active_scaffold/helpers/list_column_helpers.rb +363 -0
  164. data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
  165. data/lib/active_scaffold/helpers/search_column_helpers.rb +238 -0
  166. data/lib/active_scaffold/helpers/show_column_helpers.rb +46 -0
  167. data/lib/active_scaffold/helpers/view_helpers.rb +315 -0
  168. data/lib/active_scaffold/locale/de.rb +113 -0
  169. data/lib/active_scaffold/locale/en.rb +118 -0
  170. data/lib/active_scaffold/locale/es.yml +112 -0
  171. data/lib/active_scaffold/locale/fr.rb +113 -0
  172. data/lib/active_scaffold/locale/hu.yml +63 -0
  173. data/lib/active_scaffold/locale/ja.yml +64 -0
  174. data/lib/active_scaffold/locale/ru.yml +62 -0
  175. data/lib/active_scaffold/marked_model.rb +38 -0
  176. data/lib/dhtml_confirm.rb +54 -0
  177. data/lib/extensions/action_controller_rendering.rb +20 -0
  178. data/lib/extensions/action_view_rendering.rb +113 -0
  179. data/lib/extensions/action_view_resolver.rb +7 -0
  180. data/lib/extensions/active_record_offset.rb +12 -0
  181. data/lib/extensions/array.rb +7 -0
  182. data/lib/extensions/localize.rb +10 -0
  183. data/lib/extensions/name_option_for_datetime.rb +12 -0
  184. data/lib/extensions/nil_id_in_url_params.rb +7 -0
  185. data/lib/extensions/paginator_extensions.rb +26 -0
  186. data/lib/extensions/reverse_associations.rb +62 -0
  187. data/lib/extensions/routing_mapper.rb +34 -0
  188. data/lib/extensions/to_label.rb +8 -0
  189. data/lib/extensions/unsaved_associated.rb +61 -0
  190. data/lib/extensions/unsaved_record.rb +20 -0
  191. data/lib/extensions/usa_state.rb +46 -0
  192. data/lib/generators/active_scaffold/USAGE +29 -0
  193. data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
  194. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  195. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +28 -0
  196. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  197. data/lib/generators/active_scaffold_setup/USAGE +10 -0
  198. data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +53 -0
  199. data/lib/paginator.rb +136 -0
  200. data/lib/responds_to_parent.rb +70 -0
  201. data/public/blank.html +33 -0
  202. data/shoulda_macros/macros.rb +136 -0
  203. data/test/bridges/bridge_test.rb +47 -0
  204. data/test/config/base_test.rb +15 -0
  205. data/test/config/create_test.rb +55 -0
  206. data/test/config/list_test.rb +74 -0
  207. data/test/config/show_test.rb +43 -0
  208. data/test/config/update_test.rb +17 -0
  209. data/test/const_mocker.rb +36 -0
  210. data/test/data_structures/action_columns_test.rb +113 -0
  211. data/test/data_structures/action_link_test.rb +78 -0
  212. data/test/data_structures/action_links_test.rb +78 -0
  213. data/test/data_structures/actions_test.rb +25 -0
  214. data/test/data_structures/association_column_test.rb +42 -0
  215. data/test/data_structures/column_test.rb +185 -0
  216. data/test/data_structures/columns_test.rb +69 -0
  217. data/test/data_structures/error_message_test.rb +28 -0
  218. data/test/data_structures/set_test.rb +86 -0
  219. data/test/data_structures/sorting_test.rb +126 -0
  220. data/test/data_structures/standard_column_test.rb +24 -0
  221. data/test/data_structures/virtual_column_test.rb +23 -0
  222. data/test/extensions/active_record_test.rb +45 -0
  223. data/test/extensions/array_test.rb +12 -0
  224. data/test/helpers/form_column_helpers_test.rb +31 -0
  225. data/test/helpers/list_column_helpers_test.rb +31 -0
  226. data/test/helpers/pagination_helpers_test.rb +55 -0
  227. data/test/misc/active_record_permissions_test.rb +154 -0
  228. data/test/misc/attribute_params_test.rb +110 -0
  229. data/test/misc/configurable_test.rb +96 -0
  230. data/test/misc/constraints_test.rb +193 -0
  231. data/test/misc/finder_test.rb +93 -0
  232. data/test/misc/lang_test.rb +12 -0
  233. data/test/mock_app/.gitignore +2 -0
  234. data/test/mock_app/app/controllers/application_controller.rb +10 -0
  235. data/test/mock_app/app/helpers/application_helper.rb +3 -0
  236. data/test/mock_app/config/boot.rb +110 -0
  237. data/test/mock_app/config/database.yml +16 -0
  238. data/test/mock_app/config/environment.rb +43 -0
  239. data/test/mock_app/config/environments/development.rb +17 -0
  240. data/test/mock_app/config/environments/production.rb +28 -0
  241. data/test/mock_app/config/environments/test.rb +28 -0
  242. data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
  243. data/test/mock_app/config/initializers/inflections.rb +10 -0
  244. data/test/mock_app/config/initializers/mime_types.rb +5 -0
  245. data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  246. data/test/mock_app/config/initializers/session_store.rb +15 -0
  247. data/test/mock_app/config/locales/en.yml +5 -0
  248. data/test/mock_app/config/routes.rb +43 -0
  249. data/test/mock_app/db/test.sqlite3 +1 -0
  250. data/test/mock_app/public/blank.html +33 -0
  251. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
  252. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  253. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  254. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  255. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  256. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  257. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  258. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  259. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  260. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
  261. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
  262. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
  263. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
  264. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
  265. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
  266. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
  267. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +839 -0
  268. data/test/model_stub.rb +55 -0
  269. data/test/run_all.rb +8 -0
  270. data/test/test_helper.rb +39 -0
  271. data/uninstall.rb +13 -0
  272. metadata +478 -0
@@ -0,0 +1,59 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ # Helpers that assist with rendering of a human readable search statement
4
+ module HumanConditionHelpers
5
+
6
+ def active_scaffold_human_condition_for(column)
7
+ value = field_search_params[column.name]
8
+ search_ui = column.search_ui
9
+ search_ui ||= column.column.type if column.column
10
+ if override_human_condition_column?(column)
11
+ send(override_human_condition_column(column), value, {})
12
+ elsif search_ui and override_human_condition?(column.search_ui)
13
+ send(override_human_condition(column.search_ui), column, value)
14
+ else
15
+ case search_ui
16
+ when :integer, :decimal, :float
17
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value[:opt].downcase).downcase} #{format_number_value(controller.class.condition_value_for_numeric(column, value[:from]), column.options)} #{value[:opt] == 'BETWEEN' ? '- ' + format_number_value(controller.class.condition_value_for_numeric(column, value[:to]), column.options).to_s : ''}"
18
+ when :string
19
+ opt = ActiveScaffold::Finder::StringComparators.index(value[:opt]) || value[:opt]
20
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_(opt).downcase} '#{value[:from]}' #{opt == 'BETWEEN' ? '- ' + value[:to].to_s : ''}"
21
+ when :date, :time, :datetime, :timestamp
22
+ conversion = column.column.type == :date ? :to_date : :to_time
23
+ from = controller.condition_value_for_datetime(value[:from], conversion)
24
+ to = controller.condition_value_for_datetime(value[:to], conversion)
25
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value[:opt])} #{I18n.l(from)} #{value[:opt] == 'BETWEEN' ? '- ' + I18n.l(to) : ''}"
26
+ when :select, :multi_select, :record_select
27
+ associated = value
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
30
+ "#{column.active_record_class.human_attribute_name(column.name)} = #{associated.join(', ')}"
31
+ when :boolean, :checkbox
32
+ label = column.column.type_cast(value) ? as_(:true) : as_(:false)
33
+ "#{column.active_record_class.human_attribute_name(column.name)} = #{label}"
34
+ when :null
35
+ "#{column.active_record_class.human_attribute_name(column.name)} #{as_(value.to_sym)}"
36
+ end
37
+ end unless value.nil?
38
+ end
39
+
40
+ def override_human_condition_column?(column)
41
+ respond_to?(override_human_condition_column(column))
42
+ end
43
+
44
+ # the naming convention for overriding form fields with helpers
45
+ def override_human_condition_column(column)
46
+ "#{column.name}_human_condition_column"
47
+ end
48
+
49
+ def override_human_condition?(search_ui)
50
+ respond_to?(override_human_condition(search_ui))
51
+ end
52
+
53
+ # the naming convention for overriding human condition search_ui types
54
+ def override_human_condition(search_ui)
55
+ "active_scaffold_human_condition_#{search_ui}"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,131 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ # A bunch of helper methods to produce the common view ids
4
+ module IdHelpers
5
+ def id_from_controller(controller)
6
+ controller.to_s.gsub("/", "__")
7
+ end
8
+
9
+ def controller_id
10
+ controller_id ||= 'as_' + id_from_controller(params[:eid] || params[:parent_controller] || params[:controller])
11
+ end
12
+
13
+ def active_scaffold_id
14
+ "#{controller_id}-active-scaffold"
15
+ end
16
+
17
+ def active_scaffold_content_id
18
+ "#{controller_id}-content"
19
+ end
20
+
21
+ def active_scaffold_tbody_id
22
+ "#{controller_id}-tbody"
23
+ end
24
+
25
+ def active_scaffold_messages_id
26
+ "#{controller_id}-messages"
27
+ end
28
+
29
+ def active_scaffold_calculations_id(column = nil)
30
+ "#{controller_id}-calculations#{'-' + column.name.to_s if column}"
31
+ end
32
+
33
+ def empty_message_id
34
+ "#{controller_id}-empty-message"
35
+ end
36
+
37
+ def before_header_id
38
+ "#{controller_id}-search-container"
39
+ end
40
+
41
+ def search_form_id
42
+ "#{controller_id}-search-form"
43
+ end
44
+
45
+ def search_input_id
46
+ "#{controller_id}-search-input"
47
+ end
48
+
49
+ def table_action_id(name)
50
+ "#{controller_id}-action-table-#{name}"
51
+ end
52
+
53
+ def action_link_id(link_action,link_id)
54
+ "#{controller_id}-#{link_action}-#{link_id}-link"
55
+ end
56
+
57
+ def active_scaffold_column_header_id(column)
58
+ name = column.respond_to?(:name) ? column.name : column.to_s
59
+ clean_id "#{controller_id}-#{name}-column"
60
+ end
61
+
62
+ def element_row_id(options = {})
63
+ options[:action] ||= params[:action]
64
+ options[:id] ||= params[:id]
65
+ options[:id] ||= params[:parent_id]
66
+ clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-row"
67
+ end
68
+
69
+ def element_cell_id(options = {})
70
+ options[:action] ||= params[:action]
71
+ options[:id] ||= params[:id]
72
+ options[:id] ||= params[:parent_id]
73
+ options[:name] ||= params[:name]
74
+ clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-#{options[:name]}-cell"
75
+ end
76
+
77
+ def element_form_id(options = {})
78
+ options[:action] ||= params[:action]
79
+ options[:id] ||= params[:id]
80
+ options[:id] ||= params[:parent_id]
81
+ clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-form"
82
+ end
83
+
84
+ def association_subform_id(column)
85
+ klass = column.association.klass.to_s.underscore
86
+ clean_id "#{controller_id}-associated-#{klass}"
87
+ end
88
+
89
+ def loading_indicator_id(options = {})
90
+ options[:action] ||= params[:action]
91
+ clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-loading-indicator"
92
+ end
93
+
94
+ def sub_section_id(options = {})
95
+ options[:id] ||= params[:id]
96
+ options[:id] ||= params[:parent_id]
97
+ clean_id "#{controller_id}-#{options[:id]}-#{options[:sub_section]}-subsection"
98
+ end
99
+
100
+ def sub_form_id(options = {})
101
+ options[:id] ||= params[:id]
102
+ options[:id] ||= params[:parent_id]
103
+ clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform"
104
+ end
105
+
106
+ def sub_form_list_id(options = {})
107
+ options[:id] ||= params[:id]
108
+ options[:id] ||= params[:parent_id]
109
+ clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform-list"
110
+ end
111
+
112
+ def element_messages_id(options = {})
113
+ options[:action] ||= params[:action]
114
+ options[:id] ||= params[:id]
115
+ options[:id] ||= params[:parent_id]
116
+ clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-messages"
117
+ end
118
+
119
+ def action_iframe_id(options)
120
+ "#{controller_id}-#{options[:action]}-#{options[:id]}-iframe"
121
+ end
122
+
123
+ private
124
+
125
+ # whitelists id-safe characters
126
+ def clean_id(val)
127
+ val.gsub /[^-_0-9a-zA-Z]/, '-'
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,363 @@
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
+ # check authorization
47
+ if column.association
48
+ associated_for_authorized = if associated.nil? || (associated.respond_to?(:empty?) && associated.empty?)
49
+ column.association.klass
50
+ elsif column.plural_association?
51
+ associated.first
52
+ else
53
+ associated
54
+ end
55
+ authorized = associated_for_authorized.authorized_for?(:crud_type => link.crud_type)
56
+ authorized = authorized and record.authorized_for?(:crud_type => :update, :column => column.name) if link.crud_type == :create
57
+ else
58
+ authorized = record.authorized_for?(:crud_type => link.crud_type)
59
+ end
60
+ # to make html render properly
61
+ return "<a class='disabled'>#{text}</a>".html_safe unless authorized
62
+ render_action_link(link, url_options, record)
63
+ else
64
+ text = active_scaffold_inplace_edit(record, column, {:formatted_column => text}) if inplace_edit?(record, column)
65
+ text
66
+ end
67
+ end
68
+
69
+ # setup the action link to inline form
70
+ def action_link_to_inline_form(column, record, associated)
71
+ link = column.link.clone
72
+ if column.polymorphic_association?
73
+ polymorphic_controller = polymorphic_controller_for_nested_link(column, record)
74
+ return link if polymorphic_controller.nil?
75
+ link.controller = polymorphic_controller
76
+ end
77
+
78
+ if column_empty?(associated) # if association is empty, we only can link to create form
79
+ if column.actions_for_association_links.include?(:new)
80
+ link.action = 'new'
81
+ link.crud_type = :create
82
+ end
83
+ elsif column.actions_for_association_links.include?(:edit)
84
+ link.action = 'edit'
85
+ link.crud_type = :update
86
+ elsif column.actions_for_association_links.include?(:show)
87
+ link.action = 'show'
88
+ link.crud_type = :read
89
+ elsif column.actions_for_association_links.include?(:list)
90
+ link.parameters[:id] = record.send(column.association.name).id
91
+ link.action = 'index'
92
+ link.crud_type = :read
93
+ end
94
+ link
95
+ end
96
+
97
+ def polymorphic_controller_for_nested_link(column, record)
98
+ begin
99
+ controller = active_scaffold_controller_for(record.send(column.association.name).class)
100
+ controller.controller_path
101
+ rescue ActiveScaffold::ControllerNotFound
102
+ controller = nil
103
+ end
104
+ end
105
+
106
+ # There are two basic ways to clean a column's value: h() and sanitize(). The latter is useful
107
+ # when the column contains *valid* html data, and you want to just disable any scripting. People
108
+ # can always use field overrides to clean data one way or the other, but having this override
109
+ # lets people decide which way it should happen by default.
110
+ #
111
+ # Why is it not a configuration option? Because it seems like a somewhat rare request. But it
112
+ # could eventually be an option in config.list (and config.show, I guess).
113
+ def clean_column_value(v)
114
+ h(v)
115
+ end
116
+
117
+ ##
118
+ ## Overrides
119
+ ##
120
+ def active_scaffold_column_text(column, record)
121
+ truncate(clean_column_value(record.send(column.name)), :length => column.options[:truncate] || 50)
122
+ end
123
+
124
+ def active_scaffold_column_select(column, record)
125
+ if column.association
126
+ format_column_value(record, column)
127
+ else
128
+ value = record.send(column.name)
129
+ text, val = column.options[:options].find {|text, val| (val || text).to_s == value}
130
+ value = active_scaffold_translated_option(column, text, val).first if text
131
+ format_column_value(record, column, value)
132
+ end
133
+ end
134
+
135
+ def active_scaffold_column_checkbox(column, record)
136
+ options = {:disabled => true, :id => nil, :object => record}
137
+ options.delete(:disabled) if inplace_edit?(record, column)
138
+ check_box(:record, column.name, options)
139
+ end
140
+
141
+ def column_override(column)
142
+ "#{column.name.to_s.gsub('?', '')}_column" # parse out any question marks (see issue 227)
143
+ end
144
+
145
+ def column_override?(column)
146
+ respond_to?(column_override(column))
147
+ end
148
+
149
+ def override_column_ui?(list_ui)
150
+ respond_to?(override_column_ui(list_ui))
151
+ end
152
+
153
+ # the naming convention for overriding column types with helpers
154
+ def override_column_ui(list_ui)
155
+ "active_scaffold_column_#{list_ui}"
156
+ end
157
+
158
+ ##
159
+ ## Formatting
160
+ ##
161
+ def format_column_value(record, column, value = nil)
162
+ value ||= record.send(column.name) unless record.nil?
163
+ if value && column.association # cache association size before calling column_empty?
164
+ associated_size = value.size if column.plural_association? and column.associated_number? # get count before cache association
165
+ cache_association(value, column)
166
+ end
167
+ if column.association.nil? or column_empty?(value)
168
+ if value.is_a? Numeric
169
+ format_number_value(value, column.options)
170
+ else
171
+ format_value(value, column.options)
172
+ end
173
+ else
174
+ format_association_value(value, column, associated_size)
175
+ end
176
+ end
177
+
178
+ def format_number_value(value, options = {})
179
+ value = case options[:format]
180
+ when :size
181
+ number_to_human_size(value, options[:i18n_options] || {})
182
+ when :percentage
183
+ number_to_percentage(value, options[:i18n_options] || {})
184
+ when :currency
185
+ number_to_currency(value, options[:i18n_options] || {})
186
+ when :i18n_number
187
+ send("number_with_#{value.is_a?(Integer) ? 'delimiter' : 'precision'}", value, options[:i18n_options] || {})
188
+ else
189
+ value
190
+ end
191
+ clean_column_value(value)
192
+ end
193
+
194
+ def format_association_value(value, column, size)
195
+ case column.association.macro
196
+ when :has_one, :belongs_to
197
+ if column.polymorphic_association?
198
+ format_value("#{value.class.model_name.human}: #{value.to_label}")
199
+ else
200
+ format_value(value.to_label)
201
+ end
202
+ when :has_many, :has_and_belongs_to_many
203
+ if column.associated_limit.nil?
204
+ firsts = value.collect { |v| v.to_label }
205
+ else
206
+ firsts = value.first(column.associated_limit)
207
+ firsts.collect! { |v| v.to_label }
208
+ firsts[column.associated_limit] = '…' if value.size > column.associated_limit
209
+ end
210
+ if column.associated_limit == 0
211
+ size if column.associated_number?
212
+ else
213
+ joined_associated = format_value(firsts.join(', '))
214
+ joined_associated << " (#{size})" if column.associated_number? and column.associated_limit and value.size > column.associated_limit
215
+ joined_associated
216
+ end
217
+ end
218
+ end
219
+
220
+ def format_value(column_value, options = {})
221
+ value = if column_empty?(column_value)
222
+ active_scaffold_config.list.empty_field_text
223
+ elsif column_value.is_a?(Time) || column_value.is_a?(Date)
224
+ l(column_value, :format => options[:format] || :default)
225
+ elsif [FalseClass, TrueClass].include?(column_value.class)
226
+ as_(column_value.to_s.to_sym)
227
+ else
228
+ column_value.to_s
229
+ end
230
+ clean_column_value(value)
231
+ end
232
+
233
+ def cache_association(value, column)
234
+ # we are not using eager loading, cache firsts records in order not to query the database in a future
235
+ unless value.loaded?
236
+ # load at least one record, is needed for column_empty? and checking permissions
237
+ if column.associated_limit.nil?
238
+ Rails.logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
239
+ else
240
+ value.target = value.find(:all, :limit => column.associated_limit + 1, :select => column.select_columns)
241
+ end
242
+ end
243
+ end
244
+
245
+ # ==========
246
+ # = Inline Edit =
247
+ # ==========
248
+
249
+ def inplace_edit?(record, column)
250
+ if column.inplace_edit
251
+ editable = controller.send(:update_authorized?, record) if controller.respond_to?(:update_authorized?)
252
+ editable = record.authorized_for?(:action => :update, :column => column.name) if editable.nil? || editable == true
253
+ editable
254
+ end
255
+ end
256
+
257
+ def inplace_edit_cloning?(column)
258
+ column.inplace_edit != :ajax and (override_form_field?(column) or column.form_ui or (column.column and override_input?(column.column.type)))
259
+ end
260
+
261
+ def format_inplace_edit_column(record,column)
262
+ if column.list_ui == :checkbox
263
+ active_scaffold_column_checkbox(column, record)
264
+ else
265
+ format_column_value(record, column)
266
+ end
267
+ end
268
+
269
+ def active_scaffold_inplace_edit(record, column, options = {})
270
+ formatted_column = options[:formatted_column] || format_column_value(record, column)
271
+ id_options = {:id => record.id.to_s, :action => 'update_column', :name => column.name.to_s}
272
+ tag_options = {:id => element_cell_id(id_options), :class => "in_place_editor_field",
273
+ :title => as_(:click_to_edit), 'data-ie_id' => record.id.to_s}
274
+
275
+ content_tag(:span, formatted_column, tag_options)
276
+ end
277
+
278
+ def inplace_edit_control(column)
279
+ if inplace_edit?(active_scaffold_config.model, column) and inplace_edit_cloning?(column)
280
+ @record = active_scaffold_config.model.new
281
+ column = column.clone
282
+ column.options = column.options.clone
283
+ column.form_ui = :select if (column.association && column.form_ui.nil?)
284
+ content_tag(:div, active_scaffold_input_for(column), {:style => "display:none;", :class => inplace_edit_control_css_class})
285
+ end
286
+ end
287
+
288
+ def inplace_edit_control_css_class
289
+ "as_inplace_pattern"
290
+ end
291
+
292
+ def inplace_edit_tag_attributes(column)
293
+ tag_options = {}
294
+ tag_options['data-ie_url'] = url_for({:controller => params_for[:controller], :action => "update_column", :column => column.name, :id => '__id__'})
295
+ tag_options['data-ie_cancel_text'] = column.options[:cancel_text] || as_(:cancel)
296
+ tag_options['data-ie_loading_text'] = column.options[:loading_text] || as_(:loading)
297
+ tag_options['data-ie_save_text'] = column.options[:save_text] || as_(:update)
298
+ tag_options['data-ie_saving_text'] = column.options[:saving_text] || as_(:saving)
299
+ tag_options['data-ie_rows'] = column.options[:rows] || 5 if column.column.try(:type) == :text
300
+ tag_options['data-ie_cols'] = column.options[:cols] if column.options[:cols]
301
+ tag_options['data-ie_size'] = column.options[:size] if column.options[:size]
302
+
303
+ if column.list_ui == :checkbox
304
+ tag_options['data-ie_mode'] = :inline_checkbox
305
+ elsif inplace_edit_cloning?(column)
306
+ tag_options['data-ie_mode'] = :clone
307
+ elsif column.inplace_edit == :ajax
308
+ 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)
309
+ plural = column.plural_association? && !override_form_field?(column) && [:select, :record_select].include?(column.form_ui)
310
+ tag_options['data-ie_render_url'] = url
311
+ tag_options['data-ie_mode'] = :ajax
312
+ tag_options['data-ie_plural'] = plural
313
+ end
314
+ tag_options
315
+ end
316
+
317
+ def mark_column_heading
318
+ all_marked = (marked_records.length >= @page.pager.count)
319
+ tag_options = {:id => "#{controller_id}_mark_heading", :class => "mark_heading in_place_editor_field"}
320
+ tag_options['data-ie_url'] = url_for({:controller => params_for[:controller], :action => 'mark_all', :eid => params[:eid]})
321
+ content_tag(:span, check_box_tag(nil, !all_marked, all_marked), tag_options)
322
+ end
323
+
324
+ def render_column_heading(column, sorting, sort_direction)
325
+ tag_options = {:id => active_scaffold_column_header_id(column), :class => column_heading_class(column, sorting), :title => column.description}
326
+ tag_options.merge!(inplace_edit_tag_attributes(column)) if column.inplace_edit
327
+ content_tag(:th, column_heading_value(column, sorting, sort_direction) + inplace_edit_control(column), tag_options)
328
+ end
329
+
330
+
331
+ def column_heading_value(column, sorting, sort_direction)
332
+ if column.sortable?
333
+ options = {:id => search_form_id, :class => "as_sort",
334
+ 'data-page-history' => controller_id,
335
+ :remote => true, :method => :get}
336
+ url_options = params_for(:action => :index, :page => 1,
337
+ :sort => column.name, :sort_direction => sort_direction)
338
+ link_to column.label, url_options, options
339
+ else
340
+ if column.name != :marked
341
+ content_tag(:p, column.label)
342
+ else
343
+ mark_column_heading
344
+ end
345
+ end
346
+ end
347
+
348
+ def render_nested_view(action_links, url_options, record)
349
+ rendered = []
350
+ action_links.each do |link|
351
+ if link.nested_link? && link.column && @nested_auto_open[link.column.name] && @records.length <= @nested_auto_open[link.column.name] && respond_to?(:render_component)
352
+ link_url_options = {:adapter => '_list_inline_adapter', :format => :js}.merge(action_link_url_options(link, url_options, record, options = {:reuse_eid => true}))
353
+ link_id = get_action_link_id(link_url_options, record, link.column)
354
+ rendered << (render_component(link_url_options) + javascript_tag("ActiveScaffold.ActionLink.get('#{link_id}').set_opened();"))
355
+ end
356
+ end
357
+ rendered.join(' ').html_safe
358
+ end
359
+
360
+ end
361
+ end
362
+ end
363
+