actionpack 2.2.3 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -6,9 +6,7 @@ module ActionView
6
6
  module Helpers
7
7
  # Provides a number of methods for turning different kinds of containers into a set of option tags.
8
8
  # == Options
9
- # The <tt>collection_select</tt>, <tt>country_select</tt>, <tt>select</tt>,
10
- # and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter,
11
- # a hash.
9
+ # The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
12
10
  #
13
11
  # * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
14
12
  #
@@ -28,7 +26,7 @@ module ActionView
28
26
  #
29
27
  # Example with @post.person_id => 2:
30
28
  #
31
- # select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, {:include_blank => 'None'})
29
+ # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {:include_blank => 'None'})
32
30
  #
33
31
  # could become:
34
32
  #
@@ -43,7 +41,7 @@ module ActionView
43
41
  #
44
42
  # Example:
45
43
  #
46
- # select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, {:prompt => 'Select Person'})
44
+ # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {:prompt => 'Select Person'})
47
45
  #
48
46
  # could become:
49
47
  #
@@ -68,6 +66,36 @@ module ActionView
68
66
  # <option value="rock">rock</option>
69
67
  # <option value="country">country</option>
70
68
  # </select>
69
+ #
70
+ # * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
71
+ #
72
+ # Example:
73
+ #
74
+ # select("post", "category", Post::CATEGORIES, {:disabled => 'restricted'})
75
+ #
76
+ # could become:
77
+ #
78
+ # <select name="post[category]">
79
+ # <option></option>
80
+ # <option>joke</option>
81
+ # <option>poem</option>
82
+ # <option disabled="disabled">restricted</option>
83
+ # </select>
84
+ #
85
+ # When used with the <tt>collection_select</tt> helper, <tt>:disabled</tt> can also be a Proc that identifies those options that should be disabled.
86
+ #
87
+ # Example:
88
+ #
89
+ # collection_select(:post, :category_id, Category.all, :id, :name, {:disabled => lambda{|category| category.archived? }})
90
+ #
91
+ # If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
92
+ # <select name="post[category_id]">
93
+ # <option value="1" disabled="disabled">2008 stuff</option>
94
+ # <option value="2" disabled="disabled">Christmas</option>
95
+ # <option value="3">Jokes</option>
96
+ # <option value="4">Poems</option>
97
+ # </select>
98
+ #
71
99
  module FormOptionsHelper
72
100
  include ERB::Util
73
101
 
@@ -76,7 +104,7 @@ module ActionView
76
104
  # See options_for_select for the required format of the choices parameter.
77
105
  #
78
106
  # Example with @post.person_id => 1:
79
- # select("post", "person_id", Person.find(:all).collect {|p| [ p.name, p.id ] }, { :include_blank => true })
107
+ # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, { :include_blank => true })
80
108
  #
81
109
  # could become:
82
110
  #
@@ -94,7 +122,8 @@ module ActionView
94
122
  # In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.
95
123
  #
96
124
  # By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
97
- # or <tt>:selected => nil</tt> to leave all options unselected.
125
+ # or <tt>:selected => nil</tt> to leave all options unselected. Similarly, you can specify values to be disabled in the option
126
+ # tags by specifying the <tt>:disabled</tt> option. This can either be a single value or an array of values to be disabled.
98
127
  def select(object, method, choices, options = {}, html_options = {})
99
128
  InstanceTag.new(object, method, self, options.delete(:object)).to_select_tag(choices, options, html_options)
100
129
  end
@@ -120,7 +149,7 @@ module ActionView
120
149
  # end
121
150
  #
122
151
  # Sample usage (selecting the associated Author for an instance of Post, <tt>@post</tt>):
123
- # collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true})
152
+ # collection_select(:post, :author_id, Author.all, :id, :name_with_initial, {:prompt => true})
124
153
  #
125
154
  # If <tt>@post.author_id</tt> is already <tt>1</tt>, this would return:
126
155
  # <select name="post[author_id]">
@@ -186,14 +215,29 @@ module ActionView
186
215
  # options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
