active_scaffold_san 3.0.18

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 (284) hide show
  1. data/.autotest +27 -0
  2. data/.document +5 -0
  3. data/CHANGELOG +179 -0
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +20 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README +69 -0
  8. data/Rakefile +53 -0
  9. data/active_scaffold_vho.gemspec +388 -0
  10. data/frontends/default/images/add.gif +0 -0
  11. data/frontends/default/images/arrow_down.gif +0 -0
  12. data/frontends/default/images/arrow_up.gif +0 -0
  13. data/frontends/default/images/close.gif +0 -0
  14. data/frontends/default/images/config.png +0 -0
  15. data/frontends/default/images/cross.png +0 -0
  16. data/frontends/default/images/gears.png +0 -0
  17. data/frontends/default/images/indicator-small.gif +0 -0
  18. data/frontends/default/images/indicator.gif +0 -0
  19. data/frontends/default/images/magnifier.png +0 -0
  20. data/frontends/default/javascripts/jquery/active_scaffold.js +1004 -0
  21. data/frontends/default/javascripts/jquery/jquery.editinplace.js +743 -0
  22. data/frontends/default/javascripts/prototype/active_scaffold.js +1003 -0
  23. data/frontends/default/javascripts/prototype/dhtml_history.js +867 -0
  24. data/frontends/default/javascripts/prototype/form_enhancements.js +117 -0
  25. data/frontends/default/javascripts/prototype/rico_corner.js +370 -0
  26. data/frontends/default/stylesheets/stylesheet-ie.css +35 -0
  27. data/frontends/default/stylesheets/stylesheet.css +973 -0
  28. data/frontends/default/views/_action_group.html.erb +20 -0
  29. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  30. data/frontends/default/views/_base_form.html.erb +51 -0
  31. data/frontends/default/views/_create_form.html.erb +8 -0
  32. data/frontends/default/views/_create_form_on_list.html.erb +6 -0
  33. data/frontends/default/views/_field_search.html.erb +32 -0
  34. data/frontends/default/views/_form.html.erb +24 -0
  35. data/frontends/default/views/_form_association.html.erb +19 -0
  36. data/frontends/default/views/_form_association_footer.html.erb +40 -0
  37. data/frontends/default/views/_form_attribute.html.erb +15 -0
  38. data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
  39. data/frontends/default/views/_form_messages.html.erb +5 -0
  40. data/frontends/default/views/_horizontal_subform.html.erb +29 -0
  41. data/frontends/default/views/_horizontal_subform_header.html.erb +10 -0
  42. data/frontends/default/views/_horizontal_subform_record.html.erb +37 -0
  43. data/frontends/default/views/_human_conditions.html.erb +1 -0
  44. data/frontends/default/views/_list.html.erb +18 -0
  45. data/frontends/default/views/_list_actions.html.erb +15 -0
  46. data/frontends/default/views/_list_calculations.html.erb +16 -0
  47. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  48. data/frontends/default/views/_list_header.html.erb +10 -0
  49. data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
  50. data/frontends/default/views/_list_messages.html.erb +32 -0
  51. data/frontends/default/views/_list_pagination.html.erb +11 -0
  52. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  53. data/frontends/default/views/_list_record.html.erb +14 -0
  54. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  55. data/frontends/default/views/_list_with_header.html.erb +32 -0
  56. data/frontends/default/views/_messages.html.erb +10 -0
  57. data/frontends/default/views/_render_field.js.rjs +10 -0
  58. data/frontends/default/views/_row.html.erb +12 -0
  59. data/frontends/default/views/_search.html.erb +34 -0
  60. data/frontends/default/views/_search_attribute.html.erb +10 -0
  61. data/frontends/default/views/_show.html.erb +8 -0
  62. data/frontends/default/views/_show_columns.html.erb +15 -0
  63. data/frontends/default/views/_update_actions.html.erb +9 -0
  64. data/frontends/default/views/_update_form.html.erb +6 -0
  65. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  66. data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
  67. data/frontends/default/views/action_confirmation.html.erb +13 -0
  68. data/frontends/default/views/add_existing.js.rjs +17 -0
  69. data/frontends/default/views/add_existing_form.html.erb +5 -0
  70. data/frontends/default/views/create.html.erb +5 -0
  71. data/frontends/default/views/delete.html.erb +13 -0
  72. data/frontends/default/views/destroy.js.rjs +23 -0
  73. data/frontends/default/views/edit_associated.js.rjs +11 -0
  74. data/frontends/default/views/field_search.html.erb +5 -0
  75. data/frontends/default/views/form_messages.js.rjs +1 -0
  76. data/frontends/default/views/list.html.erb +1 -0
  77. data/frontends/default/views/list.js.rjs +1 -0
  78. data/frontends/default/views/on_action_update.js.rjs +8 -0
  79. data/frontends/default/views/on_create.js.rjs +41 -0
  80. data/frontends/default/views/on_mark_all.js.rjs +4 -0
  81. data/frontends/default/views/on_update.js.rjs +28 -0
  82. data/frontends/default/views/search.html.erb +5 -0
  83. data/frontends/default/views/show.html.erb +5 -0
  84. data/frontends/default/views/update.html.erb +8 -0
  85. data/frontends/default/views/update_column.js.rjs +13 -0
  86. data/frontends/default/views/update_row.js.rjs +1 -0
  87. data/init.rb +8 -0
  88. data/lib/active_scaffold.rb +360 -0
  89. data/lib/active_scaffold/actions/common_search.rb +22 -0
  90. data/lib/active_scaffold/actions/core.rb +180 -0
  91. data/lib/active_scaffold/actions/create.rb +149 -0
  92. data/lib/active_scaffold/actions/delete.rb +75 -0
  93. data/lib/active_scaffold/actions/field_search.rb +82 -0
  94. data/lib/active_scaffold/actions/list.rb +184 -0
  95. data/lib/active_scaffold/actions/mark.rb +63 -0
  96. data/lib/active_scaffold/actions/nested.rb +250 -0
  97. data/lib/active_scaffold/actions/search.rb +47 -0
  98. data/lib/active_scaffold/actions/show.rb +61 -0
  99. data/lib/active_scaffold/actions/subform.rb +27 -0
  100. data/lib/active_scaffold/actions/update.rb +151 -0
  101. data/lib/active_scaffold/active_record_permissions.rb +134 -0
  102. data/lib/active_scaffold/attribute_params.rb +211 -0
  103. data/lib/active_scaffold/bridges/ancestry/bridge.rb +5 -0
  104. data/lib/active_scaffold/bridges/ancestry/lib/ancestry_bridge.rb +39 -0
  105. data/lib/active_scaffold/bridges/bridge.rb +59 -0
  106. data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +16 -0
  107. data/lib/active_scaffold/bridges/calendar_date_select/lib/as_cds_bridge.rb +83 -0
  108. data/lib/active_scaffold/bridges/cancan/bridge.rb +12 -0
  109. data/lib/active_scaffold/bridges/cancan/lib/cancan_bridge.rb +107 -0
  110. data/lib/active_scaffold/bridges/carrierwave/bridge.rb +9 -0
  111. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +33 -0
  112. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +12 -0
  113. data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +45 -0
  114. data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +17 -0
  115. data/lib/active_scaffold/bridges/date_picker/bridge.rb +24 -0
  116. data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +225 -0
  117. data/lib/active_scaffold/bridges/date_picker/public/javascripts/date_picker_bridge.js +22 -0
  118. data/lib/active_scaffold/bridges/file_column/bridge.rb +11 -0
  119. data/lib/active_scaffold/bridges/file_column/lib/as_file_column_bridge.rb +46 -0
  120. data/lib/active_scaffold/bridges/file_column/lib/file_column_helpers.rb +59 -0
  121. data/lib/active_scaffold/bridges/file_column/lib/form_ui.rb +37 -0
  122. data/lib/active_scaffold/bridges/file_column/lib/list_ui.rb +26 -0
  123. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  124. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  125. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  126. data/lib/active_scaffold/bridges/paperclip/bridge.rb +12 -0
  127. data/lib/active_scaffold/bridges/paperclip/lib/form_ui.rb +27 -0
  128. data/lib/active_scaffold/bridges/paperclip/lib/list_ui.rb +16 -0
  129. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge.rb +38 -0
  130. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge_helpers.rb +26 -0
  131. data/lib/active_scaffold/bridges/semantic_attributes/bridge.rb +5 -0
  132. data/lib/active_scaffold/bridges/semantic_attributes/lib/semantic_attributes_bridge.rb +20 -0
  133. data/lib/active_scaffold/bridges/shared/date_bridge.rb +209 -0
  134. data/lib/active_scaffold/bridges/tiny_mce/bridge.rb +5 -0
  135. data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +61 -0
  136. data/lib/active_scaffold/bridges/validation_reflection/bridge.rb +8 -0
  137. data/lib/active_scaffold/bridges/validation_reflection/lib/validation_reflection_bridge.rb +21 -0
  138. data/lib/active_scaffold/config/base.rb +62 -0
  139. data/lib/active_scaffold/config/core.rb +220 -0
  140. data/lib/active_scaffold/config/create.rb +51 -0
  141. data/lib/active_scaffold/config/delete.rb +34 -0
  142. data/lib/active_scaffold/config/field_search.rb +75 -0
  143. data/lib/active_scaffold/config/form.rb +47 -0
  144. data/lib/active_scaffold/config/list.rb +174 -0
  145. data/lib/active_scaffold/config/mark.rb +22 -0
  146. data/lib/active_scaffold/config/nested.rb +44 -0
  147. data/lib/active_scaffold/config/search.rb +69 -0
  148. data/lib/active_scaffold/config/show.rb +35 -0
  149. data/lib/active_scaffold/config/subform.rb +35 -0
  150. data/lib/active_scaffold/config/update.rb +46 -0
  151. data/lib/active_scaffold/configurable.rb +29 -0
  152. data/lib/active_scaffold/constraints.rb +184 -0
  153. data/lib/active_scaffold/data_structures/action_columns.rb +137 -0
  154. data/lib/active_scaffold/data_structures/action_link.rb +175 -0
  155. data/lib/active_scaffold/data_structures/action_links.rb +185 -0
  156. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  157. data/lib/active_scaffold/data_structures/column.rb +355 -0
  158. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  159. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  160. data/lib/active_scaffold/data_structures/nested_info.rb +123 -0
  161. data/lib/active_scaffold/data_structures/set.rb +62 -0
  162. data/lib/active_scaffold/data_structures/sorting.rb +168 -0
  163. data/lib/active_scaffold/extensions/action_controller_rendering.rb +20 -0
  164. data/lib/active_scaffold/extensions/action_view_rendering.rb +123 -0
  165. data/lib/active_scaffold/extensions/action_view_resolver.rb +7 -0
  166. data/lib/active_scaffold/extensions/active_association_reflection.rb +13 -0
  167. data/lib/active_scaffold/extensions/active_record_offset.rb +12 -0
  168. data/lib/active_scaffold/extensions/array.rb +7 -0
  169. data/lib/active_scaffold/extensions/localize.rb +10 -0
  170. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +12 -0
  171. data/lib/active_scaffold/extensions/nil_id_in_url_params.rb +7 -0
  172. data/lib/active_scaffold/extensions/paginator_extensions.rb +26 -0
  173. data/lib/active_scaffold/extensions/reverse_associations.rb +62 -0
  174. data/lib/active_scaffold/extensions/routing_mapper.rb +34 -0
  175. data/lib/active_scaffold/extensions/to_label.rb +8 -0
  176. data/lib/active_scaffold/extensions/unsaved_associated.rb +61 -0
  177. data/lib/active_scaffold/extensions/unsaved_record.rb +20 -0
  178. data/lib/active_scaffold/extensions/usa_state.rb +46 -0
  179. data/lib/active_scaffold/finder.rb +343 -0
  180. data/lib/active_scaffold/helpers/association_helpers.rb +40 -0
  181. data/lib/active_scaffold/helpers/controller_helpers.rb +87 -0
  182. data/lib/active_scaffold/helpers/country_helpers.rb +352 -0
  183. data/lib/active_scaffold/helpers/form_column_helpers.rb +350 -0
  184. data/lib/active_scaffold/helpers/human_condition_helpers.rb +59 -0
  185. data/lib/active_scaffold/helpers/id_helpers.rb +127 -0
  186. data/lib/active_scaffold/helpers/list_column_helpers.rb +361 -0
  187. data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
  188. data/lib/active_scaffold/helpers/search_column_helpers.rb +249 -0
  189. data/lib/active_scaffold/helpers/show_column_helpers.rb +46 -0
  190. data/lib/active_scaffold/helpers/view_helpers.rb +360 -0
  191. data/lib/active_scaffold/locale/de.rb +120 -0
  192. data/lib/active_scaffold/locale/en.rb +119 -0
  193. data/lib/active_scaffold/locale/es.yml +115 -0
  194. data/lib/active_scaffold/locale/fr.rb +122 -0
  195. data/lib/active_scaffold/locale/hu.yml +63 -0
  196. data/lib/active_scaffold/locale/ja.yml +64 -0
  197. data/lib/active_scaffold/locale/ru.yml +119 -0
  198. data/lib/active_scaffold/marked_model.rb +38 -0
  199. data/lib/active_scaffold/paginator.rb +136 -0
  200. data/lib/active_scaffold/responds_to_parent.rb +70 -0
  201. data/lib/active_scaffold/version.rb +9 -0
  202. data/lib/active_scaffold_assets.rb +45 -0
  203. data/lib/active_scaffold_env.rb +14 -0
  204. data/lib/active_scaffold_vho.rb +2 -0
  205. data/lib/generators/active_scaffold/USAGE +29 -0
  206. data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
  207. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  208. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +29 -0
  209. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  210. data/lib/generators/active_scaffold_controller/templates/helper.rb +2 -0
  211. data/lib/generators/active_scaffold_setup/USAGE +10 -0
  212. data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +61 -0
  213. data/public/blank.html +33 -0
  214. data/shoulda_macros/macros.rb +136 -0
  215. data/test/bridges/bridge_test.rb +47 -0
  216. data/test/config/base_test.rb +15 -0
  217. data/test/config/create_test.rb +55 -0
  218. data/test/config/list_test.rb +74 -0
  219. data/test/config/show_test.rb +43 -0
  220. data/test/config/update_test.rb +17 -0
  221. data/test/const_mocker.rb +36 -0
  222. data/test/data_structures/action_columns_test.rb +113 -0
  223. data/test/data_structures/action_link_test.rb +78 -0
  224. data/test/data_structures/action_links_test.rb +78 -0
  225. data/test/data_structures/actions_test.rb +25 -0
  226. data/test/data_structures/association_column_test.rb +42 -0
  227. data/test/data_structures/column_test.rb +185 -0
  228. data/test/data_structures/columns_test.rb +69 -0
  229. data/test/data_structures/error_message_test.rb +28 -0
  230. data/test/data_structures/set_test.rb +86 -0
  231. data/test/data_structures/sorting_test.rb +126 -0
  232. data/test/data_structures/standard_column_test.rb +24 -0
  233. data/test/data_structures/virtual_column_test.rb +23 -0
  234. data/test/extensions/active_record_test.rb +45 -0
  235. data/test/extensions/array_test.rb +12 -0
  236. data/test/helpers/form_column_helpers_test.rb +31 -0
  237. data/test/helpers/list_column_helpers_test.rb +31 -0
  238. data/test/helpers/pagination_helpers_test.rb +55 -0
  239. data/test/misc/active_record_permissions_test.rb +154 -0
  240. data/test/misc/attribute_params_test.rb +110 -0
  241. data/test/misc/configurable_test.rb +96 -0
  242. data/test/misc/constraints_test.rb +193 -0
  243. data/test/misc/finder_test.rb +93 -0
  244. data/test/misc/lang_test.rb +12 -0
  245. data/test/mock_app/.gitignore +2 -0
  246. data/test/mock_app/app/controllers/application_controller.rb +10 -0
  247. data/test/mock_app/app/helpers/application_helper.rb +3 -0
  248. data/test/mock_app/config/boot.rb +110 -0
  249. data/test/mock_app/config/database.yml +16 -0
  250. data/test/mock_app/config/environment.rb +43 -0
  251. data/test/mock_app/config/environments/development.rb +17 -0
  252. data/test/mock_app/config/environments/production.rb +28 -0
  253. data/test/mock_app/config/environments/test.rb +28 -0
  254. data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
  255. data/test/mock_app/config/initializers/inflections.rb +10 -0
  256. data/test/mock_app/config/initializers/mime_types.rb +5 -0
  257. data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  258. data/test/mock_app/config/initializers/session_store.rb +15 -0
  259. data/test/mock_app/config/locales/en.yml +5 -0
  260. data/test/mock_app/config/routes.rb +43 -0
  261. data/test/mock_app/db/test.sqlite3 +1 -0
  262. data/test/mock_app/public/blank.html +33 -0
  263. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
  264. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  265. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  266. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  267. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  268. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  269. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  270. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  271. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  272. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
  273. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
  274. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
  275. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
  276. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
  277. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
  278. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
  279. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +842 -0
  280. data/test/model_stub.rb +55 -0
  281. data/test/run_all.rb +8 -0
  282. data/test/test_helper.rb +39 -0
  283. data/uninstall.rb +13 -0
  284. metadata +497 -0
