actionpack 2.1.2 → 2.2.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 (200) hide show
  1. data/CHANGELOG +223 -7
  2. data/README +6 -12
  3. data/Rakefile +11 -11
  4. data/lib/action_controller.rb +9 -9
  5. data/lib/action_controller/assertions/response_assertions.rb +29 -78
  6. data/lib/action_controller/assertions/routing_assertions.rb +33 -33
  7. data/lib/action_controller/assertions/selector_assertions.rb +9 -5
  8. data/lib/action_controller/base.rb +227 -161
  9. data/lib/action_controller/benchmarking.rb +37 -24
  10. data/lib/action_controller/caching/actions.rb +53 -21
  11. data/lib/action_controller/caching/fragments.rb +10 -36
  12. data/lib/action_controller/caching/sweeping.rb +3 -3
  13. data/lib/action_controller/cgi_ext/session.rb +2 -22
  14. data/lib/action_controller/cgi_process.rb +8 -46
  15. data/lib/action_controller/components.rb +4 -1
  16. data/lib/action_controller/cookies.rb +10 -0
  17. data/lib/action_controller/dispatcher.rb +49 -15
  18. data/lib/action_controller/filters.rb +48 -10
  19. data/lib/action_controller/headers.rb +16 -14
  20. data/lib/action_controller/helpers.rb +2 -2
  21. data/lib/action_controller/http_authentication.rb +1 -1
  22. data/lib/action_controller/integration.rb +57 -60
  23. data/lib/action_controller/layout.rb +27 -53
  24. data/lib/action_controller/mime_responds.rb +5 -1
  25. data/lib/action_controller/mime_type.rb +64 -42
  26. data/lib/action_controller/mime_types.rb +2 -1
  27. data/lib/action_controller/performance_test.rb +16 -0
  28. data/lib/action_controller/polymorphic_routes.rb +16 -9
  29. data/lib/action_controller/rack_process.rb +303 -0
  30. data/lib/action_controller/request.rb +205 -97
  31. data/lib/action_controller/request_forgery_protection.rb +2 -2
  32. data/lib/action_controller/request_profiler.rb +0 -0
  33. data/lib/action_controller/rescue.rb +20 -115
  34. data/lib/action_controller/resources.rb +186 -83
  35. data/lib/action_controller/response.rb +140 -26
  36. data/lib/action_controller/routing.rb +28 -30
  37. data/lib/action_controller/routing/builder.rb +45 -54
  38. data/lib/action_controller/routing/optimisations.rb +31 -21
  39. data/lib/action_controller/routing/recognition_optimisation.rb +33 -27
  40. data/lib/action_controller/routing/route.rb +162 -147
  41. data/lib/action_controller/routing/route_set.rb +8 -7
  42. data/lib/action_controller/routing/routing_ext.rb +4 -1
  43. data/lib/action_controller/routing/segments.rb +50 -21
  44. data/lib/action_controller/session/cookie_store.rb +3 -2
  45. data/lib/action_controller/session/drb_server.rb +7 -7
  46. data/lib/action_controller/session_management.rb +6 -2
  47. data/lib/action_controller/streaming.rb +15 -8
  48. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  49. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  50. data/lib/action_controller/test_case.rb +66 -2
  51. data/lib/action_controller/test_process.rb +71 -66
  52. data/lib/action_controller/translation.rb +13 -0
  53. data/lib/action_controller/url_rewriter.rb +90 -13
  54. data/lib/action_controller/vendor/html-scanner/html/node.rb +9 -2
  55. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
  56. data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -2
  57. data/lib/action_controller/verification.rb +2 -2
  58. data/lib/action_pack/version.rb +1 -1
  59. data/lib/action_view.rb +19 -11
  60. data/lib/action_view/base.rb +184 -150
  61. data/lib/action_view/helpers.rb +38 -0
  62. data/lib/action_view/helpers/active_record_helper.rb +56 -27
  63. data/lib/action_view/helpers/asset_tag_helper.rb +356 -153
  64. data/lib/action_view/helpers/atom_feed_helper.rb +74 -19
  65. data/lib/action_view/helpers/benchmark_helper.rb +3 -3
  66. data/lib/action_view/helpers/cache_helper.rb +1 -2
  67. data/lib/action_view/helpers/capture_helper.rb +19 -44
  68. data/lib/action_view/helpers/date_helper.rb +486 -296
  69. data/lib/action_view/helpers/debug_helper.rb +20 -13
  70. data/lib/action_view/helpers/form_helper.rb +71 -30
  71. data/lib/action_view/helpers/form_options_helper.rb +15 -85
  72. data/lib/action_view/helpers/form_tag_helper.rb +61 -38
  73. data/lib/action_view/helpers/javascript_helper.rb +80 -89
  74. data/lib/action_view/helpers/number_helper.rb +179 -74
  75. data/lib/action_view/helpers/prototype_helper.rb +216 -201
  76. data/lib/action_view/helpers/record_tag_helper.rb +4 -5
  77. data/lib/action_view/helpers/sanitize_helper.rb +65 -33
  78. data/lib/action_view/helpers/scriptaculous_helper.rb +2 -2
  79. data/lib/action_view/helpers/tag_helper.rb +39 -22
  80. data/lib/action_view/helpers/text_helper.rb +212 -118
  81. data/lib/action_view/helpers/translation_helper.rb +21 -0
  82. data/lib/action_view/helpers/url_helper.rb +100 -58
  83. data/lib/action_view/inline_template.rb +13 -14
  84. data/lib/action_view/locale/en.yml +91 -0
  85. data/lib/action_view/partials.rb +100 -55
  86. data/lib/action_view/paths.rb +125 -0
  87. data/lib/action_view/renderable.rb +102 -0
  88. data/lib/action_view/renderable_partial.rb +48 -0
  89. data/lib/action_view/template.rb +90 -101
  90. data/lib/action_view/template_error.rb +11 -21
  91. data/lib/action_view/template_handler.rb +8 -28
  92. data/lib/action_view/template_handlers.rb +45 -0
  93. data/lib/action_view/template_handlers/builder.rb +5 -15
  94. data/lib/action_view/template_handlers/erb.rb +9 -6
  95. data/lib/action_view/template_handlers/rjs.rb +2 -17
  96. data/lib/action_view/test_case.rb +7 -4
  97. data/test/abstract_unit.rb +4 -1
  98. data/test/active_record_unit.rb +28 -30
  99. data/test/activerecord/render_partial_with_record_identification_test.rb +25 -12
  100. data/test/controller/action_pack_assertions_test.rb +8 -37
  101. data/test/controller/addresses_render_test.rb +0 -3
  102. data/test/controller/assert_select_test.rb +51 -24
  103. data/test/controller/base_test.rb +4 -4
  104. data/test/controller/caching_test.rb +136 -66
  105. data/test/controller/capture_test.rb +1 -21
  106. data/test/controller/cgi_test.rb +157 -10
  107. data/test/controller/components_test.rb +41 -25
  108. data/test/controller/content_type_test.rb +49 -17
  109. data/test/controller/cookie_test.rb +1 -1
  110. data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -3
  111. data/test/controller/dispatcher_test.rb +9 -1
  112. data/test/controller/filter_params_test.rb +2 -2
  113. data/test/controller/filters_test.rb +13 -13
  114. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  115. data/test/controller/html-scanner/node_test.rb +21 -0
  116. data/test/controller/html-scanner/sanitizer_test.rb +14 -0
  117. data/test/controller/integration_test.rb +167 -6
  118. data/test/controller/layout_test.rb +11 -68
  119. data/test/controller/logging_test.rb +46 -0
  120. data/test/controller/mime_responds_test.rb +61 -59
  121. data/test/controller/mime_type_test.rb +6 -6
  122. data/test/controller/polymorphic_routes_test.rb +37 -2
  123. data/test/controller/rack_test.rb +323 -0
  124. data/test/controller/redirect_test.rb +72 -71
  125. data/test/controller/render_test.rb +1120 -108
  126. data/test/controller/request_forgery_protection_test.rb +66 -52
  127. data/test/controller/request_test.rb +103 -146
  128. data/test/controller/rescue_test.rb +20 -24
  129. data/test/controller/resources_test.rb +408 -25
  130. data/test/controller/routing_test.rb +1774 -1774
  131. data/test/controller/send_file_test.rb +0 -4
  132. data/test/controller/session/cookie_store_test.rb +53 -1
  133. data/test/controller/test_test.rb +15 -37
  134. data/test/controller/translation_test.rb +26 -0
  135. data/test/controller/url_rewriter_test.rb +27 -28
  136. data/test/controller/view_paths_test.rb +48 -47
  137. data/test/fixtures/_top_level_partial.html.erb +1 -0
  138. data/test/fixtures/_top_level_partial_only.erb +1 -0
  139. data/test/fixtures/developers/_developer.erb +1 -0
  140. data/test/fixtures/fun/games/_game.erb +1 -0
  141. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  142. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  143. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  144. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  145. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  146. data/test/fixtures/layouts/_column.html.erb +2 -0
  147. data/test/fixtures/projects/_project.erb +1 -0
  148. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  149. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  150. data/test/fixtures/replies/_reply.erb +1 -0
  151. data/test/fixtures/test/_counter.html.erb +1 -0
  152. data/test/fixtures/test/_customer.erb +1 -1
  153. data/test/fixtures/test/_customer_with_var.erb +1 -0
  154. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  155. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  156. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  157. data/test/fixtures/test/hello.builder +1 -1
  158. data/test/fixtures/test/hyphen-ated.erb +1 -0
  159. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  160. data/test/fixtures/test/nested_layout.erb +3 -0
  161. data/test/fixtures/test/non_erb_block_content_for.builder +1 -1
  162. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  163. data/test/fixtures/test/template.erb +1 -0
  164. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  165. data/test/template/active_record_helper_i18n_test.rb +46 -0
  166. data/test/template/active_record_helper_test.rb +24 -24
  167. data/test/template/asset_tag_helper_test.rb +161 -29
  168. data/test/template/atom_feed_helper_test.rb +114 -5
  169. data/test/template/compiled_templates_test.rb +59 -0
  170. data/test/template/date_helper_i18n_test.rb +113 -0
  171. data/test/template/date_helper_test.rb +403 -109
  172. data/test/template/form_helper_test.rb +213 -154
  173. data/test/template/form_options_helper_test.rb +249 -897
  174. data/test/template/form_tag_helper_test.rb +80 -32
  175. data/test/template/javascript_helper_test.rb +17 -18
  176. data/test/template/number_helper_i18n_test.rb +54 -0
  177. data/test/template/number_helper_test.rb +43 -13
  178. data/test/template/prototype_helper_test.rb +101 -84
  179. data/test/template/record_tag_helper_test.rb +24 -20
  180. data/test/template/render_test.rb +193 -0
  181. data/test/template/sanitize_helper_test.rb +3 -3
  182. data/test/template/tag_helper_test.rb +34 -14
  183. data/test/template/text_helper_test.rb +83 -9
  184. data/test/template/translation_helper_test.rb +28 -0
  185. data/test/template/url_helper_test.rb +55 -18
  186. metadata +57 -18
  187. data/lib/action_view/helpers/javascripts/controls.js +0 -963
  188. data/lib/action_view/helpers/javascripts/dragdrop.js +0 -972
  189. data/lib/action_view/helpers/javascripts/effects.js +0 -1120
  190. data/lib/action_view/helpers/javascripts/prototype.js +0 -4225
  191. data/lib/action_view/partial_template.rb +0 -70
  192. data/lib/action_view/template_finder.rb +0 -177
  193. data/lib/action_view/template_handlers/compilable.rb +0 -128
  194. data/test/controller/custom_handler_test.rb +0 -45
  195. data/test/controller/new_render_test.rb +0 -945
  196. data/test/fixtures/test/block_content_for.erb +0 -2
  197. data/test/fixtures/test/erb_content_for.erb +0 -2
  198. data/test/template/deprecated_erb_variable_test.rb +0 -9
  199. data/test/template/template_finder_test.rb +0 -73
  200. data/test/template/template_object_test.rb +0 -95