187
216
  # <option selected="selected">VISA</option>\n<option>MasterCard</option>\n<option selected="selected">Discover</option>
188
217
  #
218
+ # If you wish to specify disabled option tags, set +selected+ to be a hash, with <tt>:disabled</tt> being either a value
219
+ # or array of values to be disabled. In this case, you can use <tt>:selected</tt> to specify selected option tags.
220
+ #
221
+ # Examples:
222
+ # options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], :disabled => "Super Platinum")
223
+ # <option value="Free">Free</option>\n<option value="Basic">Basic</option>\n<option value="Advanced">Advanced</option>\n<option value="Super Platinum" disabled="disabled">Super Platinum</option>
224
+ #
225
+ # options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], :disabled => ["Advanced", "Super Platinum"])
226
+ # <option value="Free">Free</option>\n<option value="Basic">Basic</option>\n<option value="Advanced" disabled="disabled">Advanced</option>\n<option value="Super Platinum" disabled="disabled">Super Platinum</option>
227
+ #
228
+ # options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], :selected => "Free", :disabled => "Super Platinum")
229
+ # <option value="Free" selected="selected">Free</option>\n<option value="Basic">Basic</option>\n<option value="Advanced">Advanced</option>\n<option value="Super Platinum" disabled="disabled">Super Platinum</option>
230
+ #
189
231
  # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
190
232
  def options_for_select(container, selected = nil)
191
233
  container = container.to_a if Hash === container
234
+ selected, disabled = extract_selected_and_disabled(selected)
192
235
 
193
236
  options_for_select = container.inject([]) do |options, element|
194
237
  text, value = option_text_and_value(element)
195
238
  selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
196
- options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}>#{html_escape(text.to_s)}</option>)
239
+ disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
240
+ options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}>#{html_escape(text.to_s)}</option>)
197
241
  end
198
242
 
199
243
  options_for_select.join("\n")
@@ -201,18 +245,38 @@ module ActionView
201
245
 
202
246
  # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
203
247
  # the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
204
- # If +selected+ is specified, the element returning a match on +value_method+ will get the selected option tag.
248
+ # Example:
249
+ # options_from_collection_for_select(@people, 'id', 'name')
250
+ # This will output the same HTML as if you did this:
251
+ # <option value="#{person.id}">#{person.name}</option>
205
252
  #
206
- # Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate an input tag:
207
- # options_from_collection_for_select(@project.people, "id", "name")
208
- # <option value="#{person.id}">#{person.name}</option>
253
+ # This is more often than not used inside a #select_tag like this example:
254
+ # select_tag 'person', options_from_collection_for_select(@people, 'id', 'name')
209
255
  #
210
- # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
256
+ # If +selected+ is specified as a value or array of values, the element(s) returning a match on +value_method+
257
+ # will be selected option tag(s).
258
+ #
259
+ # If +selected+ is specified as a Proc, those members of the collection that return true for the anonymous
260
+ # function are the selected values.
261
+ #
262
+ # +selected+ can also be a hash, specifying both <tt>:selected</tt> and/or <tt>:disabled</tt> values as required.
263
+ #
264
+ # Be sure to specify the same class as the +value_method+ when specifying selected or disabled options.
265
+ # Failure to do this will produce undesired results. Example:
266
+ # options_from_collection_for_select(@people, 'id', 'name', '1')
267
+ # Will not select a person with the id of 1 because 1 (an Integer) is not the same as '1' (a string)
268
+ # options_from_collection_for_select(@people, 'id', 'name', 1)
269
+ # should produce the desired results.
211
270
  def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
212
271
  options = collection.map do |element|
213
272
  [element.send(text_method), element.send(value_method)]
214
273
  end
215
- options_for_select(options, selected)
274
+ selected, disabled = extract_selected_and_disabled(selected)
275
+ select_deselect = {}
276
+ select_deselect[:selected] = extract_values_from_collection(collection, value_method, selected)
277
+ select_deselect[:disabled] = extract_values_from_collection(collection, value_method, disabled)
278
+
279
+ options_for_select(options, select_deselect)
216
280
  end
