actionpack 1.9.1 → 1.10.1
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 +237 -0
- data/README +12 -12
- data/lib/action_controller.rb +17 -12
- data/lib/action_controller/assertions.rb +119 -67
- data/lib/action_controller/base.rb +184 -102
- data/lib/action_controller/benchmarking.rb +35 -6
- data/lib/action_controller/caching.rb +115 -58
- data/lib/action_controller/cgi_ext/cgi_methods.rb +54 -21
- data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +39 -35
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +34 -21
- data/lib/action_controller/cgi_process.rb +23 -20
- data/lib/action_controller/components.rb +11 -2
- data/lib/action_controller/dependencies.rb +0 -5
- data/lib/action_controller/deprecated_redirects.rb +17 -0
- data/lib/action_controller/filters.rb +13 -9
- data/lib/action_controller/flash.rb +7 -7
- data/lib/action_controller/helpers.rb +1 -14
- data/lib/action_controller/layout.rb +40 -29
- data/lib/action_controller/macros/auto_complete.rb +52 -0
- data/lib/action_controller/macros/in_place_editing.rb +32 -0
- data/lib/action_controller/pagination.rb +44 -28
- data/lib/action_controller/request.rb +54 -40
- data/lib/action_controller/rescue.rb +8 -6
- data/lib/action_controller/routing.rb +77 -28
- data/lib/action_controller/scaffolding.rb +10 -14
- data/lib/action_controller/session/active_record_store.rb +36 -7
- data/lib/action_controller/session_management.rb +126 -0
- data/lib/action_controller/streaming.rb +14 -5
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +1 -1
- data/lib/action_controller/templates/rescues/_trace.rhtml +24 -0
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -13
- data/lib/action_controller/templates/rescues/template_error.rhtml +4 -2
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +35 -17
- data/lib/action_controller/upload_progress.rb +52 -0
- data/lib/action_controller/url_rewriter.rb +21 -16
- data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
- data/lib/action_controller/vendor/html-scanner/html/node.rb +30 -3
- data/lib/action_pack/version.rb +9 -0
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +204 -60
- data/lib/action_view/compiled_templates.rb +70 -0
- data/lib/action_view/helpers/active_record_helper.rb +7 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +22 -12
- data/lib/action_view/helpers/capture_helper.rb +2 -10
- data/lib/action_view/helpers/date_helper.rb +21 -13
- data/lib/action_view/helpers/form_helper.rb +14 -10
- data/lib/action_view/helpers/form_options_helper.rb +4 -4
- data/lib/action_view/helpers/form_tag_helper.rb +59 -25
- data/lib/action_view/helpers/java_script_macros_helper.rb +188 -0
- data/lib/action_view/helpers/javascript_helper.rb +68 -133
- data/lib/action_view/helpers/javascripts/controls.js +427 -165
- data/lib/action_view/helpers/javascripts/dragdrop.js +256 -277
- data/lib/action_view/helpers/javascripts/effects.js +766 -277
- data/lib/action_view/helpers/javascripts/prototype.js +906 -218
- data/lib/action_view/helpers/javascripts/slider.js +258 -0
- data/lib/action_view/helpers/number_helper.rb +4 -3
- data/lib/action_view/helpers/pagination_helper.rb +42 -27
- data/lib/action_view/helpers/tag_helper.rb +25 -11
- data/lib/action_view/helpers/text_helper.rb +119 -13
- data/lib/action_view/helpers/upload_progress_helper.rb +2 -2
- data/lib/action_view/helpers/url_helper.rb +68 -21
- data/lib/action_view/partials.rb +17 -6
- data/lib/action_view/template_error.rb +19 -24
- data/rakefile +4 -3
- data/test/abstract_unit.rb +2 -1
- data/test/controller/action_pack_assertions_test.rb +62 -2
- data/test/controller/active_record_assertions_test.rb +5 -6
- data/test/controller/active_record_store_test.rb +23 -1
- data/test/controller/addresses_render_test.rb +4 -0
- data/test/controller/{base_tests.rb → base_test.rb} +4 -3
- data/test/controller/benchmark_test.rb +36 -0
- data/test/controller/caching_filestore.rb +22 -40
- data/test/controller/capture_test.rb +10 -1
- data/test/controller/cgi_test.rb +145 -23
- data/test/controller/components_test.rb +50 -0
- data/test/controller/custom_handler_test.rb +3 -3
- data/test/controller/fake_controllers.rb +24 -0
- data/test/controller/filters_test.rb +6 -6
- data/test/controller/flash_test.rb +6 -6
- data/test/controller/fragment_store_setting_test.rb +45 -0
- data/test/controller/helper_test.rb +1 -3
- data/test/controller/new_render_test.rb +119 -7
- data/test/controller/redirect_test.rb +11 -1
- data/test/controller/render_test.rb +34 -1
- data/test/controller/request_test.rb +14 -5
- data/test/controller/routing_test.rb +238 -42
- data/test/controller/send_file_test.rb +11 -10
- data/test/controller/session_management_test.rb +94 -0
- data/test/controller/test_test.rb +194 -5
- data/test/controller/url_rewriter_test.rb +46 -0
- data/test/fixtures/layouts/talk_from_action.rhtml +2 -0
- data/test/fixtures/layouts/yield.rhtml +2 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/multipart/large_text_file +10 -0
- data/test/fixtures/multipart/mixed_files +0 -0
- data/test/fixtures/multipart/single_parameter +5 -0
- data/test/fixtures/multipart/text_file +10 -0
- data/test/fixtures/test/_customer_greeting.rhtml +1 -0
- data/test/fixtures/test/_hash_object.rhtml +1 -0
- data/test/fixtures/test/_person.rhtml +2 -0
- data/test/fixtures/test/action_talk_to_layout.rhtml +2 -0
- data/test/fixtures/test/content_for.rhtml +2 -0
- data/test/fixtures/test/potential_conflicts.rhtml +4 -0
- data/test/template/active_record_helper_test.rb +15 -8
- data/test/template/asset_tag_helper_test.rb +40 -16
- data/test/template/compiled_templates_tests.rb +63 -0
- data/test/template/date_helper_test.rb +80 -4
- data/test/template/form_helper_test.rb +48 -42
- data/test/template/form_options_helper_test.rb +40 -40
- data/test/template/form_tag_helper_test.rb +21 -15
- data/test/template/java_script_macros_helper_test.rb +56 -0
- data/test/template/javascript_helper_test.rb +70 -47
- data/test/template/number_helper_test.rb +2 -0
- data/test/template/tag_helper_test.rb +9 -0
- data/test/template/text_helper_test.rb +146 -1
- data/test/template/upload_progress_helper_testx.rb +11 -147
- data/test/template/url_helper_test.rb +90 -22
- data/test/testing_sandbox.rb +26 -0
- metadata +37 -7
- data/lib/action_controller/auto_complete.rb +0 -47
- data/lib/action_controller/deprecated_renders_and_redirects.rb +0 -76
- data/lib/action_controller/session.rb +0 -14
@@ -17,8 +17,8 @@ module ActionView
|
|
17
17
|
# (title is a VARCHAR column and holds "Hello World"):
|
18
18
|
# input("post", "title") =>
|
19
19
|
# <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
|
20
|
-
def input(record_name, method)
|
21
|
-
InstanceTag.new(record_name, method, self).to_tag
|
20
|
+
def input(record_name, method, options = {})
|
21
|
+
InstanceTag.new(record_name, method, self).to_tag(options)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Returns an entire form with input tags and everything for a specified Active Record object. Example
|
@@ -71,7 +71,7 @@ module ActionView
|
|
71
71
|
yield contents if block_given?
|
72
72
|
contents << submit_tag(submit_value)
|
73
73
|
|
74
|
-
content_tag('form', contents, :action => action, :method => 'post')
|
74
|
+
content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil)
|
75
75
|
end
|
76
76
|
|
77
77
|
# Returns a string containing the error message attached to the +method+ on the +object+, if one exists.
|
@@ -96,6 +96,10 @@ module ActionView
|
|
96
96
|
# * <tt>header_tag</tt> - Used for the header of the error div (default: h2)
|
97
97
|
# * <tt>id</tt> - The id of the error div (default: errorExplanation)
|
98
98
|
# * <tt>class</tt> - The class of the error div (default: errorExplanation)
|
99
|
+
#
|
100
|
+
# NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what
|
101
|
+
# you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors
|
102
|
+
# instance yourself and set it up. View the source of this method to see how easy it is.
|
99
103
|
def error_messages_for(object_name, options = {})
|
100
104
|
options = options.symbolize_keys
|
101
105
|
object = instance_variable_get("@#{object_name}")
|
@@ -18,13 +18,13 @@ module ActionView
|
|
18
18
|
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/feed" />
|
19
19
|
# auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
|
20
20
|
# <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.curenthost.com/controller/feed" />
|
21
|
-
def auto_discovery_link_tag(type = :rss,
|
21
|
+
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
|
22
22
|
tag(
|
23
23
|
"link",
|
24
|
-
"rel"
|
25
|
-
"type"
|
24
|
+
"rel" => tag_options[:rel] || "alternate",
|
25
|
+
"type" => tag_options[:type] || "application/#{type}+xml",
|
26
26
|
"title" => tag_options[:title] || type.to_s.upcase,
|
27
|
-
"href"
|
27
|
+
"href" => url_options.is_a?(Hash) ? url_for(url_options.merge(:only_path => false)) : url_options
|
28
28
|
)
|
29
29
|
end
|
30
30
|
|
@@ -46,12 +46,21 @@ module ActionView
|
|
46
46
|
#
|
47
47
|
# javascript_include_tag :defaults # =>
|
48
48
|
# <script type="text/javascript" src="/javascripts/prototype.js"></script>
|
49
|
-
# <script type="text/javascript" src="/javascripts/
|
50
|
-
# <script type="text/javascript" src="/javascripts/
|
51
|
-
#
|
49
|
+
# <script type="text/javascript" src="/javascripts/scriptaculous.js"></script>
|
50
|
+
# <script type="text/javascript" src="/javascripts/application.js"></script> *see beloe
|
51
|
+
#
|
52
|
+
# If there's an <tt>application.js</tt> file in your <tt>public/javascripts</tt> directory,
|
53
|
+
# <tt>javascript_include_tag :defaults</tt> will automatically include it. This file
|
54
|
+
# facilitates the inclusion of small snippets of JavaScript code, along the lines of
|
55
|
+
# <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
|
52
56
|
def javascript_include_tag(*sources)
|
53
57
|
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
54
|
-
|
58
|
+
if sources.first == :defaults
|
59
|
+
sources = ['prototype', 'scriptaculous']
|
60
|
+
if defined?(RAILS_ROOT) and File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
|
61
|
+
sources << 'application'
|
62
|
+
end
|
63
|
+
end
|
55
64
|
sources.collect { |source|
|
56
65
|
source = javascript_path(source)
|
57
66
|
content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
|
@@ -94,7 +103,7 @@ module ActionView
|
|
94
103
|
compute_public_path(source, 'images', 'png')
|
95
104
|
end
|
96
105
|
|
97
|
-
# Returns an image tag converting the +options+
|
106
|
+
# Returns an image tag converting the +options+ into html options on the tag, but with these special cases:
|
98
107
|
#
|
99
108
|
# * <tt>:alt</tt> - If no alt text is given, the file name part of the +src+ is used (capitalized and without the extension)
|
100
109
|
# * <tt>:size</tt> - Supplied as "XxY", so "30x45" becomes width="30" and height="45"
|
@@ -119,10 +128,11 @@ module ActionView
|
|
119
128
|
|
120
129
|
private
|
121
130
|
def compute_public_path(source, dir, ext)
|
122
|
-
source = "/#{dir}/#{source}" unless source.include?("
|
131
|
+
source = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
|
123
132
|
source = "#{source}.#{ext}" unless source.include?(".")
|
124
|
-
source = "#{@request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
|
125
|
-
ActionController::Base.asset_host + source
|
133
|
+
source = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
|
134
|
+
source = ActionController::Base.asset_host + source unless source.include?(":")
|
135
|
+
source
|
126
136
|
end
|
127
137
|
end
|
128
138
|
end
|
@@ -81,17 +81,9 @@ module ActionView
|
|
81
81
|
#
|
82
82
|
# NOTE: Beware that content_for is ignored in caches. So you shouldn't use it
|
83
83
|
# for elements that are going to be fragment cached.
|
84
|
-
def content_for(name, &block)
|
85
|
-
|
86
|
-
data = capture(&block)
|
87
|
-
controller.instance_variable_set(instance_var_name(name), base + data)
|
88
|
-
data
|
84
|
+
def content_for(name, &block)
|
85
|
+
eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"
|
89
86
|
end
|
90
|
-
|
91
|
-
private
|
92
|
-
def instance_var_name(name) #:nodoc#
|
93
|
-
"@content_for_#{name}"
|
94
|
-
end
|
95
87
|
end
|
96
88
|
end
|
97
89
|
end
|
@@ -13,7 +13,7 @@ module ActionView
|
|
13
13
|
module DateHelper
|
14
14
|
DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
|
15
15
|
|
16
|
-
# Reports the approximate distance in time between
|
16
|
+
# Reports the approximate distance in time between two Time objects or integers.
|
17
17
|
# For example, if the distance is 47 minutes, it'll return
|
18
18
|
# "about 1 hour". See the source for the complete wording list.
|
19
19
|
#
|
@@ -56,12 +56,14 @@ module ActionView
|
|
56
56
|
|
57
57
|
# Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
|
58
58
|
# +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
|
59
|
-
# which
|
59
|
+
# which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month) as well as a range of
|
60
60
|
# discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
|
61
61
|
# drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
|
62
62
|
# set the order of the tags using the <tt>:order</tt> option with an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in
|
63
63
|
# the desired order. Symbols may be omitted and the respective select is not included.
|
64
64
|
#
|
65
|
+
# Passing :disabled => true as part of the +options+ will make elements inaccessible for change.
|
66
|
+
#
|
65
67
|
# NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
|
66
68
|
#
|
67
69
|
# Examples:
|
@@ -94,7 +96,7 @@ module ActionView
|
|
94
96
|
select_year(date, options) + select_month(date, options) + select_day(date, options)
|
95
97
|
end
|
96
98
|
|
97
|
-
# Returns a set of html select-tags (one for year, month, day, hour, and minute)
|
99
|
+
# Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
|
98
100
|
def select_datetime(datetime = Time.now, options = {})
|
99
101
|
select_year(datetime, options) + select_month(datetime, options) + select_day(datetime, options) +
|
100
102
|
select_hour(datetime, options) + select_minute(datetime, options)
|
@@ -118,7 +120,7 @@ module ActionView
|
|
118
120
|
)
|
119
121
|
end
|
120
122
|
|
121
|
-
select_html(options[:field_name] || 'second', second_options, options[:prefix], options[:include_blank], options[:discard_type])
|
123
|
+
select_html(options[:field_name] || 'second', second_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
122
124
|
end
|
123
125
|
|
124
126
|
# Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
|
@@ -135,7 +137,7 @@ module ActionView
|
|
135
137
|
)
|
136
138
|
end
|
137
139
|
|
138
|
-
select_html(options[:field_name] || 'minute', minute_options, options[:prefix], options[:include_blank], options[:discard_type])
|
140
|
+
select_html(options[:field_name] || 'minute', minute_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
139
141
|
end
|
140
142
|
|
141
143
|
# Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
|
@@ -151,7 +153,7 @@ module ActionView
|
|
151
153
|
)
|
152
154
|
end
|
153
155
|
|
154
|
-
select_html(options[:field_name] || 'hour', hour_options, options[:prefix], options[:include_blank], options[:discard_type])
|
156
|
+
select_html(options[:field_name] || 'hour', hour_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
155
157
|
end
|
156
158
|
|
157
159
|
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
|
@@ -167,7 +169,7 @@ module ActionView
|
|
167
169
|
)
|
168
170
|
end
|
169
171
|
|
170
|
-
select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type])
|
172
|
+
select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
171
173
|
end
|
172
174
|
|
173
175
|
# Returns a select tag with options for each of the months January through December with the current month selected.
|
@@ -181,16 +183,20 @@ module ActionView
|
|
181
183
|
# select_month(Date.today, :add_month_numbers => true) # Will use keys like "1 - January", "3 - March"
|
182
184
|
#
|
183
185
|
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
|
186
|
+
#
|
187
|
+
# If you would prefer to show month names as abbreviations, set the
|
188
|
+
# <tt>:use_short_month</tt> key in +options+ to true.
|
184
189
|
def select_month(date, options = {})
|
185
190
|
month_options = []
|
191
|
+
month_names = options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES
|
186
192
|
|
187
193
|
1.upto(12) do |month_number|
|
188
194
|
month_name = if options[:use_month_numbers]
|
189
195
|
month_number
|
190
196
|
elsif options[:add_month_numbers]
|
191
|
-
month_number.to_s + ' - ' +
|
197
|
+
month_number.to_s + ' - ' + month_names[month_number]
|
192
198
|
else
|
193
|
-
|
199
|
+
month_names[month_number]
|
194
200
|
end
|
195
201
|
|
196
202
|
month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
|
@@ -199,7 +205,7 @@ module ActionView
|
|
199
205
|
)
|
200
206
|
end
|
201
207
|
|
202
|
-
select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type])
|
208
|
+
select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
203
209
|
end
|
204
210
|
|
205
211
|
# Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
|
@@ -225,14 +231,16 @@ module ActionView
|
|
225
231
|
)
|
226
232
|
end
|
227
233
|
|
228
|
-
select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type])
|
234
|
+
select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
229
235
|
end
|
230
236
|
|
231
237
|
private
|
232
|
-
def select_html(type, options, prefix = nil, include_blank = false, discard_type = false)
|
238
|
+
def select_html(type, options, prefix = nil, include_blank = false, discard_type = false, disabled = false)
|
233
239
|
select_html = %(<select name="#{prefix || DEFAULT_PREFIX})
|
234
240
|
select_html << "[#{type}]" unless discard_type
|
235
|
-
select_html << %("
|
241
|
+
select_html << %(")
|
242
|
+
select_html << %( disabled="disabled") if disabled
|
243
|
+
select_html << %(>\n)
|
236
244
|
select_html << %(<option value=""></option>\n) if include_blank
|
237
245
|
select_html << options.to_s
|
238
246
|
select_html << "</select>\n"
|
@@ -35,7 +35,7 @@ module ActionView
|
|
35
35
|
# size="20" maxsize="20" value="<%= @person.password %>" />
|
36
36
|
#
|
37
37
|
# Single?:
|
38
|
-
# <input type="checkbox" id="person_single" name="person[single] value="1" />
|
38
|
+
# <input type="checkbox" id="person_single" name="person[single]" value="1" />
|
39
39
|
#
|
40
40
|
# Description:
|
41
41
|
# <textarea cols="20" rows="40" id="person_description" name="person[description]">
|
@@ -76,17 +76,17 @@ module ActionView
|
|
76
76
|
InstanceTag.new(object, method, self).to_input_field_tag("text", options)
|
77
77
|
end
|
78
78
|
|
79
|
-
# Works just like text_field, but returns
|
79
|
+
# Works just like text_field, but returns an input tag of the "password" type instead.
|
80
80
|
def password_field(object, method, options = {})
|
81
81
|
InstanceTag.new(object, method, self).to_input_field_tag("password", options)
|
82
82
|
end
|
83
83
|
|
84
|
-
# Works just like text_field, but returns
|
84
|
+
# Works just like text_field, but returns an input tag of the "hidden" type instead.
|
85
85
|
def hidden_field(object, method, options = {})
|
86
86
|
InstanceTag.new(object, method, self).to_input_field_tag("hidden", options)
|
87
87
|
end
|
88
88
|
|
89
|
-
# Works just like text_field, but returns
|
89
|
+
# Works just like text_field, but returns an input tag of the "file" type instead, which won't have a default value.
|
90
90
|
def file_field(object, method, options = {})
|
91
91
|
InstanceTag.new(object, method, self).to_input_field_tag("file", options)
|
92
92
|
end
|
@@ -113,12 +113,12 @@ module ActionView
|
|
113
113
|
#
|
114
114
|
# Example (call, result). Imagine that @post.validated? returns 1:
|
115
115
|
# check_box("post", "validated")
|
116
|
-
# <input type="checkbox" id="post_validate" name="post[validated] value="1" checked="checked" />
|
116
|
+
# <input type="checkbox" id="post_validate" name="post[validated]" value="1" checked="checked" />
|
117
117
|
# <input name="post[validated]" type="hidden" value="0" />
|
118
118
|
#
|
119
119
|
# Example (call, result). Imagine that @puppy.gooddog returns no:
|
120
120
|
# check_box("puppy", "gooddog", {}, "yes", "no")
|
121
|
-
# <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog] value="yes" />
|
121
|
+
# <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
|
122
122
|
# <input name="puppy[gooddog]" type="hidden" value="no" />
|
123
123
|
def check_box(object, method, options = {}, checked_value = "1", unchecked_value = "0")
|
124
124
|
InstanceTag.new(object, method, self).to_check_box_tag(options, checked_value, unchecked_value)
|
@@ -131,8 +131,8 @@ module ActionView
|
|
131
131
|
# Example (call, result). Imagine that @post.category returns "rails":
|
132
132
|
# radio_button("post", "category", "rails")
|
133
133
|
# radio_button("post", "category", "java")
|
134
|
-
# <input type="radio" id="post_category" name="post[category] value="rails" checked="checked" />
|
135
|
-
# <input type="radio" id="post_category" name="post[category] value="java" />
|
134
|
+
# <input type="radio" id="post_category" name="post[category]" value="rails" checked="checked" />
|
135
|
+
# <input type="radio" id="post_category" name="post[category]" value="java" />
|
136
136
|
#
|
137
137
|
def radio_button(object, method, tag_value, options = {})
|
138
138
|
InstanceTag.new(object, method, self).to_radio_button_tag(tag_value, options)
|
@@ -174,7 +174,7 @@ module ActionView
|
|
174
174
|
options = DEFAULT_RADIO_OPTIONS.merge(options.stringify_keys)
|
175
175
|
options["type"] = "radio"
|
176
176
|
options["value"] = tag_value
|
177
|
-
options["checked"] = "checked" if value == tag_value
|
177
|
+
options["checked"] = "checked" if value.to_s == tag_value.to_s
|
178
178
|
pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
|
179
179
|
options["id"] = @auto_index ?
|
180
180
|
"#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" :
|
@@ -234,7 +234,11 @@ module ActionView
|
|
234
234
|
tag_text << " selected" if value
|
235
235
|
tag_text << ">True</option></select>"
|
236
236
|
end
|
237
|
-
|
237
|
+
|
238
|
+
def to_content_tag(tag_name, options = {})
|
239
|
+
content_tag(tag_name, value, options)
|
240
|
+
end
|
241
|
+
|
238
242
|
def object
|
239
243
|
@template_object.instance_variable_get "@#{@object_name}"
|
240
244
|
end
|
@@ -109,7 +109,7 @@ module ActionView
|
|
109
109
|
container = container.to_a if Hash === container
|
110
110
|
|
111
111
|
options_for_select = container.inject([]) do |options, element|
|
112
|
-
if element.
|
112
|
+
if element.is_a?(Array) || element.is_a?(Range)
|
113
113
|
is_selected = ( (selected.respond_to?(:include?) ? selected.include?(element.last) : element.last == selected) )
|
114
114
|
is_selected = ( (selected.respond_to?(:include?) && !selected.is_a?(String) ? selected.include?(element.last) : element.last == selected) )
|
115
115
|
if is_selected
|
@@ -127,11 +127,11 @@ module ActionView
|
|
127
127
|
options_for_select.join("\n")
|
128
128
|
end
|
129
129
|
|
130
|
-
# Returns a string of option tags that
|
130
|
+
# Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
|
131
131
|
# the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
|
132
132
|
# If +selected_value+ is specified, the element returning a match on +value_method+ will get the selected option tag.
|
133
133
|
#
|
134
|
-
# Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate
|
134
|
+
# Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate an input tag:
|
135
135
|
# options_from_collection_for_select(@project.people, "id", "name")
|
136
136
|
# <option value="#{person.id}">#{person.name}</option>
|
137
137
|
#
|
@@ -143,7 +143,7 @@ module ActionView
|
|
143
143
|
)
|
144
144
|
end
|
145
145
|
|
146
|
-
# Returns a string of option tags, like options_from_collection_for_select, but surrounds them
|
146
|
+
# Returns a string of option tags, like options_from_collection_for_select, but surrounds them with <optgroup> tags.
|
147
147
|
#
|
148
148
|
# An array of group objects are passed. Each group should return an array of options when calling group_method
|
149
149
|
# Each group should should return its name when calling group_label_method.
|
@@ -6,7 +6,7 @@ module ActionView
|
|
6
6
|
# Provides a number of methods for creating form tags that doesn't rely on conventions with an object assigned to the template like
|
7
7
|
# FormHelper does. With the FormTagHelper, you provide the names and values yourself.
|
8
8
|
#
|
9
|
-
# NOTE: The html options disabled, readonly, and multiple can all be treated as booleans. So specifying <tt
|
9
|
+
# NOTE: The html options disabled, readonly, and multiple can all be treated as booleans. So specifying <tt>:disabled => true</tt>
|
10
10
|
# 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
|
@@ -14,6 +14,7 @@ module ActionView
|
|
14
14
|
#
|
15
15
|
# Options:
|
16
16
|
# * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
|
17
|
+
# * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post".
|
17
18
|
def form_tag(url_for_options = {}, options = {}, *parameters_for_url)
|
18
19
|
html_options = { "method" => "post" }.merge(options.stringify_keys)
|
19
20
|
|
@@ -33,26 +34,68 @@ module ActionView
|
|
33
34
|
"</form>"
|
34
35
|
end
|
35
36
|
|
37
|
+
# Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
|
38
|
+
# choice selection box.
|
39
|
+
#
|
40
|
+
# Helpers::FormOptions can be used to create common select boxes such as countries, time zones, or
|
41
|
+
# associated records.
|
42
|
+
#
|
43
|
+
# <tt>option_tags</tt> is a string containing the option tags for the select box:
|
44
|
+
# # Outputs <select id="people" name="people"><option>David</option></select>
|
45
|
+
# select_tag "people", "<option>David</option>"
|
46
|
+
#
|
47
|
+
# Options:
|
48
|
+
# * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
|
36
49
|
def select_tag(name, option_tags = nil, options = {})
|
37
|
-
content_tag("select", option_tags, { "name" => name, "id" => name }.update(
|
50
|
+
content_tag("select", option_tags, { "name" => name, "id" => name }.update(options.stringify_keys))
|
38
51
|
end
|
39
52
|
|
53
|
+
# Creates a standard text field.
|
54
|
+
#
|
55
|
+
# Options:
|
56
|
+
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
57
|
+
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
58
|
+
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
59
|
+
#
|
60
|
+
# A hash of standard HTML options for the tag.
|
40
61
|
def text_field_tag(name, value = nil, options = {})
|
41
|
-
tag("input", { "type" => "text", "name" => name, "id" => name, "value" => value }.update(
|
62
|
+
tag("input", { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys))
|
42
63
|
end
|
43
64
|
|
65
|
+
# Creates a hidden field.
|
66
|
+
#
|
67
|
+
# Takes the same options as text_field_tag
|
44
68
|
def hidden_field_tag(name, value = nil, options = {})
|
45
69
|
text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
|
46
70
|
end
|
47
71
|
|
72
|
+
# Creates a file upload field.
|
73
|
+
#
|
74
|
+
# If you are using file uploads then you will also need to set the multipart option for the form:
|
75
|
+
# <%= form_tag { :action => "post" }, { :multipart => true } %>
|
76
|
+
# <label for="file">File to Upload</label> <%= file_field_tag "file" %>
|
77
|
+
# <%= submit_tag %>
|
78
|
+
# <%= end_form_tag %>
|
79
|
+
#
|
80
|
+
# The specified URL will then be passed a File object containing the selected file, or if the field
|
81
|
+
# was left blank, a StringIO object.
|
48
82
|
def file_field_tag(name, options = {})
|
49
|
-
text_field_tag(name, nil,
|
83
|
+
text_field_tag(name, nil, options.update("type" => "file"))
|
50
84
|
end
|
51
85
|
|
86
|
+
# Creates a password field.
|
87
|
+
#
|
88
|
+
# Takes the same options as text_field_tag
|
52
89
|
def password_field_tag(name = "password", value = nil, options = {})
|
53
|
-
text_field_tag(name, value,
|
90
|
+
text_field_tag(name, value, options.update("type" => "password"))
|
54
91
|
end
|
55
92
|
|
93
|
+
# Creates a text input area.
|
94
|
+
#
|
95
|
+
# Options:
|
96
|
+
# * <tt>:size</tt> - A string specifying the dimensions of the textarea.
|
97
|
+
# # Outputs <textarea name="body" id="body" cols="25" rows="10"></textarea>
|
98
|
+
# <%= text_area_tag "body", nil, :size => 25x10 %>
|
56
99
|
def text_area_tag(name, content = nil, options = {})
|
57
100
|
options = options.stringify_keys
|
58
101
|
if options["size"]
|
@@ -60,43 +103,34 @@ module ActionView
|
|
60
103
|
options.delete("size")
|
61
104
|
end
|
62
105
|
|
63
|
-
content_tag("textarea", content, { "name" => name, "id" => name }.update(
|
106
|
+
content_tag("textarea", content, { "name" => name, "id" => name }.update(options.stringify_keys))
|
64
107
|
end
|
65
108
|
|
109
|
+
# Creates a check box.
|
66
110
|
def check_box_tag(name, value = "1", checked = false, options = {})
|
67
|
-
html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(
|
111
|
+
html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
68
112
|
html_options["checked"] = "checked" if checked
|
69
113
|
tag("input", html_options)
|
70
114
|
end
|
71
115
|
|
116
|
+
# Creates a radio button.
|
72
117
|
def radio_button_tag(name, value, checked = false, options = {})
|
73
|
-
html_options = { "type" => "radio", "name" => name, "id" => name, "value" => value }.update(
|
118
|
+
html_options = { "type" => "radio", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
|
74
119
|
html_options["checked"] = "checked" if checked
|
75
120
|
tag("input", html_options)
|
76
121
|
end
|
77
122
|
|
123
|
+
# Creates a submit button with the text <tt>value</tt> as the caption.
|
78
124
|
def submit_tag(value = "Save changes", options = {})
|
79
|
-
tag("input", { "type" => "submit", "name" => "commit", "value" => value }.update(
|
125
|
+
tag("input", { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys))
|
80
126
|
end
|
81
127
|
|
128
|
+
# Displays an image which when clicked will submit the form.
|
129
|
+
#
|
130
|
+
# <tt>source</tt> is passed to AssetTagHelper#image_path
|
82
131
|
def image_submit_tag(source, options = {})
|
83
|
-
tag("input", { "type" => "image", "src" => image_path(source) }.update(
|
132
|
+
tag("input", { "type" => "image", "src" => image_path(source) }.update(options.stringify_keys))
|
84
133
|
end
|
85
|
-
|
86
|
-
private
|
87
|
-
def convert_options(options)
|
88
|
-
options = options.stringify_keys
|
89
|
-
%w( disabled readonly multiple ).each { |a| boolean_attribute(options, a) }
|
90
|
-
options
|
91
|
-
end
|
92
|
-
|
93
|
-
def boolean_attribute(options, attribute)
|
94
|
-
if options[attribute]
|
95
|
-
options[attribute] = attribute
|
96
|
-
else
|
97
|
-
options.delete attribute
|
98
|
-
end
|
99
|
-
end
|
100
134
|
end
|
101
135
|
end
|
102
136
|
end
|