active_scaffold 3.2.18 → 3.2.19

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 (246) hide show
  1. data/CHANGELOG +3 -0
  2. data/app/assets/images/active_scaffold/add.png +0 -0
  3. data/app/assets/images/active_scaffold/arrow_down.png +0 -0
  4. data/app/assets/images/active_scaffold/arrow_up.png +0 -0
  5. data/app/assets/images/active_scaffold/close.png +0 -0
  6. data/app/assets/images/active_scaffold/close_touch.png +0 -0
  7. data/app/assets/images/active_scaffold/config.png +0 -0
  8. data/app/assets/images/active_scaffold/cross.png +0 -0
  9. data/app/assets/images/active_scaffold/gears.png +0 -0
  10. data/app/assets/images/active_scaffold/indicator-small.gif +0 -0
  11. data/app/assets/images/active_scaffold/indicator.gif +0 -0
  12. data/app/assets/images/active_scaffold/magnifier.png +0 -0
  13. data/app/assets/javascripts/active_scaffold.js.erb +19 -0
  14. data/app/assets/javascripts/jquery/active_scaffold.js +1113 -0
  15. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +24 -0
  16. data/app/assets/javascripts/jquery/draggable_lists.js +27 -0
  17. data/app/assets/javascripts/jquery/jquery.editinplace.js +743 -0
  18. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +7 -0
  19. data/app/assets/javascripts/prototype/active_scaffold.js +1107 -0
  20. data/app/assets/javascripts/prototype/dhtml_history.js +870 -0
  21. data/app/assets/javascripts/prototype/form_enhancements.js +117 -0
  22. data/app/assets/javascripts/prototype/rico_corner.js +370 -0
  23. data/app/assets/javascripts/prototype/tiny_mce_bridge.js +7 -0
  24. data/app/assets/stylesheets/active_scaffold-ie.css.scss +54 -0
  25. data/app/assets/stylesheets/active_scaffold.css.scss +14 -0
  26. data/app/assets/stylesheets/active_scaffold_colors.css.scss +395 -0
  27. data/app/assets/stylesheets/active_scaffold_extensions.css.erb +2 -0
  28. data/app/assets/stylesheets/active_scaffold_images.css.scss +40 -0
  29. data/app/assets/stylesheets/active_scaffold_layout.css +936 -0
  30. data/app/assets/stylesheets/blue-theme.css +74 -0
  31. data/config/locales/de.yml +125 -0
  32. data/config/locales/en.yml +127 -0
  33. data/config/locales/es.yml +128 -0
  34. data/config/locales/fr.yml +131 -0
  35. data/config/locales/hu.yml +126 -0
  36. data/config/locales/ja.yml +126 -0
  37. data/config/locales/ru.yml +135 -0
  38. data/frontends/default/views/_action_group.html.erb +24 -0
  39. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  40. data/frontends/default/views/_base_form.html.erb +53 -0
  41. data/frontends/default/views/_create_form.html.erb +8 -0
  42. data/frontends/default/views/_create_form_on_list.html.erb +6 -0
  43. data/frontends/default/views/_field_search.html.erb +32 -0
  44. data/frontends/default/views/_form.html.erb +28 -0
  45. data/frontends/default/views/_form_association.html.erb +17 -0
  46. data/frontends/default/views/_form_association_footer.html.erb +47 -0
  47. data/frontends/default/views/_form_attribute.html.erb +23 -0
  48. data/frontends/default/views/_form_hidden_attribute.html.erb +7 -0
  49. data/frontends/default/views/_form_messages.html.erb +5 -0
  50. data/frontends/default/views/_horizontal_subform.html.erb +22 -0
  51. data/frontends/default/views/_horizontal_subform_footer.html.erb +0 -0
  52. data/frontends/default/views/_horizontal_subform_header.html.erb +11 -0
  53. data/frontends/default/views/_horizontal_subform_record.html.erb +43 -0
  54. data/frontends/default/views/_human_conditions.html.erb +1 -0
  55. data/frontends/default/views/_list.html.erb +18 -0
  56. data/frontends/default/views/_list_actions.html.erb +15 -0
  57. data/frontends/default/views/_list_calculations.html.erb +16 -0
  58. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  59. data/frontends/default/views/_list_header.html.erb +10 -0
  60. data/frontends/default/views/_list_inline_adapter.html.erb +21 -0
  61. data/frontends/default/views/_list_messages.html.erb +28 -0
  62. data/frontends/default/views/_list_pagination.html.erb +11 -0
  63. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  64. data/frontends/default/views/_list_record.html.erb +13 -0
  65. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  66. data/frontends/default/views/_list_with_header.html.erb +36 -0
  67. data/frontends/default/views/_messages.html.erb +10 -0
  68. data/frontends/default/views/_refresh_list.js.erb +1 -0
  69. data/frontends/default/views/_render_field.js.erb +20 -0
  70. data/frontends/default/views/_row.html.erb +1 -0
  71. data/frontends/default/views/_search.html.erb +34 -0
  72. data/frontends/default/views/_search_attribute.html.erb +10 -0
  73. data/frontends/default/views/_show.html.erb +8 -0
  74. data/frontends/default/views/_show_columns.html.erb +15 -0
  75. data/frontends/default/views/_update_actions.html.erb +9 -0
  76. data/frontends/default/views/_update_calculations.js.erb +4 -0
  77. data/frontends/default/views/_update_form.html.erb +6 -0
  78. data/frontends/default/views/_update_messages.js.erb +2 -0
  79. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  80. data/frontends/default/views/_vertical_subform_record.html.erb +43 -0
  81. data/frontends/default/views/action_confirmation.html.erb +13 -0
  82. data/frontends/default/views/add_existing.js.erb +14 -0
  83. data/frontends/default/views/add_existing_form.html.erb +5 -0
  84. data/frontends/default/views/create.html.erb +5 -0
  85. data/frontends/default/views/delete.html.erb +13 -0
  86. data/frontends/default/views/destroy.js.erb +26 -0
  87. data/frontends/default/views/edit_associated.js.erb +12 -0
  88. data/frontends/default/views/field_search.html.erb +5 -0
  89. data/frontends/default/views/form_messages.js.erb +1 -0
  90. data/frontends/default/views/list.html.erb +1 -0
  91. data/frontends/default/views/on_action_update.js.erb +22 -0
  92. data/frontends/default/views/on_create.js.erb +38 -0
  93. data/frontends/default/views/on_mark.js.erb +6 -0
  94. data/frontends/default/views/on_update.js.erb +29 -0
  95. data/frontends/default/views/refresh_list.js.erb +2 -0
  96. data/frontends/default/views/render_field.js.erb +1 -0
  97. data/frontends/default/views/row.js.erb +2 -0
  98. data/frontends/default/views/search.html.erb +5 -0
  99. data/frontends/default/views/show.html.erb +5 -0
  100. data/frontends/default/views/update.html.erb +8 -0
  101. data/frontends/default/views/update_column.js.erb +15 -0
  102. data/frontends/default/views/update_row.js.erb +1 -0
  103. data/lib/active_scaffold/actions/common_search.rb +22 -0
  104. data/lib/active_scaffold/actions/core.rb +203 -0
  105. data/lib/active_scaffold/actions/create.rb +139 -0
  106. data/lib/active_scaffold/actions/delete.rb +74 -0
  107. data/lib/active_scaffold/actions/field_search.rb +78 -0
  108. data/lib/active_scaffold/actions/list.rb +208 -0
  109. data/lib/active_scaffold/actions/mark.rb +89 -0
  110. data/lib/active_scaffold/actions/nested.rb +244 -0
  111. data/lib/active_scaffold/actions/search.rb +48 -0
  112. data/lib/active_scaffold/actions/show.rb +61 -0
  113. data/lib/active_scaffold/actions/subform.rb +23 -0
  114. data/lib/active_scaffold/actions/update.rb +156 -0
  115. data/lib/active_scaffold/active_record_permissions.rb +135 -0
  116. data/lib/active_scaffold/attribute_params.rb +200 -0
  117. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +39 -0
  118. data/lib/active_scaffold/bridges/ancestry.rb +5 -0
  119. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +37 -0
  120. data/lib/active_scaffold/bridges/bitfields.rb +6 -0
  121. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +66 -0
  122. data/lib/active_scaffold/bridges/calendar_date_select.rb +24 -0
  123. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +127 -0
  124. data/lib/active_scaffold/bridges/cancan.rb +15 -0
  125. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +31 -0
  126. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge_helpers.rb +10 -0
  127. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +45 -0
  128. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +17 -0
  129. data/lib/active_scaffold/bridges/carrierwave.rb +12 -0
  130. data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +358 -0
  131. data/lib/active_scaffold/bridges/country_helper.rb +9 -0
  132. data/lib/active_scaffold/bridges/date_picker/ext.rb +63 -0
  133. data/lib/active_scaffold/bridges/date_picker/helper.rb +180 -0
  134. data/lib/active_scaffold/bridges/date_picker.rb +23 -0
  135. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +34 -0
  136. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge_helpers.rb +10 -0
  137. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +27 -0
  138. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +16 -0
  139. data/lib/active_scaffold/bridges/dragonfly.rb +9 -0
  140. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +46 -0
  141. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +57 -0
  142. data/lib/active_scaffold/bridges/file_column/form_ui.rb +34 -0
  143. data/lib/active_scaffold/bridges/file_column/list_ui.rb +26 -0
  144. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  145. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  146. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  147. data/lib/active_scaffold/bridges/file_column.rb +11 -0
  148. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +27 -0
  149. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +16 -0
  150. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +36 -0
  151. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +24 -0
  152. data/lib/active_scaffold/bridges/paperclip.rb +12 -0
  153. data/lib/active_scaffold/bridges/record_select/helpers.rb +92 -0
  154. data/lib/active_scaffold/bridges/record_select.rb +11 -0
  155. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +20 -0
  156. data/lib/active_scaffold/bridges/semantic_attributes.rb +5 -0
  157. data/lib/active_scaffold/bridges/shared/date_bridge.rb +209 -0
  158. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +46 -0
  159. data/lib/active_scaffold/bridges/tiny_mce.rb +17 -0
  160. data/lib/active_scaffold/bridges.rb +61 -0
  161. data/lib/active_scaffold/config/base.rb +75 -0
  162. data/lib/active_scaffold/config/core.rb +236 -0
  163. data/lib/active_scaffold/config/create.rb +32 -0
  164. data/lib/active_scaffold/config/delete.rb +32 -0
  165. data/lib/active_scaffold/config/field_search.rb +79 -0
  166. data/lib/active_scaffold/config/form.rb +64 -0
  167. data/lib/active_scaffold/config/list.rb +247 -0
  168. data/lib/active_scaffold/config/mark.rb +30 -0
  169. data/lib/active_scaffold/config/nested.rb +42 -0
  170. data/lib/active_scaffold/config/search.rb +73 -0
  171. data/lib/active_scaffold/config/show.rb +31 -0
  172. data/lib/active_scaffold/config/subform.rb +35 -0
  173. data/lib/active_scaffold/config/update.rb +33 -0
  174. data/lib/active_scaffold/configurable.rb +29 -0
  175. data/lib/active_scaffold/constraints.rb +171 -0
  176. data/lib/active_scaffold/data_structures/action_columns.rb +142 -0
  177. data/lib/active_scaffold/data_structures/action_link.rb +185 -0
  178. data/lib/active_scaffold/data_structures/action_links.rb +191 -0
  179. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  180. data/lib/active_scaffold/data_structures/bridge.rb +22 -0
  181. data/lib/active_scaffold/data_structures/column.rb +402 -0
  182. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  183. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  184. data/lib/active_scaffold/data_structures/nested_info.rb +171 -0
  185. data/lib/active_scaffold/data_structures/set.rb +61 -0
  186. data/lib/active_scaffold/data_structures/sorting.rb +167 -0
  187. data/lib/active_scaffold/engine.rb +4 -0
  188. data/lib/active_scaffold/extensions/action_controller_rendering.rb +20 -0
  189. data/lib/active_scaffold/extensions/action_controller_rescueing.rb +7 -0
  190. data/lib/active_scaffold/extensions/action_view_rendering.rb +115 -0
  191. data/lib/active_scaffold/extensions/active_record_offset.rb +12 -0
  192. data/lib/active_scaffold/extensions/array.rb +7 -0
  193. data/lib/active_scaffold/extensions/cache_association.rb +16 -0
  194. data/lib/active_scaffold/extensions/localize.rb +10 -0
  195. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +12 -0
  196. data/lib/active_scaffold/extensions/nil_id_in_url_params.rb +7 -0
  197. data/lib/active_scaffold/extensions/paginator_extensions.rb +26 -0
  198. data/lib/active_scaffold/extensions/reverse_associations.rb +64 -0
  199. data/lib/active_scaffold/extensions/routing_mapper.rb +48 -0
  200. data/lib/active_scaffold/extensions/to_label.rb +8 -0
  201. data/lib/active_scaffold/extensions/unsaved_associated.rb +61 -0
  202. data/lib/active_scaffold/extensions/unsaved_record.rb +20 -0
  203. data/lib/active_scaffold/extensions/usa_state.rb +46 -0
  204. data/lib/active_scaffold/finder.rb +399 -0
  205. data/lib/active_scaffold/helpers/association_helpers.rb +42 -0
  206. data/lib/active_scaffold/helpers/controller_helpers.rb +94 -0
  207. data/lib/active_scaffold/helpers/form_column_helpers.rb +322 -0
  208. data/lib/active_scaffold/helpers/human_condition_helpers.rb +64 -0
  209. data/lib/active_scaffold/helpers/id_helpers.rb +131 -0
  210. data/lib/active_scaffold/helpers/list_column_helpers.rb +374 -0
  211. data/lib/active_scaffold/helpers/pagination_helpers.rb +62 -0
  212. data/lib/active_scaffold/helpers/search_column_helpers.rb +257 -0
  213. data/lib/active_scaffold/helpers/show_column_helpers.rb +44 -0
  214. data/lib/active_scaffold/helpers/view_helpers.rb +398 -0
  215. data/lib/active_scaffold/marked_model.rb +38 -0
  216. data/lib/active_scaffold/paginator.rb +136 -0
  217. data/lib/active_scaffold/responds_to_parent.rb +70 -0
  218. data/lib/active_scaffold/tableless.rb +83 -0
  219. data/lib/active_scaffold/version.rb +9 -0
  220. data/lib/active_scaffold.rb +373 -0
  221. data/lib/active_scaffold_env.rb +13 -0
  222. data/lib/generators/active_scaffold/USAGE +29 -0
  223. data/lib/generators/active_scaffold/active_scaffold_generator.rb +21 -0
  224. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  225. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +29 -0
  226. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  227. data/lib/generators/active_scaffold_controller/templates/helper.rb +2 -0
  228. data/public/blank.html +33 -0
  229. data/shoulda_macros/macros.rb +136 -0
  230. data/vendor/assets/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  231. data/vendor/assets/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  232. data/vendor/assets/images/ui-bg_flat_10_000000_40x100.png +0 -0
  233. data/vendor/assets/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  234. data/vendor/assets/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  235. data/vendor/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  236. data/vendor/assets/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  237. data/vendor/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  238. data/vendor/assets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  239. data/vendor/assets/images/ui-icons_222222_256x240.png +0 -0
  240. data/vendor/assets/images/ui-icons_228ef1_256x240.png +0 -0
  241. data/vendor/assets/images/ui-icons_ef8c08_256x240.png +0 -0
  242. data/vendor/assets/images/ui-icons_ffd27a_256x240.png +0 -0
  243. data/vendor/assets/images/ui-icons_ffffff_256x240.png +0 -0
  244. data/vendor/assets/javascripts/jquery-ui-timepicker-addon.js +1276 -0
  245. data/vendor/assets/stylesheets/jquery-ui.css +568 -0
  246. metadata +261 -17
