actionpack 1.4.0 → 1.5.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.

Files changed (84) hide show
  1. data/CHANGELOG +66 -0
  2. data/README +94 -64
  3. data/install.rb +1 -20
  4. data/lib/action_controller.rb +15 -7
  5. data/lib/action_controller/assertions/action_pack_assertions.rb +56 -3
  6. data/lib/action_controller/base.rb +137 -64
  7. data/lib/action_controller/caching.rb +11 -11
  8. data/lib/action_controller/cgi_ext/cgi_ext.rb +2 -2
  9. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +4 -4
  10. data/lib/action_controller/cgi_process.rb +9 -1
  11. data/lib/action_controller/components.rb +73 -0
  12. data/lib/action_controller/cookies.rb +1 -1
  13. data/lib/action_controller/dependencies.rb +6 -1
  14. data/lib/action_controller/filters.rb +1 -1
  15. data/lib/action_controller/flash.rb +3 -3
  16. data/lib/action_controller/helpers.rb +17 -21
  17. data/lib/action_controller/layout.rb +2 -2
  18. data/lib/action_controller/request.rb +16 -6
  19. data/lib/action_controller/rescue.rb +15 -3
  20. data/lib/action_controller/routing.rb +304 -0
  21. data/lib/action_controller/scaffolding.rb +10 -12
  22. data/lib/action_controller/session/active_record_store.rb +4 -7
  23. data/lib/action_controller/session/mem_cache_store.rb +2 -2
  24. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +9 -1
  25. data/lib/action_controller/templates/rescues/diagnostics.rhtml +1 -1
  26. data/lib/action_controller/templates/rescues/routing_error.rhtml +8 -0
  27. data/lib/action_controller/test_process.rb +29 -7
  28. data/lib/action_controller/url_rewriter.rb +28 -112
  29. data/lib/action_view.rb +1 -1
  30. data/lib/action_view/base.rb +44 -17
  31. data/lib/action_view/helpers/active_record_helper.rb +1 -1
  32. data/lib/action_view/helpers/asset_tag_helper.rb +59 -0
  33. data/lib/action_view/helpers/date_helper.rb +24 -13
  34. data/lib/action_view/helpers/form_helper.rb +6 -1
  35. data/lib/action_view/helpers/form_options_helper.rb +87 -9
  36. data/lib/action_view/helpers/form_tag_helper.rb +80 -0
  37. data/lib/action_view/helpers/tag_helper.rb +0 -23
  38. data/lib/action_view/helpers/text_helper.rb +26 -1
  39. data/lib/action_view/helpers/url_helper.rb +29 -35
  40. data/lib/action_view/partials.rb +2 -2
  41. data/lib/action_view/vendor/builder/xmlbase.rb +3 -3
  42. data/rakefile +5 -2
  43. data/test/abstract_unit.rb +3 -1
  44. data/test/controller/action_pack_assertions_test.rb +29 -1
  45. data/test/controller/active_record_assertions_test.rb +109 -101
  46. data/test/controller/base_tests.rb +72 -0
  47. data/test/controller/components_test.rb +74 -0
  48. data/test/controller/cookie_test.rb +0 -9
  49. data/test/controller/custom_handler_test.rb +33 -0
  50. data/test/controller/filters_test.rb +36 -0
  51. data/test/controller/helper_test.rb +27 -10
  52. data/test/controller/redirect_test.rb +23 -31
  53. data/test/controller/render_test.rb +81 -66
  54. data/test/controller/request_test.rb +22 -0
  55. data/test/controller/routing_tests.rb +490 -0
  56. data/test/controller/{url_test.rb → url_obsolete.rb} +24 -14
  57. data/test/controller/url_obsolete.rb.rej +747 -0
  58. data/test/fixtures/fun/games/hello_world.rhtml +1 -0
  59. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  60. data/test/template/asset_tag_helper_test.rb +45 -0
  61. data/test/template/form_options_helper_test.rb +161 -1
  62. data/test/template/form_tag_helper_test.rb +22 -0
  63. data/test/template/text_helper_test.rb +7 -0
  64. data/test/template/url_helper_test.rb +5 -2
  65. data/test/template/url_helper_test.rb.rej +105 -0
  66. metadata +32 -27
  67. data/lib/action_controller/support/binding_of_caller.rb +0 -83
  68. data/lib/action_controller/support/breakpoint.rb +0 -518
  69. data/lib/action_controller/support/class_attribute_accessors.rb +0 -57
  70. data/lib/action_controller/support/class_inheritable_attributes.rb +0 -117
  71. data/lib/action_controller/support/clean_logger.rb +0 -10
  72. data/lib/action_controller/support/core_ext.rb +0 -1
  73. data/lib/action_controller/support/core_ext/hash.rb +0 -5
  74. data/lib/action_controller/support/core_ext/hash/keys.rb +0 -35
  75. data/lib/action_controller/support/core_ext/numeric.rb +0 -7
  76. data/lib/action_controller/support/core_ext/numeric/bytes.rb +0 -33
  77. data/lib/action_controller/support/core_ext/numeric/time.rb +0 -59
  78. data/lib/action_controller/support/core_ext/object_and_class.rb +0 -24
  79. data/lib/action_controller/support/core_ext/string.rb +0 -5
  80. data/lib/action_controller/support/core_ext/string/inflections.rb +0 -45
  81. data/lib/action_controller/support/dependencies.rb +0 -63
  82. data/lib/action_controller/support/inflector.rb +0 -84
  83. data/lib/action_controller/support/misc.rb +0 -8
  84. data/lib/action_controller/support/module_attribute_accessors.rb +0 -57
