active_scaffold-sequel 0.3.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 (318) hide show
  1. data/CHANGELOG +179 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +36 -0
  4. data/app/assets/images/active_scaffold/add.gif +0 -0
  5. data/app/assets/images/active_scaffold/arrow_down.gif +0 -0
  6. data/app/assets/images/active_scaffold/arrow_up.gif +0 -0
  7. data/app/assets/images/active_scaffold/close.gif +0 -0
  8. data/app/assets/images/active_scaffold/close_touch.png +0 -0
  9. data/app/assets/images/active_scaffold/config.png +0 -0
  10. data/app/assets/images/active_scaffold/cross.png +0 -0
  11. data/app/assets/images/active_scaffold/gears.png +0 -0
  12. data/app/assets/images/active_scaffold/indicator-small.gif +0 -0
  13. data/app/assets/images/active_scaffold/indicator.gif +0 -0
  14. data/app/assets/images/active_scaffold/magnifier.png +0 -0
  15. data/app/assets/javascripts/active_scaffold.js.erb +19 -0
  16. data/app/assets/javascripts/jquery/active_scaffold.js +1057 -0
  17. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +24 -0
  18. data/app/assets/javascripts/jquery/draggable_lists.js +27 -0
  19. data/app/assets/javascripts/jquery/jquery.editinplace.js +743 -0
  20. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +7 -0
  21. data/app/assets/javascripts/prototype/active_scaffold.js +1052 -0
  22. data/app/assets/javascripts/prototype/dhtml_history.js +870 -0
  23. data/app/assets/javascripts/prototype/form_enhancements.js +117 -0
  24. data/app/assets/javascripts/prototype/rico_corner.js +370 -0
  25. data/app/assets/javascripts/prototype/tiny_mce_bridge.js +7 -0
  26. data/app/assets/stylesheets/active_scaffold-ie.css +35 -0
  27. data/app/assets/stylesheets/active_scaffold.css.scss +14 -0
  28. data/app/assets/stylesheets/active_scaffold_colors.css.scss +395 -0
  29. data/app/assets/stylesheets/active_scaffold_extensions.css.erb +2 -0
  30. data/app/assets/stylesheets/active_scaffold_images.css.scss +43 -0
  31. data/app/assets/stylesheets/active_scaffold_layout.css +912 -0
  32. data/app/assets/stylesheets/blue-theme.css +74 -0
  33. data/config/locales/de.yml +114 -0
  34. data/config/locales/en.yml +118 -0
  35. data/config/locales/es.yml +120 -0
  36. data/config/locales/fr.yml +121 -0
  37. data/config/locales/hu.yml +74 -0
  38. data/config/locales/ja.yml +73 -0
  39. data/config/locales/ru.yml +123 -0
  40. data/frontends/default/views/_action_group.html.erb +24 -0
  41. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  42. data/frontends/default/views/_base_form.html.erb +51 -0
  43. data/frontends/default/views/_create_form.html.erb +8 -0
  44. data/frontends/default/views/_create_form_on_list.html.erb +6 -0
  45. data/frontends/default/views/_field_search.html.erb +32 -0
  46. data/frontends/default/views/_form.html.erb +24 -0
  47. data/frontends/default/views/_form_association.html.erb +15 -0
  48. data/frontends/default/views/_form_association_footer.html.erb +47 -0
  49. data/frontends/default/views/_form_attribute.html.erb +20 -0
  50. data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
  51. data/frontends/default/views/_form_messages.html.erb +5 -0
  52. data/frontends/default/views/_horizontal_subform.html.erb +28 -0
  53. data/frontends/default/views/_horizontal_subform_footer.html.erb +0 -0
  54. data/frontends/default/views/_horizontal_subform_header.html.erb +11 -0
  55. data/frontends/default/views/_horizontal_subform_record.html.erb +38 -0
  56. data/frontends/default/views/_human_conditions.html.erb +1 -0
  57. data/frontends/default/views/_list.html.erb +18 -0
  58. data/frontends/default/views/_list_actions.html.erb +15 -0
  59. data/frontends/default/views/_list_calculations.html.erb +16 -0
  60. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  61. data/frontends/default/views/_list_header.html.erb +10 -0
  62. data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
  63. data/frontends/default/views/_list_messages.html.erb +30 -0
  64. data/frontends/default/views/_list_pagination.html.erb +11 -0
  65. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  66. data/frontends/default/views/_list_record.html.erb +14 -0
  67. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  68. data/frontends/default/views/_list_with_header.html.erb +36 -0
  69. data/frontends/default/views/_messages.html.erb +10 -0
  70. data/frontends/default/views/_render_field.js.erb +20 -0
  71. data/frontends/default/views/_row.html.erb +6 -0
  72. data/frontends/default/views/_search.html.erb +34 -0
  73. data/frontends/default/views/_search_attribute.html.erb +10 -0
  74. data/frontends/default/views/_show.html.erb +8 -0
  75. data/frontends/default/views/_show_columns.html.erb +15 -0
  76. data/frontends/default/views/_update_actions.html.erb +9 -0
  77. data/frontends/default/views/_update_form.html.erb +6 -0
  78. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  79. data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
  80. data/frontends/default/views/action_confirmation.html.erb +13 -0
  81. data/frontends/default/views/add_existing.js.erb +18 -0
  82. data/frontends/default/views/add_existing_form.html.erb +5 -0
  83. data/frontends/default/views/create.html.erb +5 -0
  84. data/frontends/default/views/delete.html.erb +13 -0
  85. data/frontends/default/views/destroy.js.erb +24 -0
  86. data/frontends/default/views/edit_associated.js.erb +12 -0
  87. data/frontends/default/views/field_search.html.erb +5 -0
  88. data/frontends/default/views/form_messages.js.erb +1 -0
  89. data/frontends/default/views/list.html.erb +1 -0
  90. data/frontends/default/views/on_action_update.js.erb +13 -0
  91. data/frontends/default/views/on_create.js.erb +47 -0
  92. data/frontends/default/views/on_mark_all.js.erb +12 -0
  93. data/frontends/default/views/on_update.js.erb +31 -0
  94. data/frontends/default/views/refresh_list.js.erb +1 -0
  95. data/frontends/default/views/render_field.js.erb +1 -0
  96. data/frontends/default/views/search.html.erb +5 -0
  97. data/frontends/default/views/show.html.erb +5 -0
  98. data/frontends/default/views/update.html.erb +8 -0
  99. data/frontends/default/views/update_column.js.erb +16 -0
  100. data/frontends/default/views/update_row.js.erb +1 -0
  101. data/lib/active_scaffold/actions/common_search.rb +25 -0
  102. data/lib/active_scaffold/actions/core.rb +197 -0
  103. data/lib/active_scaffold/actions/create.rb +148 -0
  104. data/lib/active_scaffold/actions/delete.rb +76 -0
  105. data/lib/active_scaffold/actions/field_search.rb +82 -0
  106. data/lib/active_scaffold/actions/list.rb +196 -0
  107. data/lib/active_scaffold/actions/mark.rb +75 -0
  108. data/lib/active_scaffold/actions/nested.rb +245 -0
  109. data/lib/active_scaffold/actions/search.rb +48 -0
  110. data/lib/active_scaffold/actions/show.rb +61 -0
  111. data/lib/active_scaffold/actions/subform.rb +23 -0
  112. data/lib/active_scaffold/actions/update.rb +150 -0
  113. data/lib/active_scaffold/active_record_permissions.rb +136 -0
  114. data/lib/active_scaffold/attribute_params.rb +208 -0
  115. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +39 -0
  116. data/lib/active_scaffold/bridges/ancestry.rb +5 -0
  117. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +67 -0
  118. data/lib/active_scaffold/bridges/calendar_date_select.rb +24 -0
  119. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +107 -0
  120. data/lib/active_scaffold/bridges/cancan.rb +15 -0
  121. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +31 -0
  122. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge_helpers.rb +10 -0
  123. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +45 -0
  124. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +17 -0
  125. data/lib/active_scaffold/bridges/carrierwave.rb +12 -0
  126. data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +358 -0
  127. data/lib/active_scaffold/bridges/country_helper.rb +9 -0
  128. data/lib/active_scaffold/bridges/date_picker/ext.rb +45 -0
  129. data/lib/active_scaffold/bridges/date_picker/helper.rb +180 -0
  130. data/lib/active_scaffold/bridges/date_picker.rb +23 -0
  131. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +34 -0
  132. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge_helpers.rb +10 -0
  133. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +27 -0
  134. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +16 -0
  135. data/lib/active_scaffold/bridges/dragonfly.rb +9 -0
  136. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +48 -0
  137. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +57 -0
  138. data/lib/active_scaffold/bridges/file_column/form_ui.rb +34 -0
  139. data/lib/active_scaffold/bridges/file_column/list_ui.rb +26 -0
  140. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  141. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  142. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  143. data/lib/active_scaffold/bridges/file_column.rb +11 -0
  144. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +27 -0
  145. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +16 -0
  146. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +36 -0
  147. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +24 -0
  148. data/lib/active_scaffold/bridges/paperclip.rb +12 -0
  149. data/lib/active_scaffold/bridges/record_select/helpers.rb +86 -0
  150. data/lib/active_scaffold/bridges/record_select.rb +11 -0
  151. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +20 -0
  152. data/lib/active_scaffold/bridges/semantic_attributes.rb +5 -0
  153. data/lib/active_scaffold/bridges/shared/date_bridge.rb +209 -0
  154. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +46 -0
  155. data/lib/active_scaffold/bridges/tiny_mce.rb +17 -0
  156. data/lib/active_scaffold/bridges.rb +61 -0
  157. data/lib/active_scaffold/config/base.rb +71 -0
  158. data/lib/active_scaffold/config/core.rb +219 -0
  159. data/lib/active_scaffold/config/create.rb +44 -0
  160. data/lib/active_scaffold/config/delete.rb +33 -0
  161. data/lib/active_scaffold/config/field_search.rb +76 -0
  162. data/lib/active_scaffold/config/form.rb +48 -0
  163. data/lib/active_scaffold/config/list.rb +196 -0
  164. data/lib/active_scaffold/config/mark.rb +35 -0
  165. data/lib/active_scaffold/config/nested.rb +42 -0
  166. data/lib/active_scaffold/config/search.rb +73 -0
  167. data/lib/active_scaffold/config/show.rb +32 -0
  168. data/lib/active_scaffold/config/subform.rb +35 -0
  169. data/lib/active_scaffold/config/update.rb +41 -0
  170. data/lib/active_scaffold/configurable.rb +29 -0
  171. data/lib/active_scaffold/constraints.rb +170 -0
  172. data/lib/active_scaffold/data_structures/action_columns.rb +140 -0
  173. data/lib/active_scaffold/data_structures/action_link.rb +179 -0
  174. data/lib/active_scaffold/data_structures/action_links.rb +185 -0
  175. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  176. data/lib/active_scaffold/data_structures/bridge.rb +22 -0
  177. data/lib/active_scaffold/data_structures/column.rb +389 -0
  178. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  179. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  180. data/lib/active_scaffold/data_structures/nested_info.rb +130 -0
  181. data/lib/active_scaffold/data_structures/set.rb +57 -0
  182. data/lib/active_scaffold/data_structures/sorting.rb +172 -0
  183. data/lib/active_scaffold/engine.rb +4 -0
  184. data/lib/active_scaffold/extensions/action_controller_rendering.rb +22 -0
  185. data/lib/active_scaffold/extensions/action_view_rendering.rb +115 -0
  186. data/lib/active_scaffold/extensions/active_record_offset.rb +12 -0
  187. data/lib/active_scaffold/extensions/array.rb +7 -0
  188. data/lib/active_scaffold/extensions/cache_association.rb +16 -0
  189. data/lib/active_scaffold/extensions/localize.rb +10 -0
  190. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +12 -0
  191. data/lib/active_scaffold/extensions/nil_id_in_url_params.rb +7 -0
  192. data/lib/active_scaffold/extensions/paginator_extensions.rb +26 -0
  193. data/lib/active_scaffold/extensions/routing_mapper.rb +48 -0
  194. data/lib/active_scaffold/extensions/to_label.rb +8 -0
  195. data/lib/active_scaffold/extensions/unsaved_associated.rb +60 -0
  196. data/lib/active_scaffold/extensions/unsaved_record.rb +20 -0
  197. data/lib/active_scaffold/extensions/usa_state.rb +46 -0
  198. data/lib/active_scaffold/finder.rb +372 -0
  199. data/lib/active_scaffold/helpers/association_helpers.rb +48 -0
  200. data/lib/active_scaffold/helpers/controller_helpers.rb +88 -0
  201. data/lib/active_scaffold/helpers/form_column_helpers.rb +321 -0
  202. data/lib/active_scaffold/helpers/human_condition_helpers.rb +62 -0
  203. data/lib/active_scaffold/helpers/id_helpers.rb +127 -0
  204. data/lib/active_scaffold/helpers/list_column_helpers.rb +340 -0
  205. data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
  206. data/lib/active_scaffold/helpers/search_column_helpers.rb +267 -0
  207. data/lib/active_scaffold/helpers/show_column_helpers.rb +50 -0
  208. data/lib/active_scaffold/helpers/view_helpers.rb +342 -0
  209. data/lib/active_scaffold/marked_model.rb +38 -0
  210. data/lib/active_scaffold/paginator.rb +136 -0
  211. data/lib/active_scaffold/responds_to_parent.rb +70 -0
  212. data/lib/active_scaffold/version.rb +9 -0
  213. data/lib/active_scaffold.rb +368 -0
  214. data/lib/active_scaffold_env.rb +11 -0
  215. data/lib/generators/active_scaffold/USAGE +29 -0
  216. data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
  217. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  218. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +29 -0
  219. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  220. data/lib/generators/active_scaffold_controller/templates/helper.rb +2 -0
  221. data/public/blank.html +33 -0
  222. data/shoulda_macros/macros.rb +136 -0
  223. data/test/bridges/active_scaffold_dependent_protect_test.rb +34 -0
  224. data/test/bridges/bridge_test.rb +90 -0
  225. data/test/bridges/company.rb +81 -0
  226. data/test/bridges/paperclip_test.rb +68 -0
  227. data/test/bridges/tiny_mce_test.rb +27 -0
  228. data/test/bridges/unobtrusive_date_picker_test.rb +49 -0
  229. data/test/bridges/validation_reflection_test.rb +57 -0
  230. data/test/config/base_test.rb +15 -0
  231. data/test/config/core_test.rb +58 -0
  232. data/test/config/create_test.rb +58 -0
  233. data/test/config/delete_test.rb +33 -0
  234. data/test/config/field_search_test.rb +47 -0
  235. data/test/config/list_test.rb +129 -0
  236. data/test/config/nested_test.rb +62 -0
  237. data/test/config/search_test.rb +60 -0
  238. data/test/config/show_test.rb +43 -0
  239. data/test/config/subform_test.rb +17 -0
  240. data/test/config/update_test.rb +40 -0
  241. data/test/const_mocker.rb +36 -0
  242. data/test/data_structures/action_columns_test.rb +113 -0
  243. data/test/data_structures/action_link_test.rb +78 -0
  244. data/test/data_structures/action_links_test.rb +78 -0
  245. data/test/data_structures/actions_test.rb +25 -0
  246. data/test/data_structures/association_column_test.rb +42 -0
  247. data/test/data_structures/column_test.rb +185 -0
  248. data/test/data_structures/columns_test.rb +69 -0
  249. data/test/data_structures/error_message_test.rb +28 -0
  250. data/test/data_structures/set_test.rb +86 -0
  251. data/test/data_structures/sorting_test.rb +126 -0
  252. data/test/data_structures/standard_column_test.rb +24 -0
  253. data/test/data_structures/virtual_column_test.rb +23 -0
  254. data/test/extensions/active_record_test.rb +45 -0
  255. data/test/extensions/array_test.rb +12 -0
  256. data/test/helpers/form_column_helpers_test.rb +31 -0
  257. data/test/helpers/list_column_helpers_test.rb +42 -0
  258. data/test/helpers/pagination_helpers_test.rb +59 -0
  259. data/test/misc/active_record_permissions_test.rb +154 -0
  260. data/test/misc/attribute_params_test.rb +146 -0
  261. data/test/misc/configurable_test.rb +96 -0
  262. data/test/misc/constraints_test.rb +193 -0
  263. data/test/misc/finder_test.rb +92 -0
  264. data/test/misc/lang_test.rb +11 -0
  265. data/test/mock_app/app/controllers/application_controller.rb +10 -0
  266. data/test/mock_app/app/helpers/application_helper.rb +3 -0
  267. data/test/mock_app/config/boot.rb +110 -0
  268. data/test/mock_app/config/database.yml +16 -0
  269. data/test/mock_app/config/environment.rb +43 -0
  270. data/test/mock_app/config/environments/development.rb +17 -0
  271. data/test/mock_app/config/environments/production.rb +28 -0
  272. data/test/mock_app/config/environments/test.rb +28 -0
  273. data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
  274. data/test/mock_app/config/initializers/inflections.rb +10 -0
  275. data/test/mock_app/config/initializers/mime_types.rb +5 -0
  276. data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  277. data/test/mock_app/config/initializers/session_store.rb +15 -0
  278. data/test/mock_app/config/locales/en.yml +5 -0
  279. data/test/mock_app/config/routes.rb +43 -0
  280. data/test/mock_app/db/test.sqlite3 +1 -0
  281. data/test/mock_app/public/blank.html +33 -0
  282. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
  283. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  284. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  285. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  286. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  287. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  288. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  289. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  290. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  291. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
  292. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
  293. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
  294. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
  295. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
  296. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
  297. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
  298. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +848 -0
  299. data/test/model_stub.rb +55 -0
  300. data/test/run_all.rb +8 -0
  301. data/test/test_helper.rb +39 -0
  302. data/vendor/assets/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  303. data/vendor/assets/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  304. data/vendor/assets/images/ui-bg_flat_10_000000_40x100.png +0 -0
  305. data/vendor/assets/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  306. data/vendor/assets/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  307. data/vendor/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  308. data/vendor/assets/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  309. data/vendor/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  310. data/vendor/assets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  311. data/vendor/assets/images/ui-icons_222222_256x240.png +0 -0
  312. data/vendor/assets/images/ui-icons_228ef1_256x240.png +0 -0
  313. data/vendor/assets/images/ui-icons_ef8c08_256x240.png +0 -0
  314. data/vendor/assets/images/ui-icons_ffd27a_256x240.png +0 -0
  315. data/vendor/assets/images/ui-icons_ffffff_256x240.png +0 -0
  316. data/vendor/assets/javascripts/jquery-ui-timepicker-addon.js +1276 -0
  317. data/vendor/assets/stylesheets/jquery-ui.css +568 -0
  318. metadata +502 -0