217
281
 
218
282
  # Returns a string of <tt><option></tt> tags, like <tt>options_from_collection_for_select</tt>, but
@@ -230,7 +294,8 @@ module ActionView
230
294
  # +collection+, returns a value to be used as the contents of its <tt><option></tt> tag.
231
295
  # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
232
296
  # which will have the +selected+ attribute set. Corresponds to the return value of one of the calls
233
- # to +option_key_method+. If +nil+, no selection is made.
297
+ # to +option_key_method+. If +nil+, no selection is made. Can also be a hash if disabled values are
298
+ # to be specified.
234
299
  #
235
300
  # Example object structure for use with this method:
236
301
  # class Continent < ActiveRecord::Base
@@ -269,6 +334,62 @@ module ActionView
269
334
  end
270
335
  end
271
336
 
337
+ # Returns a string of <tt><option></tt> tags, like <tt>options_for_select</tt>, but
338
+ # wraps them with <tt><optgroup></tt> tags.
339
+ #
340
+ # Parameters:
341
+ # * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
342
+ # <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
343
+ # nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
344
+ # Ex. ["North America",[["United States","US"],["Canada","CA"]]]
345
+ # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
346
+ # which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
347
+ # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
348
+ # * +prompt+ - set to true or a prompt string. When the select element doesn’t have a value yet, this
349
+ # prepends an option with a generic prompt — "Please select" — or the given prompt string.
350
+ #
351
+ # Sample usage (Array):
352
+ # grouped_options = [
353
+ # ['North America',
354
+ # [['United States','US'],'Canada']],
355
+ # ['Europe',
356
+ # ['Denmark','Germany','France']]
357
+ # ]
358
+ # grouped_options_for_select(grouped_options)
359
+ #
360
+ # Sample usage (Hash):
361
+ # grouped_options = {
362
+ # 'North America' => [['United States','US], 'Canada'],
363
+ # 'Europe' => ['Denmark','Germany','France']
364
+ # }
365
+ # grouped_options_for_select(grouped_options)
366
+ #
367
+ # Possible output:
368
+ # <optgroup label="Europe">
369
+ # <option value="Denmark">Denmark</option>
370
+ # <option value="Germany">Germany</option>
371
+ # <option value="France">France</option>
372
+ # </optgroup>
373
+ # <optgroup label="North America">
374
+ # <option value="US">United States</option>
375
+ # <option value="Canada">Canada</option>
376
+ # </optgroup>
377
+ #
378
+ # <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
379
+ # wrap the output in an appropriate <tt><select></tt> tag.
380
+ def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
381
+ body = ''
382
+ body << content_tag(:option, prompt, :value => "") if prompt
383
+
384
+ grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
385
+
386
+ grouped_options.each do |group|
387
+ body << content_tag(:optgroup, options_for_select(group[1], selected_key), :label => group[0])
388
+ end
389
+
390
+ body
391
+ end
392
+
272
393
  # Returns a string of option tags for pretty much any time zone in the
273
394
  # world. Supply a TimeZone name as +selected+ to have it marked as the
274
395
  # selected option tag. You can also supply an array of TimeZone objects
@@ -324,6 +445,24 @@ module ActionView
324
445
  value == selected
325
446
  end
326
447
  end
448
+
449
+ def extract_selected_and_disabled(selected)
450
+ if selected.is_a?(Hash)
451
+ [selected[:selected], selected[:disabled]]
452
+ else
453
+ [selected, nil]
454
+ end
455
+ end
456
+
457
+ def extract_values_from_collection(collection, value_method, selected)
458
+ if selected.is_a?(Proc)
459
+ collection.map do |element|
460
+ element.send(value_method) if selected.call(element)
461
+ end.compact
462
+ else
463
+ selected
464
+ end
465
+ end
327
466
  end
328
467
 
329
468
  class InstanceTag #:nodoc:
@@ -334,15 +473,18 @@ module ActionView
334
473
  add_default_name_and_id(html_options)
