actionpack 1.13.6 → 2.0.0
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 +1400 -20
- data/MIT-LICENSE +1 -1
- data/README +5 -5
- data/RUNNING_UNIT_TESTS +4 -5
- data/Rakefile +5 -6
- data/install.rb +2 -2
- data/lib/action_controller.rb +11 -15
- data/lib/action_controller/assertions.rb +12 -25
- data/lib/action_controller/assertions/dom_assertions.rb +18 -4
- data/lib/action_controller/assertions/model_assertions.rb +8 -1
- data/lib/action_controller/assertions/response_assertions.rb +35 -12
- data/lib/action_controller/assertions/routing_assertions.rb +56 -12
- data/lib/action_controller/assertions/selector_assertions.rb +105 -38
- data/lib/action_controller/assertions/tag_assertions.rb +28 -15
- data/lib/action_controller/base.rb +318 -250
- data/lib/action_controller/benchmarking.rb +33 -29
- data/lib/action_controller/caching.rb +130 -64
- data/lib/action_controller/cgi_ext.rb +16 -0
- data/lib/action_controller/cgi_ext/{cookie_performance_fix.rb → cookie.rb} +25 -40
- data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
- data/lib/action_controller/cgi_ext/session.rb +73 -0
- data/lib/action_controller/cgi_ext/stdinput.rb +23 -0
- data/lib/action_controller/cgi_process.rb +34 -57
- data/lib/action_controller/components.rb +19 -36
- data/lib/action_controller/cookies.rb +10 -9
- data/lib/action_controller/dispatcher.rb +195 -0
- data/lib/action_controller/filters.rb +35 -34
- data/lib/action_controller/flash.rb +30 -35
- data/lib/action_controller/helpers.rb +121 -47
- data/lib/action_controller/http_authentication.rb +126 -0
- data/lib/action_controller/integration.rb +105 -101
- data/lib/action_controller/layout.rb +59 -47
- data/lib/action_controller/mime_responds.rb +57 -68
- data/lib/action_controller/mime_type.rb +43 -80
- data/lib/action_controller/mime_types.rb +20 -0
- data/lib/action_controller/polymorphic_routes.rb +88 -0
- data/lib/action_controller/record_identifier.rb +91 -0
- data/lib/action_controller/request.rb +553 -88
- data/lib/action_controller/request_forgery_protection.rb +126 -0
- data/lib/action_controller/request_profiler.rb +138 -0
- data/lib/action_controller/rescue.rb +185 -69
- data/lib/action_controller/resources.rb +211 -172
- data/lib/action_controller/response.rb +49 -8
- data/lib/action_controller/routing.rb +359 -236
- data/lib/action_controller/routing_optimisation.rb +119 -0
- data/lib/action_controller/session/active_record_store.rb +3 -2
- data/lib/action_controller/session/cookie_store.rb +161 -0
- data/lib/action_controller/session/mem_cache_store.rb +9 -16
- data/lib/action_controller/session_management.rb +17 -8
- data/lib/action_controller/streaming.rb +6 -3
- data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
- data/lib/action_controller/templates/rescues/{_trace.rhtml → _trace.erb} +0 -0
- data/lib/action_controller/templates/rescues/{diagnostics.rhtml → diagnostics.erb} +2 -2
- data/lib/action_controller/templates/rescues/{layout.rhtml → layout.erb} +0 -0
- data/lib/action_controller/templates/rescues/{missing_template.rhtml → missing_template.erb} +0 -0
- data/lib/action_controller/templates/rescues/{routing_error.rhtml → routing_error.erb} +0 -0
- data/lib/action_controller/templates/rescues/{template_error.rhtml → template_error.erb} +2 -2
- data/lib/action_controller/templates/rescues/{unknown_action.rhtml → unknown_action.erb} +0 -0
- data/lib/action_controller/test_case.rb +53 -0
- data/lib/action_controller/test_process.rb +59 -46
- data/lib/action_controller/url_rewriter.rb +48 -24
- data/lib/action_controller/vendor/html-scanner/html/document.rb +7 -4
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +11 -6
- data/lib/action_controller/verification.rb +27 -21
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +4 -4
- data/lib/action_view.rb +2 -3
- data/lib/action_view/base.rb +218 -63
- data/lib/action_view/compiled_templates.rb +1 -2
- data/lib/action_view/helpers/active_record_helper.rb +35 -17
- data/lib/action_view/helpers/asset_tag_helper.rb +395 -87
- data/lib/action_view/helpers/atom_feed_helper.rb +111 -0
- data/lib/action_view/helpers/benchmark_helper.rb +12 -5
- data/lib/action_view/helpers/cache_helper.rb +29 -0
- data/lib/action_view/helpers/capture_helper.rb +97 -63
- data/lib/action_view/helpers/date_helper.rb +295 -35
- data/lib/action_view/helpers/debug_helper.rb +6 -2
- data/lib/action_view/helpers/form_helper.rb +354 -111
- data/lib/action_view/helpers/form_options_helper.rb +171 -109
- data/lib/action_view/helpers/form_tag_helper.rb +332 -76
- data/lib/action_view/helpers/javascript_helper.rb +35 -11
- data/lib/action_view/helpers/javascripts/controls.js +484 -354
- data/lib/action_view/helpers/javascripts/dragdrop.js +88 -58
- data/lib/action_view/helpers/javascripts/effects.js +396 -364
- data/lib/action_view/helpers/javascripts/prototype.js +2817 -1107
- data/lib/action_view/helpers/number_helper.rb +84 -60
- data/lib/action_view/helpers/prototype_helper.rb +419 -43
- data/lib/action_view/helpers/record_identification_helper.rb +20 -0
- data/lib/action_view/helpers/record_tag_helper.rb +59 -0
- data/lib/action_view/helpers/sanitize_helper.rb +223 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +63 -4
- data/lib/action_view/helpers/tag_helper.rb +69 -39
- data/lib/action_view/helpers/text_helper.rb +221 -148
- data/lib/action_view/helpers/url_helper.rb +283 -165
- data/lib/action_view/partials.rb +134 -62
- data/lib/action_view/template_error.rb +4 -12
- data/lib/actionpack.rb +1 -0
- data/test/abstract_unit.rb +21 -1
- data/test/action_view_test.rb +26 -0
- data/test/active_record_unit.rb +12 -20
- data/test/activerecord/active_record_store_test.rb +2 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +74 -0
- data/test/controller/action_pack_assertions_test.rb +21 -152
- data/test/controller/addresses_render_test.rb +2 -7
- data/test/controller/assert_select_test.rb +120 -14
- data/test/controller/base_test.rb +11 -13
- data/test/controller/caching_test.rb +125 -5
- data/test/controller/capture_test.rb +23 -16
- data/test/controller/cgi_test.rb +66 -391
- data/test/controller/components_test.rb +31 -42
- data/test/controller/content_type_test.rb +1 -1
- data/test/controller/cookie_test.rb +42 -14
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -42
- data/test/controller/dispatcher_test.rb +123 -0
- data/test/controller/fake_models.rb +5 -0
- data/test/controller/filters_test.rb +44 -7
- data/test/controller/flash_test.rb +46 -2
- data/test/controller/fragment_store_setting_test.rb +10 -8
- data/test/controller/helper_test.rb +19 -2
- data/test/controller/html-scanner/document_test.rb +124 -0
- data/test/controller/html-scanner/node_test.rb +69 -0
- data/test/controller/html-scanner/sanitizer_test.rb +250 -0
- data/test/controller/html-scanner/tag_node_test.rb +239 -0
- data/test/controller/html-scanner/text_node_test.rb +51 -0
- data/test/controller/html-scanner/tokenizer_test.rb +125 -0
- data/test/controller/http_authentication_test.rb +54 -0
- data/test/controller/integration_test.rb +12 -26
- data/test/controller/layout_test.rb +64 -12
- data/test/controller/mime_responds_test.rb +193 -38
- data/test/controller/mime_type_test.rb +30 -8
- data/test/controller/new_render_test.rb +104 -22
- data/test/controller/polymorphic_routes_test.rb +98 -0
- data/test/controller/record_identifier_test.rb +103 -0
- data/test/controller/redirect_test.rb +120 -18
- data/test/controller/render_test.rb +195 -45
- data/test/controller/request_forgery_protection_test.rb +217 -0
- data/test/controller/request_test.rb +545 -27
- data/test/controller/rescue_test.rb +501 -0
- data/test/controller/resources_test.rb +258 -132
- data/test/controller/routing_test.rb +502 -106
- data/test/controller/selector_test.rb +5 -5
- data/test/controller/send_file_test.rb +17 -7
- data/test/controller/session/cookie_store_test.rb +246 -0
- data/test/controller/session/mem_cache_store_test.rb +182 -0
- data/test/controller/session_fixation_test.rb +8 -11
- data/test/controller/session_management_test.rb +7 -7
- data/test/controller/test_test.rb +150 -38
- data/test/controller/url_rewriter_test.rb +87 -12
- data/test/controller/verification_test.rb +11 -0
- data/test/controller/view_paths_test.rb +137 -0
- data/test/controller/webservice_test.rb +11 -75
- data/test/fixtures/addresses/{list.rhtml → list.erb} +0 -0
- data/test/fixtures/db_definitions/sqlite.sql +2 -1
- data/test/fixtures/developer.rb +2 -0
- data/test/fixtures/fun/games/{hello_world.rhtml → hello_world.erb} +0 -0
- data/test/fixtures/helpers/fun/pdf_helper.rb +1 -1
- data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
- data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
- data/test/fixtures/layouts/{builder.rxml → builder.builder} +0 -0
- data/test/fixtures/layouts/{standard.rhtml → standard.erb} +0 -0
- data/test/fixtures/layouts/{talk_from_action.rhtml → talk_from_action.erb} +0 -0
- data/test/fixtures/layouts/{yield.rhtml → yield.erb} +0 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/multipart/bracketed_param +5 -0
- data/test/fixtures/override/test/hello_world.erb +1 -0
- data/test/fixtures/override2/layouts/test/sub.erb +1 -0
- data/test/fixtures/post_test/layouts/post.html.erb +1 -0
- data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
- data/test/fixtures/post_test/post/index.html.erb +1 -0
- data/test/fixtures/post_test/post/index.iphone.erb +1 -0
- data/test/fixtures/post_test/super_post/index.html.erb +1 -0
- data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
- data/test/fixtures/public/404.html +1 -0
- data/test/fixtures/public/500.html +1 -0
- data/test/fixtures/public/javascripts/application.js +0 -1
- data/test/fixtures/public/javascripts/bank.js +1 -0
- data/test/fixtures/public/javascripts/robber.js +1 -0
- data/test/fixtures/public/stylesheets/bank.css +1 -0
- data/test/fixtures/public/stylesheets/robber.css +1 -0
- data/test/fixtures/replies.yml +2 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/respond_to/{all_types_with_layout.rhtml → all_types_with_layout.html.erb} +0 -0
- data/test/fixtures/respond_to/{all_types_with_layout.rjs → all_types_with_layout.js.rjs} +0 -0
- data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
- data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
- data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
- data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
- data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
- data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
- data/test/fixtures/respond_to/{using_defaults.rhtml → using_defaults.html.erb} +0 -0
- data/test/fixtures/respond_to/{using_defaults.rjs → using_defaults.js.rjs} +0 -0
- data/test/fixtures/respond_to/{using_defaults.rxml → using_defaults.xml.builder} +0 -0
- data/test/fixtures/respond_to/{using_defaults_with_type_list.rhtml → using_defaults_with_type_list.html.erb} +0 -0
- data/test/fixtures/respond_to/{using_defaults_with_type_list.rjs → using_defaults_with_type_list.js.rjs} +0 -0
- data/test/fixtures/respond_to/{using_defaults_with_type_list.rxml → using_defaults_with_type_list.xml.builder} +0 -0
- data/test/fixtures/scope/test/{modgreet.rhtml → modgreet.erb} +0 -0
- data/test/fixtures/test/{_customer.rhtml → _customer.erb} +0 -0
- data/test/fixtures/test/{_customer_greeting.rhtml → _customer_greeting.erb} +0 -0
- data/test/fixtures/test/_hash_greeting.erb +1 -0
- data/test/fixtures/test/_hash_object.erb +2 -0
- data/test/fixtures/test/{_hello.rxml → _hello.builder} +0 -0
- data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
- data/test/fixtures/test/_partial.erb +1 -0
- data/test/fixtures/test/_partial.html.erb +1 -0
- data/test/fixtures/test/_partial.js.erb +1 -0
- data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
- data/test/fixtures/test/{_partial_only.rhtml → _partial_only.erb} +0 -0
- data/test/fixtures/test/{_person.rhtml → _person.erb} +0 -0
- data/test/fixtures/test/{action_talk_to_layout.rhtml → action_talk_to_layout.erb} +0 -0
- data/test/fixtures/test/{block_content_for.rhtml → block_content_for.erb} +0 -0
- data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
- data/test/fixtures/test/{capturing.rhtml → capturing.erb} +0 -0
- data/test/fixtures/test/{content_for.rhtml → content_for.erb} +0 -0
- data/test/fixtures/test/content_for_concatenated.erb +3 -0
- data/test/fixtures/test/content_for_with_parameter.erb +2 -0
- data/test/fixtures/test/dot.directory/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
- data/test/fixtures/test/{erb_content_for.rhtml → erb_content_for.erb} +0 -0
- data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
- data/test/fixtures/test/formatted_xml_erb.builder +1 -0
- data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
- data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
- data/test/fixtures/test/{greeting.rhtml → greeting.erb} +0 -0
- data/test/fixtures/test/{hello.rxml → hello.builder} +0 -0
- data/test/fixtures/test/{hello_world.rxml → hello_world.builder} +0 -0
- data/test/fixtures/test/{hello_world.rhtml → hello_world.erb} +0 -0
- data/test/fixtures/test/{hello_world_container.rxml → hello_world_container.builder} +0 -0
- data/test/fixtures/test/{hello_world_with_layout_false.rhtml → hello_world_with_layout_false.erb} +0 -0
- data/test/fixtures/test/{hello_xml_world.rxml → hello_xml_world.builder} +0 -0
- data/test/fixtures/test/list.erb +1 -0
- data/test/fixtures/test/{non_erb_block_content_for.rxml → non_erb_block_content_for.builder} +0 -0
- data/test/fixtures/test/{potential_conflicts.rhtml → potential_conflicts.erb} +0 -0
- data/test/fixtures/test/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
- data/test/fixtures/test/{render_file_with_locals.rhtml → render_file_with_locals.erb} +0 -0
- data/test/fixtures/test/{render_to_string_test.rhtml → render_to_string_test.erb} +0 -0
- data/test/fixtures/test/{update_element_with_capture.rhtml → update_element_with_capture.erb} +0 -0
- data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
- data/test/fixtures/topic.rb +1 -1
- data/test/template/active_record_helper_test.rb +67 -20
- data/test/template/asset_tag_helper_test.rb +222 -54
- data/test/template/atom_feed_helper_test.rb +101 -0
- data/test/template/benchmark_helper_test.rb +2 -2
- data/test/template/compiled_templates_test.rb +76 -32
- data/test/template/date_helper_test.rb +125 -9
- data/test/template/form_helper_test.rb +326 -33
- data/test/template/form_options_helper_test.rb +822 -15
- data/test/template/form_tag_helper_test.rb +96 -30
- data/test/template/javascript_helper_test.rb +61 -13
- data/test/template/number_helper_test.rb +12 -11
- data/test/template/prototype_helper_test.rb +185 -24
- data/test/template/sanitize_helper_test.rb +49 -0
- data/test/template/scriptaculous_helper_test.rb +9 -3
- data/test/template/tag_helper_test.rb +13 -2
- data/test/template/text_helper_test.rb +38 -52
- data/test/template/url_helper_test.rb +216 -46
- metadata +144 -116
- data/examples/.htaccess +0 -24
- data/examples/address_book/index.rhtml +0 -33
- data/examples/address_book/layout.rhtml +0 -8
- data/examples/address_book_controller.cgi +0 -9
- data/examples/address_book_controller.fcgi +0 -6
- data/examples/address_book_controller.rb +0 -52
- data/examples/address_book_controller.rbx +0 -4
- data/examples/benchmark.rb +0 -52
- data/examples/benchmark_with_ar.fcgi +0 -89
- data/examples/blog_controller.cgi +0 -53
- data/examples/debate/index.rhtml +0 -14
- data/examples/debate/new_topic.rhtml +0 -22
- data/examples/debate/topic.rhtml +0 -32
- data/examples/debate_controller.cgi +0 -57
- data/lib/action_controller/assertions/deprecated_assertions.rb +0 -228
- data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -36
- data/lib/action_controller/cgi_ext/cgi_methods.rb +0 -211
- data/lib/action_controller/cgi_ext/pstore_performance_fix.rb +0 -30
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +0 -95
- data/lib/action_controller/cgi_ext/session_performance_fix.rb +0 -30
- data/lib/action_controller/deprecated_dependencies.rb +0 -65
- data/lib/action_controller/deprecated_redirects.rb +0 -17
- data/lib/action_controller/deprecated_request_methods.rb +0 -34
- data/lib/action_controller/macros/auto_complete.rb +0 -53
- data/lib/action_controller/macros/in_place_editing.rb +0 -33
- data/lib/action_controller/pagination.rb +0 -408
- data/lib/action_controller/scaffolding.rb +0 -189
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +0 -44
- data/lib/action_controller/templates/scaffolds/edit.rhtml +0 -7
- data/lib/action_controller/templates/scaffolds/layout.rhtml +0 -69
- data/lib/action_controller/templates/scaffolds/list.rhtml +0 -27
- data/lib/action_controller/templates/scaffolds/new.rhtml +0 -6
- data/lib/action_controller/templates/scaffolds/show.rhtml +0 -9
- data/lib/action_controller/vendor/xml_node.rb +0 -97
- data/lib/action_view/helpers/deprecated_helper.rb +0 -37
- data/lib/action_view/helpers/java_script_macros_helper.rb +0 -233
- data/lib/action_view/helpers/pagination_helper.rb +0 -86
- data/test/activerecord/active_record_assertions_test.rb +0 -92
- data/test/activerecord/pagination_test.rb +0 -165
- data/test/controller/deprecated_instance_variables_test.rb +0 -48
- data/test/controller/raw_post_test.rb +0 -68
- data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +0 -1
- data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +0 -1
- data/test/fixtures/respond_to/layouts/standard.rhtml +0 -1
- data/test/fixtures/test/_hash_object.rhtml +0 -1
- data/test/fixtures/test/list.rhtml +0 -1
- data/test/template/deprecated_helper_test.rb +0 -36
- data/test/template/deprecated_instance_variables_test.rb +0 -43
- data/test/template/java_script_macros_helper_test.rb +0 -109
@@ -1,22 +1,28 @@
|
|
1
1
|
module ActionView
|
2
2
|
module Helpers #:nodoc:
|
3
|
-
# Provides methods for converting
|
3
|
+
# Provides methods for converting numbers into formatted strings.
|
4
4
|
# Methods are provided for phone numbers, currency, percentage,
|
5
5
|
# precision, positional notation, and file size.
|
6
6
|
module NumberHelper
|
7
|
-
# Formats a +number+ into a US phone number. You can customize the format
|
7
|
+
# Formats a +number+ into a US phone number (e.g., (555) 123-9876). You can customize the format
|
8
8
|
# in the +options+ hash.
|
9
|
+
#
|
10
|
+
# ==== Options
|
9
11
|
# * <tt>:area_code</tt> - Adds parentheses around the area code.
|
10
|
-
# * <tt>:delimiter</tt> - Specifies the delimiter to use
|
12
|
+
# * <tt>:delimiter</tt> - Specifies the delimiter to use (defaults to "-").
|
11
13
|
# * <tt>:extension</tt> - Specifies an extension to add to the end of the
|
12
|
-
# generated number
|
14
|
+
# generated number.
|
13
15
|
# * <tt>:country_code</tt> - Sets the country code for the phone number.
|
14
16
|
#
|
15
|
-
#
|
16
|
-
# number_to_phone(1235551234
|
17
|
-
# number_to_phone(1235551234, :
|
18
|
-
# number_to_phone(1235551234, :
|
19
|
-
# number_to_phone(1235551234, :
|
17
|
+
# ==== Examples
|
18
|
+
# number_to_phone(1235551234) # => 123-555-1234
|
19
|
+
# number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
|
20
|
+
# number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
|
21
|
+
# number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
|
22
|
+
# number_to_phone(1235551234, :country_code => 1) # => +1-123-555-1234
|
23
|
+
#
|
24
|
+
# number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
|
25
|
+
# => +1.123.555.1234 x 1343
|
20
26
|
def number_to_phone(number, options = {})
|
21
27
|
number = number.to_s.strip unless number.nil?
|
22
28
|
options = options.stringify_keys
|
@@ -40,25 +46,29 @@ module ActionView
|
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
43
|
-
# Formats a +number+ into a currency string. You can customize the format
|
49
|
+
# Formats a +number+ into a currency string (e.g., $13.65). You can customize the format
|
44
50
|
# in the +options+ hash.
|
45
|
-
# * <tt>:precision</tt> - Sets the level of precision, defaults to 2
|
46
|
-
# * <tt>:unit</tt> - Sets the denomination of the currency, defaults to "$"
|
47
|
-
# * <tt>:separator</tt> - Sets the separator between the units, defaults to "."
|
48
|
-
# * <tt>:delimiter</tt> - Sets the thousands delimiter, defaults to ","
|
49
51
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
52
|
+
# ==== Options
|
53
|
+
# * <tt>:precision</tt> - Sets the level of precision (defaults to 2).
|
54
|
+
# * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$").
|
55
|
+
# * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
|
56
|
+
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
|
57
|
+
#
|
58
|
+
# ==== Examples
|
59
|
+
# number_to_currency(1234567890.50) # => $1,234,567,890.50
|
60
|
+
# number_to_currency(1234567890.506) # => $1,234,567,890.51
|
61
|
+
# number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506
|
62
|
+
#
|
63
|
+
# number_to_currency(1234567890.50, :unit => "£", :separator => ",", :delimiter => "")
|
64
|
+
# # => £1234567890,50
|
55
65
|
def number_to_currency(number, options = {})
|
56
66
|
options = options.stringify_keys
|
57
67
|
precision = options["precision"] || 2
|
58
68
|
unit = options["unit"] || "$"
|
59
69
|
separator = precision > 0 ? options["separator"] || "." : ""
|
60
70
|
delimiter = options["delimiter"] || ","
|
61
|
-
|
71
|
+
|
62
72
|
begin
|
63
73
|
parts = number_with_precision(number, precision).split('.')
|
64
74
|
unit + number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s
|
@@ -67,19 +77,24 @@ module ActionView
|
|
67
77
|
end
|
68
78
|
end
|
69
79
|
|
70
|
-
# Formats a +number+ as a percentage string. You can customize the
|
80
|
+
# Formats a +number+ as a percentage string (e.g., 65%). You can customize the
|
71
81
|
# format in the +options+ hash.
|
72
|
-
# * <tt>:precision</tt> - Sets the level of precision, defaults to 3
|
73
|
-
# * <tt>:separator</tt> - Sets the separator between the units, defaults to "."
|
74
82
|
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
83
|
+
# ==== Options
|
84
|
+
# * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
|
85
|
+
# * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
|
86
|
+
#
|
87
|
+
# ==== Examples
|
88
|
+
# number_to_percentage(100) # => 100.000%
|
89
|
+
# number_to_percentage(100, :precision => 0) # => 100%
|
90
|
+
#
|
91
|
+
# number_to_percentage(302.24398923423, :precision => 5)
|
92
|
+
# # => 302.24399%
|
78
93
|
def number_to_percentage(number, options = {})
|
79
94
|
options = options.stringify_keys
|
80
95
|
precision = options["precision"] || 3
|
81
96
|
separator = options["separator"] || "."
|
82
|
-
|
97
|
+
|
83
98
|
begin
|
84
99
|
number = number_with_precision(number, precision)
|
85
100
|
parts = number.split('.')
|
@@ -93,14 +108,20 @@ module ActionView
|
|
93
108
|
end
|
94
109
|
end
|
95
110
|
|
96
|
-
# Formats a +number+ with grouped thousands using +delimiter
|
111
|
+
# Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You
|
97
112
|
# can customize the format using optional <em>delimiter</em> and <em>separator</em> parameters.
|
98
|
-
# * <tt>delimiter</tt> - Sets the thousands delimiter, defaults to ","
|
99
|
-
# * <tt>separator</tt> - Sets the separator between the units, defaults to "."
|
100
113
|
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
114
|
+
# ==== Options
|
115
|
+
# * <tt>delimiter</tt> - Sets the thousands delimiter (defaults to ",").
|
116
|
+
# * <tt>separator</tt> - Sets the separator between the units (defaults to ".").
|
117
|
+
#
|
118
|
+
# ==== Examples
|
119
|
+
# number_with_delimiter(12345678) # => 12,345,678
|
120
|
+
# number_with_delimiter(12345678.05) # => 12,345,678.05
|
121
|
+
# number_with_delimiter(12345678, ".") # => 12.345.678
|
122
|
+
#
|
123
|
+
# number_with_delimiter(98765432.98, " ", ",")
|
124
|
+
# # => 98 765 432,98
|
104
125
|
def number_with_delimiter(number, delimiter=",", separator=".")
|
105
126
|
begin
|
106
127
|
parts = number.to_s.split('.')
|
@@ -110,46 +131,49 @@ module ActionView
|
|
110
131
|
number
|
111
132
|
end
|
112
133
|
end
|
113
|
-
|
114
|
-
# Formats a +number+ with the specified level of +precision
|
134
|
+
|
135
|
+
# Formats a +number+ with the specified level of +precision+ (e.g., 112.32 has a precision of 2). The default
|
115
136
|
# level of precision is 3.
|
116
137
|
#
|
117
|
-
#
|
118
|
-
# number_with_precision(111.2345
|
138
|
+
# ==== Examples
|
139
|
+
# number_with_precision(111.2345) # => 111.235
|
140
|
+
# number_with_precision(111.2345, 2) # => 111.24
|
141
|
+
# number_with_precision(13, 5) # => 13.00000
|
142
|
+
# number_with_precision(389.32314, 0) # => 389
|
119
143
|
def number_with_precision(number, precision=3)
|
120
144
|
"%01.#{precision}f" % number
|
121
145
|
rescue
|
122
146
|
number
|
123
147
|
end
|
124
|
-
|
125
|
-
# Formats the bytes in +size+ into a more understandable representation
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
# number_to_human_size(
|
133
|
-
# number_to_human_size(
|
134
|
-
# number_to_human_size(
|
135
|
-
# number_to_human_size(
|
136
|
-
# number_to_human_size(
|
148
|
+
|
149
|
+
# Formats the bytes in +size+ into a more understandable representation
|
150
|
+
# (e.g., giving it 1500 yields 1.5 KB). This method is useful for
|
151
|
+
# reporting file sizes to users. This method returns nil if
|
152
|
+
# +size+ cannot be converted into a number. You can change the default
|
153
|
+
# precision of 1 using the precision parameter +precision+.
|
154
|
+
#
|
155
|
+
# ==== Examples
|
156
|
+
# number_to_human_size(123) # => 123 Bytes
|
157
|
+
# number_to_human_size(1234) # => 1.2 KB
|
158
|
+
# number_to_human_size(12345) # => 12.1 KB
|
159
|
+
# number_to_human_size(1234567) # => 1.2 MB
|
160
|
+
# number_to_human_size(1234567890) # => 1.1 GB
|
161
|
+
# number_to_human_size(1234567890123) # => 1.1 TB
|
162
|
+
# number_to_human_size(1234567, 2) # => 1.18 MB
|
163
|
+
# number_to_human_size(483989, 0) # => 4 MB
|
137
164
|
def number_to_human_size(size, precision=1)
|
138
165
|
size = Kernel.Float(size)
|
139
|
-
case
|
140
|
-
when size == 1
|
141
|
-
when size < 1.kilobyte
|
142
|
-
when size < 1.megabyte
|
143
|
-
when size < 1.gigabyte
|
144
|
-
when size < 1.terabyte
|
166
|
+
case
|
167
|
+
when size.to_i == 1; "1 Byte"
|
168
|
+
when size < 1.kilobyte; "%d Bytes" % size
|
169
|
+
when size < 1.megabyte; "%.#{precision}f KB" % (size / 1.0.kilobyte)
|
170
|
+
when size < 1.gigabyte; "%.#{precision}f MB" % (size / 1.0.megabyte)
|
171
|
+
when size < 1.terabyte; "%.#{precision}f GB" % (size / 1.0.gigabyte)
|
145
172
|
else "%.#{precision}f TB" % (size / 1.0.terabyte)
|
146
|
-
end.sub(
|
173
|
+
end.sub(/([0-9])\.?0+ /, '\1 ' )
|
147
174
|
rescue
|
148
175
|
nil
|
149
176
|
end
|
150
|
-
|
151
|
-
alias_method :human_size, :number_to_human_size # deprecated alias
|
152
|
-
deprecate :human_size => :number_to_human_size
|
153
177
|
end
|
154
178
|
end
|
155
179
|
end
|
@@ -2,25 +2,106 @@ require 'set'
|
|
2
2
|
|
3
3
|
module ActionView
|
4
4
|
module Helpers
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# Ajax[http://www.adaptivepath.com/publications/essays/archives/000385.php]
|
5
|
+
# Prototype[http://www.prototypejs.org/] is a JavaScript library that provides
|
6
|
+
# DOM[http://en.wikipedia.org/wiki/Document_Object_Model] manipulation,
|
7
|
+
# Ajax[http://www.adaptivepath.com/publications/essays/archives/000385.php]
|
8
|
+
# functionality, and more traditional object-oriented facilities for JavaScript.
|
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.
|
8
12
|
# This means that you can call actions in your controllers without
|
9
13
|
# reloading the page, but still update certain parts of it using
|
10
|
-
# injections into the DOM.
|
11
|
-
# a new element to a list without reloading the page
|
14
|
+
# injections into the DOM. A common use case is having a form that adds
|
15
|
+
# a new element to a list without reloading the page or updating a shopping
|
16
|
+
# cart total when a new item is added.
|
12
17
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# the necessary JavaScript.
|
18
|
+
# == Usage
|
19
|
+
# To be able to use these helpers, you must first include the Prototype
|
20
|
+
# JavaScript framework in your pages.
|
17
21
|
#
|
22
|
+
# javascript_include_tag 'prototype'
|
23
|
+
#
|
24
|
+
# (See the documentation for
|
25
|
+
# ActionView::Helpers::JavaScriptHelper for more information on including
|
26
|
+
# this and other JavaScript files in your Rails templates.)
|
27
|
+
#
|
28
|
+
# Now you're ready to call a remote action either through a link...
|
29
|
+
#
|
30
|
+
# link_to_remote "Add to cart",
|
31
|
+
# :url => { :action => "add", :id => product.id },
|
32
|
+
# :update => { :success => "cart", :failure => "error" }
|
33
|
+
#
|
34
|
+
# ...through a form...
|
35
|
+
#
|
36
|
+
# <% form_remote_tag :url => '/shipping' do -%>
|
37
|
+
# <div><%= submit_tag 'Recalculate Shipping' %></div>
|
38
|
+
# <% end -%>
|
39
|
+
#
|
40
|
+
# ...periodically...
|
41
|
+
#
|
42
|
+
# periodically_call_remote(:url => 'update', :frequency => '5', :update => 'ticker')
|
43
|
+
#
|
44
|
+
# ...or through an observer (i.e., a form or field that is observed and calls a remote
|
45
|
+
# action when changed).
|
46
|
+
#
|
47
|
+
# <%= observe_field(:searchbox,
|
48
|
+
# :url => { :action => :live_search }),
|
49
|
+
# :frequency => 0.5,
|
50
|
+
# :update => :hits,
|
51
|
+
# :with => 'query'
|
52
|
+
# %>
|
53
|
+
#
|
54
|
+
# As you can see, there are numerous ways to use Prototype's Ajax functions (and actually more than
|
55
|
+
# are listed here); check out the documentation for each method to find out more about its usage and options.
|
56
|
+
#
|
57
|
+
# === Common Options
|
18
58
|
# See link_to_remote for documentation of options common to all Ajax
|
19
|
-
# helpers
|
59
|
+
# helpers; any of the options specified by link_to_remote can be used
|
60
|
+
# by the other helpers.
|
61
|
+
#
|
62
|
+
# == Designing your Rails actions for Ajax
|
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
|
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.
|
67
|
+
# You can turn the layout off on particular actions by doing the following:
|
68
|
+
#
|
69
|
+
# class SiteController < ActionController::Base
|
70
|
+
# layout "standard", :except => [:ajax_method, :more_ajax, :another_ajax]
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# Optionally, you could do this in the method you wish to lack a layout:
|
74
|
+
#
|
75
|
+
# render :layout => false
|
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.
|
79
|
+
# def name
|
80
|
+
# # Is this an XmlHttpRequest request?
|
81
|
+
# if (request.xhr?)
|
82
|
+
# render :text => @name.to_s
|
83
|
+
# else
|
84
|
+
# # No? Then render an action.
|
85
|
+
# render :action => 'view_attribute', :attr => @name
|
86
|
+
# end
|
87
|
+
# end
|
20
88
|
#
|
21
|
-
#
|
22
|
-
#
|
89
|
+
# The else clause can be left off and the current action will render with full layout and template. An extension
|
90
|
+
# to this solution was posted to Ryan Heneise's blog at ArtOfMission["http://www.artofmission.com/"].
|
23
91
|
#
|
92
|
+
# layout proc{ |c| c.request.xhr? ? false : "application" }
|
93
|
+
#
|
94
|
+
# Dropping this in your ApplicationController turns the layout off for every request that is an "xhr" request.
|
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
|
97
|
+
# render text output, like this:
|
98
|
+
#
|
99
|
+
# render :text => 'Return this from my method!'
|
100
|
+
#
|
101
|
+
# Since whatever the method returns is injected into the DOM, this will simply inject some text (or HTML, if you
|
102
|
+
# tell it to). This is usually how small updates, such updating a cart total or a file count, are handled.
|
103
|
+
#
|
104
|
+
# == Updating multiple elements
|
24
105
|
# See JavaScriptGenerator for information on updating multiple elements
|
25
106
|
# on the page in an Ajax response.
|
26
107
|
module PrototypeHelper
|
@@ -41,16 +122,30 @@ module ActionView
|
|
41
122
|
# render :partial.
|
42
123
|
#
|
43
124
|
# Examples:
|
125
|
+
# # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true});
|
126
|
+
# # return false;">Delete this post</a>
|
44
127
|
# link_to_remote "Delete this post", :update => "posts",
|
45
128
|
# :url => { :action => "destroy", :id => post.id }
|
129
|
+
#
|
130
|
+
# # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true});
|
131
|
+
# # return false;"><img alt="Refresh" src="/images/refresh.png?" /></a>
|
46
132
|
# link_to_remote(image_tag("refresh"), :update => "emails",
|
47
133
|
# :url => { :action => "list_emails" })
|
134
|
+
#
|
135
|
+
# You can override the generated HTML options by specifying a hash in
|
136
|
+
# <tt>options[:html]</tt>.
|
137
|
+
#
|
138
|
+
# link_to_remote "Delete this post", :update => "posts",
|
139
|
+
# :url => post_url(@post), :method => :delete,
|
140
|
+
# :html => { :class => "destructive" }
|
48
141
|
#
|
49
142
|
# You can also specify a hash for <tt>options[:update]</tt> to allow for
|
50
143
|
# easy redirection of output to an other DOM element if a server-side
|
51
144
|
# error occurs:
|
52
145
|
#
|
53
146
|
# Example:
|
147
|
+
# # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5',
|
148
|
+
# # {asynchronous:true, evalScripts:true}); return false;">Delete this post</a>
|
54
149
|
# link_to_remote "Delete this post",
|
55
150
|
# :url => { :action => "destroy", :id => post.id },
|
56
151
|
# :update => { :success => "posts", :failure => "error" }
|
@@ -63,6 +158,8 @@ module ActionView
|
|
63
158
|
# can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt>
|
64
159
|
#
|
65
160
|
# Example:
|
161
|
+
# # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'});
|
162
|
+
# # return false;">Destroy</a>
|
66
163
|
# link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete
|
67
164
|
#
|
68
165
|
# By default, these remote requests are processed asynchronous during
|
@@ -74,6 +171,9 @@ module ActionView
|
|
74
171
|
# find out the HTTP status, use <tt>request.status</tt>.
|
75
172
|
#
|
76
173
|
# Example:
|
174
|
+
# # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true,
|
175
|
+
# # onComplete:function(request){undoRequestCompleted(request)}}); return false;">hello</a>
|
176
|
+
# word = 'hello'
|
77
177
|
# link_to_remote word,
|
78
178
|
# :url => { :action => "undo", :n => word_counter },
|
79
179
|
# :complete => "undoRequestCompleted(request)"
|
@@ -100,6 +200,9 @@ module ActionView
|
|
100
200
|
# adding additional callbacks for specific status codes.
|
101
201
|
#
|
102
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...?')},
|
205
|
+
# # onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a>
|
103
206
|
# link_to_remote word,
|
104
207
|
# :url => { :action => "action" },
|
105
208
|
# 404 => "alert('Not found...? Wrong URL...?')",
|
@@ -129,8 +232,27 @@ module ActionView
|
|
129
232
|
# default this is the current form, but
|
130
233
|
# it could just as well be the ID of a
|
131
234
|
# table row or any other DOM element.
|
132
|
-
|
133
|
-
|
235
|
+
# <tt>:with</tt>:: A JavaScript expression specifying
|
236
|
+
# the parameters for the XMLHttpRequest.
|
237
|
+
# Any expressions should return a valid
|
238
|
+
# URL query string.
|
239
|
+
#
|
240
|
+
# Example:
|
241
|
+
#
|
242
|
+
# :with => "'name=' + $('name').value"
|
243
|
+
#
|
244
|
+
# You can generate a link that uses AJAX in the general case, while
|
245
|
+
# degrading gracefully to plain link behavior in the absence of
|
246
|
+
# JavaScript by setting <tt>html_options[:href]</tt> to an alternate URL.
|
247
|
+
# Note the extra curly braces around the <tt>options</tt> hash separate
|
248
|
+
# it as the second parameter from <tt>html_options</tt>, the third.
|
249
|
+
#
|
250
|
+
# Example:
|
251
|
+
# link_to_remote "Delete this post",
|
252
|
+
# { :update => "posts", :url => { :action => "destroy", :id => post.id } },
|
253
|
+
# :href => url_for(:action => "destroy", :id => post.id)
|
254
|
+
def link_to_remote(name, options = {}, html_options = nil)
|
255
|
+
link_to_function(name, remote_function(options), html_options || options.delete(:html))
|
134
256
|
end
|
135
257
|
|
136
258
|
# Periodically calls the specified url (<tt>options[:url]</tt>) every
|
@@ -138,6 +260,26 @@ module ActionView
|
|
138
260
|
# update a specified div (<tt>options[:update]</tt>) with the results
|
139
261
|
# of the remote call. The options for specifying the target with :url
|
140
262
|
# and defining callbacks is the same as link_to_remote.
|
263
|
+
# Examples:
|
264
|
+
# # 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',
|
267
|
+
# # {asynchronous:true, evalScripts:true})}, 10)
|
268
|
+
# periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')
|
269
|
+
#
|
270
|
+
# # Call invoice every 10 seconds with the id of the customer
|
271
|
+
# # If it succeeds, update the invoice DIV; if it fails, update the error DIV
|
272
|
+
# # Generates:
|
273
|
+
# # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'},
|
274
|
+
# # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10)
|
275
|
+
# periodically_call_remote(:url => { :action => 'invoice', :id => customer.id },
|
276
|
+
# :update => { :success => "invoice", :failure => "error" }
|
277
|
+
#
|
278
|
+
# # Call update every 20 seconds and update the new_block DIV
|
279
|
+
# # Generates:
|
280
|
+
# # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20)
|
281
|
+
# periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block')
|
282
|
+
#
|
141
283
|
def periodically_call_remote(options = {})
|
142
284
|
frequency = options[:frequency] || 10 # every ten seconds by default
|
143
285
|
code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
|
@@ -156,6 +298,9 @@ module ActionView
|
|
156
298
|
# specified with the :action/:method options on :html.
|
157
299
|
#
|
158
300
|
# Example:
|
301
|
+
# # Generates:
|
302
|
+
# # <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
|
303
|
+
# # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
|
159
304
|
# form_remote_tag :html => { :action =>
|
160
305
|
# url_for(:controller => "some", :action => "place") }
|
161
306
|
#
|
@@ -166,6 +311,11 @@ module ActionView
|
|
166
311
|
# the :url (and the default method is :post).
|
167
312
|
#
|
168
313
|
# form_remote_tag also takes a block, like form_tag:
|
314
|
+
# # Generates:
|
315
|
+
# # <form action="/" method="post" onsubmit="new Ajax.Request('/',
|
316
|
+
# # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
|
317
|
+
# # return false;"> <div><input name="commit" type="submit" value="Save" /></div>
|
318
|
+
# # </form>
|
169
319
|
# <% form_remote_tag :url => '/posts' do -%>
|
170
320
|
# <div><%= submit_tag 'Save' %></div>
|
171
321
|
# <% end -%>
|
@@ -180,18 +330,85 @@ module ActionView
|
|
180
330
|
form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
|
181
331
|
end
|
182
332
|
|
183
|
-
#
|
184
|
-
|
185
|
-
|
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
|
335
|
+
# specific resource that is used as a base for questioning about
|
336
|
+
# values for the fields.
|
337
|
+
#
|
338
|
+
# === Resource
|
339
|
+
#
|
340
|
+
# Example:
|
341
|
+
# <% remote_form_for(@post) do |f| %>
|
342
|
+
# ...
|
343
|
+
# <% end %>
|
344
|
+
#
|
345
|
+
# This will expand to be the same as:
|
346
|
+
#
|
347
|
+
# <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
|
348
|
+
# ...
|
349
|
+
# <% end %>
|
350
|
+
#
|
351
|
+
# === Nested Resource
|
352
|
+
#
|
353
|
+
# Example:
|
354
|
+
# <% remote_form_for([@post, @comment]) do |f| %>
|
355
|
+
# ...
|
356
|
+
# <% end %>
|
357
|
+
#
|
358
|
+
# This will expand to be the same as:
|
359
|
+
#
|
360
|
+
# <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %>
|
361
|
+
# ...
|
362
|
+
# <% end %>
|
363
|
+
#
|
364
|
+
# If you don't need to attach a form to a resource, then check out form_remote_tag.
|
365
|
+
#
|
366
|
+
# See FormHelper#form_for for additional semantics.
|
367
|
+
def remote_form_for(record_or_name_or_array, *args, &proc)
|
368
|
+
options = args.extract_options!
|
369
|
+
|
370
|
+
case record_or_name_or_array
|
371
|
+
when String, Symbol
|
372
|
+
object_name = record_or_name_or_array
|
373
|
+
when Array
|
374
|
+
object = record_or_name_or_array.last
|
375
|
+
object_name = ActionController::RecordIdentifier.singular_class_name(object)
|
376
|
+
apply_form_for_options!(record_or_name_or_array, options)
|
377
|
+
args.unshift object
|
378
|
+
else
|
379
|
+
object = record_or_name_or_array
|
380
|
+
object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name_or_array)
|
381
|
+
apply_form_for_options!(object, options)
|
382
|
+
args.unshift object
|
383
|
+
end
|
384
|
+
|
186
385
|
concat(form_remote_tag(options), proc.binding)
|
187
386
|
fields_for(object_name, *(args << options), &proc)
|
188
387
|
concat('</form>', proc.binding)
|
189
388
|
end
|
190
389
|
alias_method :form_remote_for, :remote_form_for
|
191
390
|
|
192
|
-
# Returns a button input tag
|
193
|
-
# in the background instead of regular
|
194
|
-
#
|
391
|
+
# Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+
|
392
|
+
# that will submit form using XMLHttpRequest in the background instead of a regular POST request that
|
393
|
+
# reloads the page.
|
394
|
+
#
|
395
|
+
# # 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)});
|
399
|
+
# # return false;" type="button" value="Create" />
|
400
|
+
# <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
|
401
|
+
#
|
402
|
+
# # Submit to the remote action update and update the DIV succeed or fail based
|
403
|
+
# # on the success or failure of the request
|
404
|
+
# #
|
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)});
|
407
|
+
# # return false;" type="button" value="Update" />
|
408
|
+
# <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
|
409
|
+
# :update => { :success => "succeed", :failure => "fail" }
|
410
|
+
#
|
411
|
+
# <tt>options</tt> argument is the same as in form_remote_tag.
|
195
412
|
def submit_to_remote(name, value, options = {})
|
196
413
|
options[:with] ||= 'Form.serialize(this.form)'
|
197
414
|
|
@@ -204,7 +421,7 @@ module ActionView
|
|
204
421
|
tag("input", options[:html], false)
|
205
422
|
end
|
206
423
|
|
207
|
-
# Returns 'eval(request.responseText)' which is the JavaScript function
|
424
|
+
# Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
|
208
425
|
# that form_remote_tag can call in :complete to evaluate a multiple
|
209
426
|
# update return document using update_element_function calls.
|
210
427
|
def evaluate_remote_response
|
@@ -215,6 +432,8 @@ module ActionView
|
|
215
432
|
# Takes the same arguments as link_to_remote.
|
216
433
|
#
|
217
434
|
# Example:
|
435
|
+
# # Generates: <select id="options" onchange="new Ajax.Updater('options',
|
436
|
+
# # '/testing/update_options', {asynchronous:true, evalScripts:true})">
|
218
437
|
# <select id="options" onchange="<%= remote_function(:update => "options",
|
219
438
|
# :url => { :action => :update_options }) %>">
|
220
439
|
# <option value="0">Hello</option>
|
@@ -255,11 +474,29 @@ module ActionView
|
|
255
474
|
# Ajax call. By default the value of the observed field is sent as a
|
256
475
|
# parameter with the Ajax call.
|
257
476
|
#
|
477
|
+
# Example:
|
478
|
+
# # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest',
|
479
|
+
# # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})})
|
480
|
+
# <%= observe_field :suggest, :url => { :action => :find_suggestion },
|
481
|
+
# :frequency => 0.25,
|
482
|
+
# :update => :suggest,
|
483
|
+
# :with => 'q'
|
484
|
+
# %>
|
485
|
+
#
|
258
486
|
# Required +options+ are either of:
|
259
487
|
# <tt>:url</tt>:: +url_for+-style options for the action to call
|
260
488
|
# when the field has changed.
|
261
489
|
# <tt>:function</tt>:: Instead of making a remote call to a URL, you
|
262
|
-
# can specify
|
490
|
+
# can specify javascript code to be called instead.
|
491
|
+
# Note that the value of this option is used as the
|
492
|
+
# *body* of the javascript function, a function definition
|
493
|
+
# with parameters named element and value will be generated for you
|
494
|
+
# for example:
|
495
|
+
# observe_field("glass", :frequency => 1, :function => "alert('Element changed')")
|
496
|
+
# will generate:
|
497
|
+
# new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')})
|
498
|
+
# The element parameter is the DOM element being observed, and the value is its value at the
|
499
|
+
# time the observer is triggered.
|
263
500
|
#
|
264
501
|
# Additional options are:
|
265
502
|
# <tt>:frequency</tt>:: The frequency (in seconds) at which changes to
|
@@ -294,8 +531,23 @@ module ActionView
|
|
294
531
|
# you can specify it instead to be "blur" or "focus" or
|
295
532
|
# any other event.
|
296
533
|
#
|
297
|
-
# Additionally, you may specify any of the options documented in
|
298
|
-
#
|
534
|
+
# Additionally, you may specify any of the options documented in the
|
535
|
+
# <em>Common options</em> section at the top of this document.
|
536
|
+
#
|
537
|
+
# Example:
|
538
|
+
#
|
539
|
+
# # Sends params: {:title => 'Title of the book'} when the book_title input
|
540
|
+
# # field is changed.
|
541
|
+
# observe_field 'book_title',
|
542
|
+
# :url => 'http://example.com/books/edit/1',
|
543
|
+
# :with => 'title'
|
544
|
+
#
|
545
|
+
# # Sends params: {:book_title => 'Title of the book'} when the focus leaves
|
546
|
+
# # the input field.
|
547
|
+
# observe_field 'book_title',
|
548
|
+
# :url => 'http://example.com/books/edit/1',
|
549
|
+
# :on => 'blur'
|
550
|
+
#
|
299
551
|
def observe_field(field_id, options = {})
|
300
552
|
if options[:frequency] && options[:frequency] > 0
|
301
553
|
build_observer('Form.Element.Observer', field_id, options)
|
@@ -350,17 +602,16 @@ module ActionView
|
|
350
602
|
#
|
351
603
|
# Example:
|
352
604
|
#
|
605
|
+
# # Generates:
|
606
|
+
# # new Insertion.Bottom("list", "<li>Some item</li>");
|
607
|
+
# # new Effect.Highlight("list");
|
608
|
+
# # ["status-indicator", "cancel-link"].each(Element.hide);
|
353
609
|
# update_page do |page|
|
354
610
|
# page.insert_html :bottom, 'list', "<li>#{@item.name}</li>"
|
355
611
|
# page.visual_effect :highlight, 'list'
|
356
612
|
# page.hide 'status-indicator', 'cancel-link'
|
357
613
|
# end
|
358
614
|
#
|
359
|
-
# generates the following JavaScript:
|
360
|
-
#
|
361
|
-
# new Insertion.Bottom("list", "<li>Some item</li>");
|
362
|
-
# new Effect.Highlight("list");
|
363
|
-
# ["status-indicator", "cancel-link"].each(Element.hide);
|
364
615
|
#
|
365
616
|
# Helper methods can be used in conjunction with JavaScriptGenerator.
|
366
617
|
# When a helper method is called inside an update block on the +page+
|
@@ -400,8 +651,19 @@ module ActionView
|
|
400
651
|
# page['blank_slate'] # => $('blank_slate');
|
401
652
|
# page['blank_slate'].show # => $('blank_slate').show();
|
402
653
|
# page['blank_slate'].show('first').up # => $('blank_slate').show('first').up();
|
654
|
+
#
|
655
|
+
# You can also pass in a record, which will use ActionController::RecordIdentifier.dom_id to lookup
|
656
|
+
# the correct id:
|
657
|
+
#
|
658
|
+
# page[@post] # => $('post_45')
|
659
|
+
# page[Post.new] # => $('new_post')
|
403
660
|
def [](id)
|
404
|
-
|
661
|
+
case id
|
662
|
+
when String, Symbol, NilClass
|
663
|
+
JavaScriptElementProxy.new(self, id)
|
664
|
+
else
|
665
|
+
JavaScriptElementProxy.new(self, ActionController::RecordIdentifier.dom_id(id))
|
666
|
+
end
|
405
667
|
end
|
406
668
|
|
407
669
|
# Returns an object whose <tt>#to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
|
@@ -419,18 +681,19 @@ module ActionView
|
|
419
681
|
#
|
420
682
|
# You can also use prototype enumerations with the collection. Observe:
|
421
683
|
#
|
684
|
+
# # Generates: $$('#items li').each(function(value) { value.hide(); });
|
422
685
|
# page.select('#items li').each do |value|
|
423
686
|
# value.hide
|
424
687
|
# end
|
425
|
-
# # => $$('#items li').each(function(value) { value.hide(); });
|
426
688
|
#
|
427
689
|
# Though you can call the block param anything you want, they are always rendered in the
|
428
690
|
# javascript as 'value, index.' Other enumerations, like collect() return the last statement:
|
429
|
-
#
|
691
|
+
#
|
692
|
+
# # Generates: var hidden = $$('#items li').collect(function(value, index) { return value.hide(); });
|
430
693
|
# page.select('#items li').collect('hidden') do |item|
|
431
694
|
# item.hide
|
432
695
|
# end
|
433
|
-
#
|
696
|
+
#
|
434
697
|
def select(pattern)
|
435
698
|
JavaScriptElementCollectionProxy.new(self, pattern)
|
436
699
|
end
|
@@ -444,7 +707,7 @@ module ActionView
|
|
444
707
|
# element's existing content.
|
445
708
|
# <tt>:bottom</tt>:: HTML is inserted inside the element, after the
|
446
709
|
# element's existing content.
|
447
|
-
# <tt>:before</tt>:: HTML is inserted immediately
|
710
|
+
# <tt>:before</tt>:: HTML is inserted immediately preceding the element.
|
448
711
|
# <tt>:after</tt>:: HTML is inserted immediately following the element.
|
449
712
|
#
|
450
713
|
# +options_for_render+ may be either a string of HTML to insert, or a hash
|
@@ -452,9 +715,11 @@ module ActionView
|
|
452
715
|
#
|
453
716
|
# # Insert the rendered 'navigation' partial just before the DOM
|
454
717
|
# # element with ID 'content'.
|
718
|
+
# # Generates: new Insertion.Before("content", "-- Contents of 'navigation' partial --");
|
455
719
|
# insert_html :before, 'content', :partial => 'navigation'
|
456
720
|
#
|
457
721
|
# # Add a list item to the bottom of the <ul> with ID 'list'.
|
722
|
+
# # Generates: new Insertion.Bottom("list", "<li>Last item</li>");
|
458
723
|
# insert_html :bottom, 'list', '<li>Last item</li>'
|
459
724
|
#
|
460
725
|
def insert_html(position, id, *options_for_render)
|
@@ -469,6 +734,7 @@ module ActionView
|
|
469
734
|
#
|
470
735
|
# # Replace the HTML of the DOM element having ID 'person-45' with the
|
471
736
|
# # 'person' partial for the appropriate object.
|
737
|
+
# # Generates: Element.update("person-45", "-- Contents of 'person' partial --");
|
472
738
|
# replace_html 'person-45', :partial => 'person', :object => @person
|
473
739
|
#
|
474
740
|
def replace_html(id, *options_for_render)
|
@@ -496,9 +762,13 @@ module ActionView
|
|
496
762
|
# </div>
|
497
763
|
#
|
498
764
|
# # Insert a new person
|
765
|
+
# #
|
766
|
+
# # Generates: new Insertion.Bottom({object: "Matz", partial: "person"}, "");
|
499
767
|
# page.insert_html :bottom, :partial => 'person', :object => @person
|
500
768
|
#
|
501
769
|
# # Replace an existing person
|
770
|
+
#
|
771
|
+
# # Generates: Element.replace("person_45", "-- Contents of partial --");
|
502
772
|
# page.replace 'person_45', :partial => 'person', :object => @person
|
503
773
|
#
|
504
774
|
def replace(id, *options_for_render)
|
@@ -506,31 +776,72 @@ module ActionView
|
|
506
776
|
end
|
507
777
|
|
508
778
|
# Removes the DOM elements with the given +ids+ from the page.
|
779
|
+
#
|
780
|
+
# Example:
|
781
|
+
#
|
782
|
+
# # Remove a few people
|
783
|
+
# # Generates: ["person_23", "person_9", "person_2"].each(Element.remove);
|
784
|
+
# page.remove 'person_23', 'person_9', 'person_2'
|
785
|
+
#
|
509
786
|
def remove(*ids)
|
510
787
|
loop_on_multiple_args 'Element.remove', ids
|
511
788
|
end
|
512
789
|
|
513
790
|
# Shows hidden DOM elements with the given +ids+.
|
791
|
+
#
|
792
|
+
# Example:
|
793
|
+
#
|
794
|
+
# # Show a few people
|
795
|
+
# # Generates: ["person_6", "person_13", "person_223"].each(Element.show);
|
796
|
+
# page.show 'person_6', 'person_13', 'person_223'
|
797
|
+
#
|
514
798
|
def show(*ids)
|
515
799
|
loop_on_multiple_args 'Element.show', ids
|
516
800
|
end
|
517
801
|
|
518
802
|
# Hides the visible DOM elements with the given +ids+.
|
803
|
+
#
|
804
|
+
# Example:
|
805
|
+
#
|
806
|
+
# # Hide a few people
|
807
|
+
# # Generates: ["person_29", "person_9", "person_0"].each(Element.hide);
|
808
|
+
# page.hide 'person_29', 'person_9', 'person_0'
|
809
|
+
#
|
519
810
|
def hide(*ids)
|
520
811
|
loop_on_multiple_args 'Element.hide', ids
|
521
812
|
end
|
522
813
|
|
523
814
|
# Toggles the visibility of the DOM elements with the given +ids+.
|
815
|
+
# Example:
|
816
|
+
#
|
817
|
+
# # Show a few people
|
818
|
+
# # Generates: ["person_14", "person_12", "person_23"].each(Element.toggle);
|
819
|
+
# page.toggle 'person_14', 'person_12', 'person_23' # Hides the elements
|
820
|
+
# page.toggle 'person_14', 'person_12', 'person_23' # Shows the previously hidden elements
|
821
|
+
#
|
524
822
|
def toggle(*ids)
|
525
823
|
loop_on_multiple_args 'Element.toggle', ids
|
526
824
|
end
|
527
825
|
|
528
826
|
# Displays an alert dialog with the given +message+.
|
827
|
+
#
|
828
|
+
# Example:
|
829
|
+
#
|
830
|
+
# # Generates: alert('This message is from Rails!')
|
831
|
+
# page.alert('This message is from Rails!')
|
529
832
|
def alert(message)
|
530
833
|
call 'alert', message
|
531
834
|
end
|
532
835
|
|
533
|
-
# Redirects the browser to the given +location
|
836
|
+
# Redirects the browser to the given +location+ using JavaScript, in the same form as +url_for+.
|
837
|
+
#
|
838
|
+
# Examples:
|
839
|
+
#
|
840
|
+
# # Generates: window.location.href = "/mycontroller";
|
841
|
+
# page.redirect_to(:action => 'index')
|
842
|
+
#
|
843
|
+
# # Generates: window.location.href = "/account/signup";
|
844
|
+
# page.redirect_to(:controller => 'account', :action => 'signup')
|
534
845
|
def redirect_to(location)
|
535
846
|
assign 'window.location.href', @context.url_for(location)
|
536
847
|
end
|
@@ -540,22 +851,52 @@ module ActionView
|
|
540
851
|
# If a block is given, the block will be passed to a new JavaScriptGenerator;
|
541
852
|
# the resulting JavaScript code will then be wrapped inside <tt>function() { ... }</tt>
|
542
853
|
# and passed as the called function's final argument.
|
854
|
+
#
|
855
|
+
# Examples:
|
856
|
+
#
|
857
|
+
# # Generates: Element.replace(my_element, "My content to replace with.")
|
858
|
+
# page.call 'Element.replace', 'my_element', "My content to replace with."
|
859
|
+
#
|
860
|
+
# # Generates: alert('My message!')
|
861
|
+
# page.call 'alert', 'My message!'
|
862
|
+
#
|
543
863
|
def call(function, *arguments, &block)
|
544
864
|
record "#{function}(#{arguments_for_call(arguments, block)})"
|
545
865
|
end
|
546
866
|
|
547
867
|
# Assigns the JavaScript +variable+ the given +value+.
|
868
|
+
#
|
869
|
+
# Examples:
|
870
|
+
#
|
871
|
+
# # Generates: my_string = "This is mine!";
|
872
|
+
# page.assign 'my_string', 'This is mine!'
|
873
|
+
#
|
874
|
+
# # Generates: record_count = 33;
|
875
|
+
# page.assign 'record_count', 33
|
876
|
+
#
|
877
|
+
# # Generates: tabulated_total = 47
|
878
|
+
# page.assign 'tabulated_total', @total_from_cart
|
879
|
+
#
|
548
880
|
def assign(variable, value)
|
549
881
|
record "#{variable} = #{javascript_object_for(value)}"
|
550
882
|
end
|
551
883
|
|
552
884
|
# Writes raw JavaScript to the page.
|
885
|
+
#
|
886
|
+
# Example:
|
887
|
+
#
|
888
|
+
# page << "alert('JavaScript with Prototype.');"
|
553
889
|
def <<(javascript)
|
554
890
|
@lines << javascript
|
555
891
|
end
|
556
892
|
|
557
893
|
# Executes the content of the block after a delay of +seconds+. Example:
|
558
894
|
#
|
895
|
+
# # Generates:
|
896
|
+
# # setTimeout(function() {
|
897
|
+
# # ;
|
898
|
+
# # new Effect.Fade("notice",{});
|
899
|
+
# # }, 20000);
|
559
900
|
# page.delay(20) do
|
560
901
|
# page.visual_effect :fade, 'notice'
|
561
902
|
# end
|
@@ -609,9 +950,13 @@ module ActionView
|
|
609
950
|
end
|
610
951
|
|
611
952
|
def render(*options_for_render)
|
953
|
+
old_format = @context && @context.template_format
|
954
|
+
@context.template_format = :html if @context
|
612
955
|
Hash === options_for_render.first ?
|
613
956
|
@context.render(*options_for_render) :
|
614
957
|
options_for_render.first.to_s
|
958
|
+
ensure
|
959
|
+
@context.template_format = old_format if @context
|
615
960
|
end
|
616
961
|
|
617
962
|
def javascript_object_for(object)
|
@@ -637,6 +982,12 @@ module ActionView
|
|
637
982
|
# Yields a JavaScriptGenerator and returns the generated JavaScript code.
|
638
983
|
# Use this to update multiple elements on a page in an Ajax response.
|
639
984
|
# See JavaScriptGenerator for more information.
|
985
|
+
#
|
986
|
+
# Example:
|
987
|
+
#
|
988
|
+
# update_page do |page|
|
989
|
+
# page.hide 'spinner'
|
990
|
+
# end
|
640
991
|
def update_page(&block)
|
641
992
|
JavaScriptGenerator.new(@template, &block).to_s
|
642
993
|
end
|
@@ -667,6 +1018,15 @@ module ActionView
|
|
667
1018
|
elsif options[:with]
|
668
1019
|
js_options['parameters'] = options[:with]
|
669
1020
|
end
|
1021
|
+
|
1022
|
+
if protect_against_forgery?
|
1023
|
+
if js_options['parameters']
|
1024
|
+
js_options['parameters'] << " + '&"
|
1025
|
+
else
|
1026
|
+
js_options['parameters'] = "'"
|
1027
|
+
end
|
1028
|
+
js_options['parameters'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
|
1029
|
+
end
|
670
1030
|
|
671
1031
|
options_for_javascript(js_options)
|
672
1032
|
end
|
@@ -676,7 +1036,7 @@ module ActionView
|
|
676
1036
|
end
|
677
1037
|
|
678
1038
|
def build_observer(klass, name, options = {})
|
679
|
-
if options[:with] && (options[:with] !~ /[=(.]/)
|
1039
|
+
if options[:with] && (options[:with] !~ /[\{=(.]/)
|
680
1040
|
options[:with] = "'#{options[:with]}=' + value"
|
681
1041
|
else
|
682
1042
|
options[:with] ||= 'value' unless options[:function]
|
@@ -705,7 +1065,7 @@ module ActionView
|
|
705
1065
|
end
|
706
1066
|
|
707
1067
|
# Converts chained method calls on DOM proxy elements into JavaScript chains
|
708
|
-
class JavaScriptProxy <
|
1068
|
+
class JavaScriptProxy < BasicObject #:nodoc:
|
709
1069
|
def initialize(generator, root = nil)
|
710
1070
|
@generator = generator
|
711
1071
|
@generator << root if root
|
@@ -787,7 +1147,7 @@ module ActionView
|
|
787
1147
|
true
|
788
1148
|
end
|
789
1149
|
|
790
|
-
def to_json
|
1150
|
+
def to_json(options = nil)
|
791
1151
|
@variable
|
792
1152
|
end
|
793
1153
|
|
@@ -800,7 +1160,7 @@ module ActionView
|
|
800
1160
|
end
|
801
1161
|
|
802
1162
|
class JavaScriptCollectionProxy < JavaScriptProxy #:nodoc:
|
803
|
-
ENUMERABLE_METHODS_WITH_RETURN = [:all, :any, :collect, :map, :detect, :find, :find_all, :select, :max, :min, :partition, :reject, :sort_by] unless defined? ENUMERABLE_METHODS_WITH_RETURN
|
1163
|
+
ENUMERABLE_METHODS_WITH_RETURN = [:all, :any, :collect, :map, :detect, :find, :find_all, :select, :max, :min, :partition, :reject, :sort_by, :in_groups_of, :each_slice] unless defined? ENUMERABLE_METHODS_WITH_RETURN
|
804
1164
|
ENUMERABLE_METHODS = ENUMERABLE_METHODS_WITH_RETURN + [:each] unless defined? ENUMERABLE_METHODS
|
805
1165
|
attr_reader :generator
|
806
1166
|
delegate :arguments_for_call, :to => :generator
|
@@ -808,11 +1168,27 @@ module ActionView
|
|
808
1168
|
def initialize(generator, pattern)
|
809
1169
|
super(generator, @pattern = pattern)
|
810
1170
|
end
|
811
|
-
|
1171
|
+
|
1172
|
+
def each_slice(variable, number, &block)
|
1173
|
+
if block
|
1174
|
+
enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block
|
1175
|
+
else
|
1176
|
+
add_variable_assignment!(variable)
|
1177
|
+
append_enumerable_function!("eachSlice(#{number.to_json});")
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
|
812
1181
|
def grep(variable, pattern, &block)
|
813
1182
|
enumerate :grep, :variable => variable, :return => true, :method_args => [pattern], :yield_args => %w(value index), &block
|
814
1183
|
end
|
815
|
-
|
1184
|
+
|
1185
|
+
def in_groups_of(variable, number, fill_with = nil)
|
1186
|
+
arguments = [number]
|
1187
|
+
arguments << fill_with unless fill_with.nil?
|
1188
|
+
add_variable_assignment!(variable)
|
1189
|
+
append_enumerable_function!("inGroupsOf(#{arguments_for_call arguments});")
|
1190
|
+
end
|
1191
|
+
|
816
1192
|
def inject(variable, memo, &block)
|
817
1193
|
enumerate :inject, :variable => variable, :method_args => [memo], :yield_args => %w(memo value index), :return => true, &block
|
818
1194
|
end
|
@@ -860,7 +1236,7 @@ module ActionView
|
|
860
1236
|
add_variable_assignment!(options[:variable]) if options[:variable]
|
861
1237
|
append_enumerable_function!("#{enumerable.to_s.camelize(:lower)}(#{method_args}function(#{yield_args}) {")
|
862
1238
|
# only yield as many params as were passed in the block
|
863
|
-
yield
|
1239
|
+
yield(*options[:yield_args].collect { |p| JavaScriptVariableProxy.new(@generator, p) }[0..block.arity-1])
|
864
1240
|
add_return_statement! if options[:return]
|
865
1241
|
@generator << '});'
|
866
1242
|
end
|
@@ -889,4 +1265,4 @@ module ActionView
|
|
889
1265
|
end
|
890
1266
|
end
|
891
1267
|
|
892
|
-
require
|
1268
|
+
require 'action_view/helpers/javascript_helper'
|