@@ -0,0 +1,389 @@
1
+ module ActiveScaffold::DataStructures
2
+ class Column
3
+ include ActiveScaffold::Configurable
4
+
5
+ attr_reader :active_record_class
6
+
7
+ # this is the name of the getter on the ActiveRecord model. it is the only absolutely required attribute ... all others will be inferred from this name.
8
+ attr_accessor :name
9
+
10
+ # Whether to enable inplace editing for this column. Currently works for text columns, in the List.
11
+ attr_reader :inplace_edit
12
+ def inplace_edit=(value)
13
+ self.clear_link if value
14
+ @inplace_edit = value
15
+ end
16
+
17
+ # Whether this column set is collapsed by default in contexts where collapsing is supported
18
+ attr_accessor :collapsed
19
+
20
+ # Whether to enable add_existing for this column
21
+ attr_accessor :allow_add_existing
22
+
23
+ # Any extra parameters this particular column uses. This is for create/update purposes.
24
+ def params
25
+ # lazy initialize
26
+ @params ||= Set.new
27
+ end
28
+
29
+ # the display-name of the column. this will be used, for instance, as the column title in the table and as the field name in the form.
30
+ # if left alone it will utilize human_attribute_name which includes localization
31
+ attr_writer :label
32
+ def label
33
+ as_(@label) || active_record_class.human_attribute_name(name)
34
+ end
35
+
36
+ # a textual description of the column and its contents. this will be displayed with any associated form input widget, so you may want to consider adding a content example.
37
+ attr_writer :description
38
+ def description
39
+ if @description
40
+ @description
41
+ else
42
+ I18n.t name, :scope => [:activerecord, :description, active_record_class.to_s.underscore.to_sym], :default => ''
43
+ end
44
+ end
45
+
46
+ # this will be /joined/ to the :name for the td's class attribute. useful if you want to style columns on different ActiveScaffolds the same way, but the columns have different names.
47
+ attr_accessor :css_class
48
+
49
+ # whether the field is required or not. used on the form for visually indicating the fact to the user.
50
+ # TODO: move into predicate
51
+ attr_writer :required
52
+ def required?
53
+ @required
54
+ end
55
+
56
+ attr_reader :update_columns
57
+
58
+ # update dependent columns after value change in form
59
+ # update_columns = :name
60
+ # update_columns = [:name, :age]
61
+ def update_columns=(column_names)
62
+ @update_columns = Array(column_names)
63
+ end
64
+
65
+ # send all the form instead of only new value when this column change
66
+ cattr_accessor :send_form_on_update_column
67
+ attr_accessor :send_form_on_update_column
68
+
69
+ # column to be updated in a form when this column changes
70
+ attr_accessor :update_column
71
+
72
+ # send all the form instead of only new value when this column change
73
+ cattr_accessor :send_form_on_update_column
74
+ attr_accessor :send_form_on_update_column
75
+
76
+ # sorting on a column can be configured four ways:
77
+ # sort = true default, uses intelligent sorting sql default
78
+ # sort = false sometimes sorting doesn't make sense
79
+ # sort = {:sql => ""} define your own sql for sorting. this should be result in a sortable value in SQL. ActiveScaffold will handle the ascending/descending.
80
+ # sort = {:method => ""} define ruby-side code for sorting. this is SLOW with large recordsets!
81
+ def sort=(value)
82
+ if value.is_a? Hash
83
+ value.assert_valid_keys(:sql, :method)
84
+ @sort = value
85
+ else
86
+ @sort = value ? true : false # force true or false
87
+ end
88
+ end
89
+
90
+ def sort
91
+ self.initialize_sort if @sort === true
92
+ @sort
93
+ end
94
+
95
+ def sortable?
96
+ sort != false && !sort.nil?
97
+ end
98
+
99
+ # a configuration helper for the self.sort property. simply provides a method syntax instead of setter syntax.
100
+ def sort_by(options)
101
+ self.sort = options
102
+ end
103
+
104
+ # supported options:
105
+ # * for association columns
106
+ # * :select - displays a simple <select> or a collection of checkboxes to (dis)associate records
107
+ attr_writer :form_ui
108
+ def form_ui
109
+ @form_ui
110
+ end
111
+
112
+ attr_writer :list_ui
113
+ def list_ui
114
+ @list_ui || @form_ui
115
+ end
116
+
117
+ attr_writer :search_ui
118
+ def search_ui
119
+ @search_ui || @form_ui || (@association ? :select : nil)
120
+ end
121
+
122
+ # a place to store dev's column specific options
123
+ attr_accessor :options
124
+ def options
125
+ @options ||= {}
126
+ end
127
+
128
+ def link
129
+ @link = @link.call(self) if @link.is_a? Proc
130
+ @link
131
+ end
132
+
133
+ # associate an action_link with this column
134
+ def set_link(action, options = {})
135
+ if action.is_a?(ActiveScaffold::DataStructures::ActionLink) || (action.is_a? Proc)
136
+ @link = action
137
+ else
138
+ options[:label] ||= self.label
139
+ options[:position] ||= :after unless options.has_key?(:position)
140
+ options[:type] ||= :member
141
+ @link = ActiveScaffold::DataStructures::ActionLink.new(action, options)
142
+ end
143
+ end
144
+
145
+ # set an action_link to nested list or inline form in this column
146
+ def autolink?
147
+ @autolink
148
+ end
149
+
150
+ # this should not only delete any existing link but also prevent column links from being automatically added by later routines
151
+ def clear_link
152
+ @link = nil
153
+ @autolink = false
154
+ end
155
+
156
+ # define a calculation for the column. anything that ActiveRecord::Calculations::ClassMethods#calculate accepts will do.
157
+ attr_accessor :calculate
158
+
159
+ # get whether to run a calculation on this column
160
+ def calculation?
161
+ !(@calculate == false or @calculate.nil?)
162
+ end
163
+
164
+ # a collection of associations to pre-load when finding the records on a page
165
+ attr_reader :includes
166
+ def includes=(value)
167
+ @includes = case value
168
+ when Array, Hash then value
169
+ else [value] # automatically convert to an array
170
+ end
171
+ end
172
+
173
+ # a collection of columns to load when eager loading is disabled, if it's nil all columns will be loaded
174
+ attr_accessor :select_columns
175
+
176
+ # describes how to search on a column
177
+ # search = true default, uses intelligent search sql
178
+ # search = "CONCAT(a, b)" define your own sql for searching. this should be the "left-side" of a WHERE condition. the operator and value will be supplied by ActiveScaffold.
179
+ attr_writer :search_sql
180
+ def search_sql
181
+ self.initialize_search_sql if @search_sql === true
182
+ @search_sql
183
+ end
184
+ def searchable?
185
+ search_sql != false && search_sql != nil
186
+ end
187
+
188
+ # to modify the default order of columns
189
+ attr_accessor :weight
190
+
191
+ # to set how many associated records a column with plural association must show in list
192
+ cattr_accessor :associated_limit
193
+ @@associated_limit = 3
194
+ attr_accessor :associated_limit
195
+
196
+ # whether the number of associated records must be shown or not
197
+ cattr_accessor :associated_number
198
+ @@associated_number = true
199
+ attr_writer :associated_number
200
+ def associated_number?
201
+ @associated_number
202
+ end
203
+
204
+ # whether a blank row must be shown in the subform
205
+ cattr_accessor :show_blank_record
206
+ @@show_blank_record = true
207
+ attr_writer :show_blank_record
208
+ def show_blank_record?(associated)
209
+ if @show_blank_record
210
+ return false unless self.association.associated_class.authorized_for?(:crud_type => :create)
211
+ self.plural_association? or (self.singular_association? and associated.blank?)
212
+ end
213
+ end
214
+
215
+ # methods for automatic links in singular association columns
216
+ cattr_accessor :actions_for_association_links
217
+ @@actions_for_association_links = [:new, :edit, :show]
218
+ attr_accessor :actions_for_association_links
219
+
220
+ cattr_accessor :association_form_ui
221
+ @@association_form_ui = nil
222
+
223
+ # ----------------------------------------------------------------- #
224
+ # the below functionality is intended for internal consumption only #
225
+ # ----------------------------------------------------------------- #
226
+
227
+ # the ConnectionAdapter::*Column object from the ActiveRecord class
228
+ attr_reader :column
229
+
230
+ # maximal length of a string column - obtained from @column
231
+ attr_reader :maxlength
232
+
233
+ # the association from the ActiveRecord class
234
+ attr_reader :association
235
+
236
+ def singular_association?
237
+ self.association and [:one_to_one, :many_to_one].include? self.association[:type]
238
+ end
239
+
240
+ def plural_association?
241
+ self.association and [:one_to_many, :many_to_many].include? self.association[:type]
242
+ end
243
+
244
+ # an interpreted property. the column is virtual if it isn't from the active record model or any associated models
245
+ def virtual?
246
+ column.nil? && association.nil?
247
+ end
248
+
249
+ attr_writer :number
250
+ def number?
251
+ @number
252
+ end
253
+
254
+ # this is so that array.delete and array.include?, etc., will work by column name
255
+ def ==(other) #:nodoc:
256
+ # another column
257
+ if other.respond_to? :name and other.class == self.class
258
+ self.name == other.name
259
+ # a string or symbol
260
+ elsif other.respond_to? :to_sym
261
+ self.name == other.to_sym rescue false # catch "interning empty string"
262
+ # unknown
263
+ else
264
+ self.eql? other
265
+ end
266
+ end
267
+
268
+ # instantiation is handled internally through the DataStructures::Columns object
269
+ def initialize(name, active_record_class) #:nodoc:
270
+ self.name = name
271
+ @column = active_record_class.db_schema[name]
272
+ @association = active_record_class.association_reflection(name)
273
+ @autolink = !@association.nil?
274
+ @active_record_class = active_record_class
275
+ @table = active_record_class.table_name
276
+ @associated_limit = self.class.associated_limit
277
+ @associated_number = self.class.associated_number
278
+ @show_blank_record = self.class.show_blank_record
279
+ @send_form_on_update_column = self.class.send_form_on_update_column
280
+ @actions_for_association_links = self.class.actions_for_association_links.clone if @association
281
+
282
+ self.number = (@column and (@column[:type] == :integer or @column[:type] == :float or @column[:type] == :decimal))
283
+ @options = {:format => :i18n_number} if self.number?
284
+ @form_ui = :checkbox if @column and @column[:type] == :boolean
285
+ @form_ui = :textarea if @column and @column[:type] == :string and (@column[:db_type] == 'text' or ((mc = @column[:max_chars]) and mc > 255))
286
+ @maxlength = parse_column_length if @column and @column[:type] == :string
287
+ @allow_add_existing = true
288
+ @form_ui = self.class.association_form_ui if @association && self.class.association_form_ui
289
+
290
+ # default all the configurable variables
291
+ self.css_class = ''
292
+ self.required = (@column and @column[:default].nil? and not @column[:allow_null])
293
+ self.sort = true
294
+ self.search_sql = true
295
+
296
+ @weight = estimate_weight
297
+
298
+ self.includes = association ? [association[:name]] : []
299
+ end
300
+
301
+ # just the field (not table.field)
302
+ def field_name
303
+ return nil if virtual?
304
+ column ? name : association[:key]
305
+ end
306
+
307
+ def <=>(other_column)
308
+ order_weight = self.weight <=> other_column.weight
309
+ order_weight != 0 ? order_weight : self.name.to_s <=> other_column.name.to_s
310
+ end
311
+
312
+ def number_to_native(value)
313
+ return value if value.blank? || !value.is_a?(String)
314
+ native = '.' # native ruby separator
315
+ format = {:separator => '', :delimiter => ''}.merge! I18n.t('number.format', :default => {})
316
+ specific = case self.options[:format]
317
+ when :currency
318
+ I18n.t('number.currency.format', :default => nil)
319
+ when :size
320
+ I18n.t('number.human.format', :default => nil)
321
+ when :percentage
322
+ I18n.t('number.percentage.format', :default => nil)
323
+ end
324
+ format.merge! specific unless specific.nil?
325
+ unless format[:separator].blank? || !value.include?(format[:separator]) && value.include?(native) && (format[:delimiter] != native || value !~ /\.\d{3}$/)
326
+ value.gsub(/[^0-9\-#{format[:separator]}]/, '').gsub(format[:separator], native)
327
+ else
328
+ value
329
+ end
330
+ end
331
+
332
+ protected
333
+
334
+ def initialize_sort
335
+ if self.virtual?
336
+ # we don't automatically enable method sorting for virtual columns because it's slow, and we expect fewer complaints this way.
337
+ self.sort = false
338
+ else
339
+ if self.singular_association?
340
+ self.sort = {:method => "#{self.name}.to_s"}
341
+ elsif self.plural_association?
342
+ self.sort = {:method => "#{self.name}.join(',')"}
343
+ else
344
+ self.sort = {:sql => self.field}
345
+ end
346
+ end
347
+ end
348
+
349
+ def initialize_search_sql
350
+ self.search_sql = unless self.virtual?
351
+ if association.nil?
352
+ self.field
353
+ else
354
+ "#{association.associated_class.table_name}__#{association.associated_class.primary_key}".to_sym
355
+ end
356
+ end
357
+ end
358
+
359
+ # the table name from the ActiveRecord class
360
+ attr_reader :table
361
+
362
+ # the table.field name for this column, if applicable
363
+ def field
364
+ @field ||= "#{@table}__#{field_name}".to_sym
365
+ end
366
+
367
+ def estimate_weight
368
+ if singular_association?
369
+ 400
370
+ elsif plural_association?
371
+ 500
372
+ elsif [:created_at, :updated_at].include?(self.name)
373
+ 600
374
+ elsif [:name, :label, :title].include?(self.name)
375
+ 100
376
+ elsif required?
377
+ 200
378
+ else
379
+ 300
380
+ end
381
+ end
382
+
383
+ def parse_column_length
384
+ if @column and @column[:db_type] =~ /\((\d+)\)/
385
+ $1.to_i
386
+ end
387
+ end
388
+ end
389
+ end
@@ -0,0 +1,75 @@
1
+ module ActiveScaffold::DataStructures
2
+ class Columns
3
+ include Enumerable
4
+ include ActiveScaffold::Configurable
5
+
6
+ # The motivation for this collection is that this Columns data structure fills two roles: it provides
7
+ # the master list of all known columns, and it provides an inheritable list for all other actions (e.g.
8
+ # Create and Update and List). Well we actually want to *know* about as many columns as possible, so
9
+ # we don't want people actually removing columns from @set. But at the same time, we want to be able to
10
+ # manage which columns get inherited. Tada!
11
+ #
12
+ # This collection is referenced by other parts of ActiveScaffold and by methods within this DataStructure.
13
+ # IT IS NOT MEANT FOR PUBLIC USE (but if you know what you're doing, go ahead)
14
+ def _inheritable=(value)
15
+ @sorted = true
16
+ @_inheritable = value
17
+ end
18
+
19
+ # This accessor is used by ActionColumns to create new Column objects without adding them to this set
20
+ attr_reader :active_record_class
21
+
22
+ def initialize(active_record_class, *args)
23
+ @active_record_class = active_record_class
24
+ @_inheritable = []
25
+ @set = []
26
+
27
+ self.add *args
28
+ end
29
+
30
+ # the way to add columns to the set. this is primarily useful for virtual columns.
31
+ # note that this also makes columns inheritable
32
+ def add(*args)
33
+ args.flatten! # allow [] as a param
34
+ args = args.collect{ |a| a.to_sym }
35
+
36
+ # make the columns inheritable
37
+ @_inheritable.concat(args)
38
+ # then add columns to @set (unless they already exist)
39
+ args.each { |a| @set << ActiveScaffold::DataStructures::Column.new(a.to_sym, @active_record_class) unless find_by_name(a) }
40
+ end
41
+ alias_method :<<, :add
42
+
43
+ def exclude(*args)
44
+ # only remove columns from _inheritable. we never want to completely forget about a column.
45
+ args.each { |a| @_inheritable.delete a }
46
+ end
47
+
48
+ # returns an array of columns with the provided names
49
+ def find_by_names(*names)
50
+ @set.find_all { |column| names.include? column.name }
51
+ end
52
+
53
+ # returns the column of the given name.
54
+ def find_by_name(name)
55
+ # this works because of `def column.=='
56
+ column = @set.find { |c| c == name }
57
+ column
58
+ end
59
+ alias_method :[], :find_by_name
60
+
61
+ def each
62
+ @set.each {|i| yield i }
63
+ end
64
+
65
+ def _inheritable
66
+ if @sorted
67
+ @_inheritable
68
+ else
69
+ @_inheritable.sort do |a, b|
70
+ self[a] <=> self[b]
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveScaffold::DataStructures
2
+ # Wrapper for error strings so that they may be exported using to_xxx
3
+ class ErrorMessage
4
+ def initialize(error)
5
+ @error = error
6
+ end
7
+
8
+ def public_attributes
9
+ { :error => @error }
10
+ end
11
+
12
+ def to_xml
13
+ public_attributes.to_xml(:root => "errors")
14
+ end
15
+
16
+ def to_yaml
17
+ public_attributes.to_yaml
18
+ end
19
+
20
+ def to_s
21
+ @error
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,130 @@
1
+ module ActiveScaffold::DataStructures
2
+ class NestedInfo
3
+ def self.get(model, params)
4
+ nested_info = {}
5
+ begin
6
+ nested_info[:name] = (params[:association] || params[:named_scope]).to_sym
7
+ nested_info[:parent_scaffold] = "#{params[:parent_scaffold].to_s.camelize}Controller".constantize
8
+ nested_info[:parent_model] = nested_info[:parent_scaffold].active_scaffold_config.model
9
+ nested_info[:parent_id] = params[nested_info[:parent_model].name.foreign_key]
10
+ if nested_info[:parent_id]
11
+ unless params[:association].nil?
12
+ ActiveScaffold::DataStructures::NestedInfoAssociation.new(model, nested_info)
13
+ else
14
+ ActiveScaffold::DataStructures::NestedInfoScope.new(model, nested_info)
15
+ end
16
+ end
17
+ rescue ActiveScaffold::ControllerNotFound
18
+ nil
19
+ end
20
+ end
21
+
22
+ attr_accessor :association, :child_association, :parent_model, :parent_scaffold, :parent_id, :constrained_fields, :scope
23
+
24
+ def initialize(model, nested_info)
25
+ @parent_model = nested_info[:parent_model]
26
+ @parent_id = nested_info[:parent_id]
27
+ @parent_scaffold = nested_info[:parent_scaffold]
28
+ end
29
+
30
+ def to_params
31
+ {:parent_scaffold => parent_scaffold.controller_path}
32
+ end
33
+
34
+ def new_instance?
35
+ result = @new_instance.nil?
36
+ @new_instance = false
37
+ result
38
+ end
39
+
40
+ def parent_scope
41
+ parent_model.find(parent_id)
42
+ end
43
+
44
+ def habtm?
45
+ false
46
+ end
47
+
48
+ def belongs_to?
49
+ false
50
+ end
51
+
52
+ def has_one?
53
+ false
54
+ end
55
+
56
+ def sorted?
57
+ false
58
+ end
59
+ end
60
+
61
+ class NestedInfoAssociation < NestedInfo
62
+ def initialize(model, nested_info)
63
+ super(model, nested_info)
64
+ @association = parent_model.association_reflection(nested_info[:name])
65
+ iterate_model_associations(model)
66
+ end
67
+
68
+ def name
69
+ self.association[:name]
70
+ end
71
+
72
+ def habtm?
73
+ association[:type] == :many_to_many
74
+ end
75
+
76
+ def belongs_to?
77
+ association[:type] == :many_to_one
78
+ end
79
+
80
+ def has_one?
81
+ association[:type] == :one_to_one
82
+ end
83
+
84
+ def sorted?
85
+ association.has_key? :order
86
+ end
87
+
88
+ def default_sorting
89
+ association[:order]
90
+ end
91
+
92
+ def to_params
93
+ super.merge(:association => @association[:name], :assoc_id => parent_id)
94
+ end
95
+
96
+ protected
97
+
98
+ def iterate_model_associations(model)
99
+ @constrained_fields = []
100
+ @constrained_fields << association[:key] unless belongs_to?
101
+ model.association_reflections.each do |ass_name, ass_properties|
102
+ if !ass_properties[:type] == :many_to_one && association[:key] == ass_properties[:class_name].foreign_key
103
+ constrained_fields << ass_name
104
+ @child_association = ass_properties if ass_properties.associated_class == @parent_model
105
+ end
106
+ if association[:key] == ass_properties[:key]
107
+ # show columns for has_many and has_one child associationes
108
+ constrained_fields << ass_name if ass_properties[:type] == :many_to_one
109
+ @child_association = ass_properties if ass_properties.associated_class == @parent_model
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ class NestedInfoScope < NestedInfo
116
+ def initialize(model, nested_info)
117
+ super(model, nested_info)
118
+ @scope = nested_info[:name]
119
+ @constrained_fields = []
120
+ end
121
+
122
+ def to_params
123
+ super.merge(:named_scope => @scope)
124
+ end
125
+
126
+ def name
127
+ self.scope
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,57 @@
1
+ module ActiveScaffold::DataStructures
2
+ class Set
3
+ include Enumerable
4
+ include ActiveScaffold::Configurable
5
+
6
+ def initialize(*args)
7
+ @set = []
8
+ self.add *args
9
+ end
10
+
11
+ # the way to add items to the set.
12
+ def add(*args)
13
+ args.flatten! # allow [] as a param
14
+ args.each { |arg|
15
+ arg = arg.to_sym if arg.is_a? String
16
+ @set << arg unless @set.include? arg # avoid duplicates
17
+ }
18
+ end
19
+ alias_method :<<, :add
20
+
21
+ # the way to remove items from the set.
22
+ def exclude(*args)
23
+ args.flatten! # allow [] as a param
24
+ args.collect! { |a| a.to_sym } # symbolize the args
25
+ # check respond_to? :to_sym, ActionColumns doesn't respond to to_sym
26
+ @set.reject! { |c| c.respond_to? :to_sym and args.include? c.to_sym } # reject all items specified
27
+ end
28
+ alias_method :remove, :exclude
29
+
30
+ # returns an array of items with the provided names
31
+ def find_by_names(*names)
32
+ @set.find_all { |item| names.include? item }
33
+ end
34
+
35
+ # returns the item of the given name.
36
+ def find_by_name(name)
37
+ # this works because of `def item.=='
38
+ item = @set.find { |c| c == name }
39
+ item
40
+ end
41
+ alias_method :[], :find_by_name
42
+
43
+ def each
44
+ @set.each {|i| yield i }
45
+ end
46
+
47
+ # returns the number of items in the set
48
+ def length
49
+ @set.length
50
+ end
51
+
52
+ def empty?
53
+ @set.empty?
54
+ end
55
+
56
+ end
57
+ end