335
474
  value = value(object)
336
475
  selected_value = options.has_key?(:selected) ? options[:selected] : value
337
- content_tag("select", add_options(options_for_select(choices, selected_value), options, selected_value), html_options)
476
+ disabled_value = options.has_key?(:disabled) ? options[:disabled] : nil
477
+ content_tag("select", add_options(options_for_select(choices, :selected => selected_value, :disabled => disabled_value), options, selected_value), html_options)
338
478
  end
339
479
 
340
480
  def to_collection_select_tag(collection, value_method, text_method, options, html_options)
341
481
  html_options = html_options.stringify_keys
342
482
  add_default_name_and_id(html_options)
343
483
  value = value(object)
484
+ disabled_value = options.has_key?(:disabled) ? options[:disabled] : nil
485
+ selected_value = options.has_key?(:selected) ? options[:selected] : value
344
486
  content_tag(
345
- "select", add_options(options_from_collection_for_select(collection, value_method, text_method, value), options, value), html_options
487
+ "select", add_options(options_from_collection_for_select(collection, value_method, text_method, :selected => selected_value, :disabled => disabled_value), options, value), html_options
346
488
  )
347
489
  end
348
490
 
@@ -360,8 +360,8 @@ module ActionView
360
360
  end
361
361
 
362
362
  if confirm = options.delete("confirm")
363
- options["onclick"] ||= ''
364
- options["onclick"] << "return #{confirm_javascript_function(confirm)};"
363
+ options["onclick"] ||= 'return true;'
364
+ options["onclick"] = "if (!#{confirm_javascript_function(confirm)}) return false; #{options['onclick']}"
365
365
  end
366
366
 
367
367
  tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
@@ -15,6 +15,7 @@ module ActionView
15
15
  # * <tt>:country_code</tt> - Sets the country code for the phone number.
16
16
  #
17
17
  # ==== Examples
18
+ # number_to_phone(5551234) # => 555-1234
18
19
  # number_to_phone(1235551234) # => 123-555-1234
19
20
  # number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
20
21
  # number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
@@ -37,7 +38,8 @@ module ActionView
37
38
  str << if area_code
38
39
  number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
39
40
  else
40
- number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
41
+ number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
42
+ number.starts_with?('-') ? number.slice!(1..-1) : number
41
43
  end
42
44
  str << " x #{extension}" unless extension.blank?
43
45
  str
@@ -220,6 +222,8 @@ module ActionView
220
222
  end
221
223
  end
222
224
 
225
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
226
+
223
227
  # Formats the bytes in +size+ into a more understandable representation
224
228
  # (e.g., giving it 1500 yields 1.5 KB). This method is useful for
225
229
  # reporting file sizes to users. This method returns nil if
@@ -247,7 +251,7 @@ module ActionView
247
251
  # number_to_human_size(1234567, 2) # => 1.18 MB
248
252
  # number_to_human_size(483989, 0) # => 473 KB
249
253
  def number_to_human_size(number, *args)
250
- return number.nil? ? nil : pluralize(number.to_i, "Byte") if number.to_i < 1024
254
+ return nil if number.nil?
251
255
 
252
256
  options = args.extract_options!
253
257
  options.symbolize_keys!
@@ -255,7 +259,6 @@ module ActionView
255
259
  defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
256
260
  human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {}
257
261
  defaults = defaults.merge(human)
258
- storage_units = I18n.translate(:'number.human.storage_units', :locale => options[:locale], :raise => true)
259
262
 
260
263
  unless args.empty?