@@ -3,25 +3,25 @@ require 'set'
3
3
  module ActionView
4
4
  module Helpers
5
5
  # Prototype[http://www.prototypejs.org/] is a JavaScript library that provides
6
- # DOM[http://en.wikipedia.org/wiki/Document_Object_Model] manipulation,
6
+ # DOM[http://en.wikipedia.org/wiki/Document_Object_Model] manipulation,
7
7
  # Ajax[http://www.adaptivepath.com/publications/essays/archives/000385.php]
8
- # functionality, and more traditional object-oriented facilities for JavaScript.
8
+ # functionality, and more traditional object-oriented facilities for JavaScript.
9
9
  # This module provides a set of helpers to make it more convenient to call
10
- # functions from Prototype using Rails, including functionality to call remote
11
- # Rails methods (that is, making a background request to a Rails action) using Ajax.
12
- # This means that you can call actions in your controllers without
13
- # reloading the page, but still update certain parts of it using
10
+ # functions from Prototype using Rails, including functionality to call remote
11
+ # Rails methods (that is, making a background request to a Rails action) using Ajax.
12
+ # This means that you can call actions in your controllers without
13
+ # reloading the page, but still update certain parts of it using
14
14
  # injections into the DOM. A common use case is having a form that adds
15
15
  # a new element to a list without reloading the page or updating a shopping
16
16
  # cart total when a new item is added.
17
17
  #
18
18
  # == Usage
19
- # To be able to use these helpers, you must first include the Prototype
20
- # JavaScript framework in your pages.
19
+ # To be able to use these helpers, you must first include the Prototype
20
+ # JavaScript framework in your pages.
21
21
  #
22
22
  # javascript_include_tag 'prototype'
23
23
  #
24
- # (See the documentation for
24
+ # (See the documentation for
25
25
  # ActionView::Helpers::JavaScriptHelper for more information on including
26
26
  # this and other JavaScript files in your Rails templates.)
27
27
  #
@@ -29,7 +29,7 @@ module ActionView
29
29
  #
30
30
  # link_to_remote "Add to cart",
31
31
  # :url => { :action => "add", :id => product.id },
32
- # :update => { :success => "cart", :failure => "error" }
32
+ # :update => { :success => "cart", :failure => "error" }
33
33
  #
34
34
  # ...through a form...
35
35
  #
@@ -50,8 +50,8 @@ module ActionView
50
50
  # :update => :hits,
51
51
  # :with => 'query'
52
52
  # %>
53
- #
54
- # As you can see, there are numerous ways to use Prototype's Ajax functions (and actually more than
53
+ #
54
+ # As you can see, there are numerous ways to use Prototype's Ajax functions (and actually more than
55
55
  # are listed here); check out the documentation for each method to find out more about its usage and options.
56
56
  #
57
57
  # === Common Options
@@ -61,9 +61,9 @@ module ActionView
61
61
  #