@@ -0,0 +1,352 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ module CountryHelpers
4
+ # Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags.
5
+ def country_select(object, method, priority_countries = nil, options = {}, html_options = {})
6
+ ActionView::Helpers::InstanceTag.new(object, method, self, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options)
7
+ end
8
+
9
+ def usa_state_select(object, method, priority_states = nil, options = {}, html_options = {})
10
+ ActionView::Helpers::InstanceTag.new(object, method, self, options.delete(:object)).to_usa_state_select_tag(priority_states, options, html_options)
11
+ end
12
+
13
+ # Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to
14
+ # have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so
15
+ # that they will be listed above the rest of the (long) list.
16
+ #
17
+ # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
18
+ def country_options_for_select(selected = nil, priority_countries = nil)
19
+ if priority_countries
20
+ country_options = options_for_select(priority_countries.collect {|country| [I18n.t("countries.#{country}", :default => country.to_s.titleize), country.to_s]} + [['-------------', '']], :selected => selected, :disabled => '')
21
+ else
22
+ country_options = ""
23
+ end
24
+
25
+ return country_options + options_for_select(COUNTRIES.collect {|country| [I18n.t("countries.#{country}", :default => country.to_s.titleize), country.to_s]}, :selected => selected)
26
+ end
27
+
28
+ # Returns a string of option tags for the states in the United States. Supply a state name as +selected to
29
+ # have it marked as the selected option tag. Included also is the option to set a couple of +priority_states+
30
+ # in case you want to highligh a local area
31
+ # NOTE: Only the option tags are returned from this method, wrap it in a <select>
32
+ def usa_state_options_for_select(selected = nil, priority_states = nil)
33
+ if priority_states
34
+ state_options = options_for_select(priority_states + [['-------------', '']], :selected => selected, :disabled => '')
35
+ else
36
+ state_options = ""
37
+ end
38
+
39
+ if priority_states && priority_states.include?(selected)
40
+ state_options += options_for_select(USASTATES - priority_states, :selected => selected)
41
+ else
42
+ state_options += options_for_select(USASTATES, :selected => selected)
43
+ end
44
+
45
+ return state_options
46
+ end
47
+ # All the countries included in the country_options output.
48
+ COUNTRIES = [
49
+ :afghanistan,
50
+ :aland_islands,
51
+ :albania,
52
+ :algeria,
53
+ :american_samoa,
54
+ :andorra,
55
+ :angola,
56
+ :anguilla,
57
+ :antarctica,
58
+ :antigua_and_barbuda,
59
+ :argentina,
60
+ :armenia,
61
+ :aruba,
62
+ :australia,
63
+ :austria,
64
+ :azerbaijan,
65
+ :bahamas,
66
+ :bahrain,
67
+ :bangladesh,
68
+ :barbados,
69
+ :belarus,
70
+ :belgium,
71
+ :belize,
72
+ :benin,
73
+ :bermuda,
74
+ :bhutan,
75
+ :bolivia,
76
+ :bosnia_and_herzegowina,
77
+ :botswana,
78
+ :bouvet_island,
79
+ :brazil,
80
+ :british_indian_ocean_territory,
81
+ :brunei_darussalam,
82
+ :bulgaria,
83
+ :burkina_faso,
84
+ :burundi,
85
+ :cambodia,
86
+ :cameroon,
87
+ :canada,
88
+ :cape_verde,
89
+ :cayman_islands,
90
+ :central_african_republic,
91
+ :chad,
92
+ :chile,
93
+ :china,
94
+ :christmas_island,
95
+ :cocos_keeling_islands,
96
+ :colombia,
97
+ :comoros,
98
+ :congo,
99
+ :congo_the_democratic_republic_of_the,
100
+ :cook_islands,
101
+ :costa_rica,
102
+ :cote_divoire,
103
+ :croatia,
104
+ :cuba,
105
+ :cyprus,
106
+ :czech_republic,
107
+ :denmark,
108
+ :djibouti,
109
+ :dominica,
110
+ :dominican_republic,
111
+ :ecuador,
112
+ :egypt,
113
+ :el_salvador,
114
+ :equatorial_guinea,
115
+ :eritrea,
116
+ :estonia,
117
+ :ethiopia,
118
+ :falkland_islands_malvinas,
119
+ :faroe_islands,
120
+ :fiji,
121
+ :finland,
122
+ :france,
123
+ :french_guiana,
124
+ :french_polynesia,
125
+ :french_southern_territories,
126
+ :gabon,
127
+ :gambia,
128
+ :georgia,
129
+ :germany,
130
+ :ghana,
131
+ :gibraltar,
132
+ :greece,
133
+ :greenland,
134
+ :grenada,
135
+ :guadeloupe,
136
+ :guam,
137
+ :guatemala,
138
+ :guernsey,
139
+ :guinea,
140
+ :guinea_bissau,
141
+ :guyana,
142
+ :haiti,
143
+ :heard_and_mcdonald_islands,
144
+ :holy_see_vatican_city_state,
145
+ :honduras,
146
+ :hong_kong,
147
+ :hungary,
148
+ :iceland,
149
+ :india,
150
+ :indonesia,
151
+ :iran_islamic_republic_of,
152
+ :iraq,
153
+ :ireland,
154
+ :isle_of_man,
155
+ :israel,
156
+ :italy,
157
+ :jamaica,
158
+ :japan,
159
+ :jersey,
160
+ :jordan,
161
+ :kazakhstan,
162
+ :kenya,
163
+ :kiribati,
164
+ :korea_democratic_peoples_republic_of,
165
+ :korea_republic_of,
166
+ :kuwait,
167
+ :kyrgyzstan,
168
+ :lao_peoples_democratic_republic,
169
+ :latvia,
170
+ :lebanon,
171
+ :lesotho,
172
+ :liberia,
173
+ :libyan_arab_jamahiriya,
174
+ :liechtenstein,
175
+ :lithuania,
176
+ :luxembourg,
177
+ :macao,
178
+ :macedonia_the_former_yugoslav_republic_of,
179
+ :madagascar,
180
+ :malawi,
181
+ :malaysia,
182
+ :maldives,
183
+ :mali,
184
+ :malta,
185
+ :marshall_islands,
186
+ :martinique,
187
+ :mauritania,
188
+ :mauritius,
189
+ :mayotte,
190
+ :mexico,
191
+ :micronesia_federated_states_of,
192
+ :moldova_republic_of,
193
+ :monaco,
194
+ :mongolia,
195
+ :montenegro,
196
+ :montserrat,
197
+ :morocco,
198
+ :mozambique,
199
+ :myanmar,
200
+ :namibia,
201
+ :nauru,
202
+ :nepal,
203
+ :netherlands,
204
+ :netherlands_antilles,
205
+ :new_caledonia,
206
+ :new_zealand,
207
+ :nicaragua,
208
+ :niger,
209
+ :nigeria,
210
+ :niue,
211
+ :norfolk_island,
212
+ :northern_mariana_islands,
213
+ :norway,
214
+ :oman,
215
+ :pakistan,
216
+ :palau,
217
+ :palestinian_territory_occupied,
218
+ :panama,
219
+ :papua_new_guinea,
220
+ :paraguay,
221
+ :peru,
222
+ :philippines,
223
+ :pitcairn,
224
+ :poland,
225
+ :portugal,
226
+ :puerto_rico,
227
+ :qatar,
228
+ :reunion,
229
+ :romania,
230
+ :russian_federation,
231
+ :rwanda,
232
+ :saint_barthelemy,
233
+ :saint_helena,
234
+ :saint_kitts_and_nevis,
235
+ :saint_lucia,
236
+ :saint_pierre_and_miquelon,
237
+ :saint_vincent_and_the_grenadines,
238
+ :samoa,
239
+ :san_marino,
240
+ :sao_tome_and_principe,
241
+ :saudi_arabia,
242
+ :senegal,
243
+ :serbia,
244
+ :seychelles,
245
+ :sierra_leone,
246
+ :singapore,
247
+ :slovakia,
248
+ :slovenia,
249
+ :solomon_islands,
250
+ :somalia,
251
+ :south_africa,
252
+ :south_georgia_and_the_south_sandwich_islands,
253
+ :spain,
254
+ :sri_lanka,
255
+ :sudan,
256
+ :suriname,
257
+ :svalbard_and_jan_mayen,
258
+ :swaziland,
259
+ :sweden,
260
+ :switzerland,
261
+ :syrian_arab_republic,
262
+ :taiwan_province_of_china,
263
+ :tajikistan,
264
+ :tanzania_united_republic_of,
265
+ :thailand,
266
+ :timor_leste,
267
+ :togo,
268
+ :tokelau,
269
+ :tonga,
270
+ :trinidad_and_tobago,
271
+ :tunisia,
272
+ :turkey,
273
+ :turkmenistan,
274
+ :turks_and_caicos_islands,
275
+ :tuvalu,
276
+ :uganda,
277
+ :ukraine,
278
+ :united_arab_emirates,
279
+ :united_kingdom,
280
+ :united_states,
281
+ :united_states_minor_outlying_islands,
282
+ :uruguay,
283
+ :uzbekistan,
284
+ :vanuatu,
285
+ :venezuela,
286
+ :viet_nam,
287
+ :virgin_islands_british,
288
+ :virgin_islands_us,
289
+ :wallis_and_futuna,
290
+ :western_sahara,
291
+ :yemen,
292
+ :zambia,
293
+ :zimbabwe] unless const_defined?("COUNTRIES")
294
+
295
+
296
+ USASTATES = [["Alabama", "AL"], ["Alaska", "AK"], ["Arizona", "AZ"], ["Arkansas", "AR"], ["California", "CA"], ["Colorado", "CO"], ["Connecticut", "CT"], ["Delaware", "DE"], ["District of Columbia", "DC"], ["Florida", "FL"], ["Georgia", "GA"], ["Hawaii", "HI"], ["Idaho", "ID"], ["Illinois", "IL"], ["Indiana", "IN"], ["Iowa", "IA"], ["Kansas", "KS"], ["Kentucky", "KY"], ["Louisiana", "LA"], ["Maine", "ME"], ["Maryland", "MD"], ["Massachusetts", "MA"], ["Michigan", "MI"], ["Minnesota", "MN"], ["Mississippi", "MS"], ["Missouri", "MO"], ["Montana", "MT"], ["Nebraska", "NE"], ["Nevada", "NV"], ["New Hampshire", "NH"], ["New Jersey", "NJ"], ["New Mexico", "NM"], ["New York", "NY"], ["North Carolina", "NC"], ["North Dakota", "ND"], ["Ohio", "OH"], ["Oklahoma", "OK"], ["Oregon", "OR"], ["Pennsylvania", "PA"], ["Rhode Island", "RI"], ["South Carolina", "SC"], ["South Dakota", "SD"], ["Tennessee", "TN"], ["Texas", "TX"], ["Utah", "UT"], ["Vermont", "VT"], ["Virginia", "VA"], ["Washington", "WA"], ["Wisconsin", "WI"], ["West Virginia", "WV"], ["Wyoming", "WY"]] unless const_defined?("USASTATES")
297
+
298
+ class ActionView::Helpers::InstanceTag #:nodoc:
299
+ include CountryHelpers
300
+
301
+ def to_country_select_tag(priority_countries, options, html_options)
302
+ html_options = html_options.stringify_keys
303
+ add_default_name_and_id(html_options)
304
+ value = value(object)
305
+ selected_value = options.has_key?(:selected) ? options[:selected] : value
306
+ content_tag("select",
307
+ add_options(
308
+ country_options_for_select(selected_value, priority_countries),
309
+ options, selected_value
310
+ ), html_options
311
+ )
312
+ end
313
+
314
+ def to_usa_state_select_tag(priority_states, options, html_options)
315
+ html_options = html_options.stringify_keys
316
+ add_default_name_and_id(html_options)
317
+ value = value(object)
318
+ selected_value = options.has_key?(:selected) ? options[:selected] : value
319
+ content_tag("select", add_options(usa_state_options_for_select(selected_value, priority_states), options, selected_value), html_options)
320
+ end
321
+ end
322
+ end
323
+
324
+ module FormColumnHelpers
325
+ def active_scaffold_input_country(column, options)
326
+ select_options = {:prompt => as_(:_select_)}
327
+ select_options.merge!(options)
328
+ options.reverse_merge!(column.options).except!(:prompt, :priority)
329
+ options[:name] += '[]' if options[:multiple]
330
+ country_select(:record, column.name, column.options[:priority] || [:united_states], select_options, options)
331
+ end
332
+
333
+ def active_scaffold_input_usa_state(column, options)
334
+ select_options = {:prompt => as_(:_select_)}
335
+ select_options.merge!(options)
336
+ options.reverse_merge!(column.options).except!(:prompt, :priority)
337
+ options[:name] += '[]' if options[:multiple]
338
+ usa_state_select(:record, column.name, column.options[:priority], select_options, options)
339
+ end
340
+ end
341
+
342
+ module SearchColumnHelpers
343
+ def active_scaffold_search_country(column, options)
344
+ active_scaffold_input_country(column, options.merge!(:selected => options.delete(:value)))
345
+ end
346
+
347
+ def active_scaffold_search_usa_state(column, options)
348
+ active_scaffold_input_usa_state(column, options.merge!(:selected => options.delete(:value)))
349
+ end
350
+ end
351
+ end
352
+ end
@@ -0,0 +1,350 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ # Helpers that assist with the rendering of a Form Column
4
+ module FormColumnHelpers
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_input_for(column, scope = nil, options = {})
8
+ options = active_scaffold_input_options(column, scope, options)
9
+ options = update_columns_options(column, scope, options)
10
+ active_scaffold_render_input(column, options)
11
+ end
12
+
13
+ alias form_column active_scaffold_input_for
14
+
15
+ def active_scaffold_render_input(column, options)
16
+ begin
17
+ # first, check if the dev has created an override for this specific field
18
+ if override_form_field?(column)
19
+ send(override_form_field(column), @record, options)
20
+ # second, check if the dev has specified a valid form_ui for this column
21
+ elsif column.form_ui and override_input?(column.form_ui)
22
+ send(override_input(column.form_ui), column, options)
23
+ # fallback: we get to make the decision
24
+ else
25
+ if column.association
26
+ if column.form_ui.nil?
27
+ # its an association and nothing is specified, we will assume form_ui :select
28
+ active_scaffold_input_select(column, options)
29
+ else
30
+ # if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
31
+ raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'"
32
+ end
33
+ elsif column.virtual?
34
+ active_scaffold_input_virtual(column, options)
35
+
36
+ else # regular model attribute column
37
+ # if we (or someone else) have created a custom render option for the column type, use that
38
+ if override_input?(column.column.type)
39
+ send(override_input(column.column.type), column, options)
40
+ # final ultimate fallback: use rails' generic input method
41
+ else
42
+ # for textual fields we pass different options
43
+ text_types = [:text, :string, :integer, :float, :decimal, :date, :time, :datetime]
44
+ options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
45
+ if column.column.type == :string && options[:maxlength].blank?
46
+ options[:maxlength] = column.column.limit
47
+ options[:size] ||= ActionView::Helpers::InstanceTag::DEFAULT_FIELD_OPTIONS["size"]
48
+ end
49
+ options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
50
+ options[:value] = format_number_value(@record.send(column.name), column.options) if column.column.number?
51
+ text_field(:record, column.name, options.merge(column.options))
52
+ end
53
+ end
54
+ end
55
+ rescue Exception => e
56
+ logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
57
+ raise e
58
+ end
59
+ end
60
+
61
+ # the standard active scaffold options used for textual inputs
62
+ def active_scaffold_input_text_options(options = {})
63
+ options[:autocomplete] = 'off'
64
+ options[:class] = "#{options[:class]} text-input".strip
65
+ options
66
+ end
67
+
68
+ # the standard active scaffold options used for class, name and scope
69
+ def active_scaffold_input_options(column, scope = nil, options = {})
70
+ name = scope ? "record#{scope}[#{column.name}]" : "record[#{column.name}]"
71
+
72
+ # Fix for keeping unique IDs in subform
73
+ id_control = "record_#{column.name}_#{[params[:eid], params[:id]].compact.join '_'}"
74
+ id_control += scope.gsub(/(\[|\])/, '_').gsub('__', '_').gsub(/_$/, '') if scope
75
+
76
+ { :name => name, :class => "#{column.name}-input", :id => id_control}.merge(options)
77
+ end
78
+
79
+ def update_columns_options(column, scope, options)
80
+ if column.update_columns
81
+ form_action = params[:action] == 'edit' ? :update : :create
82
+ url_params = {:action => 'render_field', :id => params[:id], :column => column.name, :update_columns => column.update_columns}
83
+ url_params[:eid] = params[:eid] if params[:eid]
84
+ url_params[:controller] = controller.class.active_scaffold_controller_for(@record.class).controller_path if scope
85
+ url_params[:scope] = params[:scope] if scope
86
+
87
+ options[:class] = "#{options[:class]} update_form".strip
88
+ options['data-update_url'] = url_for(url_params)
89
+ end
90
+ options
91
+ end
92
+
93
+ ##
94
+ ## Form input methods
95
+ ##
96
+
97
+ def active_scaffold_input_singular_association(column, html_options)
98
+ associated = @record.send(column.association.name)
99
+
100
+ select_options = options_for_association(column.association)
101
+ select_options.unshift([ associated.to_label, associated.id ]) unless associated.nil? or select_options.find {|label, id| id == associated.id}
102
+
103
+ selected = associated.nil? ? nil : associated.id
104
+ method = column.name
105
+ #html_options[:name] += '[id]'
106
+ options = {:selected => selected, :include_blank => as_(:_select_)}
107
+
108
+ html_options.update(column.options[:html_options] || {})
109
+ options.update(column.options)
110
+ html_options[:name] = "#{html_options[:name]}[]" if (html_options[:multiple] == true && !html_options[:name].to_s.ends_with?("[]"))
111
+ select(:record, method, select_options.uniq, options, html_options)
112
+ end
113
+
114
+ def active_scaffold_input_plural_association(column, options)
115
+ associated_options = @record.send(column.association.name).collect {|r| [r.to_label, r.id]}
116
+ select_options = associated_options | options_for_association(column.association)
117
+ return content_tag(:span, as_(:no_options), :id => options[:id]) if select_options.empty?
118
+
119
+ active_scaffold_checkbox_list(column, select_options, associated_options.collect {|a| a[1]}, options)
120
+ end
121
+
122
+ def active_scaffold_checkbox_list(column, select_options, associated_ids, options)
123
+ html = "<ul class=\"checkbox-list\" id=\"#{options[:id]}\">"
124
+
125
+ select_options.each_with_index do |option, i|
126
+ label, id = option
127
+ this_id = "#{options[:id]}_#{i}_id"
128
+ html << content_tag(:li) do
129
+ check_box_tag("#{options[:name]}[]", id, associated_ids.include?(id), :id => this_id) <<
130
+ content_tag(:label, h(label), :for => this_id)
131
+ end
132
+ end
133
+ html << '</ul>'
134
+ html << javascript_tag("new DraggableLists('#{options[:id]}')") if column.options[:draggable_lists]
135
+ html.html_safe
136
+ end
137
+
138
+ def active_scaffold_translated_option(column, text, value = nil)
139
+ value = text if value.nil?
140
+ [(text.is_a?(Symbol) ? column.active_record_class.human_attribute_name(text) : text), value]
141
+ end
142
+
143
+ def active_scaffold_input_enum(column, html_options)
144
+ options = { :selected => @record.send(column.name) }
145
+ options_for_select = column.options[:options].collect do |text, value|
146
+ active_scaffold_translated_option(column, text, value)
147
+ end
148
+ html_options.update(column.options[:html_options] || {})
149
+ options.update(column.options)
150
+ select(:record, column.name, options_for_select, options, html_options)
151
+ end
152
+
153
+ def active_scaffold_input_select(column, html_options)
154
+ if column.singular_association?
155
+ active_scaffold_input_singular_association(column, html_options)
156
+ elsif column.plural_association?
157
+ active_scaffold_input_plural_association(column, html_options)
158
+ else
159
+ active_scaffold_input_enum(column, html_options)
160
+ end
161
+ end
162
+
163
+ def active_scaffold_input_radio(column, html_options)
164
+ html_options.update(column.options[:html_options] || {})
165
+ column.options[:options].inject('') do |html, (text, value)|
166
+ text, value = active_scaffold_translated_option(column, text, value)
167
+ html << content_tag(:label, radio_button(:record, column.name, value, html_options.merge(:id => html_options[:id] + '-' + value.to_s)) + text)
168
+ end.html_safe
169
+ end
170
+
171
+ # requires RecordSelect plugin to be installed and configured.
172
+ # ... maybe this should be provided in a bridge?
173
+ def active_scaffold_input_record_select(column, options)
174
+ if column.singular_association?
175
+ multiple = false
176
+ multiple = column.options[:html_options][:multiple] if column.options[:html_options] && column.options[:html_options][:multiple]
177
+ active_scaffold_record_select(column, options, @record.send(column.name), multiple)
178
+ elsif column.plural_association?
179
+ active_scaffold_record_select(column, options, @record.send(column.name), true)
180
+ end
181
+ end
182
+
183
+ def active_scaffold_record_select(column, options, value, multiple)
184
+ unless column.association
185
+ raise ArgumentError, "record_select can only work against associations (and #{column.name} is not). A common mistake is to specify the foreign key field (like :user_id), instead of the association (:user)."
186
+ end
187
+ remote_controller = active_scaffold_controller_for(column.association.klass).controller_path
188
+
189
+ # if the opposite association is a :belongs_to (in that case association in this class must be has_one or has_many)
190
+ # then only show records that have not been associated yet
191
+ if [:has_one, :has_many].include?(column.association.macro)
192
+ params.merge!({column.association.primary_key_name => ''})
193
+ end
194
+
195
+ record_select_options = {:controller => remote_controller, :id => options[:id]}
196
+ record_select_options.merge!(active_scaffold_input_text_options)
197
+ record_select_options.merge!(column.options)
198
+
199
+ if multiple
200
+ record_multi_select_field(options[:name], value || [], record_select_options)
201
+ else
202
+ record_select_field(options[:name], value || column.association.klass.new, record_select_options)
203
+ end
204
+ end
205
+
206
+ def active_scaffold_input_checkbox(column, options)
207
+ check_box(:record, column.name, options)
208
+ end
209
+
210
+ def active_scaffold_input_password(column, options)
211
+ options = active_scaffold_input_text_options(options)
212
+ password_field :record, column.name, options.merge(column.options)
213
+ end
214
+
215
+ def active_scaffold_input_textarea(column, options)
216
+ text_area(:record, column.name, options.merge(:cols => column.options[:cols], :rows => column.options[:rows], :size => column.options[:size]))
217
+ end
218
+
219
+ def active_scaffold_input_virtual(column, options)
220
+ options = active_scaffold_input_text_options(options)
221
+ text_field :record, column.name, options.merge(column.options)
222
+ end
223
+
224
+ #
225
+ # Column.type-based inputs
226
+ #
227
+
228
+ def active_scaffold_input_boolean(column, options)
229
+ select_options = []
230
+ select_options << [as_(:_select_), nil] if !column.virtual? && column.column.null
231
+ select_options << [as_(:true), true]
232
+ select_options << [as_(:false), false]
233
+
234
+ select_tag(options[:name], options_for_select(select_options, @record.send(column.name)), options)
235
+ end
236
+
237
+ def onsubmit
238
+ end
239
+
240
+ ##
241
+ ## Form column override signatures
242
+ ##
243
+
244
+ # add functionality for overriding subform partials from association class path
245
+ def override_subform_partial?(column, subform_partial)
246
+ path, partial_name = partial_pieces(override_subform_partial(column, subform_partial))
247
+ template_exists?(partial_name, path, true)
248
+ end
249
+
250
+ def override_subform_partial(column, subform_partial)
251
+ File.join(active_scaffold_controller_for(column.association.klass).controller_path, subform_partial) if column_renders_as(column) == :subform
252
+ end
253
+
254
+ def override_form_field_partial?(column)
255
+ path, partial_name = partial_pieces(override_form_field_partial(column))
256
+ template_exists?(partial_name, path, true)
257
+ end
258
+
259
+ # the naming convention for overriding form fields with partials
260
+ def override_form_field_partial(column)
261
+ "#{column.name}_form_column"
262
+ end
263
+
264
+ def override_form_field?(column)
265
+ respond_to?(override_form_field(column))
266
+ end
267
+
268
+ # the naming convention for overriding form fields with helpers
269
+ def override_form_field(column)
270
+ "#{column.name}_form_column"
271
+ end
272
+
273
+ def override_input?(form_ui)
274
+ respond_to?(override_input(form_ui))
275
+ end
276
+
277
+ # the naming convention for overriding form input types with helpers
278
+ def override_input(form_ui)
279
+ "active_scaffold_input_#{form_ui}"
280
+ end
281
+
282
+ def form_partial_for_column(column, renders_as = nil)
283
+ renders_as ||= column_renders_as(column)
284
+ if override_form_field_partial?(column)
285
+ override_form_field_partial(column)
286
+ elsif renders_as == :field or override_form_field?(column)
287
+ "form_attribute"
288
+ elsif renders_as == :subform
289
+ "form_association"
290
+ elsif renders_as == :hidden
291
+ "form_hidden_attribute"
292
+ end
293
+ end
294
+
295
+ def subform_partial_for_column(column)
296
+ subform_partial = "#{active_scaffold_config_for(column.association.klass).subform.layout}_subform"
297
+ if override_subform_partial?(column, subform_partial)
298
+ override_subform_partial(column, subform_partial)
299
+ else
300
+ subform_partial
301
+ end
302
+ end
303
+
304
+ ##
305
+ ## Macro-level rendering decisions for columns
306
+ ##
307
+
308
+ def column_renders_as(column)
309
+ if column.is_a? ActiveScaffold::DataStructures::ActionColumns
310
+ return :subsection
311
+ elsif column.active_record_class.locking_column.to_s == column.name.to_s or column.form_ui == :hidden
312
+ return :hidden
313
+ elsif column.association.nil? or column.form_ui or !active_scaffold_config_for(column.association.klass).actions.include?(:subform)
314
+ return :field
315
+ else
316
+ return :subform
317
+ end
318
+ end
319
+
320
+ def column_scope(column)
321
+ if column.plural_association?
322
+ "[#{column.name}][#{@record.id || generate_temporary_id}]"
323
+ else
324
+ "[#{column.name}]"
325
+ end
326
+ end
327
+
328
+ def active_scaffold_add_existing_input(options)
329
+ if ActiveScaffold.js_framework == :prototype && controller.respond_to?(:record_select_config)
330
+ remote_controller = active_scaffold_controller_for(record_select_config.model).controller_path
331
+ options.merge!(:controller => remote_controller)
332
+ options.merge!(active_scaffold_input_text_options)
333
+ record_select_field(options[:name], @record, options)
334
+ else
335
+ select_options = options_for_select(options_for_association(nested.association)) #unless column.through_association?
336
+ select_options ||= options_for_select(active_scaffold_config.model.all.collect {|c| [h(c.to_label), c.id]})
337
+ select_tag 'associated_id', ('<option value="">' + as_(:_select_) + '</option>' + select_options).html_safe unless select_options.empty?
338
+ end
339
+ end
340
+
341
+ def active_scaffold_add_existing_label
342
+ if controller.respond_to?(:record_select_config)
343
+ record_select_config.model.model_name.human
344
+ else
345
+ active_scaffold_config.model.model_name.human
346
+ end
347
+ end
348
+ end
349
+ end
350
+ end