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.
- data/CHANGELOG +223 -7
- data/README +6 -12
- data/Rakefile +11 -11
- data/lib/action_controller.rb +9 -9
- data/lib/action_controller/assertions/response_assertions.rb +29 -78
- data/lib/action_controller/assertions/routing_assertions.rb +33 -33
- data/lib/action_controller/assertions/selector_assertions.rb +9 -5
- data/lib/action_controller/base.rb +227 -161
- data/lib/action_controller/benchmarking.rb +37 -24
- data/lib/action_controller/caching/actions.rb +53 -21
- data/lib/action_controller/caching/fragments.rb +10 -36
- data/lib/action_controller/caching/sweeping.rb +3 -3
- data/lib/action_controller/cgi_ext/session.rb +2 -22
- data/lib/action_controller/cgi_process.rb +8 -46
- data/lib/action_controller/components.rb +4 -1
- data/lib/action_controller/cookies.rb +10 -0
- data/lib/action_controller/dispatcher.rb +49 -15
- data/lib/action_controller/filters.rb +48 -10
- data/lib/action_controller/headers.rb +16 -14
- data/lib/action_controller/helpers.rb +2 -2
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +57 -60
- data/lib/action_controller/layout.rb +27 -53
- data/lib/action_controller/mime_responds.rb +5 -1
- data/lib/action_controller/mime_type.rb +64 -42
- data/lib/action_controller/mime_types.rb +2 -1
- data/lib/action_controller/performance_test.rb +16 -0
- data/lib/action_controller/polymorphic_routes.rb +16 -9
- data/lib/action_controller/rack_process.rb +303 -0
- data/lib/action_controller/request.rb +205 -97
- data/lib/action_controller/request_forgery_protection.rb +2 -2
- data/lib/action_controller/request_profiler.rb +0 -0
- data/lib/action_controller/rescue.rb +20 -115
- data/lib/action_controller/resources.rb +186 -83
- data/lib/action_controller/response.rb +140 -26
- data/lib/action_controller/routing.rb +28 -30
- data/lib/action_controller/routing/builder.rb +45 -54
- data/lib/action_controller/routing/optimisations.rb +31 -21
- data/lib/action_controller/routing/recognition_optimisation.rb +33 -27
- data/lib/action_controller/routing/route.rb +162 -147
- data/lib/action_controller/routing/route_set.rb +8 -7
- data/lib/action_controller/routing/routing_ext.rb +4 -1
- data/lib/action_controller/routing/segments.rb +50 -21
- data/lib/action_controller/session/cookie_store.rb +3 -2
- data/lib/action_controller/session/drb_server.rb +7 -7
- data/lib/action_controller/session_management.rb +6 -2
- data/lib/action_controller/streaming.rb +15 -8
- data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
- data/lib/action_controller/templates/rescues/template_error.erb +2 -2
- data/lib/action_controller/test_case.rb +66 -2
- data/lib/action_controller/test_process.rb +71 -66
- data/lib/action_controller/translation.rb +13 -0
- data/lib/action_controller/url_rewriter.rb +90 -13
- data/lib/action_controller/vendor/html-scanner/html/node.rb +9 -2
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -2
- data/lib/action_controller/verification.rb +2 -2
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view.rb +19 -11
- data/lib/action_view/base.rb +184 -150
- data/lib/action_view/helpers.rb +38 -0
- data/lib/action_view/helpers/active_record_helper.rb +56 -27
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -153
- data/lib/action_view/helpers/atom_feed_helper.rb +74 -19
- data/lib/action_view/helpers/benchmark_helper.rb +3 -3
- data/lib/action_view/helpers/cache_helper.rb +1 -2
- data/lib/action_view/helpers/capture_helper.rb +19 -44
- data/lib/action_view/helpers/date_helper.rb +486 -296
- data/lib/action_view/helpers/debug_helper.rb +20 -13
- data/lib/action_view/helpers/form_helper.rb +71 -30
- data/lib/action_view/helpers/form_options_helper.rb +15 -85
- data/lib/action_view/helpers/form_tag_helper.rb +61 -38
- data/lib/action_view/helpers/javascript_helper.rb +80 -89
- data/lib/action_view/helpers/number_helper.rb +179 -74
- data/lib/action_view/helpers/prototype_helper.rb +216 -201
- data/lib/action_view/helpers/record_tag_helper.rb +4 -5
- data/lib/action_view/helpers/sanitize_helper.rb +65 -33
- data/lib/action_view/helpers/scriptaculous_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +39 -22
- data/lib/action_view/helpers/text_helper.rb +212 -118
- data/lib/action_view/helpers/translation_helper.rb +21 -0
- data/lib/action_view/helpers/url_helper.rb +100 -58
- data/lib/action_view/inline_template.rb +13 -14
- data/lib/action_view/locale/en.yml +91 -0
- data/lib/action_view/partials.rb +100 -55
- data/lib/action_view/paths.rb +125 -0
- data/lib/action_view/renderable.rb +102 -0
- data/lib/action_view/renderable_partial.rb +48 -0
- data/lib/action_view/template.rb +90 -101
- data/lib/action_view/template_error.rb +11 -21
- data/lib/action_view/template_handler.rb +8 -28
- data/lib/action_view/template_handlers.rb +45 -0
- data/lib/action_view/template_handlers/builder.rb +5 -15
- data/lib/action_view/template_handlers/erb.rb +9 -6
- data/lib/action_view/template_handlers/rjs.rb +2 -17
- data/lib/action_view/test_case.rb +7 -4
- data/test/abstract_unit.rb +4 -1
- data/test/active_record_unit.rb +28 -30
- data/test/activerecord/render_partial_with_record_identification_test.rb +25 -12
- data/test/controller/action_pack_assertions_test.rb +8 -37
- data/test/controller/addresses_render_test.rb +0 -3
- data/test/controller/assert_select_test.rb +51 -24
- data/test/controller/base_test.rb +4 -4
- data/test/controller/caching_test.rb +136 -66
- data/test/controller/capture_test.rb +1 -21
- data/test/controller/cgi_test.rb +157 -10
- data/test/controller/components_test.rb +41 -25
- data/test/controller/content_type_test.rb +49 -17
- data/test/controller/cookie_test.rb +1 -1
- data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -3
- data/test/controller/dispatcher_test.rb +9 -1
- data/test/controller/filter_params_test.rb +2 -2
- data/test/controller/filters_test.rb +13 -13
- data/test/controller/html-scanner/cdata_node_test.rb +15 -0
- data/test/controller/html-scanner/node_test.rb +21 -0
- data/test/controller/html-scanner/sanitizer_test.rb +14 -0
- data/test/controller/integration_test.rb +167 -6
- data/test/controller/layout_test.rb +11 -68
- data/test/controller/logging_test.rb +46 -0
- data/test/controller/mime_responds_test.rb +61 -59
- data/test/controller/mime_type_test.rb +6 -6
- data/test/controller/polymorphic_routes_test.rb +37 -2
- data/test/controller/rack_test.rb +323 -0
- data/test/controller/redirect_test.rb +72 -71
- data/test/controller/render_test.rb +1120 -108
- data/test/controller/request_forgery_protection_test.rb +66 -52
- data/test/controller/request_test.rb +103 -146
- data/test/controller/rescue_test.rb +20 -24
- data/test/controller/resources_test.rb +408 -25
- data/test/controller/routing_test.rb +1774 -1774
- data/test/controller/send_file_test.rb +0 -4
- data/test/controller/session/cookie_store_test.rb +53 -1
- data/test/controller/test_test.rb +15 -37
- data/test/controller/translation_test.rb +26 -0
- data/test/controller/url_rewriter_test.rb +27 -28
- data/test/controller/view_paths_test.rb +48 -47
- data/test/fixtures/_top_level_partial.html.erb +1 -0
- data/test/fixtures/_top_level_partial_only.erb +1 -0
- data/test/fixtures/developers/_developer.erb +1 -0
- data/test/fixtures/fun/games/_game.erb +1 -0
- data/test/fixtures/fun/serious/games/_game.erb +1 -0
- data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
- data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
- data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
- data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
- data/test/fixtures/layouts/_column.html.erb +2 -0
- data/test/fixtures/projects/_project.erb +1 -0
- data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
- data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
- data/test/fixtures/replies/_reply.erb +1 -0
- data/test/fixtures/test/_counter.html.erb +1 -0
- data/test/fixtures/test/_customer.erb +1 -1
- data/test/fixtures/test/_customer_with_var.erb +1 -0
- data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
- data/test/fixtures/test/_local_inspector.html.erb +1 -0
- data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
- data/test/fixtures/test/hello.builder +1 -1
- data/test/fixtures/test/hyphen-ated.erb +1 -0
- data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
- data/test/fixtures/test/nested_layout.erb +3 -0
- data/test/fixtures/test/non_erb_block_content_for.builder +1 -1
- data/test/fixtures/test/sub_template_raise.html.erb +1 -0
- data/test/fixtures/test/template.erb +1 -0
- data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
- data/test/template/active_record_helper_i18n_test.rb +46 -0
- data/test/template/active_record_helper_test.rb +24 -24
- data/test/template/asset_tag_helper_test.rb +161 -29
- data/test/template/atom_feed_helper_test.rb +114 -5
- data/test/template/compiled_templates_test.rb +59 -0
- data/test/template/date_helper_i18n_test.rb +113 -0
- data/test/template/date_helper_test.rb +403 -109
- data/test/template/form_helper_test.rb +213 -154
- data/test/template/form_options_helper_test.rb +249 -897
- data/test/template/form_tag_helper_test.rb +80 -32
- data/test/template/javascript_helper_test.rb +17 -18
- data/test/template/number_helper_i18n_test.rb +54 -0
- data/test/template/number_helper_test.rb +43 -13
- data/test/template/prototype_helper_test.rb +101 -84
- data/test/template/record_tag_helper_test.rb +24 -20
- data/test/template/render_test.rb +193 -0
- data/test/template/sanitize_helper_test.rb +3 -3
- data/test/template/tag_helper_test.rb +34 -14
- data/test/template/text_helper_test.rb +83 -9
- data/test/template/translation_helper_test.rb +28 -0
- data/test/template/url_helper_test.rb +55 -18
- metadata +57 -18
- data/lib/action_view/helpers/javascripts/controls.js +0 -963
- data/lib/action_view/helpers/javascripts/dragdrop.js +0 -972
- data/lib/action_view/helpers/javascripts/effects.js +0 -1120
- data/lib/action_view/helpers/javascripts/prototype.js +0 -4225
- data/lib/action_view/partial_template.rb +0 -70
- data/lib/action_view/template_finder.rb +0 -177
- data/lib/action_view/template_handlers/compilable.rb +0 -128
- data/test/controller/custom_handler_test.rb +0 -45
- data/test/controller/new_render_test.rb +0 -945
- data/test/fixtures/test/block_content_for.erb +0 -2
- data/test/fixtures/test/erb_content_for.erb +0 -2
- data/test/template/deprecated_erb_variable_test.rb +0 -9
- data/test/template/template_finder_test.rb +0 -73
- 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
|
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)
|
393
|
+
concat(form_remote_tag(options))
|
386
394
|
fields_for(object_name, *(args << options), &proc)
|
387
|
-
concat('</form>'
|
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
|
416
|
-
|
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
|
-
|
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.
|
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.
|
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})")
|