62
62
  # == Designing your Rails actions for Ajax
63
63
  # When building your action handlers (that is, the Rails actions that receive your background requests), it's
64
- # important to remember a few things. First, whatever your action would normall return to the browser, it will
64
+ # important to remember a few things. First, whatever your action would normally return to the browser, it will
65
65
  # return to the Ajax call. As such, you typically don't want to render with a layout. This call will cause
66
- # the layout to be transmitted back to your page, and, if you have a full HTML/CSS, will likely mess a lot of things up.
66
+ # the layout to be transmitted back to your page, and, if you have a full HTML/CSS, will likely mess a lot of things up.
67
67
  # You can turn the layout off on particular actions by doing the following:
68
68
  #
69
69
  # class SiteController < ActionController::Base
@@ -74,8 +74,8 @@ module ActionView
74
74
  #
75
75
  # render :layout => false
76
76
  #
77
- # You can tell the type of request from within your action using the <tt>request.xhr?</tt> (XmlHttpRequest, the
78
- # method that Ajax uses to make background requests) method.
77
+ # You can tell the type of request from within your action using the <tt>request.xhr?</tt> (XmlHttpRequest, the
78
+ # method that Ajax uses to make background requests) method.
79
79
  # def name
80
80
  # # Is this an XmlHttpRequest request?
81
81
  # if (request.xhr?)
@@ -93,7 +93,7 @@ module ActionView
93
93
  #
94
94
  # Dropping this in your ApplicationController turns the layout off for every request that is an "xhr" request.
95
95
  #
96
- # If you are just returning a little data or don't want to build a template for your output, you may opt to simply
96
+ # If you are just returning a little data or don't want to build a template for your output, you may opt to simply
97
97
  # render text output, like this:
98
98
  #
99
99
  # render :text => 'Return this from my method!'
@@ -103,7 +103,7 @@ module ActionView
103
103
  #
104
104
  # == Updating multiple elements
105
105
  # See JavaScriptGenerator for information on updating multiple elements
106
- # on the page in an Ajax response.
106
+ # on the page in an Ajax response.
107
107
  module PrototypeHelper
108
108
  unless const_defined? :CALLBACKS
109
109
  CALLBACKS = Set.new([ :uninitialized, :loading, :loaded,
@@ -114,64 +114,64 @@ module ActionView
114
114
  :form, :with, :update, :script, :type ]).merge(CALLBACKS)
115
115
  end
116
116
 
117
- # Returns a link to a remote action defined by <tt>options[:url]</tt>
118
- # (using the url_for format) that's called in the background using
117
+ # Returns a link to a remote action defined by <tt>options[:url]</tt>
118
+ # (using the url_for format) that's called in the background using
119
119
  # XMLHttpRequest. The result of that request can then be inserted into a
120
- # DOM object whose id can be specified with <tt>options[:update]</tt>.
120
+ # DOM object whose id can be specified with <tt>options[:update]</tt>.
121
121
  # Usually, the result would be a partial prepared by the controller with
122
- # render :partial.
122
+ # render :partial.
123
123
  #
124
124
  # Examples:
125
- # # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true});
125
+ # # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true});
126
126
  # # return false;">Delete this post</a>
127
- # link_to_remote "Delete this post", :update => "posts",
127
+ # link_to_remote "Delete this post", :update => "posts",
128
128
  # :url => { :action => "destroy", :id => post.id }
129
129
  #
130
- # # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true});
130
+ # # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true});
131
131
  # # return false;"><img alt="Refresh" src="/images/refresh.png?" /></a>
132
- # link_to_remote(image_tag("refresh"), :update => "emails",
132
+ # link_to_remote(image_tag("refresh"), :update => "emails",
133
133
  # :url => { :action => "list_emails" })
134
- #
134
+ #
135
135
  # You can override the generated HTML options by specifying a hash in
136
136
  # <tt>options[:html]</tt>.
137
- #
137
+ #
138
138
  # link_to_remote "Delete this post", :update => "posts",
139
- # :url => post_url(@post), :method => :delete,
140
- # :html => { :class => "destructive" }
139
+ # :url => post_url(@post), :method => :delete,
140
+ # :html => { :class => "destructive" }
141
141
  #
142
142
  # You can also specify a hash for <tt>options[:update]</tt> to allow for
143
- # easy redirection of output to an other DOM element if a server-side
143
+ # easy redirection of output to an other DOM element if a server-side
144
144
  # error occurs:
145
145
  #
146
146
  # Example:
147
- # # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5',
147
+ # # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5',
148
148
  # # {asynchronous:true, evalScripts:true}); return false;">Delete this post</a>
149
149
  # link_to_remote "Delete this post",
150
150
  # :url => { :action => "destroy", :id => post.id },
151
151
  # :update => { :success => "posts", :failure => "error" }
152
152
  #
153
- # Optionally, you can use the <tt>options[:position]</tt> parameter to
154
- # influence how the target DOM element is updated. It must be one of
153
+ # Optionally, you can use the <tt>options[:position]</tt> parameter to
154
+ # influence how the target DOM element is updated. It must be one of
155
155
  # <tt>:before</tt>, <tt>:top</tt>, <tt>:bottom</tt>, or <tt>:after</tt>.
156
156
  #
157
157
  # The method used is by default POST. You can also specify GET or you
158
158
  # can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt>
159
159
  #
160
160
  # Example:
161
- # # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'});
161
+ # # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'});
162
162
  # # return false;">Destroy</a>
163
163
  # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete
164
164
  #
165
- # By default, these remote requests are processed asynchronous during
166
- # which various JavaScript callbacks can be triggered (for progress
167
- # indicators and the likes). All callbacks get access to the
168
- # <tt>request</tt> object, which holds the underlying XMLHttpRequest.
165
+ # By default, these remote requests are processed asynchronous during
166
+ # which various JavaScript callbacks can be triggered (for progress
167
+ # indicators and the likes). All callbacks get access to the
168
+ # <tt>request</tt> object, which holds the underlying XMLHttpRequest.
169
169
  #
170
170
  # To access the server response, use <tt>request.responseText</tt>, to
171
171
  # find out the HTTP status, use <tt>request.status</tt>.
172
172
  #
173
173
  # Example:
174
- # # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true,
174
+ # # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true,
175
175
  # # onComplete:function(request){undoRequestCompleted(request)}}); return false;">hello</a>
176
176
  # word = 'hello'
177
177
  # link_to_remote word,
@@ -180,43 +180,43 @@ module ActionView
180
180
  #
181
181
  # The callbacks that may be specified are (in order):
182
182
  #
183
- # <tt>:loading</tt>:: Called when the remote document is being
183
+ # <tt>:loading</tt>:: Called when the remote document is being
184
184
  # loaded with data by the browser.
185
185
  # <tt>:loaded</tt>:: Called when the browser has finished loading
186
186
  # the remote document.
187
- # <tt>:interactive</tt>:: Called when the user can interact with the
188
- # remote document, even though it has not
187
+ # <tt>:interactive</tt>:: Called when the user can interact with the
188
+ # remote document, even though it has not
189
189
  # finished loading.
190
190
  # <tt>:success</tt>:: Called when the XMLHttpRequest is completed,
191
191
  # and the HTTP status code is in the 2XX range.
192
192
  # <tt>:failure</tt>:: Called when the XMLHttpRequest is completed,
193
193
  # and the HTTP status code is not in the 2XX
194
194
  # range.