@@ -10,7 +10,7 @@ module ActionView
10
10
  module Helpers
11
11
  # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the form
12
12
  # method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This
13
- # is a great of making the record quickly available for editing, but likely to prove lacklusters for a complicated real-world form.
13
+ # is a great of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form.
14
14
  # In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html
15
15
  module ActiveRecordHelper
16
16
  # Returns a default input tag for the type of object returned by the method. Example
@@ -0,0 +1,59 @@
1
+ require 'cgi'
2
+ require File.dirname(__FILE__) + '/url_helper'
3
+ require File.dirname(__FILE__) + '/tag_helper'
4
+
5
+ module ActionView
6
+ module Helpers
7
+ # Provides methods for linking a HTML page together with other assets, such as javascripts, stylesheets, and feeds.
8
+ module AssetTagHelper
9
+ # Returns a link tag that browsers and news readers can use to auto-detect a RSS or ATOM feed for this page. The +type+ can
10
+ # either be <tt>:rss</tt> (default) or <tt>:atom</tt> and the +options+ follow the url_for style of declaring a link target.
11
+ #
12
+ # Examples:
13
+ # auto_discovery_link_tag # =>
14
+ # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/action" />
15
+ # auto_discovery_link_tag(:atom) # =>
16
+ # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/action" />
17
+ # auto_discovery_link_tag(:rss, :action => "feed") # =>
18
+ # <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/feed" />
19
+ def auto_discovery_link_tag(type = :rss, options = {})
20
+ tag(
21
+ "link", "rel" => "alternate", "type" => "application/#{type}+xml", "title" => type.to_s.upcase,
22
+ "href" => url_for(options.merge(:only_path => false))
23
+ )
24
+ end
25
+
26
+ # Returns a script include tag per source given as argument. Examples:
27
+ #
28
+ # javascript_include_tag "xmlhr" # =>
29
+ # <script language="JavaScript" type="text/javascript" src="/javascripts/xmlhr.js"></script>
30
+ #
31
+ # javascript_include_tag "common.javascript", "/elsewhere/cools" # =>
32
+ # <script language="JavaScript" type="text/javascript" src="/javascripts/common.javascript"></script>
33
+ # <script language="JavaScript" type="text/javascript" src="/elsewhere/cools.js"></script>
34
+ def javascript_include_tag(*sources)
35
+ sources.collect { |source|
36
+ source = "/javascripts/#{source}" unless source.include?("/")
37
+ source = "#{source}.js" unless source.include?(".")
38
+ content_tag("script", "", "language" => "JavaScript", "type" => "text/javascript", "src" => source)
39
+ }.join("\n")
40
+ end
41
+
42
+ # Returns a css link tag per source given as argument. Examples:
43
+ #
44
+ # stylesheet_link_tag "style" # =>
45
+ # <link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />
46
+ #
47
+ # stylesheet_link_tag "random.styles", "/css/stylish" # =>
48
+ # <link href="/stylesheets/random.styles" media="screen" rel="Stylesheet" type="text/css" />
49
+ # <link href="/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" />
50
+ def stylesheet_link_tag(*sources)
51
+ sources.collect { |source|
52
+ source = "/stylesheets/#{source}" unless source.include?("/")
53
+ source = "#{source}.css" unless source.include?(".")
54
+ tag("link", "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source)
55
+ }.join("\n")
56
+ end
57
+ end
58
+ end
59
+ end
@@ -35,19 +35,23 @@ module ActionView
35
35
  end
36
36
 
37
37
  # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
38
- # +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
39
- # which both accepts all the keys that each of the individual select builders does (like :use_month_numbers for select_month) and a range
40
- # of discard options. The discard options are <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll drop the respective
41
- # select. Discarding the month select will also automatically discard the day select.
38
+ # +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
39
+ # which both accepts all the keys that each of the individual select builders does (like :use_month_numbers for select_month) and a range of
40
+ # discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
41
+ # drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
42
+ # 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
43
+ # the desired order. Symbols may be omitted and the respective select is not included.
44
+ #
45
+ # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
42
46
  #
43
- # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed. Additionally, you can get the
44
- # month select before the year by setting :month_before_year to true in the options. This is especially useful for credit card forms.
45
47
  # Examples:
46
48
  #
47
49
  # date_select("post", "written_on")
48
50
  # date_select("post", "written_on", :start_year => 1995)
49
51
  # date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true,
50
52
  # :discard_day => true, :include_blank => true)
53
+ # date_select("post", "written_on", :order => [:day, :month, :year])
54
+ # date_select("user", "birthday", :order => [:month, :day])
51
55
  #
52
56
  # The selects are prepared for multi-parameter assignment to an Active Record object.
53
57
  def date_select(object, method, options = {})
@@ -219,15 +223,22 @@ module ActionView
219
223
 
220
224
  date_select = ""
221
225
 
222
- if options[:month_before_year]
223
- date_select << select_month(date, options_with_prefix.call(2)) unless options[:discard_month]
224
- date_select << select_year(date, options_with_prefix.call(1))
225
- else
226
- date_select << select_year(date, options_with_prefix.call(1))
227
- date_select << select_month(date, options_with_prefix.call(2)) unless options[:discard_month]
226
+ if options[:month_before_year] # For backwards compatibility
227
+ options[:order] = [:month, :year, :day]
228
228
  end
229
229
 
230
- date_select << select_day(date, options_with_prefix.call(3)) unless options[:discard_day] || options[:discard_month]
230
+ options[:order] ||= [:year, :month, :day]
231
+
232
+ position = {:year => 1, :month => 2, :day => 3}
233
+
234
+ discard = {}
235
+ discard[:year] = true if options[:discard_year]
236
+ discard[:month] = true if options[:discard_month]
237
+ discard[:day] = true if options[:discard_day] or options[:discard_month]
238
+
239
+ options[:order].each do |param|
240
+ date_select << self.send("select_#{param}", date, options_with_prefix.call(position[param])) unless discard[param]
241
+ end
231
242
 
232
243
  return date_select
233
244
  end
@@ -78,6 +78,11 @@ module ActionView
78
78
  InstanceTag.new(object, method, self).to_input_field_tag("hidden", options)
79
79
  end
80
80
 
81
+ # Works just like text_field, but returns a input tag of the "file" type instead, which won't have any default value.
82
+ def file_field(object, method, options = {})
83
+ InstanceTag.new(object, method, self).to_input_field_tag("file", options)
84
+ end
85
+
81
86
  # Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
82
87
  # on an object assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
83
88
  # hash with +options+.
@@ -147,7 +152,7 @@ module ActionView
147
152
  html_options.merge!({ "size" => options["maxlength"]}) if options["maxlength"] && !options["size"]
148
153
  html_options.delete("size") if field_type == "hidden"
149
154
  html_options.merge!({ "type" => field_type})
150
- html_options.merge!({ "value" => value_before_type_cast }) unless options["value"]
155
+ html_options.merge!({ "value" => value_before_type_cast }) if options["value"].nil? && field_type != "file"
151
156
  add_default_name_and_id(html_options)
152
157
  tag("input", html_options)
153
158
  end
@@ -5,11 +5,26 @@ require File.dirname(__FILE__) + '/form_helper'
5
5
  module ActionView
6
6
  module Helpers
7
7
  # Provides a number of methods for turning different kinds of containers into a set of option tags.
8
+ # == Options
9
+ # The <tt>collection_select</tt>, <tt>country_select</tt>, <tt>select</tt>,
10
+ # and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter,
11
+ # a hash.
12
+ #
13
+ # * <tt>:include_blank</tt> - set to true if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
14
+ # select("post", "category", Post::CATEGORIES, {:include_blank => true})
15
+ #
16
+ # Could become:
17
+ #
18
+ # <select name="post[category]">
19
+ # <option></option>
20
+ # <option>joke</option>
21
+ # <option>poem</option>
22
+ # </select>
8
23
  module FormOptionsHelper
9
24
  include ERB::Util
10
25
 
11
26
  # Create a select tag and a series of contained option tags for the provided object and method.
12
- # The option currenlty held by the object will be selected, provided that the object is available.
27
+ # The option currently held by the object will be selected, provided that the object is available.
13
28
  #
14
29
  # This can be used to provide a default set of options in the standard way: before rendering the create form, a
15
30
  # new model instance is assigned the default options and bound to @model_name. Usually this model is not saved
@@ -30,24 +45,38 @@ module ActionView
30
45
  InstanceTag.new(object, method, self).to_country_select_tag(priority_countries, options, html_options)
31
46
  end
32
47
 
48
+ # Return select and option tags for the given object and method, using
49
+ # #time_zone_options_for_select to generate the list of option tags.
50
+ #
51
+ # In addition to the <tt>:include_blank</tt> option documented above,
52
+ # this method also supports a <tt>:model</tt> option, which defaults
53
+ # to TimeZone. This may be used by users to specify a different time
54
+ # zone model object. (See #time_zone_options_for_select for more
55
+ # information.)
56
+ def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
57
+ InstanceTag.new(object, method, self).to_time_zone_select_tag(priority_zones, options, html_options)
58
+ end
59
+
33
60
  # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
34
61
  # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
35
62
  # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
36
63
  # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +Selected+
37
- # may also be an array of values to be selected when using a multiple select.
64
+ # may also be an array of values to be selected when using a multiple select.
38
65
  #
39
66
  # Examples (call, result):
40
67
  # options_for_select([["Dollar", "$"], ["Kroner", "DKK"]])
41
68
  # <option value="$">Dollar</option>\n<option value="DKK">Kroner</option>
42
69
  #
43
- # options_for_select([ "VISA", "Mastercard" ], "Mastercard")
44
- # <option>VISA</option>\n<option selected="selected">Mastercard</option>
70
+ # options_for_select([ "VISA", "MasterCard" ], "MasterCard")
71
+ # <option>VISA</option>\n<option selected="selected">MasterCard</option>
45
72
  #
46
73
  # options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
47
74
  # <option value="$20">Basic</option>\n<option value="$40" selected="selected">Plus</option>
48
75
  #
49
- # options_for_select([ "VISA", "Mastercard", "Discover" ], ["VISA", "Discover"])
50
- # <option selected="selected">VISA</option>\n<option>Mastercard</option>\n<option selected="selected">Discover</option>
76
+ # options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
77
+ # <option selected="selected">VISA</option>\n<option>MasterCard</option>\n<option selected="selected">Discover</option>
78
+ #
79
+ # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
51
80
  def options_for_select(container, selected = nil)
52
81
  container = container.to_a if Hash === container
53
82
 
@@ -75,6 +104,8 @@ module ActionView
75
104
  # Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate a input tag:
76
105
  # options_from_collection_for_select(@project.people, "id", "name")
77
106
  # <option value="#{person.id}">#{person.name}</option>
107
+ #
108
+ # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
78
109
  def options_from_collection_for_select(collection, value_method, text_method, selected_value = nil)
79
110
  options_for_select(
80
111
  collection.inject([]) { |options, object| options << [ object.send(text_method), object.send(value_method) ] },
@@ -87,7 +118,7 @@ module ActionView
87
118
  # An array of group objects are passed. Each group should return an array of options when calling group_method
88
119
  # Each group should should return its name when calling group_label_method.
89
120
  #
90
- # html_option_groups_from_collection(@continents, "countries", "contient_name", "country_id", "country_name", @selected_country.id)
121
+ # html_option_groups_from_collection(@continents, "countries", "continent_name", "country_id", "country_name", @selected_country.id)
91
122
  #
92
123
  # Could become:
93
124
  # <optgroup label="Africa">
@@ -113,6 +144,8 @@ module ActionView
113
144
  # def country_id() @id; end
114
145
  # def country_name() @name; end
115
146
  # end
147
+ #
148
+ # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
116
149
  def option_groups_from_collection_for_select(collection, group_method, group_label_method,
117
150
  option_key_method, option_value_method, selected_key = nil)
118
151
  collection.inject("") do |options_for_select, group|
@@ -126,6 +159,8 @@ module ActionView
126
159
  # Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to
127
160
  # have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so
128
161
  # that they will be listed above the rest of the (long) list.
162
+ #
163
+ # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
129
164
  def country_options_for_select(selected = nil, priority_countries = nil)
130
165
  country_options = ""
131
166
 
@@ -143,10 +178,43 @@ module ActionView
143
178
  return country_options
144
179
  end
145
180
 
181
+ # Returns a string of option tags for pretty much any time zone in the
182
+ # world. Supply a TimeZone object as +selected+ to have it marked as the
183
+ # selected option tag. You can also supply an array of TimeZone objects
184
+ # as +priority_zones+, so that they will be listed above the rest of the
185
+ # (long) list. (You can use TimeZone.us_zones as a convenience for
186
+ # obtaining a list of the US time zones.)
187
+ #
188
+ # The +selected+ parameter must be either +nil+, or a string that names
189
+ # a TimeZone.
190
+ #
191
+ # By default, +model+ is the TimeZone constant (which can be obtained
192
+ # in ActiveRecord as a value object). The only requirement is that the
193
+ # +model+ parameter be an object that responds to #all, and returns
194
+ # an array of objects that represent time zones.
195
+ #
196
+ # NOTE: Only the option tags are returned, you have to wrap this call in
197
+ # a regular HTML select tag.
198
+ def time_zone_options_for_select(selected = nil, priority_zones = nil, model = TimeZone)
199
+ zone_options = ""
200
+
201
+ zones = model.all
202
+ convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
203
+
204
+ if priority_zones
205
+ zone_options += options_for_select(convert_zones[priority_zones], selected)
206
+ zone_options += "<option>-------------</option>\n"
207
+
208
+ zones = zones.reject { |z| priority_zones.include?( z ) }
209
+ end
210
+
211
+ zone_options += options_for_select(convert_zones[zones], selected)
212
+ zone_options
213
+ end
146
214
 
147
215
  private
148
216
  # All the countries included in the country_options output.
149
- COUNTRIES = [ "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla",
217
+ COUNTRIES = [ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla",
150
218
  "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia",
151
219
  "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus",
152
220
  "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina",
@@ -163,7 +231,7 @@ module ActionView
163
231
  "Georgia", "Germany", "Ghana", "Gibraltar", "Great Britain", "Greece", "Greenland",
164
232
  "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana",
165
233
  "Haiti", "Heard and Mc Donald Islands", "Honduras", "Hong Kong", "Hungary", "Iceland",
166
- "India", "Indonesia", "Ireland", "Israel", "Italy", "Jamaica", "Japan", "Jordan",
234
+ "India", "Indonesia", "Ireland", "Israel", "Italy", "Iran", "Irak", "Jamaica", "Japan", "Jordan",
167
235
  "Kazakhstan", "Kenya", "Kiribati", "Korea, Republic of", "Korea (South)", "Kuwait",
168
236
  "Kyrgyzstan", "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho",
169
237
  "Liberia", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia",
@@ -212,6 +280,16 @@ module ActionView
212
280
  content_tag("select", add_blank_option(country_options_for_select(value, priority_countries), options[:include_blank]), html_options)
213
281
  end
214
282
 
283
+ def to_time_zone_select_tag(priority_zones, options, html_options)
284
+ add_default_name_and_id(html_options)
285
+ content_tag("select",
286
+ add_blank_option(
287
+ time_zone_options_for_select(value, priority_zones, options[:model] || TimeZone),
288
+ options[:include_blank]
289
+ ), html_options
290
+ )
291
+ end
292
+
215
293
  private
216
294
  def add_blank_option(option_tags, add_blank)
217
295
  add_blank ? "<option></option>\n" + option_tags : option_tags
@@ -0,0 +1,80 @@
1
+ require 'cgi'
2
+ require File.dirname(__FILE__) + '/tag_helper'
3
+
4
+ module ActionView
5
+ module Helpers
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
+ # FormHelper does. With the FormTagHelper, you provide the names and values yourself.
8
+ module FormTagHelper
9
+ # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
10
+ # ActionController::Base#url_for. The method for the form defaults to POST.
11
+ #
12
+ # Options:
13
+ # * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
14
+ def form_tag(url_for_options = {}, options = {}, *parameters_for_url)
15
+ html_options = { "method" => "post" }.merge(options)
16
+
17
+ if html_options[:multipart]
18
+ html_options["enctype"] = "multipart/form-data"
19
+ html_options.delete(:multipart)
20
+ end
21
+
22
+ html_options["action"] = url_for(url_for_options, *parameters_for_url)
23
+
24
+ tag("form", html_options, true)
25
+ end
26
+
27
+ alias_method :start_form_tag, :form_tag
28
+
29
+ # Outputs "</form>"
30
+ def end_form_tag
31
+ "</form>"
32
+ end
33
+
34
+ def select_tag(name, option_tags = nil, options = {})
35
+ content_tag("select", option_tags, { "name" => name, "id" => name }.update(options))
36
+ end
37
+
38
+ def text_field_tag(name, value = nil, options = {})
39
+ tag("input", {"type" => "text", "name" => name, "id" => name, "value" => value}.update(options))
40
+ end
41
+
42
+ def hidden_field_tag(name, value = nil, options = {})
43
+ text_field_tag(name, value, options.update("type" => "hidden"))
44
+ end
45
+
46
+ def file_field_tag(name, options = {})
47
+ text_field_tag(name, nil, options.update("type" => "file"))
48
+ end
49
+
50
+ def password_field_tag(name = "password", value = nil, options = {})
51
+ text_field_tag(name, value, options.update("type" => "password"))
52
+ end
53
+
54
+ def text_area_tag(name, content = nil, options = {})
55
+ if options[:size]
56
+ options["cols"], options["rows"] = options[:size].split("x")
57
+ options.delete(:size)
58
+ end
59
+
60
+ content_tag("textarea", content, { "name" => name, "id" => name }.update(options))
61
+ end
62
+
63
+ def check_box_tag(name, value = "1", checked = false, options = {})
64
+ html_options = {"type" => "checkbox", "name" => name, "id" => name, "value" => value}.update(options)
65
+ html_options["checked"] = "checked" if checked
66
+ tag("input", html_options)
67
+ end
68
+
69
+ def radio_button_tag(name, value, checked = false, options = {})
70
+ html_options = {"type" => "radio", "name" => name, "id" => name, "value" => value}.update(options)
71
+ html_options["checked"] = "checked" if checked
72
+ tag("input", html_options)
73
+ end
74
+
75
+ def submit_tag(value = "Save changes", options = {})
76
+ tag("input", {"type" => "submit", "name" => "submit", "value" => value}.update(options))
77
+ end
78
+ end
79
+ end
80
+ end
@@ -22,29 +22,6 @@ module ActionView
22
22
  "<#{name}#{tag_options(options)}>#{content}</#{name}>"
23
23
  end
24
24
 
25
- # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
26
- # ActionController::Base#url_for.
27
- def form_tag(url_for_options = {}, options = {}, *parameters_for_url)
28
- html_options = { "method" => "post" }.merge(options)
29
-
30
- if html_options[:multipart]
31
- html_options["enctype"] = "multipart/form-data"
32
- html_options.delete(:multipart)
33
- end
34
-
35
- html_options["action"] = url_for(url_for_options, *parameters_for_url)
36
-
37
- tag("form", html_options, true)
38
- end
39
-
40
- alias_method :start_form_tag, :form_tag
41
-
42
- # Outputs "</form>"
43
- def end_form_tag
44
- "</form>"
45
- end
46
-
47
-
48
25
  private
49
26
  def tag_options(options)
50
27
  unless options.empty?
@@ -69,7 +69,7 @@ module ActionView
69
69
  # Returns the text with all the Textile codes turned into HTML-tags.
70
70
  # <i>This method is only available if RedCloth can be required</i>.
71
71
  def textilize(text)
72
- text.empty? ? "" : RedCloth.new(text).to_html
72
+ text.empty? ? "" : RedCloth.new(text, [ :hard_breaks ]).to_html
73
73
  end
74
74
 
75
75
  # Returns the text with all the Textile codes turned into HTML-tags, but without the regular bounding <p> tag.
@@ -96,6 +96,21 @@ module ActionView
96
96
  # We can't really help what's not there
97
97
  end
98
98
 
99
+ # Turns all urls and email addresses into clickable links. The +link+ parameter can limit what should be linked.
100
+ # Options are :all (default), :email_addresses, and :urls.
101
+ #
102
+ # Example:
103
+ # auto_link("Go to http://www.rubyonrails.com and say hello to david@loudthinking.com") =>
104
+ # Go to <a href="http://www.rubyonrails.com">http://www.rubyonrails.com</a> and
105
+ # say hello to <a href="mailto:david@loudthinking.com">david@loudthinking.com</a>
106
+ def auto_link(text, link = :all)
107
+ case link
108
+ when :all then auto_link_urls(auto_link_email_addresses(text))
109
+ when :email_addresses then auto_link_email_addresses(text)
110
+ when :urls then auto_link_urls(text)
111
+ end
112
+ end
113
+
99
114
  # Turns all links into words, like "<a href="something">else</a>" to "else".
100
115
  def strip_links(text)
101
116
  text.gsub(/<a.*>(.*)<\/a>/m, '\1')
@@ -106,6 +121,16 @@ module ActionView
106
121
  def escape_regexp(text)
107
122
  text.gsub(/([\\|?+*\/\)\(])/) { |m| "\\#{$1}" }
108
123
  end
124
+
125
+ # Turns all urls into clickable links.
126
+ def auto_link_urls(text)
127
+ text.gsub(/([^=><!:'"\/]|^)((http[s]?:\/\/)|(www\.))(\S+\b\/?)([[:punct:]]*)(\s|$)/, '\1<a href="\3\4\5">\3\4\5</a>\6\7')
128
+ end
129
+
130
+ # Turns all email addresses into clickable links.
131
+ def auto_link_email_addresses(text)
132
+ text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/, '<a href="mailto:\1">\1</a>')
133
+ end
109
134
  end
110
135
  end
111
136
  end