261
264
  ActiveSupport::Deprecation.warn('number_to_human_size takes an option hash ' +
@@ -267,22 +270,32 @@ module ActionView
267
270
  separator ||= (options[:separator] || defaults[:separator])
268
271
  delimiter ||= (options[:delimiter] || defaults[:delimiter])
269
272
 
270
- max_exp = storage_units.size - 1
271
- number = Float(number)
272
- exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
273
- exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
274
- number /= 1024 ** exponent
275
- unit = storage_units[exponent]
273
+ storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
276
274
 
277
- begin
278
- escaped_separator = Regexp.escape(separator)
279
- number_with_precision(number,
280
- :precision => precision,
281
- :separator => separator,
282
- :delimiter => delimiter
283
- ).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '') + " #{unit}"
284
- rescue
285
- number
275
+ if number.to_i < 1024
276
+ unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
277
+ storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
278
+ else
279
+ max_exp = STORAGE_UNITS.size - 1
280
+ number = Float(number)
281
+ exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
282
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
283
+ number /= 1024 ** exponent
284
+
285
+ unit_key = STORAGE_UNITS[exponent]
286
+ unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
287
+
288
+ begin
289
+ escaped_separator = Regexp.escape(separator)
290
+ formatted_number = number_with_precision(number,
291
+ :precision => precision,
292
+ :separator => separator,
293
+ :delimiter => delimiter
294
+ ).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
295
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
296
+ rescue
297
+ number
298
+ end
286
299
  end
287
300
  end
288
301
  end
@@ -1,4 +1,5 @@
1
1
  require 'set'
2
+ require 'active_support/json'
2
3
 
3
4
  module ActionView
4
5
  module Helpers
@@ -106,7 +107,7 @@ module ActionView
106
107
  # on the page in an Ajax response.
107
108
  module PrototypeHelper
108
109
  unless const_defined? :CALLBACKS
109
- CALLBACKS = Set.new([ :uninitialized, :loading, :loaded,
110
+ CALLBACKS = Set.new([ :create, :uninitialized, :loading, :loaded,
110
111
  :interactive, :complete, :failure, :success ] +
111
112
  (100..599).to_a)
112
113
  AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
@@ -530,11 +531,6 @@ module ActionView
530
531
  # is shorthand for
531
532
  # :with => "'name=' + value"
532
533
  # This essentially just changes the key of the parameter.
533
- # <tt>:on</tt>:: Specifies which event handler to observe. By default,
534
- # it's set to "changed" for text fields and areas and
535
- # "click" for radio buttons and checkboxes. With this,
536
- # you can specify it instead to be "blur" or "focus" or
537
- # any other event.
538
534
  #
539
535
  # Additionally, you may specify any of the options documented in the
540
536
  # <em>Common options</em> section at the top of this document.
@@ -547,11 +543,6 @@ module ActionView
547
543
  # :url => 'http://example.com/books/edit/1',
548
544
  # :with => 'title'
549
545
  #
550
- # # Sends params: {:book_title => 'Title of the book'} when the focus leaves
551
- # # the input field.
552
- # observe_field 'book_title',
553
- # :url => 'http://example.com/books/edit/1',
554
- # :on => 'blur'
555
546
  #
556
547
  def observe_field(field_id, options = {})
557
548
  if options[:frequency] && options[:frequency] > 0
@@ -1093,7 +1084,6 @@ module ActionView
1093
1084
  javascript << "#{options[:frequency]}, " if options[:frequency]
1094
1085
  javascript << "function(element, value) {"
1095
1086
  javascript << "#{callback}}"
1096
- javascript << ", '#{options[:on]}'" if options[:on]
1097
1087
  javascript << ")"
1098
1088
  javascript_tag(javascript)
1099
1089
  end
@@ -1,15 +1,5 @@
1
1
  require 'action_view/helpers/tag_helper'
2
2
 
3
- begin
4
- require 'html/document'
5
- rescue LoadError
6
- html_scanner_path = "#{File.dirname(__FILE__)}/../../action_controller/vendor/html-scanner"
7
- if File.directory?(html_scanner_path)
8
- $:.unshift html_scanner_path
9
- require 'html/document'
10
- end
11
- end
12
-
13
3
  module ActionView
14
4
  module Helpers #:nodoc:
15
5
  # The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
@@ -1,4 +1,5 @@
1
1
  require 'action_view/helpers/javascript_helper'
2
+ require 'active_support/json'
2
3
 
3
4
  module ActionView
4
5
  module Helpers