195
- # <tt>:complete</tt>:: Called when the XMLHttpRequest is complete
196
- # (fires after success/failure if they are
195
+ # <tt>:complete</tt>:: Called when the XMLHttpRequest is complete
196
+ # (fires after success/failure if they are
197
197
  # present).
198
- #
199
- # You can further refine <tt>:success</tt> and <tt>:failure</tt> by
198
+ #
199
+ # You can further refine <tt>:success</tt> and <tt>:failure</tt> by
200
200
  # adding additional callbacks for specific status codes.
201
201
  #
202
202
  # Example:
203
- # # Generates: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true,
204
- # # on404:function(request){alert('Not found...? Wrong URL...?')},
203
+ # # Generates: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true,
204
+ # # on404:function(request){alert('Not found...? Wrong URL...?')},
205
205
  # # onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a>
206
206
  # link_to_remote word,
207
207
  # :url => { :action => "action" },
208
208
  # 404 => "alert('Not found...? Wrong URL...?')",
209
209
  # :failure => "alert('HTTP Error ' + request.status + '!')"
210
210
  #
211
- # A status code callback overrides the success/failure handlers if
211
+ # A status code callback overrides the success/failure handlers if
212
212
  # present.
213
213
  #
214
214
  # If you for some reason or another need synchronous processing (that'll
215
- # block the browser while the request is happening), you can specify
215
+ # block the browser while the request is happening), you can specify
216
216
  # <tt>options[:type] = :synchronous</tt>.
217
217
  #
218
218
  # You can customize further browser side call logic by passing in
219
- # JavaScript code snippets via some optional parameters. In their order
219
+ # JavaScript code snippets via some optional parameters. In their order
220
220
  # of use these are:
221
221
  #
222
222
  # <tt>:confirm</tt>:: Adds confirmation dialog.
@@ -228,7 +228,7 @@ module ActionView
228
228
  # <tt>:after</tt>:: Called immediately after request was
229
229
  # initiated and before <tt>:loading</tt>.
230
230
  # <tt>:submit</tt>:: Specifies the DOM element ID that's used
231
- # as the parent of the form elements. By
231
+ # as the parent of the form elements. By
232
232
  # default this is the current form, but
233
233
  # it could just as well be the ID of a
234
234
  # table row or any other DOM element.
@@ -238,10 +238,10 @@ module ActionView
238
238
  # URL query string.
239
239
  #
240
240
  # Example:
241
- #
241
+ #
242
242
  # :with => "'name=' + $('name').value"
243
243
  #
244
- # You can generate a link that uses AJAX in the general case, while
244
+ # You can generate a link that uses AJAX in the general case, while
245
245
  # degrading gracefully to plain link behavior in the absence of
246
246
  # JavaScript by setting <tt>html_options[:href]</tt> to an alternate URL.
247
247
  # Note the extra curly braces around the <tt>options</tt> hash separate
@@ -251,10 +251,18 @@ module ActionView
251
251
  # link_to_remote "Delete this post",
252
252
  # { :update => "posts", :url => { :action => "destroy", :id => post.id } },
253
253
  # :href => url_for(:action => "destroy", :id => post.id)
254
- def link_to_remote(name, options = {}, html_options = nil)
254
+ def link_to_remote(name, options = {}, html_options = nil)
255
255
  link_to_function(name, remote_function(options), html_options || options.delete(:html))
256
256
  end
257
257
 
258
+ # Creates a button with an onclick event which calls a remote action
259
+ # via XMLHttpRequest
260
+ # The options for specifying the target with :url
261
+ # and defining callbacks is the same as link_to_remote.
262
+ def button_to_remote(name, options = {}, html_options = {})
263
+ button_to_function(name, remote_function(options), html_options)
264
+ end
265
+
258
266
  # Periodically calls the specified url (<tt>options[:url]</tt>) every
259
267
  # <tt>options[:frequency]</tt> seconds (default is 10). Usually used to
260
268
  # update a specified div (<tt>options[:update]</tt>) with the results
@@ -262,15 +270,15 @@ module ActionView
262
270
  # and defining callbacks is the same as link_to_remote.
263
271
  # Examples:
264
272
  # # Call get_averages and put its results in 'avg' every 10 seconds
265
- # # Generates:
266
- # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages',
273
+ # # Generates:
274
+ # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages',
267
275
  # # {asynchronous:true, evalScripts:true})}, 10)
268
276
  # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')
269
277
  #
270
278
  # # Call invoice every 10 seconds with the id of the customer
271
279
  # # If it succeeds, update the invoice DIV; if it fails, update the error DIV
272
280
  # # Generates:
273
- # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'},
281
+ # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'},
274
282
  # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10)
275
283
  # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id },
276
284
  # :update => { :success => "invoice", :failure => "error" }
@@ -286,11 +294,11 @@ module ActionView
286
294
  javascript_tag(code)
287
295
  end
288
296
 
289
- # Returns a form tag that will submit using XMLHttpRequest in the
290
- # background instead of the regular reloading POST arrangement. Even
297
+ # Returns a form tag that will submit using XMLHttpRequest in the
298
+ # background instead of the regular reloading POST arrangement. Even
291
299
  # though it's using JavaScript to serialize the form elements, the form
292
300
  # submission will work just like a regular submission as viewed by the
293
- # receiving side (all elements available in <tt>params</tt>). The options for
301
+ # receiving side (all elements available in <tt>params</tt>). The options for
294
302
  # specifying the target with <tt>:url</tt> and defining callbacks is the same as
295
303
  # +link_to_remote+.
296
304
  #
@@ -299,21 +307,21 @@ module ActionView
299
307
  #
300
308
  # Example:
301
309
  # # Generates:
302
- # # <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
310
+ # # <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
303
311
  # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
304
- # form_remote_tag :html => { :action =>
312
+ # form_remote_tag :html => { :action =>
305
313
  # url_for(:controller => "some", :action => "place") }
306
314
  #
307
315
  # The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd)
308
316
  # argument in the FormTagHelper.form_tag method.
309
317
  #
310
- # By default the fall-through action is the same as the one specified in
318
+ # By default the fall-through action is the same as the one specified in
311
319
  # the <tt>:url</tt> (and the default method is <tt>:post</tt>).
312
320
  #
313
321
  # form_remote_tag also takes a block, like form_tag:
314
322
  # # Generates:
315
- # # <form action="/" method="post" onsubmit="new Ajax.Request('/',
316
- # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
323
+ # # <form action="/" method="post" onsubmit="new Ajax.Request('/',
324
+ # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
317
325
  # # return false;"> <div><input name="commit" type="submit" value="Save" /></div>
318
326
  # # </form>
319
327
  # <% form_remote_tag :url => '/posts' do -%>
@@ -323,19 +331,19 @@ module ActionView
323
331
  options[:form] = true
324
332
 
325
333
  options[:html] ||= {}
