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
@@ -2,21 +2,28 @@ module ActionView
|
|
2
2
|
module Helpers
|
3
3
|
# Provides a set of methods for making it easier to debug Rails objects.
|
4
4
|
module DebugHelper
|
5
|
-
# Returns a
|
6
|
-
#
|
5
|
+
# Returns a YAML representation of +object+ wrapped with <pre> and </pre>.
|
6
|
+
# If the object cannot be converted to YAML using +to_yaml+, +inspect+ will be called instead.
|
7
|
+
# Useful for inspecting an object at the time of rendering.
|
7
8
|
#
|
8
9
|
# ==== Example
|
9
|
-
# my_hash = {'first' => 1, 'second' => 'two', 'third' => [1,2,3]}
|
10
|
-
# debug(my_hash)
|
11
10
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
11
|
+
# @user = User.new({ :username => 'testing', :password => 'xyz', :age => 42}) %>
|
12
|
+
# debug(@user)
|
13
|
+
# # =>
|
14
|
+
# <pre class='debug_dump'>--- !ruby/object:User
|
15
|
+
# attributes:
|
16
|
+
# updated_at:
|
17
|
+
# username: testing
|
18
|
+
#
|
19
|
+
# age: 42
|
20
|
+
# password: xyz
|
21
|
+
# created_at:
|
22
|
+
# attributes_cache: {}
|
23
|
+
#
|
24
|
+
# new_record: true
|
25
|
+
# </pre>
|
26
|
+
|
20
27
|
def debug(object)
|
21
28
|
begin
|
22
29
|
Marshal::dump(object)
|
@@ -28,4 +35,4 @@ module ActionView
|
|
28
35
|
end
|
29
36
|
end
|
30
37
|
end
|
31
|
-
end
|
38
|
+
end
|
@@ -76,7 +76,7 @@ module ActionView
|
|
76
76
|
# Creates a form and a scope around a specific model object that is used as
|
77
77
|
# a base for questioning about values for the fields.
|
78
78
|
#
|
79
|
-
# Rails provides
|
79
|
+
# Rails provides succinct resource-oriented form generation with +form_for+
|
80
80
|
# like this:
|
81
81
|
#
|
82
82
|
# <% form_for @offer do |f| %>
|
@@ -249,9 +249,9 @@ module ActionView
|
|
249
249
|
args.unshift object
|
250
250
|
end
|
251
251
|
|
252
|
-
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {})
|
252
|
+
concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}))
|
253
253
|
fields_for(object_name, *(args << options), &proc)
|
254
|
-
concat('</form>'
|
254
|
+
concat('</form>')
|
255
255
|
end
|
256
256
|
|
257
257
|
def apply_form_for_options!(object_or_array, options) #:nodoc:
|
@@ -304,10 +304,6 @@ module ActionView
|
|
304
304
|
when String, Symbol
|
305
305
|
object_name = record_or_name_or_array
|
306
306
|
object = args.first
|
307
|
-
when Array
|
308
|
-
object = record_or_name_or_array.last
|
309
|
-
object_name = ActionController::RecordIdentifier.singular_class_name(object)
|
310
|
-
apply_form_for_options!(record_or_name_or_array, options)
|
311
307
|
else
|
312
308
|
object = record_or_name_or_array
|
313
309
|
object_name = ActionController::RecordIdentifier.singular_class_name(object)
|
@@ -333,7 +329,7 @@ module ActionView
|
|
333
329
|
# # => <label for="post_title" class="title_label">A short title</label>
|
334
330
|
#
|
335
331
|
def label(object_name, method, text = nil, options = {})
|
336
|
-
InstanceTag.new(object_name, method, self,
|
332
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options)
|
337
333
|
end
|
338
334
|
|
339
335
|
# Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +method+) on an object
|
@@ -355,7 +351,7 @@ module ActionView
|
|
355
351
|
# # => <input type="text" id="snippet_code" name="snippet[code]" size="20" value="#{@snippet.code}" class="code_input" />
|
356
352
|
#
|
357
353
|
def text_field(object_name, method, options = {})
|
358
|
-
InstanceTag.new(object_name, method, self,
|
354
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("text", options)
|
359
355
|
end
|
360
356
|
|
361
357
|
# Returns an input tag of the "password" type tailored for accessing a specified attribute (identified by +method+) on an object
|
@@ -377,7 +373,7 @@ module ActionView
|
|
377
373
|
# # => <input type="text" id="account_pin" name="account[pin]" size="20" value="#{@account.pin}" class="form_input" />
|
378
374
|
#
|
379
375
|
def password_field(object_name, method, options = {})
|
380
|
-
InstanceTag.new(object_name, method, self,
|
376
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("password", options)
|
381
377
|
end
|
382
378
|
|
383
379
|
# Returns a hidden input tag tailored for accessing a specified attribute (identified by +method+) on an object
|
@@ -395,7 +391,7 @@ module ActionView
|
|
395
391
|
# hidden_field(:user, :token)
|
396
392
|
# # => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" />
|
397
393
|
def hidden_field(object_name, method, options = {})
|
398
|
-
InstanceTag.new(object_name, method, self,
|
394
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("hidden", options)
|
399
395
|
end
|
400
396
|
|
401
397
|
# Returns an file upload input tag tailored for accessing a specified attribute (identified by +method+) on an object
|
@@ -414,7 +410,7 @@ module ActionView
|
|
414
410
|
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
|
415
411
|
#
|
416
412
|
def file_field(object_name, method, options = {})
|
417
|
-
InstanceTag.new(object_name, method, self,
|
413
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("file", options)
|
418
414
|
end
|
419
415
|
|
420
416
|
# Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
|
@@ -442,15 +438,44 @@ module ActionView
|
|
442
438
|
# # #{@entry.body}
|
443
439
|
# # </textarea>
|
444
440
|
def text_area(object_name, method, options = {})
|
445
|
-
InstanceTag.new(object_name, method, self,
|
441
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_text_area_tag(options)
|
446
442
|
end
|
447
443
|
|
448
444
|
# Returns a checkbox tag tailored for accessing a specified attribute (identified by +method+) on an object
|
449
|
-
# assigned to the template (identified by +object+).
|
450
|
-
# integer is above zero, then the checkbox is checked.
|
451
|
-
# hash with +options+. The +checked_value+ defaults to 1
|
452
|
-
# is set to 0 which is convenient for boolean values.
|
453
|
-
#
|
445
|
+
# assigned to the template (identified by +object+). This object must be an instance object (@object) and not a local object.
|
446
|
+
# It's intended that +method+ returns an integer and if that integer is above zero, then the checkbox is checked.
|
447
|
+
# Additional options on the input tag can be passed as a hash with +options+. The +checked_value+ defaults to 1
|
448
|
+
# while the default +unchecked_value+ is set to 0 which is convenient for boolean values.
|
449
|
+
#
|
450
|
+
# ==== Gotcha
|
451
|
+
#
|
452
|
+
# The HTML specification says unchecked check boxes are not successful, and
|
453
|
+
# thus web browsers do not send them. Unfortunately this introduces a gotcha:
|
454
|
+
# if an Invoice model has a +paid+ flag, and in the form that edits a paid
|
455
|
+
# invoice the user unchecks its check box, no +paid+ parameter is sent. So,
|
456
|
+
# any mass-assignment idiom like
|
457
|
+
#
|
458
|
+
# @invoice.update_attributes(params[:invoice])
|
459
|
+
#
|
460
|
+
# wouldn't update the flag.
|
461
|
+
#
|
462
|
+
# To prevent this the helper generates a hidden field with the same name as
|
463
|
+
# the checkbox after the very check box. So, the client either sends only the
|
464
|
+
# hidden field (representing the check box is unchecked), or both fields.
|
465
|
+
# Since the HTML specification says key/value pairs have to be sent in the
|
466
|
+
# same order they appear in the form and Rails parameters extraction always
|
467
|
+
# gets the first occurrence of any given key, that works in ordinary forms.
|
468
|
+
#
|
469
|
+
# Unfortunately that workaround does not work when the check box goes
|
470
|
+
# within an array-like parameter, as in
|
471
|
+
#
|
472
|
+
# <% fields_for "project[invoice_attributes][]", invoice, :index => nil do |form| %>
|
473
|
+
# <%= form.check_box :paid %>
|
474
|
+
# ...
|
475
|
+
# <% end %>
|
476
|
+
#
|
477
|
+
# because parameter name repetition is precisely what Rails seeks to distinguish
|
478
|
+
# the elements of the array.
|
454
479
|
#
|
455
480
|
# ==== Examples
|
456
481
|
# # Let's say that @post.validated? is 1:
|
@@ -468,7 +493,7 @@ module ActionView
|
|
468
493
|
# # <input name="eula[accepted]" type="hidden" value="no" />
|
469
494
|
#
|
470
495
|
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
|
471
|
-
InstanceTag.new(object_name, method, self,
|
496
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)
|
472
497
|
end
|
473
498
|
|
474
499
|
# Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object
|
@@ -488,7 +513,7 @@ module ActionView
|
|
488
513
|
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
|
489
514
|
# # <input type="radio" id="user_receive_newsletter_no" name="user[receive_newsletter]" value="no" checked="checked" />
|
490
515
|
def radio_button(object_name, method, tag_value, options = {})
|
491
|
-
InstanceTag.new(object_name, method, self,
|
516
|
+
InstanceTag.new(object_name, method, self, options.delete(:object)).to_radio_button_tag(tag_value, options)
|
492
517
|
end
|
493
518
|
end
|
494
519
|
|
@@ -501,12 +526,12 @@ module ActionView
|
|
501
526
|
DEFAULT_RADIO_OPTIONS = { }.freeze unless const_defined?(:DEFAULT_RADIO_OPTIONS)
|
502
527
|
DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 }.freeze unless const_defined?(:DEFAULT_TEXT_AREA_OPTIONS)
|
503
528
|
|
504
|
-
def initialize(object_name, method_name, template_object,
|
529
|
+
def initialize(object_name, method_name, template_object, object = nil)
|
505
530
|
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
|
506
|
-
@template_object
|
531
|
+
@template_object = template_object
|
507
532
|
@object = object
|
508
|
-
if @object_name.sub!(/\[\]$/,"")
|
509
|
-
if object ||= @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}")
|
533
|
+
if @object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
|
534
|
+
if (object ||= @template_object.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param)
|
510
535
|
@auto_index = object.to_param
|
511
536
|
else
|
512
537
|
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
@@ -683,7 +708,7 @@ module ActionView
|
|
683
708
|
end
|
684
709
|
|
685
710
|
def sanitized_object_name
|
686
|
-
@sanitized_object_name ||= @object_name.gsub(
|
711
|
+
@sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
|
687
712
|
end
|
688
713
|
|
689
714
|
def sanitized_method_name
|
@@ -701,6 +726,13 @@ module ActionView
|
|
701
726
|
def initialize(object_name, object, template, options, proc)
|
702
727
|
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
|
703
728
|
@default_options = @options ? @options.slice(:index) : {}
|
729
|
+
if @object_name.to_s.match(/\[\]$/)
|
730
|
+
if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param)
|
731
|
+
@auto_index = object.to_param
|
732
|
+
else
|
733
|
+
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
734
|
+
end
|
735
|
+
end
|
704
736
|
end
|
705
737
|
|
706
738
|
(field_helpers - %w(label check_box radio_button fields_for)).each do |selector|
|
@@ -713,16 +745,25 @@ module ActionView
|
|
713
745
|
end
|
714
746
|
|
715
747
|
def fields_for(record_or_name_or_array, *args, &block)
|
748
|
+
if options.has_key?(:index)
|
749
|
+
index = "[#{options[:index]}]"
|
750
|
+
elsif defined?(@auto_index)
|
751
|
+
self.object_name = @object_name.to_s.sub(/\[\]$/,"")
|
752
|
+
index = "[#{@auto_index}]"
|
753
|
+
else
|
754
|
+
index = ""
|
755
|
+
end
|
756
|
+
|
716
757
|
case record_or_name_or_array
|
717
758
|
when String, Symbol
|
718
|
-
name = "#{object_name}[#{record_or_name_or_array}]"
|
759
|
+
name = "#{object_name}#{index}[#{record_or_name_or_array}]"
|
719
760
|
when Array
|
720
761
|
object = record_or_name_or_array.last
|
721
|
-
name = "#{object_name}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
|
762
|
+
name = "#{object_name}#{index}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
|
722
763
|
args.unshift(object)
|
723
764
|
else
|
724
765
|
object = record_or_name_or_array
|
725
|
-
name = "#{object_name}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
|
766
|
+
name = "#{object_name}#{index}[#{ActionController::RecordIdentifier.singular_class_name(object)}]"
|
726
767
|
args.unshift(object)
|
727
768
|
end
|
728
769
|
|
@@ -741,8 +782,8 @@ module ActionView
|
|
741
782
|
@template.radio_button(@object_name, method, tag_value, objectify_options(options))
|
742
783
|
end
|
743
784
|
|
744
|
-
def error_message_on(method,
|
745
|
-
@template.error_message_on(@object, method,
|
785
|
+
def error_message_on(method, *args)
|
786
|
+
@template.error_message_on(@object, method, *args)
|
746
787
|
end
|
747
788
|
|
748
789
|
def error_messages(options = {})
|
@@ -96,7 +96,7 @@ module ActionView
|
|
96
96
|
# By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
|
97
97
|
# or <tt>:selected => nil</tt> to leave all options unselected.
|
98
98
|
def select(object, method, choices, options = {}, html_options = {})
|
99
|
-
InstanceTag.new(object, method, self,
|
99
|
+
InstanceTag.new(object, method, self, options.delete(:object)).to_select_tag(choices, options, html_options)
|
100
100
|
end
|
101
101
|
|
102
102
|
# Returns <tt><select></tt> and <tt><option></tt> tags for the collection of existing return values of
|
@@ -130,12 +130,7 @@ module ActionView
|
|
130
130
|
# <option value="3">M. Clark</option>
|
131
131
|
# </select>
|
132
132
|
def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
|
133
|
-
InstanceTag.new(object, method, self,
|
134
|
-
end
|
135
|
-
|
136
|
-
# Return select and option tags for the given object and method, using country_options_for_select to generate the list of option tags.
|
137
|
-
def country_select(object, method, priority_countries = nil, options = {}, html_options = {})
|
138
|
-
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_country_select_tag(priority_countries, options, html_options)
|
133
|
+
InstanceTag.new(object, method, self, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
|
139
134
|
end
|
140
135
|
|
141
136
|
# Return select and option tags for the given object and method, using
|
@@ -150,7 +145,8 @@ module ActionView
|
|
150
145
|
# You can also supply an array of TimeZone objects
|
151
146
|
# as +priority_zones+, so that they will be listed above the rest of the
|
152
147
|
# (long) list. (You can use TimeZone.us_zones as a convenience for
|
153
|
-
# obtaining a list of the US time zones
|
148
|
+
# obtaining a list of the US time zones, or a Regexp to select the zones
|
149
|
+
# of your choice)
|
154
150
|
#
|
155
151
|
# Finally, this method supports a <tt>:default</tt> option, which selects
|
156
152
|
# a default TimeZone if the object's time zone is +nil+.
|
@@ -164,9 +160,11 @@ module ActionView
|
|
164
160
|
#
|
165
161
|
# time_zone_select( "user", 'time_zone', [ TimeZone['Alaska'], TimeZone['Hawaii'] ])
|
166
162
|
#
|
163
|
+
# time_zone_select( "user", 'time_zone', /Australia/)
|
164
|
+
#
|
167
165
|
# time_zone_select( "user", "time_zone", TZInfo::Timezone.all.sort, :model => TZInfo::Timezone)
|
168
166
|
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
|
169
|
-
InstanceTag.new(object, method, self,
|
167
|
+
InstanceTag.new(object, method, self, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
|
170
168
|
end
|
171
169
|
|
172
170
|
# Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
|
@@ -271,28 +269,13 @@ module ActionView
|
|
271
269
|
end
|
272
270
|
end
|
273
271
|
|
274
|
-
# Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to
|
275
|
-
# have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so
|
276
|
-
# that they will be listed above the rest of the (long) list.
|
277
|
-
#
|
278
|
-
# NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
|
279
|
-
def country_options_for_select(selected = nil, priority_countries = nil)
|
280
|
-
country_options = ""
|
281
|
-
|
282
|
-
if priority_countries
|
283
|
-
country_options += options_for_select(priority_countries, selected)
|
284
|
-
country_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
|
285
|
-
end
|
286
|
-
|
287
|
-
return country_options + options_for_select(COUNTRIES, selected)
|
288
|
-
end
|
289
|
-
|
290
272
|
# Returns a string of option tags for pretty much any time zone in the
|
291
273
|
# world. Supply a TimeZone name as +selected+ to have it marked as the
|
292
274
|
# selected option tag. You can also supply an array of TimeZone objects
|
293
275
|
# as +priority_zones+, so that they will be listed above the rest of the
|
294
276
|
# (long) list. (You can use TimeZone.us_zones as a convenience for
|
295
|
-
# obtaining a list of the US time zones
|
277
|
+
# obtaining a list of the US time zones, or a Regexp to select the zones
|
278
|
+
# of your choice)
|
296
279
|
#
|
297
280
|
# The +selected+ parameter must be either +nil+, or a string that names
|
298
281
|
# a TimeZone.
|
@@ -311,6 +294,9 @@ module ActionView
|
|
311
294
|
convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
|
312
295
|
|
313
296
|
if priority_zones
|
297
|
+
if priority_zones.is_a?(Regexp)
|
298
|
+
priority_zones = model.all.find_all {|z| z =~ priority_zones}
|
299
|
+
end
|
314
300
|
zone_options += options_for_select(convert_zones[priority_zones], selected)
|
315
301
|
zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
|
316
302
|
|
@@ -338,45 +324,6 @@ module ActionView
|
|
338
324
|
value == selected
|
339
325
|
end
|
340
326
|
end
|
341
|
-
|
342
|
-
# All the countries included in the country_options output.
|
343
|
-
COUNTRIES = ["Afghanistan", "Aland Islands", "Albania", "Algeria", "American Samoa", "Andorra", "Angola",
|
344
|
-
"Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria",
|
345
|
-
"Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin",
|
346
|
-
"Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil",
|
347
|
-
"British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia",
|
348
|
-
"Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
|
349
|
-
"Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
|
350
|
-
"Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba",
|
351
|
-
"Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt",
|
352
|
-
"El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)",
|
353
|
-
"Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia",
|
354
|
-
"French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea",
|
355
|
-
"Guinea-Bissau", "Guyana", "Haiti", "Heard and McDonald Islands", "Holy See (Vatican City State)",
|
356
|
-
"Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran, Islamic Republic of", "Iraq",
|
357
|
-
"Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya",
|
358
|
-
"Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan",
|
359
|
-
"Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya",
|
360
|
-
"Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Macedonia, The Former Yugoslav Republic Of",
|
361
|
-
"Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique",
|
362
|
-
"Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of",
|
363
|
-
"Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru",
|
364
|
-
"Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger",
|
365
|
-
"Nigeria", "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau",
|
366
|
-
"Palestinian Territory, Occupied", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines",
|
367
|
-
"Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation",
|
368
|
-
"Rwanda", "Saint Barthelemy", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia",
|
369
|
-
"Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino",
|
370
|
-
"Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore",
|
371
|
-
"Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa",
|
372
|
-
"South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka", "Sudan", "Suriname",
|
373
|
-
"Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic",
|
374
|
-
"Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Timor-Leste",
|
375
|
-
"Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan",
|
376
|
-
"Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom",
|
377
|
-
"United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela",
|
378
|
-
"Viet Nam", "Virgin Islands, British", "Virgin Islands, U.S.", "Wallis and Futuna", "Western Sahara",
|
379
|
-
"Yemen", "Zambia", "Zimbabwe"] unless const_defined?("COUNTRIES")
|
380
327
|
end
|
381
328
|
|
382
329
|
class InstanceTag #:nodoc:
|
@@ -399,19 +346,6 @@ module ActionView
|
|
399
346
|
)
|
400
347
|
end
|
401
348
|
|
402
|
-
def to_country_select_tag(priority_countries, options, html_options)
|
403
|
-
ActiveSupport::Deprecation.warn("country_select will be removed from 2.2.0. http://www.rubyonrails.org/deprecation/list-of-countries has more information.", caller)
|
404
|
-
html_options = html_options.stringify_keys
|
405
|
-
add_default_name_and_id(html_options)
|
406
|
-
value = value(object)
|
407
|
-
content_tag("select",
|
408
|
-
add_options(
|
409
|
-
country_options_for_select(value, priority_countries),
|
410
|
-
options, value
|
411
|
-
), html_options
|
412
|
-
)
|
413
|
-
end
|
414
|
-
|
415
349
|
def to_time_zone_select_tag(priority_zones, options, html_options)
|
416
350
|
html_options = html_options.stringify_keys
|
417
351
|
add_default_name_and_id(html_options)
|
@@ -439,19 +373,15 @@ module ActionView
|
|
439
373
|
|
440
374
|
class FormBuilder
|
441
375
|
def select(method, choices, options = {}, html_options = {})
|
442
|
-
@template.select(@object_name, method, choices, options.merge(
|
376
|
+
@template.select(@object_name, method, choices, objectify_options(options), @default_options.merge(html_options))
|
443
377
|
end
|
444
378
|
|
445
379
|
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
|
446
|
-
@template.collection_select(@object_name, method, collection, value_method, text_method, options.merge(
|
447
|
-
end
|
448
|
-
|
449
|
-
def country_select(method, priority_countries = nil, options = {}, html_options = {})
|
450
|
-
@template.country_select(@object_name, method, priority_countries, options.merge(:object => @object), html_options)
|
380
|
+
@template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
|
451
381
|
end
|
452
382
|
|
453
383
|
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
|
454
|
-
@template.time_zone_select(@object_name, method, priority_zones, options.merge(
|
384
|
+
@template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
|
455
385
|
end
|
456
386
|
end
|
457
387
|
end
|
@@ -6,7 +6,7 @@ module ActionView
|
|
6
6
|
# Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like
|
7
7
|
# FormHelper does. Instead, you provide the names and values manually.
|
8
8
|
#
|
9
|
-
# NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
|
9
|
+
# NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
|
10
10
|
# <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>.
|
11
11
|
module FormTagHelper
|
12
12
|
# Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
|
@@ -20,15 +20,15 @@ module ActionView
|
|
20
20
|
# * A list of parameters to feed to the URL the form will be posted to.
|
21
21
|
#
|
22
22
|
# ==== Examples
|
23
|
-
# form_tag('/posts')
|
23
|
+
# form_tag('/posts')
|
24
24
|
# # => <form action="/posts" method="post">
|
25
25
|
#
|
26
|
-
# form_tag('/posts/1', :method => :put)
|
26
|
+
# form_tag('/posts/1', :method => :put)
|
27
27
|
# # => <form action="/posts/1" method="put">
|
28
28
|
#
|
29
|
-
# form_tag('/upload', :multipart => true)
|
29
|
+
# form_tag('/upload', :multipart => true)
|
30
30
|
# # => <form action="/upload" method="post" enctype="multipart/form-data">
|
31
|
-
#
|
31
|
+
#
|
32
32
|
# <% form_tag '/posts' do -%>
|
33
33
|
# <div><%= submit_tag 'Save' %></div>
|
34
34
|
# <% end -%>
|
@@ -62,7 +62,7 @@ module ActionView
|
|
62
62
|
# # <option>3</option><option>4</option></select>
|
63
63
|
#
|
64
64
|
# select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>", :multiple => true
|
65
|
-
# # => <select id="colors" multiple="multiple" name="colors"><option>Red</option>
|
65
|
+
# # => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option>
|
66
66
|
# # <option>Green</option><option>Blue</option></select>
|
67
67
|
#
|
68
68
|
# select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>"
|
@@ -70,14 +70,15 @@ module ActionView
|
|
70
70
|
# # <option>Out</option></select>
|
71
71
|
#
|
72
72
|
# select_tag "access", "<option>Read</option><option>Write</option>", :multiple => true, :class => 'form_input'
|
73
|
-
# # => <select class="form_input" id="access" multiple="multiple" name="access"><option>Read</option>
|
73
|
+
# # => <select class="form_input" id="access" multiple="multiple" name="access[]"><option>Read</option>
|
74
74
|
# # <option>Write</option></select>
|
75
75
|
#
|
76
76
|
# select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true
|
77
77
|
# # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
|
78
78
|
# # <option>Paris</option><option>Rome</option></select>
|
79
79
|
def select_tag(name, option_tags = nil, options = {})
|
80
|
-
|
80
|
+
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
|
81
|
+
content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
|
81
82
|
end
|
82
83
|
|
83
84
|
# Creates a standard text field; use these text fields to input smaller chunks of text like a username
|
@@ -88,7 +89,7 @@ module ActionView
|
|
88
89
|
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
89
90
|
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
90
91
|
# * Any other key creates standard HTML attributes for the tag.
|
91
|
-
#
|
92
|
+
#
|
92
93
|
# ==== Examples
|
93
94
|
# text_field_tag 'name'
|
94
95
|
# # => <input id="name" name="name" type="text" />
|
@@ -111,7 +112,7 @@ module ActionView
|
|
111
112
|
# text_field_tag 'ip', '0.0.0.0', :maxlength => 15, :size => 20, :class => "ip-input"
|
112
113
|
# # => <input class="ip-input" id="ip" maxlength="15" name="ip" size="20" type="text" value="0.0.0.0" />
|
113
114
|
def text_field_tag(name, value = nil, options = {})
|
114
|
-
tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
115
|
+
tag :input, { "type" => "text", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
|
115
116
|
end
|
116
117
|
|
117
118
|
# Creates a label field
|
@@ -129,7 +130,7 @@ module ActionView
|
|
129
130
|
# label_tag 'name', nil, :class => 'small_label'
|
130
131
|
# # => <label for="name" class="small_label">Name</label>
|
131
132
|
def label_tag(name, text = nil, options = {})
|
132
|
-
content_tag :label, text || name.to_s.humanize, { "for" => name }.update(options.stringify_keys)
|
133
|
+
content_tag :label, text || name.to_s.humanize, { "for" => sanitize_to_id(name) }.update(options.stringify_keys)
|
133
134
|
end
|
134
135
|
|
135
136
|
# Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or
|
@@ -146,21 +147,21 @@ module ActionView
|
|
146
147
|
# # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
|
147
148
|
#
|
148
149
|
# hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')"
|
149
|
-
# # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
|
150
|
+
# # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
|
150
151
|
# # type="hidden" value="" />
|
151
152
|
def hidden_field_tag(name, value = nil, options = {})
|
152
153
|
text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
|
153
154
|
end
|
154
155
|
|
155
|
-
# Creates a file upload field. If you are using file uploads then you will also need
|
156
|
+
# Creates a file upload field. If you are using file uploads then you will also need
|
156
157
|
# to set the multipart option for the form tag:
|
157
158
|
#
|
158
|
-
#
|
159
|
+
# <% form_tag '/upload', :multipart => true do %>
|
159
160
|
# <label for="file">File to Upload</label> <%= file_field_tag "file" %>
|
160
161
|
# <%= submit_tag %>
|
161
|
-
#
|
162
|
+
# <% end %>
|
162
163
|
#
|
163
|
-
# The specified URL will then be passed a File object containing the selected file, or if the field
|
164
|
+
# The specified URL will then be passed a File object containing the selected file, or if the field
|
164
165
|
# was left blank, a StringIO object.
|
165
166
|
#
|
166
167
|
# ==== Options
|
@@ -181,7 +182,7 @@ module ActionView
|
|
181
182
|
# # => <input id="resume" name="resume" type="file" value="~/resume.doc" />
|
182
183
|
#
|
183
184
|
# file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg'
|
184
|
-
# # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
|
185
|
+
# # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
|
185
186
|
#
|
186
187
|
# file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html'
|
187
188
|
# # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
|
@@ -281,12 +282,12 @@ module ActionView
|
|
281
282
|
# check_box_tag 'eula', 'accepted', false, :disabled => true
|
282
283
|
# # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
|
283
284
|
def check_box_tag(name, value = "1", checked = false, options = {})
|
284
|
-
html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
285
|
+
html_options = { "type" => "checkbox", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
|
285
286
|
html_options["checked"] = "checked" if checked
|
286
287
|
tag :input, html_options
|
287
288
|
end
|
288
289
|
|
289
|
-
# Creates a radio button; use groups of radio buttons named the same to allow users to
|
290
|
+
# Creates a radio button; use groups of radio buttons named the same to allow users to
|
290
291
|
# select from a group of options.
|
291
292
|
#
|
292
293
|
# ==== Options
|
@@ -313,14 +314,14 @@ module ActionView
|
|
313
314
|
tag :input, html_options
|
314
315
|
end
|
315
316
|
|
316
|
-
# Creates a submit button with the text <tt>value</tt> as the caption.
|
317
|
+
# Creates a submit button with the text <tt>value</tt> as the caption.
|
317
318
|
#
|
318
319
|
# ==== Options
|
319
320
|
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
|
320
321
|
# prompt with the question specified. If the user accepts, the form is
|
321
322
|
# processed normally, otherwise no action is taken.
|
322
323
|
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
|
323
|
-
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
|
324
|
+
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
|
324
325
|
# of the submit button when the form is submitted.
|
325
326
|
# * Any other key creates standard HTML options for the tag.
|
326
327
|
#
|
@@ -335,7 +336,7 @@ module ActionView
|
|
335
336
|
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
|
336
337
|
#
|
337
338
|
# submit_tag "Complete sale", :disable_with => "Please wait..."
|
338
|
-
# # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
|
339
|
+
# # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
|
339
340
|
# # type="submit" value="Complete sale" />
|
340
341
|
#
|
341
342
|
# submit_tag nil, :class => "form_submit"
|
@@ -346,7 +347,7 @@ module ActionView
|
|
346
347
|
# # name="commit" type="submit" value="Edit" />
|
347
348
|
def submit_tag(value = "Save changes", options = {})
|
348
349
|
options.stringify_keys!
|
349
|
-
|
350
|
+
|
350
351
|
if disable_with = options.delete("disable_with")
|
351
352
|
disable_with = "this.value='#{disable_with}'"
|
352
353
|
disable_with << ";#{options.delete('onclick')}" if options['onclick']
|
@@ -357,20 +358,23 @@ module ActionView
|
|
357
358
|
options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());"
|
358
359
|
options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;"
|
359
360
|
end
|
360
|
-
|
361
|
+
|
361
362
|
if confirm = options.delete("confirm")
|
362
363
|
options["onclick"] ||= ''
|
363
364
|
options["onclick"] << "return #{confirm_javascript_function(confirm)};"
|
364
365
|
end
|
365
|
-
|
366
|
+
|
366
367
|
tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
|
367
368
|
end
|
368
|
-
|
369
|
+
|
369
370
|
# Displays an image which when clicked will submit the form.
|
370
371
|
#
|
371
372
|
# <tt>source</tt> is passed to AssetTagHelper#image_path
|
372
373
|
#
|
373
374
|
# ==== Options
|
375
|
+
# * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
|
376
|
+
# prompt with the question specified. If the user accepts, the form is
|
377
|
+
# processed normally, otherwise no action is taken.
|
374
378
|
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
375
379
|
# * Any other key creates standard HTML options for the tag.
|
376
380
|
#
|
@@ -387,12 +391,20 @@ module ActionView
|
|
387
391
|
# image_submit_tag("agree.png", :disabled => true, :class => "agree-disagree-button")
|
388
392
|
# # => <input class="agree-disagree-button" disabled="disabled" src="/images/agree.png" type="image" />
|
389
393
|
def image_submit_tag(source, options = {})
|
394
|
+
options.stringify_keys!
|
395
|
+
|
396
|
+
if confirm = options.delete("confirm")
|
397
|
+
options["onclick"] ||= ''
|
398
|
+
options["onclick"] += "return #{confirm_javascript_function(confirm)};"
|
399
|
+
end
|
400
|
+
|
390
401
|
tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys)
|
391
402
|
end
|
392
403
|
|
393
404
|
# Creates a field set for grouping HTML form elements.
|
394
405
|
#
|
395
406
|
# <tt>legend</tt> will become the fieldset's title (optional as per W3C).
|
407
|
+
# <tt>options</tt> accept the same values as tag.
|
396
408
|
#
|
397
409
|
# === Examples
|
398
410
|
# <% field_set_tag do %>
|
@@ -404,14 +416,19 @@ module ActionView
|
|
404
416
|
# <p><%= text_field_tag 'name' %></p>
|
405
417
|
# <% end %>
|
406
418
|
# # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset>
|
407
|
-
|
419
|
+
#
|
420
|
+
# <% field_set_tag nil, :class => 'format' do %>
|
421
|
+
# <p><%= text_field_tag 'name' %></p>
|
422
|
+
# <% end %>
|
423
|
+
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
|
424
|
+
def field_set_tag(legend = nil, options = nil, &block)
|
408
425
|
content = capture(&block)
|
409
|
-
concat(tag(:fieldset,
|
410
|
-
concat(content_tag(:legend, legend)
|
411
|
-
concat(content
|
412
|
-
concat("</fieldset>"
|
426
|
+
concat(tag(:fieldset, options, true))
|
427
|
+
concat(content_tag(:legend, legend)) unless legend.blank?
|
428
|
+
concat(content)
|
429
|
+
concat("</fieldset>")
|
413
430
|
end
|
414
|
-
|
431
|
+
|
415
432
|
private
|
416
433
|
def html_options_for_form(url_for_options, options, *parameters_for_url)
|
417
434
|
returning options.stringify_keys do |html_options|
|
@@ -419,7 +436,7 @@ module ActionView
|
|
419
436
|
html_options["action"] = url_for(url_for_options, *parameters_for_url)
|
420
437
|
end
|
421
438
|
end
|
422
|
-
|
439
|
+
|
423
440
|
def extra_tags_for_form(html_options)
|
424
441
|
case method = html_options.delete("method").to_s
|
425
442
|
when /^get$/i # must be case-insentive, but can't use downcase as might be nil
|
@@ -433,17 +450,17 @@ module ActionView
|
|
433
450
|
content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0')
|
434
451
|
end
|
435
452
|
end
|
436
|
-
|
453
|
+
|
437
454
|
def form_tag_html(html_options)
|
438
455
|
extra_tags = extra_tags_for_form(html_options)
|
439
456
|
tag(:form, html_options, true) + extra_tags
|
440
457
|
end
|
441
|
-
|
458
|
+
|
442
459
|
def form_tag_in_block(html_options, &block)
|
443
460
|
content = capture(&block)
|
444
|
-
concat(form_tag_html(html_options)
|
445
|
-
concat(content
|
446
|
-
concat("</form>"
|
461
|
+
concat(form_tag_html(html_options))
|
462
|
+
concat(content)
|
463
|
+
concat("</form>")
|
447
464
|
end
|
448
465
|
|
449
466
|
def token_tag
|
@@ -453,6 +470,12 @@ module ActionView
|
|
453
470
|
tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
|
454
471
|
end
|
455
472
|
end
|
473
|
+
|
474
|
+
# see http://www.w3.org/TR/html4/types.html#type-name
|
475
|
+
def sanitize_to_id(name)
|
476
|
+
name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_")
|
477
|
+
end
|
478
|
+
|
456
479
|
end
|
457
480
|
end
|
458
481
|
end
|