@@ -0,0 +1,374 @@
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 (method = 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
+ if method(method).arity == 1
14
+ ActiveSupport::Deprecation.warn("Add column argument to field override, signature is unified with list_ui")
15
+ send(method, record)
16
+ else
17
+ send(method, record, column)
18
+ end
19
+ # second, check if the dev has specified a valid list_ui for this column
20
+ elsif column.list_ui and (method = override_column_ui(column.list_ui))
21
+ send(method, column, record)
22
+ elsif column.column and (method = override_column_ui(column.column.type))
23
+ send(method, column, record)
24
+ else
25
+ format_column_value(record, column)
26
+ end
27
+
28
+ value = ' '.html_safe if value.nil? or (value.respond_to?(:empty?) and value.empty?) # fix for IE 6
29
+ return value
30
+ rescue Exception => e
31
+ logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
32
+ raise e
33
+ end
34
+ end
35
+
36
+ # TODO: move empty_field_text and   logic in here?
37
+ # 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.
38
+ def render_list_column(text, column, record)
39
+ if column.link
40
+ link = column.link
41
+ associated = record.send(column.association.name) if column.association
42
+ url_options = params_for(:action => nil, :id => record.id)
43
+
44
+ # setup automatic link
45
+ if column.autolink? && column.singular_association? # link to inline form
46
+ link = action_link_to_inline_form(column, record, associated, text)
47
+ return text if link.nil?
48
+ else
49
+ url_options[:link] = text
50
+ end
51
+
52
+ if column_link_authorized?(link, column, record, associated)
53
+ render_action_link(link, url_options, record)
54
+ else
55
+ "<a class='disabled'>#{text}</a>".html_safe
56
+ end
57
+ elsif inplace_edit?(record, column)
58
+ active_scaffold_inplace_edit(record, column, {:formatted_column => text})
59
+ elsif active_scaffold_config.list.wrap_tag
60
+ content_tag active_scaffold_config.list.wrap_tag, text
61
+ else
62
+ text
63
+ end
64
+ end
65
+
66
+ # setup the action link to inline form
67
+ def action_link_to_inline_form(column, record, associated, text)
68
+ link = column.link.clone
69
+ link.label = text
70
+ if column.polymorphic_association?
71
+ polymorphic_controller = controller_path_for_activerecord(record.send(column.association.name).class)
72
+ return link if polymorphic_controller.nil?
73
+ link.controller = polymorphic_controller
74
+ end
75
+ configure_column_link(link, associated, column.actions_for_association_links)
76
+ end
77
+
78
+ def configure_column_link(link, associated, actions)
79
+ if column_empty?(associated) # if association is empty, we only can link to create form
80
+ if actions.include?(:new)
81
+ link.action = 'new'
82
+ link.crud_type = :create
83
+ link.label = as_(:create_new)
84
+ end
85
+ elsif actions.include?(:edit)
86
+ link.action = 'edit'
87
+ link.crud_type = :update
88
+ elsif actions.include?(:show)
89
+ link.action = 'show'
90
+ link.crud_type = :read
91
+ elsif actions.include?(:list)
92
+ link.action = 'index'
93
+ link.crud_type = :read
94
+ end
95
+ link if link.action.present?
96
+ end
97
+
98
+ def column_link_authorized?(link, column, record, associated)
99
+ if column.association
100
+ associated_for_authorized = if column.plural_association? || (associated.respond_to?(:blank?) && associated.blank?)
101
+ column.association.klass
102
+ else
103
+ associated
104
+ end
105
+ authorized = associated_for_authorized.authorized_for?(:crud_type => link.crud_type)
106
+ authorized = authorized and record.authorized_for?(:crud_type => :update, :column => column.name) if link.crud_type == :create
107
+ authorized
108
+ else
109
+ record.authorized_for?(:crud_type => link.crud_type)
110
+ end
111
+ end
112
+
113
+ # There are two basic ways to clean a column's value: h() and sanitize(). The latter is useful
114
+ # when the column contains *valid* html data, and you want to just disable any scripting. People
115
+ # can always use field overrides to clean data one way or the other, but having this override
116
+ # lets people decide which way it should happen by default.
117
+ #
118
+ # Why is it not a configuration option? Because it seems like a somewhat rare request. But it
119
+ # could eventually be an option in config.list (and config.show, I guess).
120
+ def clean_column_value(v)
121
+ h(v)
122
+ end
123
+
124
+ ##
125
+ ## Overrides
126
+ ##
127
+ def active_scaffold_column_text(column, record)
128
+ clean_column_value(truncate(record.send(column.name), :length => column.options[:truncate] || 50))
129
+ end
130
+
131
+ def active_scaffold_column_marked(column, record)
132
+ options = {:id => nil, :object => record}
133
+ content_tag(:span, check_box(:record, column.name, options), :class => 'in_place_editor_field', :data => {:ie_id => record.id.to_s})
134
+ end
135
+
136
+ def active_scaffold_column_checkbox(column, record)
137
+ options = {:disabled => true, :id => nil, :object => record}
138
+ options.delete(:disabled) if inplace_edit?(record, column)
139
+ check_box(:record, column.name, options)
140
+ end
141
+
142
+ def column_override(column)
143
+ override_helper column, 'column'
144
+ end
145
+ alias_method :column_override?, :column_override
146
+
147
+ # the naming convention for overriding column types with helpers
148
+ def override_column_ui(list_ui)
149
+ method = "active_scaffold_column_#{list_ui}"
150
+ method if respond_to? method
151
+ end
152
+ alias_method :override_column_ui?, :override_column_ui
153
+
154
+ ##
155
+ ## Formatting
156
+ ##
157
+ def format_column_value(record, column, value = nil)
158
+ value ||= record.send(column.name) unless record.nil?
159
+ if value && column.association # cache association size before calling column_empty?
160
+ associated_size = value.size if column.plural_association? and column.associated_number? # get count before cache association
161
+ cache_association(value, column, associated_size) if column.plural_association?
162
+ end
163
+ if column.association.nil? or column_empty?(value)
164
+ if column.form_ui == :select && column.options[:options]
165
+ text, val = column.options[:options].find {|text, val| (val.nil? ? text : val).to_s == value.to_s}
166
+ value = active_scaffold_translated_option(column, text, val).first if text
167
+ end
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
+ number_with_delimiter(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
+ format_value case column.association.macro
196
+ when :has_one, :belongs_to
197
+ if column.polymorphic_association?
198
+ "#{value.class.model_name.human}: #{value.to_label}"
199
+ else
200
+ 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 = firsts.join(active_scaffold_config.list.association_join_text)
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, size)
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 to display '...'
237
+ if column.associated_limit.nil?
238
+ Rails.logger.warn "ActiveScaffold: Enable eager loading for #{column.name} association to reduce SQL queries"
239
+ elsif column.associated_limit > 0
240
+ value.target = value.find(:all, :limit => column.associated_limit + 1, :select => column.select_columns)
241
+ elsif @cache_associations
242
+ value.target = size.to_i.zero? ? [] : [nil]
243
+ end
244
+ end
245
+ end
246
+
247
+ # ==========
248
+ # = Inline Edit =
249
+ # ==========
250
+
251
+ def inplace_edit?(record, column)
252
+ if column.inplace_edit
253
+ editable = controller.send(:update_authorized?, record) if controller.respond_to?(:update_authorized?)
254
+ editable = record.authorized_for?(:crud_type => :update, :column => column.name) if editable.nil? || editable == true
255
+ editable
256
+ end
257
+ end
258
+
259
+ def inplace_edit_cloning?(column)
260
+ column.inplace_edit != :ajax and (override_form_field?(column) or column.form_ui or (column.column and override_input?(column.column.type)))
261
+ end
262
+
263
+ def active_scaffold_inplace_edit(record, column, options = {})
264
+ formatted_column = options[:formatted_column] || format_column_value(record, column)
265
+ id_options = {:id => record.id.to_s, :action => 'update_column', :name => column.name.to_s}
266
+ tag_options = {:id => element_cell_id(id_options), :class => "in_place_editor_field",
267
+ :title => as_(:click_to_edit), :data => {:ie_id => record.id.to_s}}
268
+
269
+ content_tag(:span, as_(:inplace_edit_handle), :class => 'handle') <<
270
+ content_tag(:span, formatted_column, tag_options)
271
+ end
272
+
273
+ def inplace_edit_control(column)
274
+ if inplace_edit?(active_scaffold_config.model, column) and inplace_edit_cloning?(column)
275
+ old_record, @record = @record, new_model
276
+ column = column.clone
277
+ column.options = column.options.clone
278
+ column.form_ui = :select if (column.association && column.form_ui.nil?)
279
+ content_tag(:div, active_scaffold_input_for(column), :style => "display:none;", :class => inplace_edit_control_css_class).tap do
280
+ @record = old_record
281
+ end
282
+ end
283
+ end
284
+
285
+ def inplace_edit_control_css_class
286
+ "as_inplace_pattern"
287
+ end
288
+
289
+ def inplace_edit_data(column)
290
+ data = {}
291
+ data[:ie_url] = url_for({:controller => params_for[:controller], :action => "update_column", :column => column.name, :id => '__id__'})
292
+ data[:ie_cancel_text] = column.options[:cancel_text] || as_(:cancel)
293
+ data[:ie_loading_text] = column.options[:loading_text] || as_(:loading)
294
+ data[:ie_save_text] = column.options[:save_text] || as_(:update)
295
+ data[:ie_saving_text] = column.options[:saving_text] || as_(:saving)
296
+ data[:ie_rows] = column.options[:rows] || 5 if column.column.try(:type) == :text
297
+ data[:ie_cols] = column.options[:cols] if column.options[:cols]
298
+ data[:ie_size] = column.options[:size] if column.options[:size]
299
+
300
+ if column.list_ui == :checkbox
301
+ data[:ie_mode] = :inline_checkbox
302
+ elsif inplace_edit_cloning?(column)
303
+ data[:ie_mode] = :clone
304
+ elsif column.inplace_edit == :ajax
305
+ url = url_for(:controller => params_for[:controller], :action => 'render_field', :id => '__id__', :column => column.name, :update_column => column.name, :in_place_editing => true)
306
+ plural = column.plural_association? && !override_form_field?(column) && [:select, :record_select].include?(column.form_ui)
307
+ data[:ie_render_url] = url
308
+ data[:ie_mode] = :ajax
309
+ data[:ie_plural] = plural
310
+ end
311
+ data
312
+ end
313
+
314
+ def all_marked?
315
+ if active_scaffold_config.mark.mark_all_mode == :page
316
+ all_marked = @page.items.detect { |record| !marked_records.include?(record.id) }.nil?
317
+ else
318
+ all_marked = (marked_records.length >= @page.pager.count)
319
+ end
320
+ end
321
+
322
+ def mark_column_heading
323
+ tag_options = {
324
+ :id => "#{controller_id}_mark_heading",
325
+ :class => "mark_heading in_place_editor_field",
326
+ }
327
+ content_tag(:span, check_box_tag("#{controller_id}_mark_heading_span_input", '1', all_marked?), tag_options)
328
+ end
329
+
330
+ def render_column_heading(column, sorting, sort_direction)
331
+ tag_options = {:id => active_scaffold_column_header_id(column), :class => column_heading_class(column, sorting), :title => column.description}
332
+ if column.name == :as_marked
333
+ tag_options[:data] = {
334
+ :ie_mode => :inline_checkbox,
335
+ :ie_url => url_for(params_for(:action => 'mark', :id => '__id__'))
336
+ }
337
+ else
338
+ tag_options[:data] = inplace_edit_data(column) if column.inplace_edit
339
+ end
340
+ content_tag(:th, column_heading_value(column, sorting, sort_direction) + inplace_edit_control(column), tag_options)
341
+ end
342
+
343
+
344
+ def column_heading_value(column, sorting, sort_direction)
345
+ if column.name == :as_marked
346
+ mark_column_heading
347
+ elsif column.sortable?
348
+ options = {:id => nil, :class => "as_sort",
349
+ 'data-page-history' => controller_id,
350
+ :remote => true, :method => :get}
351
+ url_options = params_for(:action => :index, :page => 1,
352
+ :sort => column.name, :sort_direction => sort_direction)
353
+ link_to column.label, url_options, options
354
+ else
355
+ content_tag(:p, column.label)
356
+ end
357
+ end
358
+
359
+ def render_nested_view(action_links, url_options, record)
360
+ rendered = []
361
+ action_links.member.each do |link|
362
+ 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)
363
+ link_url_options = {:adapter => '_list_inline_adapter', :format => :js}.merge(action_link_url_options(link, url_options, record, options = {:reuse_eid => true}))
364
+ link_id = get_action_link_id(link_url_options, record, link.column)
365
+ rendered << (controller.send(:render_component_into_view, link_url_options) + javascript_tag("ActiveScaffold.ActionLink.get('#{link_id}').set_opened();"))
366
+ end
367
+ end
368
+ rendered.join(' ').html_safe
369
+ end
370
+
371
+ end
372
+ end
373
+ end
374
+
@@ -0,0 +1,62 @@
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, inner_window, outer_window)
9
+ start_number = current_page.number - inner_window
10
+ end_number = current_page.number + inner_window
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
+ if current_page.number == 1
20
+ last_page = 0
21
+ else
22
+ last_page = 1
23
+ last_page.upto([last_page + outer_window, current_page.number - 1].min) do |num|
24
+ html << pagination_ajax_link(num, url_options, options)
25
+ last_page = num
26
+ end
27
+ end
28
+ if current_page.pager.infinite?
29
+ offsets.reverse.each do |offset|
30
+ page = current_page.number - offset
31
+ if page < start_number && page > last_page
32
+ html << '..' if page > last_page + 1
33
+ html << pagination_ajax_link(page, params)
34
+ last_page = page
35
+ end
36
+ end
37
+ end
38
+ html << ".." if start_number > last_page + 1
39
+
40
+ [start_number, last_page + 1].max.upto(end_number) do |num|
41
+ if current_page.number == num
42
+ html << content_tag(:span, num.to_s, {:class => "as_paginate current"})
43
+ else
44
+ html << pagination_ajax_link(num, url_options, options)
45
+ end
46
+ end
47
+
48
+ if current_page.pager.infinite?
49
+ offsets.each do |offset|
50
+ html << '..' << pagination_ajax_link(current_page.number + offset, url_options, options)
51
+ end
52
+ else
53
+ html << ".." unless end_number >= current_page.pager.last.number - outer_window - 1
54
+ [end_number + 1, current_page.pager.last.number - outer_window].max.upto(current_page.pager.last.number) do |num|
55
+ html << pagination_ajax_link(num, url_options, options)
56
+ end
57
+ end
58
+ html.join(' ').html_safe
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,257 @@
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 (method = override_search_field(column))
12
+ send(method, @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 (method = override_search(column.search_ui))
16
+ send(method, 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 (method = override_input(column.search_ui))
20
+ send(method, column, options)
21
+
22
+ # fourth, check if the dev has created an override for this specific field
23
+ elsif (method = override_form_field(column))
24
+ send(method, @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 (method = override_search(column.column.type))
34
+ send(method, column, options)
35
+ # if we (or someone else) have created a custom render option for the column type, use that
36
+ elsif (method = override_input(column.column.type))
37
+ send(method, 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 = column.options[:options].collect do |text, value|
67
+ active_scaffold_translated_option(column, text, value)
68
+ end
69
+ end
70
+ return as_(:no_options) if select_options.empty?
71
+
72
+ active_scaffold_checkbox_list(column, select_options, associated, options)
73
+ end
74
+
75
+ def active_scaffold_search_select(column, html_options)
76
+ associated = html_options.delete :value
77
+ if column.association
78
+ associated = associated.is_a?(Array) ? associated.map(&:to_i) : associated.to_i unless associated.nil?
79
+ method = column.association.macro == :belongs_to ? column.association.foreign_key : column.name
80
+ select_options = options_for_association(column.association, true)
81
+ else
82
+ method = column.name
83
+ select_options = column.options[:options].collect do |text, value|
84
+ active_scaffold_translated_option(column, text, value)
85
+ end
86
+ end
87
+
88
+ options = { :selected => associated }.merge! column.options
89
+ html_options.merge! column.options[:html_options] || {}
90
+ if html_options[:multiple]
91
+ html_options[:name] += '[]'
92
+ else
93
+ options[:include_blank] ||= as_(:_select_)
94
+ end
95
+ select(:record, method, select_options, options, html_options)
96
+ end
97
+
98
+ def active_scaffold_search_text(column, options)
99
+ text_field :record, column.name, active_scaffold_input_text_options(options)
100
+ end
101
+
102
+ # we can't use active_scaffold_input_boolean because we need to have a nil value even when column can't be null
103
+ # to decide whether search for this field or not
104
+ def active_scaffold_search_boolean(column, options)
105
+ select_options = []
106
+ select_options << [as_(:_select_), nil]
107
+ select_options << [as_(:true), true]
108
+ select_options << [as_(:false), false]
109
+
110
+ select_tag(options[:name], options_for_select(select_options, column.column.type_cast(field_search_params[column.name])))
111
+ end
112
+ # we can't use checkbox ui because it's not possible to decide whether search for this field or not
113
+ alias_method :active_scaffold_search_checkbox, :active_scaffold_search_boolean
114
+
115
+ def active_scaffold_search_null(column, options)
116
+ select_options = []
117
+ select_options << [as_(:_select_), nil]
118
+ select_options.concat ActiveScaffold::Finder::NullComparators.collect {|comp| [as_(comp), comp]}
119
+ select_tag(options[:name], options_for_select(select_options, field_search_params[column.name]))
120
+ end
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].blank? ? nil : values[:from]), (values[:to].blank? ? nil : values[:to])
126
+
127
+ end
128
+
129
+ def active_scaffold_search_range_string?(column)
130
+ (column.column && column.column.text?) || column.search_ui == :string
131
+ end
132
+
133
+ def include_null_comparators?(column)
134
+ return column.options[:null_comparators] if column.options.has_key? :null_comparators
135
+ if column.association
136
+ column.association.macro != :belongs_to || active_scaffold_config.columns[column.association.foreign_key].column.try(:null)
137
+ else
138
+ column.column.try(:null)
139
+ end
140
+ end
141
+
142
+ def active_scaffold_search_range_comparator_options(column)
143
+ select_options = ActiveScaffold::Finder::NumericComparators.collect {|comp| [as_(comp.downcase.to_sym), comp]}
144
+ if active_scaffold_search_range_string?(column)
145
+ select_options.unshift *ActiveScaffold::Finder::StringComparators.collect {|title, comp| [as_(title), comp]}
146
+ end
147
+ if include_null_comparators? column
148
+ select_options += ActiveScaffold::Finder::NullComparators.collect {|comp| [as_(comp), comp]}
149
+ end
150
+ select_options
151
+ end
152
+
153
+ def include_null_comparators?(column)
154
+ return column.options[:null_comparators] if column.options.has_key? :null_comparators
155
+ if column.association
156
+ column.association.macro != :belongs_to || active_scaffold_config.columns[column.association.foreign_key].column.try(:null)
157
+ else
158
+ column.column.try(:null)
159
+ end
160
+ end
161
+
162
+ def active_scaffold_search_range(column, options)
163
+ opt_value, from_value, to_value = field_search_params_range_values(column)
164
+
165
+ select_options = active_scaffold_search_range_comparator_options(column)
166
+ if active_scaffold_search_range_string?(column)
167
+ text_field_size = 15
168
+ opt_value ||= '%?%'
169
+ else
170
+ text_field_size = 10
171
+ opt_value ||= '='
172
+ end
173
+
174
+ from_value = controller.class.condition_value_for_numeric(column, from_value)
175
+ to_value = controller.class.condition_value_for_numeric(column, to_value)
176
+ from_value = format_number_value(from_value, column.options) if from_value.is_a?(Numeric)
177
+ to_value = format_number_value(to_value, column.options) if to_value.is_a?(Numeric)
178
+ html = select_tag("#{options[:name]}[opt]",
179
+ options_for_select(select_options, opt_value),
180
+ :id => "#{options[:id]}_opt",
181
+ :class => "as_search_range_option")
182
+ html << content_tag("span", :id => "#{options[:id]}_numeric", :style => ActiveScaffold::Finder::NullComparators.include?(opt_value) ? "display: none" : nil) do
183
+ text_field_tag("#{options[:name]}[from]", from_value, active_scaffold_input_text_options(:id => options[:id], :size => text_field_size)) <<
184
+ content_tag(:span, (' - ' + text_field_tag("#{options[:name]}[to]", to_value,
185
+ active_scaffold_input_text_options(:id => "#{options[:id]}_to", :size => text_field_size))).html_safe,
186
+ :id => "#{options[:id]}_between", :class => "as_search_range_between", :style => (opt_value == 'BETWEEN') ? nil : "display: none")
187
+ end
188
+ content_tag :span, html, :class => 'search_range'
189
+ end
190
+ alias_method :active_scaffold_search_integer, :active_scaffold_search_range
191
+ alias_method :active_scaffold_search_decimal, :active_scaffold_search_range
192
+ alias_method :active_scaffold_search_float, :active_scaffold_search_range
193
+ alias_method :active_scaffold_search_string, :active_scaffold_search_range
194
+
195
+ def field_search_datetime_value(value)
196
+ 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?
197
+ end
198
+
199
+ def active_scaffold_search_datetime(column, options)
200
+ opt_value, from_value, to_value = field_search_params_range_values(column)
201
+ options = column.options.merge(options)
202
+ helper = "select_#{'date' unless options[:discard_date]}#{'time' unless options[:discard_time]}"
203
+
204
+ send(helper, field_search_datetime_value(from_value), {:include_blank => true, :prefix => "#{options[:name]}[from]"}.merge(options)) <<
205
+ ' - '.html_safe << send(helper, field_search_datetime_value(to_value), {:include_blank => true, :prefix => "#{options[:name]}[to]"}.merge(options))
206
+ end
207
+
208
+ def active_scaffold_search_date(column, options)
209
+ active_scaffold_search_datetime(column, options.merge!(:discard_time => true))
210
+ end
211
+ def active_scaffold_search_time(column, options)
212
+ active_scaffold_search_datetime(column, options.merge!(:discard_date => true))
213
+ end
214
+ alias_method :active_scaffold_search_timestamp, :active_scaffold_search_datetime
215
+
216
+ ##
217
+ ## Search column override signatures
218
+ ##
219
+
220
+ def override_search_field(column)
221
+ override_helper column, 'search_column'
222
+ end
223
+
224
+ # the naming convention for overriding search input types with helpers
225
+ def override_search(form_ui)
226
+ method = "active_scaffold_search_#{form_ui}"
227
+ method if respond_to? method
228
+ end
229
+
230
+ def visibles_and_hiddens(search_config)
231
+ visibles = []
232
+ hiddens = []
233
+ search_config.columns.each do |column|
234
+ next unless column.search_sql
235
+ if search_config.optional_columns.include?(column.name) && !searched_by?(column)
236
+ hiddens << column
237
+ else
238
+ visibles << column
239
+ end
240
+ end
241
+ return visibles, hiddens
242
+ end
243
+
244
+ def searched_by?(column)
245
+ value = field_search_params[column.name]
246
+ case value
247
+ when Hash
248
+ !value['from'].blank?
249
+ when String
250
+ !value.blank?
251
+ else
252
+ false
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end