326
- options[:html][:onsubmit] =
327
- (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
334
+ options[:html][:onsubmit] =
335
+ (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
328
336
  "#{remote_function(options)}; return false;"
329
337
 
330
338
  form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
331
339
  end
332
340
 
333
- # Creates a form that will submit using XMLHttpRequest in the background
334
- # instead of the regular reloading POST arrangement and a scope around a
341
+ # Creates a form that will submit using XMLHttpRequest in the background
342
+ # instead of the regular reloading POST arrangement and a scope around a
335
343
  # specific resource that is used as a base for questioning about
336
- # values for the fields.
344
+ # values for the fields.
337
345
  #
338
- # === Resource
346
+ # === Resource
339
347
  #
340
348
  # Example:
341
349
  # <% remote_form_for(@post) do |f| %>
@@ -348,7 +356,7 @@ module ActionView
348
356
  # ...
349
357
  # <% end %>
350
358
  #
351
- # === Nested Resource
359
+ # === Nested Resource
352
360
  #
353
361
  # Example:
354
362
  # <% remote_form_for([@post, @comment]) do |f| %>
@@ -382,28 +390,28 @@ module ActionView
382
390
  args.unshift object
383
391
  end
384
392
 
385
- concat(form_remote_tag(options), proc.binding)
393
+ concat(form_remote_tag(options))
386
394
  fields_for(object_name, *(args << options), &proc)
387
- concat('</form>', proc.binding)
395
+ concat('</form>')
388
396
  end
389
397
  alias_method :form_remote_for, :remote_form_for
390
-
398
+
391
399
  # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+
392
400
  # that will submit form using XMLHttpRequest in the background instead of a regular POST request that
393
- # reloads the page.
401
+ # reloads the page.
394
402
  #
395
403
  # # Create a button that submits to the create action
396
- # #
397
- # # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create',
398
- # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
404
+ # #
405
+ # # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create',
406
+ # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
399
407
  # # return false;" type="button" value="Create" />
400
408
  # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
401
409
  #
402
410
  # # Submit to the remote action update and update the DIV succeed or fail based
403
411
  # # on the success or failure of the request
404
412
  # #
405
- # # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'},
406
- # # '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
413
+ # # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'},
414
+ # # '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
407
415
  # # return false;" type="button" value="Update" />
408
416
  # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
409
417
  # :update => { :success => "succeed", :failure => "fail" }
@@ -412,15 +420,12 @@ module ActionView
412
420
  def submit_to_remote(name, value, options = {})
413
421
  options[:with] ||= 'Form.serialize(this.form)'
414
422
 
415
- options[:html] ||= {}
416
- options[:html][:type] = 'button'
417
- options[:html][:onclick] = "#{remote_function(options)}; return false;"
418
- options[:html][:name] = name
419
- options[:html][:value] = value
423
+ html_options = options.delete(:html) || {}
424
+ html_options[:name] = name
420
425
 
421
- tag("input", options[:html], false)
426
+ button_to_remote(value, options, html_options)
422
427
  end
423
-
428
+
424
429
  # Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
425
430
  # that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple
426
431
  # update return document using +update_element_function+ calls.
@@ -430,11 +435,11 @@ module ActionView
430
435
 
431
436
  # Returns the JavaScript needed for a remote function.
432
437
  # Takes the same arguments as link_to_remote.
433
- #
438
+ #
434
439
  # Example:
435
- # # Generates: <select id="options" onchange="new Ajax.Updater('options',
440
+ # # Generates: <select id="options" onchange="new Ajax.Updater('options',
436
441
  # # '/testing/update_options', {asynchronous:true, evalScripts:true})">
437
- # <select id="options" onchange="<%= remote_function(:update => "options",
442
+ # <select id="options" onchange="<%= remote_function(:update => "options",
438
443
  # :url => { :action => :update_options }) %>">
439
444
  # <option value="0">Hello</option>
440
445
  # <option value="1">World</option>
@@ -452,7 +457,7 @@ module ActionView
452
457
  update << "'#{options[:update]}'"
453
458
  end
454
459
 
455
- function = update.empty? ?
460
+ function = update.empty? ?
456
461
  "new Ajax.Request(" :
457
462
  "new Ajax.Updater(#{update}, "
458
463
 
@@ -473,9 +478,9 @@ module ActionView
473
478
  # callback when its contents have changed. The default callback is an
474
479
  # Ajax call. By default the value of the observed field is sent as a
475
480
  # parameter with the Ajax call.
476
- #
481
+ #
477
482
  # Example:
478
- # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest',
483
+ # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest',
479
484
  # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})})
480
485
  # <%= observe_field :suggest, :url => { :action => :find_suggestion },
481
486
  # :frequency => 0.25,
@@ -497,14 +502,14 @@ module ActionView
497
502
  # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')})
498
503
  # The element parameter is the DOM element being observed, and the value is its value at the
499
504
  # time the observer is triggered.
500
- #
505
+ #
501
506
  # Additional options are:
502
507
  # <tt>:frequency</tt>:: The frequency (in seconds) at which changes to
503
508
  # this field will be detected. Not setting this
504
509
  # option at all or to a value equal to or less than
505
510
  # zero will use event based observation instead of
506
511
  # time based observation.
507
- # <tt>:update</tt>:: Specifies the DOM ID of the element whose
512
+ # <tt>:update</tt>:: Specifies the DOM ID of the element whose
508
513
  # innerHTML should be updated with the
509
514
  # XMLHttpRequest response text.
510
515
  # <tt>:with</tt>:: A JavaScript expression specifying the parameters
@@ -515,7 +520,7 @@ module ActionView
515
520
  # variable +value+.
516
521
  #
517
522
  # Examples
518
- #
523
+ #
519
524
  # :with => "'my_custom_key=' + value"
520
525
  # :with => "'person[name]=' + prompt('New name')"
521
526
  # :with => "Form.Element.serialize('other-field')"
@@ -541,7 +546,7 @@ module ActionView
541
546
  # observe_field 'book_title',
542
547
  # :url => 'http://example.com/books/edit/1',
543
548
  # :with => 'title'
544
- #
549
+ #
545
550
  # # Sends params: {:book_title => 'Title of the book'} when the focus leaves
546
551
  # # the input field.
547
552
  # observe_field 'book_title',
@@ -555,7 +560,7 @@ module ActionView
555
560
  build_observer('Form.Element.EventObserver', field_id, options)
556
561
  end
557
562
  end
558
-
563
+
559
564
  # Observes the form with the DOM ID specified by +form_id+ and calls a
560
565
  # callback when its contents have changed. The default callback is an
561
566
  # Ajax call. By default all fields of the observed field are sent as
@@ -571,39 +576,39 @@ module ActionView
571
576
  build_observer('Form.EventObserver', form_id, options)
572
577
  end
573
578
  end
574
-
575
- # All the methods were moved to GeneratorMethods so that
579
+
580
+ # All the methods were moved to GeneratorMethods so that
576
581
  # #include_helpers_from_context has nothing to overwrite.
577
582
  class JavaScriptGenerator #:nodoc:
578
583
  def initialize(context, &block) #:nodoc:
579
584
  @context, @lines = context, []
580
585
  include_helpers_from_context
581
- @context.instance_exec(self, &block)
586
+ @context.with_output_buffer(@lines) do
587
+ @context.instance_exec(self, &block)
588
+ end
582
589
  end
583
-
590
+
584
591
  private
585
592
  def include_helpers_from_context
586
- @context.extended_by.each do |mod|
587
- extend mod unless mod.name =~ /^ActionView::Helpers/
588
- end
593
+ extend @context.helpers if @context.respond_to?(:helpers)
589
594
  extend GeneratorMethods
590
595
  end
591
-
592
- # JavaScriptGenerator generates blocks of JavaScript code that allow you
593
- # to change the content and presentation of multiple DOM elements. Use
596
+
597
+ # JavaScriptGenerator generates blocks of JavaScript code that allow you
598
+ # to change the content and presentation of multiple DOM elements. Use
594
599
  # this in your Ajax response bodies, either in a <script> tag or as plain
595
600
  # JavaScript sent with a Content-type of "text/javascript".
596
601
  #
597
- # Create new instances with PrototypeHelper#update_page or with
598
- # ActionController::Base#render, then call +insert_html+, +replace_html+,
599
- # +remove+, +show+, +hide+, +visual_effect+, or any other of the built-in
600
- # methods on the yielded generator in any order you like to modify the
601
- # content and appearance of the current page.
602
+ # Create new instances with PrototypeHelper#update_page or with
603
+ # ActionController::Base#render, then call +insert_html+, +replace_html+,
604
+ # +remove+, +show+, +hide+, +visual_effect+, or any other of the built-in
605
+ # methods on the yielded generator in any order you like to modify the
606
+ # content and appearance of the current page.
602
607
  #
603
608
  # Example:
604
609
  #
605
610
  # # Generates:
606
- # # new Element.insert("list", { bottom: <li>Some item</li>" });
611
+ # # new Element.insert("list", { bottom: "<li>Some item</li>" });
607
612
  # # new Effect.Highlight("list");
608
613
  # # ["status-indicator", "cancel-link"].each(Element.hide);
609
614
  # update_page do |page|
@@ -611,12 +616,12 @@ module ActionView
611
616
  # page.visual_effect :highlight, 'list'
612
617
  # page.hide 'status-indicator', 'cancel-link'
613
618
  # end
614
- #
619
+ #
615
620
  #
616
621
  # Helper methods can be used in conjunction with JavaScriptGenerator.
617
- # When a helper method is called inside an update block on the +page+
622
+ # When a helper method is called inside an update block on the +page+
618
623
  # object, that method will also have access to a +page+ object.
619
- #
624
+ #
620
625
  # Example:
621
626
  #
622
627
  # module ApplicationHelper
@@ -652,7 +657,7 @@ module ActionView
652
657
  # end
653
658
  # end
654
659
  #
655
- # You can also use PrototypeHelper#update_page_tag instead of
660
+ # You can also use PrototypeHelper#update_page_tag instead of
656
661
  # PrototypeHelper#update_page to wrap the generated JavaScript in a
657
662
  # <script> tag.
658
663
  module GeneratorMethods
@@ -665,7 +670,7 @@ module ActionView
665
670
  end
666
671
  end
667
672
  end
668
-
673
+
669
674
  # Returns a element reference by finding it through +id+ in the DOM. This element can then be
670
675
  # used for further method calls. Examples:
671
676
  #
@@ -686,31 +691,31 @@ module ActionView
686
691
  JavaScriptElementProxy.new(self, ActionController::RecordIdentifier.dom_id(id))
687
692
  end
688
693
  end
689
-
690
- # Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
694
+
695
+ # Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
691
696
  # expression as an argument to another JavaScriptGenerator method.
692
697
  def literal(code)
693
698
  ActiveSupport::JSON::Variable.new(code.to_s)
694
699
  end
695
-
700
+
696
701
  # Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be
697
702
  # used for further method calls. Examples:
698
703
  #
699
704
  # page.select('p') # => $$('p');
700
705
  # page.select('p.welcome b').first # => $$('p.welcome b').first();
701
706
  # page.select('p.welcome b').first.hide # => $$('p.welcome b').first().hide();
702
- #
707
+ #
703
708
  # You can also use prototype enumerations with the collection. Observe:
704
- #
709
+ #
705
710
  # # Generates: $$('#items li').each(function(value) { value.hide(); });
706
711
  # page.select('#items li').each do |value|
707
712
  # value.hide
708
- # end
713
+ # end
709
714
  #
710
- # Though you can call the block param anything you want, they are always rendered in the
715
+ # Though you can call the block param anything you want, they are always rendered in the
711
716
  # javascript as 'value, index.' Other enumerations, like collect() return the last statement:
712
717
  #
713
- # # Generates: var hidden = $$('#items li').collect(function(value, index) { return value.hide(); });
718
+ # # Generates: var hidden = $$('#items li').collect(function(value, index) { return value.hide(); });
714
719
  # page.select('#items li').collect('hidden') do |item|
715
720
  # item.hide
716
721
  # end
@@ -718,13 +723,13 @@ module ActionView
718
723
  def select(pattern)
719
724
  JavaScriptElementCollectionProxy.new(self, pattern)
720
725
  end
721
-
726
+
722
727
  # Inserts HTML at the specified +position+ relative to the DOM element
723
728
  # identified by the given +id+.
724
- #
729
+ #
725
730
  # +position+ may be one of:
726
- #
727
- # <tt>:top</tt>:: HTML is inserted inside the element, before the
731
+ #
732
+ # <tt>:top</tt>:: HTML is inserted inside the element, before the
728
733
  # element's existing content.
729
734
  # <tt>:bottom</tt>:: HTML is inserted inside the element, after the
730
735
  # element's existing content.
@@ -747,7 +752,7 @@ module ActionView
747
752
  content = javascript_object_for(render(*options_for_render))
748
753
  record "Element.insert(\"#{id}\", { #{position.to_s.downcase}: #{content} });"
749
754
  end
750
-
755
+
751
756
  # Replaces the inner HTML of the DOM element with the given +id+.
752
757
  #
753
758
  # +options_for_render+ may be either a string of HTML to insert, or a hash
@@ -761,7 +766,7 @@ module ActionView
761
766
  def replace_html(id, *options_for_render)
762
767
  call 'Element.update', id, render(*options_for_render)
763
768
  end
764
-
769
+
765
770
  # Replaces the "outer HTML" (i.e., the entire element, not just its
766
771
  # contents) of the DOM element with the given +id+.
767
772
  #
@@ -783,7 +788,7 @@ module ActionView
783
788
  # </div>
784
789
  #
785
790
  # # Insert a new person
786
- # #
791
+ # #
787
792
  # # Generates: new Insertion.Bottom({object: "Matz", partial: "person"}, "");
788
793
  # page.insert_html :bottom, :partial => 'person', :object => @person
789
794
  #
@@ -795,7 +800,7 @@ module ActionView
795
800
  def replace(id, *options_for_render)
796
801
  call 'Element.replace', id, render(*options_for_render)
797
802
  end
798
-
803
+
799
804
  # Removes the DOM elements with the given +ids+ from the page.
800
805
  #
801
806
  # Example:
@@ -807,9 +812,9 @@ module ActionView
807
812
  def remove(*ids)
808
813
  loop_on_multiple_args 'Element.remove', ids
809
814
  end
810
-
815
+
811
816
  # Shows hidden DOM elements with the given +ids+.
812
- #
817
+ #
813
818
  # Example:
814
819
  #
815
820
  # # Show a few people
@@ -819,7 +824,7 @@ module ActionView
819
824
  def show(*ids)
820
825
  loop_on_multiple_args 'Element.show', ids
821
826
  end
822
-
827
+
823
828
  # Hides the visible DOM elements with the given +ids+.
824
829
  #
825
830
  # Example:
@@ -829,9 +834,9 @@ module ActionView
829
834
  # page.hide 'person_29', 'person_9', 'person_0'
830
835
  #
831
836
  def hide(*ids)
832
- loop_on_multiple_args 'Element.hide', ids
837
+ loop_on_multiple_args 'Element.hide', ids
833
838
  end
834
-
839
+
835
840
  # Toggles the visibility of the DOM elements with the given +ids+.
836
841
  # Example:
837
842
  #
@@ -841,9 +846,9 @@ module ActionView
841
846
  # page.toggle 'person_14', 'person_12', 'person_23' # Shows the previously hidden elements
842
847
  #
843
848
  def toggle(*ids)
844
- loop_on_multiple_args 'Element.toggle', ids
849
+ loop_on_multiple_args 'Element.toggle', ids
845
850
  end
846
-
851
+
847
852
  # Displays an alert dialog with the given +message+.
848
853
  #
849
854
  # Example:
@@ -853,35 +858,45 @@ module ActionView
853
858
  def alert(message)
854
859
  call 'alert', message
855
860
  end
856
-
861
+
857
862
  # Redirects the browser to the given +location+ using JavaScript, in the same form as +url_for+.
858
863
  #
859
864
  # Examples:
860
865
  #
861
866
  # # Generates: window.location.href = "/mycontroller";
862
867
  # page.redirect_to(:action => 'index')
863
- #
868
+ #
864
869
  # # Generates: window.location.href = "/account/signup";
865
870
  # page.redirect_to(:controller => 'account', :action => 'signup')
866
871
  def redirect_to(location)
867
872
  url = location.is_a?(String) ? location : @context.url_for(location)
868
873
  record "window.location.href = #{url.inspect}"
869
874
  end
870
-
875
+
876
+ # Reloads the browser's current +location+ using JavaScript
877
+ #
878
+ # Examples:
879
+ #
880
+ # # Generates: window.location.reload();
881
+ # page.reload
882
+ def reload
883
+ record 'window.location.reload()'
884
+ end
885
+
871
886
  # Calls the JavaScript +function+, optionally with the given +arguments+.
872
887
  #
873
888
  # If a block is given, the block will be passed to a new JavaScriptGenerator;
874
- # the resulting JavaScript code will then be wrapped inside <tt>function() { ... }</tt>
889
+ # the resulting JavaScript code will then be wrapped inside <tt>function() { ... }</tt>
875
890
  # and passed as the called function's final argument.
876
- #
891
+ #
877
892
  # Examples:
878
893
  #
879
894
  # # Generates: Element.replace(my_element, "My content to replace with.")
880
895
  # page.call 'Element.replace', 'my_element', "My content to replace with."
881
- #
896
+ #
882
897
  # # Generates: alert('My message!')
883
898
  # page.call 'alert', 'My message!'
884
- #
899
+ #
885
900
  # # Generates:
886
901
  # # my_method(function() {
887
902
  # # $("one").show();
@@ -894,7 +909,7 @@ module ActionView
894
909
  def call(function, *arguments, &block)
895
910
  record "#{function}(#{arguments_for_call(arguments, block)})"
896
911
  end
897
-
912
+
898
913
  # Assigns the JavaScript +variable+ the given +value+.
899
914
  #
900
915
  # Examples:
@@ -905,13 +920,13 @@ module ActionView
905
920
  # # Generates: record_count = 33;
906
921
  # page.assign 'record_count', 33
907
922
  #
908
- # # Generates: tabulated_total = 47
923
+ # # Generates: tabulated_total = 47
909
924
  # page.assign 'tabulated_total', @total_from_cart
910
925
  #
911
926
  def assign(variable, value)
912
927
  record "#{variable} = #{javascript_object_for(value)}"
913
928
  end
914
-
929
+
915
930
  # Writes raw JavaScript to the page.
916
931
  #
917
932
  # Example:
@@ -920,10 +935,10 @@ module ActionView
920
935
  def <<(javascript)
921
936
  @lines << javascript
922
937
  end
923
-
938
+
924
939
  # Executes the content of the block after a delay of +seconds+. Example:
925
940
  #
926
- # # Generates:
941
+ # # Generates:
927
942
  # # setTimeout(function() {
928
943
  # # ;
929
944
  # # new Effect.Fade("notice",{});
@@ -936,13 +951,13 @@ module ActionView
936
951
  yield
937
952
  record "}, #{(seconds * 1000).to_i})"
938
953
  end
939
-
940
- # Starts a script.aculo.us visual effect. See
954
+
955
+ # Starts a script.aculo.us visual effect. See
941
956
  # ActionView::Helpers::ScriptaculousHelper for more information.
942
957
  def visual_effect(name, id = nil, options = {})
943
958
  record @context.send(:visual_effect, name, id, options)
944
959
  end
945
-
960
+
946
961
  # Creates a script.aculo.us sortable element. Useful
947
962
  # to recreate sortable elements after items get added
948
963
  # or deleted.
@@ -950,66 +965,66 @@ module ActionView
950
965
  def sortable(id, options = {})
951
966
  record @context.send(:sortable_element_js, id, options)
952
967
  end
953
-
968
+
954
969
  # Creates a script.aculo.us draggable element.
955
970
  # See ActionView::Helpers::ScriptaculousHelper for more information.
956
971
  def draggable(id, options = {})
957
972
  record @context.send(:draggable_element_js, id, options)
958
973
  end
959
-
974
+
960
975
  # Creates a script.aculo.us drop receiving element.
961
976
  # See ActionView::Helpers::ScriptaculousHelper for more information.
962
977
  def drop_receiving(id, options = {})
963
978
  record @context.send(:drop_receiving_element_js, id, options)
964
979
  end
965
-
980
+
966
981
  private
967
982
  def loop_on_multiple_args(method, ids)
968
- record(ids.size>1 ?
969
- "#{javascript_object_for(ids)}.each(#{method})" :
983
+ record(ids.size>1 ?
984
+ "#{javascript_object_for(ids)}.each(#{method})" :
970
985
  "#{method}(#{ids.first.to_json})")
971
986
  end
972
-
987
+
973
988
  def page
974
989
  self
975
990
  end
976
-
991
+
977
992
  def record(line)
978
993
  returning line = "#{line.to_s.chomp.gsub(/\;\z/, '')};" do
979
994
  self << line
980
995
  end
981
996
  end
982
-
997
+
983
998
  def render(*options_for_render)
984
999
  old_format = @context && @context.template_format
985
1000
  @context.template_format = :html if @context
986
- Hash === options_for_render.first ?
987
- @context.render(*options_for_render) :
1001
+ Hash === options_for_render.first ?
1002
+ @context.render(*options_for_render) :
988
1003
  options_for_render.first.to_s
989
1004
  ensure
990
1005
  @context.template_format = old_format if @context
991
1006
  end
992
-
1007
+
993
1008
  def javascript_object_for(object)
994
1009
  object.respond_to?(:to_json) ? object.to_json : object.inspect
995
1010
  end
996
-
1011
+
997
1012
  def arguments_for_call(arguments, block = nil)
998
1013
  arguments << block_to_function(block) if block
999
1014
  arguments.map { |argument| javascript_object_for(argument) }.join ', '
1000
1015
  end
1001
-
1016
+
1002
1017
  def block_to_function(block)
1003
1018
  generator = self.class.new(@context, &block)
1004
1019
  literal("function() { #{generator.to_s} }")
1005
- end
1020
+ end
1006
1021
 
1007
1022
  def method_missing(method, *arguments)
1008
1023
  JavaScriptProxy.new(self, method.to_s.camelize)
1009
1024
  end
1010
1025
  end
1011
1026
  end
1012
-
1027
+
1013
1028
  # Yields a JavaScriptGenerator and returns the generated JavaScript code.
1014
1029
  # Use this to update multiple elements on a page in an Ajax response.
1015
1030
  # See JavaScriptGenerator for more information.
@@ -1022,13 +1037,13 @@ module ActionView
1022
1037
  def update_page(&block)
1023
1038
  JavaScriptGenerator.new(@template, &block).to_s
1024
1039
  end
1025
-
1040
+
1026
1041
  # Works like update_page but wraps the generated JavaScript in a <script>
1027
1042
  # tag. Use this to include generated JavaScript in an ERb template.
1028
1043
  # See JavaScriptGenerator for more information.
1029
1044
  #
1030
1045
  # +html_options+ may be a hash of <script> attributes to be passed
1031
- # to ActionView::Helpers::JavaScriptHelper#javascript_tag.
1046
+ # to ActionView::Helpers::JavaScriptHelper#javascript_tag.
1032
1047
  def update_page_tag(html_options = {}, &block)
1033
1048
  javascript_tag update_page(&block), html_options
1034
1049
  end
@@ -1036,7 +1051,7 @@ module ActionView
1036
1051
  protected
1037
1052
  def options_for_ajax(options)
1038
1053
  js_options = build_callbacks(options)
1039
-
1054
+
1040
1055
  js_options['asynchronous'] = options[:type] != :synchronous
1041
1056
  js_options['method'] = method_option_to_s(options[:method]) if options[:method]
1042
1057
  js_options['insertion'] = "'#{options[:position].to_s.downcase}'" if options[:position]
@@ -1049,7 +1064,7 @@ module ActionView
1049
1064
  elsif options[:with]
1050
1065
  js_options['parameters'] = options[:with]
1051
1066
  end
1052
-
1067
+
1053
1068
  if protect_against_forgery? && !options[:form]
1054
1069
  if js_options['parameters']
1055
1070
  js_options['parameters'] << " + '&"
@@ -1058,14 +1073,14 @@ module ActionView
1058
1073
  end
1059
1074
  js_options['parameters'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
1060
1075
  end
1061
-
1076
+
1062
1077
  options_for_javascript(js_options)
1063
1078
  end
1064
1079
 
1065
- def method_option_to_s(method)
1080
+ def method_option_to_s(method)
1066
1081
  (method.is_a?(String) and !method.index("'").nil?) ? method : "'#{method}'"
1067
1082
  end
1068
-
1083
+
1069
1084
  def build_observer(klass, name, options = {})
1070
1085
  if options[:with] && (options[:with] !~ /[\{=(.]/)
1071
1086
  options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)"
@@ -1082,7 +1097,7 @@ module ActionView
1082
1097
  javascript << ")"
1083
1098
  javascript_tag(javascript)
1084
1099
  end
1085
-
1100
+
1086
1101
  def build_callbacks(options)
1087
1102
  callbacks = {}
1088
1103
  options.each do |callback, code|
@@ -1095,7 +1110,7 @@ module ActionView
1095
1110
  end
1096
1111
  end
1097
1112
 
1098
- # Converts chained method calls on DOM proxy elements into JavaScript chains
1113
+ # Converts chained method calls on DOM proxy elements into JavaScript chains
1099
1114
  class JavaScriptProxy < ActiveSupport::BasicObject #:nodoc:
1100
1115
 
1101
1116
  def initialize(generator, root = nil)
@@ -1111,7 +1126,7 @@ module ActionView
1111
1126
  call("#{method.to_s.camelize(:lower)}", *arguments, &block)
1112
1127
  end
1113
1128
  end
1114
-
1129
+
1115
1130
  def call(function, *arguments, &block)
1116
1131
  append_to_function_chain!("#{function}(#{@generator.send(:arguments_for_call, arguments, block)})")
1117
1132
  self
@@ -1120,23 +1135,23 @@ module ActionView
1120
1135
  def assign(variable, value)
1121
1136
  append_to_function_chain!("#{variable} = #{@generator.send(:javascript_object_for, value)}")
1122
1137
  end
1123
-
1138
+
1124
1139
  def function_chain
1125
1140
  @function_chain ||= @generator.instance_variable_get(:@lines)
1126
1141
  end
1127
-
1142
+
1128
1143
  def append_to_function_chain!(call)
1129
1144
  function_chain[-1].chomp!(';')
1130
1145
  function_chain[-1] += ".#{call};"
1131
1146
  end
1132
1147
  end
1133
-
1148
+
1134
1149
  class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
1135
1150
  def initialize(generator, id)
1136
1151
  @id = id
1137
1152
  super(generator, "$(#{id.to_json})")
1138
1153
  end
1139
-
1154
+
1140
1155
  # Allows access of element attributes through +attribute+. Examples:
1141
1156
  #
1142
1157
  # page['foo']['style'] # => $('foo').style;
@@ -1147,11 +1162,11 @@ module ActionView
1147
1162
  append_to_function_chain!(attribute)
1148
1163
  self
1149
1164
  end
1150
-
1165
+
1151
1166
  def []=(variable, value)
1152
1167
  assign(variable, value)
1153
1168
  end
1154
-
1169
+
1155
1170
  def replace_html(*options_for_render)
1156
1171
  call 'update', @generator.send(:render, *options_for_render)
1157
1172
  end
@@ -1159,11 +1174,11 @@ module ActionView
1159
1174
  def replace(*options_for_render)
1160
1175
  call 'replace', @generator.send(:render, *options_for_render)
1161
1176
  end
1162
-
1177
+
1163
1178
  def reload(options_for_replace = {})
1164
1179
  replace(options_for_replace.merge({ :partial => @id.to_s }))
1165
1180
  end
1166
-
1181
+
1167
1182
  end
1168
1183
 
1169
1184
  class JavaScriptVariableProxy < JavaScriptProxy #:nodoc:
@@ -1182,7 +1197,7 @@ module ActionView
1182
1197
  def to_json(options = nil)
1183
1198
  @variable
1184
1199
  end
1185
-
1200
+
1186
1201
  private
1187
1202
  def append_to_function_chain!(call)
1188
1203
  @generator << @variable if @empty
@@ -1200,7 +1215,7 @@ module ActionView
1200
1215
  def initialize(generator, pattern)
1201
1216
  super(generator, @pattern = pattern)
1202
1217
  end
1203
-
1218
+
1204
1219
  def each_slice(variable, number, &block)
1205
1220
  if block
1206
1221
  enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block
@@ -1209,18 +1224,18 @@ module ActionView
1209
1224
  append_enumerable_function!("eachSlice(#{number.to_json});")
1210
1225
  end
1211
1226
  end
1212
-
1227
+
1213
1228
  def grep(variable, pattern, &block)
1214
1229
  enumerate :grep, :variable => variable, :return => true, :method_args => [pattern], :yield_args => %w(value index), &block
1215
1230
  end
1216
-
1231
+
1217
1232
  def in_groups_of(variable, number, fill_with = nil)
1218
1233
  arguments = [number]
1219
1234
  arguments << fill_with unless fill_with.nil?
1220
1235
  add_variable_assignment!(variable)
1221
1236
  append_enumerable_function!("inGroupsOf(#{arguments_for_call arguments});")
1222
- end
1223
-
1237
+ end
1238
+
1224
1239
  def inject(variable, memo, &block)
1225
1240
  enumerate :inject, :variable => variable, :method_args => [memo], :yield_args => %w(memo value index), :return => true, &block
1226
1241
  end
@@ -1282,13 +1297,13 @@ module ActionView
1282
1297
  function_chain.push("return #{function_chain.pop.chomp(';')};")
1283
1298
  end
1284
1299
  end
1285
-
1300
+
1286
1301
  def append_enumerable_function!(call)
1287
1302
  function_chain[-1].chomp!(';')
1288
1303
  function_chain[-1] += ".#{call}"
1289
1304
  end
1290
1305
  end
1291
-
1306
+
1292
1307
  class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
1293
1308
  def initialize(generator, pattern)
1294
1309
  super(generator, "$$(#{pattern.to_json})")