actionpack 1.12.5 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +517 -15
- data/MIT-LICENSE +1 -1
- data/README +18 -20
- data/Rakefile +7 -4
- data/examples/address_book_controller.rb +3 -3
- data/examples/blog_controller.cgi +3 -3
- data/examples/debate_controller.cgi +5 -5
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions.rb +73 -311
- data/lib/action_controller/{deprecated_assertions.rb → assertions/deprecated_assertions.rb} +32 -8
- data/lib/action_controller/assertions/dom_assertions.rb +25 -0
- data/lib/action_controller/assertions/model_assertions.rb +12 -0
- data/lib/action_controller/assertions/response_assertions.rb +140 -0
- data/lib/action_controller/assertions/routing_assertions.rb +82 -0
- data/lib/action_controller/assertions/selector_assertions.rb +571 -0
- data/lib/action_controller/assertions/tag_assertions.rb +117 -0
- data/lib/action_controller/base.rb +334 -163
- data/lib/action_controller/benchmarking.rb +3 -6
- data/lib/action_controller/caching.rb +83 -22
- data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -7
- data/lib/action_controller/cgi_ext/cgi_methods.rb +167 -173
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +43 -22
- data/lib/action_controller/cgi_process.rb +50 -27
- data/lib/action_controller/components.rb +21 -25
- data/lib/action_controller/cookies.rb +10 -9
- data/lib/action_controller/{dependencies.rb → deprecated_dependencies.rb} +9 -27
- data/lib/action_controller/filters.rb +448 -225
- data/lib/action_controller/flash.rb +24 -20
- data/lib/action_controller/helpers.rb +2 -5
- data/lib/action_controller/integration.rb +40 -16
- data/lib/action_controller/layout.rb +11 -8
- data/lib/action_controller/macros/auto_complete.rb +3 -2
- data/lib/action_controller/macros/in_place_editing.rb +3 -2
- data/lib/action_controller/mime_responds.rb +41 -29
- data/lib/action_controller/mime_type.rb +68 -10
- data/lib/action_controller/pagination.rb +4 -3
- data/lib/action_controller/request.rb +22 -14
- data/lib/action_controller/rescue.rb +25 -22
- data/lib/action_controller/resources.rb +302 -0
- data/lib/action_controller/response.rb +20 -2
- data/lib/action_controller/response.rb.rej +17 -0
- data/lib/action_controller/routing.rb +1165 -567
- data/lib/action_controller/scaffolding.rb +30 -31
- data/lib/action_controller/session/active_record_store.rb +2 -0
- data/lib/action_controller/session/drb_store.rb +4 -0
- data/lib/action_controller/session/mem_cache_store.rb +4 -0
- data/lib/action_controller/session_management.rb +6 -9
- data/lib/action_controller/status_codes.rb +89 -0
- data/lib/action_controller/streaming.rb +6 -15
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +5 -5
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -2
- data/lib/action_controller/templates/rescues/routing_error.rhtml +4 -4
- data/lib/action_controller/templates/rescues/template_error.rhtml +1 -1
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +52 -30
- data/lib/action_controller/url_rewriter.rb +63 -29
- data/lib/action_controller/vendor/html-scanner/html/document.rb +1 -0
- data/lib/action_controller/vendor/html-scanner/html/node.rb +3 -4
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +822 -0
- data/lib/action_controller/verification.rb +22 -11
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +46 -43
- data/lib/action_view/compiled_templates.rb +1 -1
- data/lib/action_view/helpers/active_record_helper.rb +54 -17
- data/lib/action_view/helpers/asset_tag_helper.rb +97 -46
- data/lib/action_view/helpers/capture_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +258 -136
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/deprecated_helper.rb +34 -0
- data/lib/action_view/helpers/form_helper.rb +75 -35
- data/lib/action_view/helpers/form_options_helper.rb +7 -5
- data/lib/action_view/helpers/form_tag_helper.rb +44 -6
- data/lib/action_view/helpers/java_script_macros_helper.rb +59 -46
- data/lib/action_view/helpers/javascript_helper.rb +71 -10
- data/lib/action_view/helpers/javascripts/controls.js +41 -23
- data/lib/action_view/helpers/javascripts/dragdrop.js +105 -76
- data/lib/action_view/helpers/javascripts/effects.js +293 -163
- data/lib/action_view/helpers/javascripts/prototype.js +897 -389
- data/lib/action_view/helpers/javascripts/prototype.js.rej +561 -0
- data/lib/action_view/helpers/number_helper.rb +111 -65
- data/lib/action_view/helpers/prototype_helper.rb +84 -109
- data/lib/action_view/helpers/scriptaculous_helper.rb +5 -0
- data/lib/action_view/helpers/tag_helper.rb +69 -16
- data/lib/action_view/helpers/text_helper.rb +149 -112
- data/lib/action_view/helpers/url_helper.rb +200 -107
- data/lib/action_view/template_error.rb +66 -42
- data/test/abstract_unit.rb +4 -2
- data/test/active_record_unit.rb +84 -56
- data/test/activerecord/active_record_assertions_test.rb +26 -18
- data/test/activerecord/active_record_store_test.rb +4 -36
- data/test/activerecord/pagination_test.rb +1 -6
- data/test/controller/action_pack_assertions_test.rb +230 -113
- data/test/controller/addresses_render_test.rb +2 -6
- data/test/controller/assert_select_test.rb +576 -0
- data/test/controller/base_test.rb +73 -3
- data/test/controller/caching_test.rb +228 -0
- data/test/controller/capture_test.rb +12 -10
- data/test/controller/cgi_test.rb +89 -12
- data/test/controller/components_test.rb +24 -2
- data/test/controller/content_type_test.rb +139 -0
- data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
- data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
- data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
- data/test/controller/cookie_test.rb +33 -25
- data/test/controller/deprecated_instance_variables_test.rb +48 -0
- data/test/controller/deprecation/deprecated_base_methods_test.rb +60 -0
- data/test/controller/fake_controllers.rb +0 -1
- data/test/controller/filters_test.rb +301 -16
- data/test/controller/flash_test.rb +19 -2
- data/test/controller/helper_test.rb +2 -2
- data/test/controller/integration_test.rb +154 -0
- data/test/controller/layout_test.rb +115 -1
- data/test/controller/mime_responds_test.rb +94 -0
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/new_render_test.rb +161 -11
- data/test/controller/raw_post_test.rb +52 -15
- data/test/controller/redirect_test.rb +27 -14
- data/test/controller/render_test.rb +76 -29
- data/test/controller/request_test.rb +55 -4
- data/test/controller/resources_test.rb +274 -0
- data/test/controller/routing_test.rb +1533 -824
- data/test/controller/selector_test.rb +628 -0
- data/test/controller/send_file_test.rb +9 -1
- data/test/controller/session_management_test.rb +51 -0
- data/test/controller/test_test.rb +113 -29
- data/test/controller/url_rewriter_test.rb +86 -17
- data/test/controller/verification_test.rb +19 -17
- data/test/controller/webservice_test.rb +0 -7
- data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
- data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
- data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
- data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
- data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +1 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/test/_hello.rxml +1 -0
- data/test/fixtures/test/hello_world_container.rxml +3 -0
- data/test/fixtures/topic.rb +2 -2
- data/test/template/active_record_helper_test.rb +83 -12
- data/test/template/asset_tag_helper_test.rb +75 -95
- data/test/template/compiled_templates_test.rb +1 -0
- data/test/template/date_helper_test.rb +873 -181
- data/test/template/deprecated_helper_test.rb +36 -0
- data/test/template/deprecated_instance_variables_test.rb +43 -0
- data/test/template/form_helper_test.rb +77 -1
- data/test/template/form_options_helper_test.rb +4 -0
- data/test/template/form_tag_helper_test.rb +66 -2
- data/test/template/java_script_macros_helper_test.rb +4 -1
- data/test/template/javascript_helper_test.rb +29 -0
- data/test/template/number_helper_test.rb +63 -27
- data/test/template/prototype_helper_test.rb +77 -34
- data/test/template/tag_helper_test.rb +34 -6
- data/test/template/text_helper_test.rb +69 -34
- data/test/template/url_helper_test.rb +168 -16
- data/test/testing_sandbox.rb +7 -22
- metadata +66 -20
- data/filler.txt +0 -50
- data/lib/action_controller/code_generation.rb +0 -235
- data/lib/action_controller/vendor/xml_simple.rb +0 -1019
- data/test/controller/caching_filestore.rb +0 -74
- data/test/fixtures/application_root/app/controllers/a_class_that_contains_a_controller/poorly_placed_controller.rb +0 -7
- data/test/fixtures/application_root/app/controllers/module_that_holds_controllers/nested_controller.rb +0 -3
- data/test/fixtures/application_root/app/models/a_class_that_contains_a_controller.rb +0 -7
- data/test/fixtures/dont_load.rb +0 -3
@@ -3,20 +3,36 @@ require File.dirname(__FILE__) + '/url_helper'
|
|
3
3
|
require File.dirname(__FILE__) + '/tag_helper'
|
4
4
|
|
5
5
|
module ActionView
|
6
|
-
module Helpers
|
7
|
-
# Provides methods for linking
|
6
|
+
module Helpers #:nodoc:
|
7
|
+
# Provides methods for linking an HTML page together with other assets such
|
8
|
+
# as images, javascripts, stylesheets, and feeds. You can direct Rails to
|
9
|
+
# link to assets from a dedicated assets server by setting ActionController::Base.asset_host
|
10
|
+
# in your environment.rb. These methods do not verify the assets exist before
|
11
|
+
# linking to them.
|
12
|
+
#
|
13
|
+
# ActionController::Base.asset_host = "http://assets.example.com"
|
14
|
+
# image_tag("rails.png")
|
15
|
+
# => <img src="http://assets.example.com/images/rails.png" alt="Rails" />
|
16
|
+
# stylesheet_include_tag("application")
|
17
|
+
# => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="Stylesheet" type="text/css" />
|
8
18
|
module AssetTagHelper
|
9
|
-
# Returns a link tag that browsers and news readers can use to auto-detect
|
10
|
-
# either be <tt>:rss</tt> (default) or
|
19
|
+
# Returns a link tag that browsers and news readers can use to auto-detect
|
20
|
+
# an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or
|
21
|
+
# <tt>:atom</tt>. Control the link options in url_for format using the
|
22
|
+
# +url_options+. You can modify the LINK tag itself in +tag_options+.
|
11
23
|
#
|
12
|
-
#
|
13
|
-
#
|
24
|
+
# Tag Options:
|
25
|
+
# * <tt>:rel</tt> - Specify the relation of this link, defaults to "alternate"
|
26
|
+
# * <tt>:type</tt> - Override the auto-generated mime type
|
27
|
+
# * <tt>:title</tt> - Specify the title of the link, defaults to the +type+
|
28
|
+
#
|
29
|
+
# auto_discovery_link_tag # =>
|
14
30
|
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/action" />
|
15
|
-
#
|
31
|
+
# auto_discovery_link_tag(:atom) # =>
|
16
32
|
# <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.curenthost.com/controller/action" />
|
17
|
-
#
|
33
|
+
# auto_discovery_link_tag(:rss, {:action => "feed"}) # =>
|
18
34
|
# <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/feed" />
|
19
|
-
#
|
35
|
+
# auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
|
20
36
|
# <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.curenthost.com/controller/feed" />
|
21
37
|
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
|
22
38
|
tag(
|
@@ -28,9 +44,14 @@ module ActionView
|
|
28
44
|
)
|
29
45
|
end
|
30
46
|
|
31
|
-
#
|
47
|
+
# Computes the path to a javascript asset in the public javascripts directory.
|
48
|
+
# If the +source+ filename has no extension, .js will be appended.
|
49
|
+
# Full paths from the document root will be passed through.
|
50
|
+
# Used internally by javascript_include_tag to build the script path.
|
32
51
|
#
|
33
52
|
# javascript_path "xmlhr" # => /javascripts/xmlhr.js
|
53
|
+
# javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
|
54
|
+
# javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
|
34
55
|
def javascript_path(source)
|
35
56
|
compute_public_path(source, 'javascripts', 'js')
|
36
57
|
end
|
@@ -38,7 +59,15 @@ module ActionView
|
|
38
59
|
JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls'] unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
|
39
60
|
@@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup
|
40
61
|
|
41
|
-
# Returns
|
62
|
+
# Returns an html script tag for each of the +sources+ provided. You
|
63
|
+
# can pass in the filename (.js extension is optional) of javascript files
|
64
|
+
# that exist in your public/javascripts directory for inclusion into the
|
65
|
+
# current page or you can pass the full path relative to your document
|
66
|
+
# root. To include the Prototype and Scriptaculous javascript libraries in
|
67
|
+
# your application, pass <tt>:defaults</tt> as the source. When using
|
68
|
+
# :defaults, if an <tt>application.js</tt> file exists in your public
|
69
|
+
# javascripts directory, it will be included as well. You can modify the
|
70
|
+
# html attributes of the script tag by passing a hash as the last argument.
|
42
71
|
#
|
43
72
|
# javascript_include_tag "xmlhr" # =>
|
44
73
|
# <script type="text/javascript" src="/javascripts/xmlhr.js"></script>
|
@@ -52,11 +81,6 @@ module ActionView
|
|
52
81
|
# <script type="text/javascript" src="/javascripts/effects.js"></script>
|
53
82
|
# ...
|
54
83
|
# <script type="text/javascript" src="/javascripts/application.js"></script> *see below
|
55
|
-
#
|
56
|
-
# If there's an <tt>application.js</tt> file in your <tt>public/javascripts</tt> directory,
|
57
|
-
# <tt>javascript_include_tag :defaults</tt> will automatically include it. This file
|
58
|
-
# facilitates the inclusion of small snippets of JavaScript code, along the lines of
|
59
|
-
# <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
|
60
84
|
def javascript_include_tag(*sources)
|
61
85
|
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
62
86
|
|
@@ -69,18 +93,16 @@ module ActionView
|
|
69
93
|
sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
|
70
94
|
end
|
71
95
|
|
72
|
-
sources.collect
|
96
|
+
sources.collect do |source|
|
73
97
|
source = javascript_path(source)
|
74
98
|
content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
|
75
|
-
|
99
|
+
end.join("\n")
|
76
100
|
end
|
77
101
|
|
78
102
|
# Register one or more additional JavaScript files to be included when
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
# is called. This method is intended to be called only from plugin initialization
|
83
|
-
# to register extra .js files the plugin installed in <tt>public/javascripts</tt>.
|
103
|
+
# <tt>javascript_include_tag :defaults</tt> is called. This method is
|
104
|
+
# only intended to be called from plugin initialization to register additional
|
105
|
+
# .js files that the plugin installed in <tt>public/javascripts</tt>.
|
84
106
|
def self.register_javascript_include_default(*sources)
|
85
107
|
@@javascript_default_sources.concat(sources)
|
86
108
|
end
|
@@ -89,14 +111,21 @@ module ActionView
|
|
89
111
|
@@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup
|
90
112
|
end
|
91
113
|
|
92
|
-
#
|
114
|
+
# Computes the path to a stylesheet asset in the public stylesheets directory.
|
115
|
+
# If the +source+ filename has no extension, .css will be appended.
|
116
|
+
# Full paths from the document root will be passed through.
|
117
|
+
# Used internally by stylesheet_link_tag to build the stylesheet path.
|
93
118
|
#
|
94
119
|
# stylesheet_path "style" # => /stylesheets/style.css
|
120
|
+
# stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
|
121
|
+
# stylesheet_path "/dir/style.css" # => /dir/style.css
|
95
122
|
def stylesheet_path(source)
|
96
123
|
compute_public_path(source, 'stylesheets', 'css')
|
97
124
|
end
|
98
125
|
|
99
|
-
# Returns a
|
126
|
+
# Returns a stylesheet link tag for the sources specified as arguments. If
|
127
|
+
# you don't specify an extension, .css will be appended automatically.
|
128
|
+
# You can modify the link attributes by passing a hash as the last argument.
|
100
129
|
#
|
101
130
|
# stylesheet_link_tag "style" # =>
|
102
131
|
# <link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />
|
@@ -109,31 +138,50 @@ module ActionView
|
|
109
138
|
# <link href="/css/stylish.css" media="screen" rel="Stylesheet" type="text/css" />
|
110
139
|
def stylesheet_link_tag(*sources)
|
111
140
|
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
112
|
-
sources.collect
|
141
|
+
sources.collect do |source|
|
113
142
|
source = stylesheet_path(source)
|
114
143
|
tag("link", { "rel" => "Stylesheet", "type" => "text/css", "media" => "screen", "href" => source }.merge(options))
|
115
|
-
|
144
|
+
end.join("\n")
|
116
145
|
end
|
117
146
|
|
118
|
-
#
|
147
|
+
# Computes the path to an image asset in the public images directory.
|
148
|
+
# Full paths from the document root will be passed through.
|
149
|
+
# Used internally by image_tag to build the image path. Passing
|
150
|
+
# a filename without an extension is deprecated.
|
119
151
|
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
# * file name without extension, like "logo", that gets expanded to "/images/logo.png"
|
152
|
+
# image_path("edit.png") # => /images/edit.png
|
153
|
+
# image_path("icons/edit.png") # => /images/icons/edit.png
|
154
|
+
# image_path("/icons/edit.png") # => /icons/edit.png
|
124
155
|
def image_path(source)
|
156
|
+
unless (source.split("/").last || source).include?(".") || source.blank?
|
157
|
+
ActiveSupport::Deprecation.warn(
|
158
|
+
"You've called image_path with a source that doesn't include an extension. " +
|
159
|
+
"In Rails 2.0, that will not result in .png automatically being appended. " +
|
160
|
+
"So you should call image_path('#{source}.png') instead", caller
|
161
|
+
)
|
162
|
+
end
|
163
|
+
|
125
164
|
compute_public_path(source, 'images', 'png')
|
126
165
|
end
|
127
166
|
|
128
|
-
# Returns an image tag
|
167
|
+
# Returns an html image tag for the +source+. The +source+ can be a full
|
168
|
+
# path or a file that exists in your public images directory. Note that
|
169
|
+
# specifying a filename without the extension is now deprecated in Rails.
|
170
|
+
# You can add html attributes using the +options+. The +options+ supports
|
171
|
+
# two additional keys for convienence and conformance:
|
129
172
|
#
|
130
|
-
# * <tt>:alt</tt> - If no alt text is given, the file name part of the
|
131
|
-
#
|
173
|
+
# * <tt>:alt</tt> - If no alt text is given, the file name part of the
|
174
|
+
# +source+ is used (capitalized and without the extension)
|
175
|
+
# * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes
|
176
|
+
# width="30" and height="45". <tt>:size</tt> will be ignored if the
|
177
|
+
# value is not in the correct format.
|
132
178
|
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
179
|
+
# image_tag("icon.png") # =>
|
180
|
+
# <img src="/images/icon.png" alt="Icon" />
|
181
|
+
# image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # =>
|
182
|
+
# <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" />
|
183
|
+
# image_tag("/icons/icon.gif", :size => "16x16") # =>
|
184
|
+
# <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
|
137
185
|
def image_tag(source, options = {})
|
138
186
|
options.symbolize_keys!
|
139
187
|
|
@@ -141,8 +189,8 @@ module ActionView
|
|
141
189
|
options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
|
142
190
|
|
143
191
|
if options[:size]
|
144
|
-
options[:width], options[:height] = options[:size].split("x")
|
145
|
-
options.delete
|
192
|
+
options[:width], options[:height] = options[:size].split("x") if options[:size] =~ %r{^\d+x\d+$}
|
193
|
+
options.delete(:size)
|
146
194
|
end
|
147
195
|
|
148
196
|
tag("img", options)
|
@@ -150,11 +198,14 @@ module ActionView
|
|
150
198
|
|
151
199
|
private
|
152
200
|
def compute_public_path(source, dir, ext)
|
153
|
-
source
|
154
|
-
source << ".#{ext}"
|
155
|
-
|
156
|
-
|
157
|
-
|
201
|
+
source = source.dup
|
202
|
+
source << ".#{ext}" if File.extname(source).blank?
|
203
|
+
unless source =~ %r{^[-a-z]+://}
|
204
|
+
source = "/#{dir}/#{source}" unless source[0] == ?/
|
205
|
+
asset_id = rails_asset_id(source)
|
206
|
+
source << '?' + asset_id if defined?(RAILS_ROOT) && !asset_id.blank?
|
207
|
+
source = "#{ActionController::Base.asset_host}#{@controller.request.relative_url_root}#{source}"
|
208
|
+
end
|
158
209
|
source
|
159
210
|
end
|
160
211
|
|
@@ -89,7 +89,7 @@ module ActionView
|
|
89
89
|
# named @@content_for_#{name_of_the_content_block}@. So <tt><%= content_for('footer') %></tt>
|
90
90
|
# would be avaiable as <tt><%= @content_for_footer %></tt>. The preferred notation now is
|
91
91
|
# <tt><%= yield :footer %></tt>.
|
92
|
-
def content_for(name, &block)
|
92
|
+
def content_for(name, content = nil, &block)
|
93
93
|
eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"
|
94
94
|
end
|
95
95
|
|
@@ -13,14 +13,38 @@ 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 two Time objects or integers.
|
17
|
-
#
|
18
|
-
#
|
16
|
+
# Reports the approximate distance in time between two Time or Date objects or integers as seconds.
|
17
|
+
# Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
|
18
|
+
# Distances are reported base on the following table:
|
19
19
|
#
|
20
|
-
#
|
21
|
-
#
|
20
|
+
# 0 <-> 29 secs # => less than a minute
|
21
|
+
# 30 secs <-> 1 min, 29 secs # => 1 minute
|
22
|
+
# 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
|
23
|
+
# 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
|
24
|
+
# 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
|
25
|
+
# 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
|
26
|
+
# 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
|
27
|
+
# 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
|
28
|
+
# 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 31 secs # => [2..12] months
|
29
|
+
# 1 yr minus 30 secs <-> 2 yrs minus 31 secs # => about 1 year
|
30
|
+
# 2 yrs minus 30 secs <-> max time or date # => over [2..X] years
|
22
31
|
#
|
23
|
-
#
|
32
|
+
# With include_seconds = true and the difference < 1 minute 29 seconds
|
33
|
+
# 0-4 secs # => less than 5 seconds
|
34
|
+
# 5-9 secs # => less than 10 seconds
|
35
|
+
# 10-19 secs # => less than 20 seconds
|
36
|
+
# 20-39 secs # => half a minute
|
37
|
+
# 40-59 secs # => less than a minute
|
38
|
+
# 60-89 secs # => 1 minute
|
39
|
+
#
|
40
|
+
# Examples:
|
41
|
+
#
|
42
|
+
# from_time = Time.now
|
43
|
+
# distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
|
44
|
+
# distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
|
45
|
+
# distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
|
46
|
+
#
|
47
|
+
# Note: Rails calculates one year as 365.25 days.
|
24
48
|
def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
|
25
49
|
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
26
50
|
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
@@ -29,29 +53,33 @@ module ActionView
|
|
29
53
|
|
30
54
|
case distance_in_minutes
|
31
55
|
when 0..1
|
32
|
-
return (distance_in_minutes==0) ? 'less than a minute' : '1 minute' unless include_seconds
|
56
|
+
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
|
33
57
|
case distance_in_seconds
|
34
|
-
when 0..
|
35
|
-
when
|
36
|
-
when
|
37
|
-
when
|
38
|
-
when
|
58
|
+
when 0..4 then 'less than 5 seconds'
|
59
|
+
when 5..9 then 'less than 10 seconds'
|
60
|
+
when 10..19 then 'less than 20 seconds'
|
61
|
+
when 20..39 then 'half a minute'
|
62
|
+
when 40..59 then 'less than a minute'
|
39
63
|
else '1 minute'
|
40
64
|
end
|
41
|
-
|
42
|
-
when 2..
|
43
|
-
when
|
44
|
-
when 90..
|
45
|
-
when
|
46
|
-
|
65
|
+
|
66
|
+
when 2..44 then "#{distance_in_minutes} minutes"
|
67
|
+
when 45..89 then 'about 1 hour'
|
68
|
+
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
69
|
+
when 1440..2879 then '1 day'
|
70
|
+
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
|
71
|
+
when 43200..86399 then 'about 1 month'
|
72
|
+
when 86400..525959 then "#{(distance_in_minutes / 43200).round} months"
|
73
|
+
when 525960..1051919 then 'about 1 year'
|
74
|
+
else "over #{(distance_in_minutes / 525960).round} years"
|
47
75
|
end
|
48
76
|
end
|
49
|
-
|
77
|
+
|
50
78
|
# Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
|
51
79
|
def time_ago_in_words(from_time, include_seconds = false)
|
52
80
|
distance_of_time_in_words(from_time, Time.now, include_seconds)
|
53
81
|
end
|
54
|
-
|
82
|
+
|
55
83
|
alias_method :distance_of_time_in_words_to_now, :time_ago_in_words
|
56
84
|
|
57
85
|
# Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
|
@@ -80,6 +108,19 @@ module ActionView
|
|
80
108
|
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options)
|
81
109
|
end
|
82
110
|
|
111
|
+
# Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
|
112
|
+
# time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
|
113
|
+
# You can include the seconds with <tt>:include_seconds</tt>.
|
114
|
+
# Examples:
|
115
|
+
#
|
116
|
+
# time_select("post", "sunrise")
|
117
|
+
# time_select("post", "start_time", :include_seconds => true)
|
118
|
+
#
|
119
|
+
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
120
|
+
def time_select(object_name, method, options = {})
|
121
|
+
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options)
|
122
|
+
end
|
123
|
+
|
83
124
|
# Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
|
84
125
|
# attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples:
|
85
126
|
#
|
@@ -91,36 +132,55 @@ module ActionView
|
|
91
132
|
InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options)
|
92
133
|
end
|
93
134
|
|
135
|
+
# Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
|
136
|
+
# It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
|
137
|
+
# symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
|
138
|
+
# will be appened onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt> and <tt>:time_separator</tt>
|
139
|
+
# keys to the +options+ to control visual display of the elements.
|
140
|
+
def select_datetime(datetime = Time.now, options = {})
|
141
|
+
separator = options[:datetime_separator] || ''
|
142
|
+
select_date(datetime, options) + separator + select_time(datetime, options)
|
143
|
+
end
|
144
|
+
|
94
145
|
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
|
146
|
+
# It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
|
147
|
+
# symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
|
148
|
+
# will be appened onto the <tt>:order</tt> passed in.
|
95
149
|
def select_date(date = Date.today, options = {})
|
96
|
-
|
97
|
-
|
150
|
+
options[:order] ||= []
|
151
|
+
[:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
|
98
152
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
153
|
+
select_date = ''
|
154
|
+
options[:order].each do |o|
|
155
|
+
select_date << self.send("select_#{o}", date, options)
|
156
|
+
end
|
157
|
+
select_date
|
103
158
|
end
|
104
159
|
|
105
160
|
# Returns a set of html select-tags (one for hour and minute)
|
161
|
+
# You can set <tt>:add_separator</tt> key to format the output.
|
106
162
|
def select_time(datetime = Time.now, options = {})
|
107
|
-
|
163
|
+
separator = options[:time_separator] || ''
|
164
|
+
select_hour(datetime, options) + separator + select_minute(datetime, options) + (options[:include_seconds] ? separator + select_second(datetime, options) : '')
|
108
165
|
end
|
109
166
|
|
110
167
|
# Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
|
111
168
|
# The <tt>second</tt> can also be substituted for a second number.
|
112
169
|
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
|
113
170
|
def select_second(datetime, options = {})
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
171
|
+
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
|
172
|
+
if options[:use_hidden]
|
173
|
+
options[:include_seconds] ? hidden_html(options[:field_name] || 'second', val, options) : ''
|
174
|
+
else
|
175
|
+
second_options = []
|
176
|
+
0.upto(59) do |second|
|
177
|
+
second_options << ((val == second) ?
|
178
|
+
%(<option value="#{leading_zero_on_single_digits(second)}" selected="selected">#{leading_zero_on_single_digits(second)}</option>\n) :
|
179
|
+
%(<option value="#{leading_zero_on_single_digits(second)}">#{leading_zero_on_single_digits(second)}</option>\n)
|
180
|
+
)
|
181
|
+
end
|
182
|
+
select_html(options[:field_name] || 'second', second_options, options)
|
121
183
|
end
|
122
|
-
|
123
|
-
select_html(options[:field_name] || 'second', second_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
124
184
|
end
|
125
185
|
|
126
186
|
# Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
|
@@ -128,84 +188,100 @@ module ActionView
|
|
128
188
|
# The <tt>minute</tt> can also be substituted for a minute number.
|
129
189
|
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
|
130
190
|
def select_minute(datetime, options = {})
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
191
|
+
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
|
192
|
+
if options[:use_hidden]
|
193
|
+
hidden_html(options[:field_name] || 'minute', val, options)
|
194
|
+
else
|
195
|
+
minute_options = []
|
196
|
+
0.step(59, options[:minute_step] || 1) do |minute|
|
197
|
+
minute_options << ((val == minute) ?
|
198
|
+
%(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
|
199
|
+
%(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
|
200
|
+
)
|
201
|
+
end
|
202
|
+
select_html(options[:field_name] || 'minute', minute_options, options)
|
203
|
+
end
|
141
204
|
end
|
142
205
|
|
143
206
|
# Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
|
144
207
|
# The <tt>hour</tt> can also be substituted for a hour number.
|
145
208
|
# Override the field name using the <tt>:field_name</tt> option, 'hour' by default.
|
146
209
|
def select_hour(datetime, options = {})
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
210
|
+
val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
|
211
|
+
if options[:use_hidden]
|
212
|
+
hidden_html(options[:field_name] || 'hour', val, options)
|
213
|
+
else
|
214
|
+
hour_options = []
|
215
|
+
0.upto(23) do |hour|
|
216
|
+
hour_options << ((val == hour) ?
|
217
|
+
%(<option value="#{leading_zero_on_single_digits(hour)}" selected="selected">#{leading_zero_on_single_digits(hour)}</option>\n) :
|
218
|
+
%(<option value="#{leading_zero_on_single_digits(hour)}">#{leading_zero_on_single_digits(hour)}</option>\n)
|
219
|
+
)
|
220
|
+
end
|
221
|
+
select_html(options[:field_name] || 'hour', hour_options, options)
|
154
222
|
end
|
155
|
-
|
156
|
-
select_html(options[:field_name] || 'hour', hour_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
157
223
|
end
|
158
224
|
|
159
225
|
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
|
160
226
|
# The <tt>date</tt> can also be substituted for a hour number.
|
161
227
|
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
|
162
228
|
def select_day(date, options = {})
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
229
|
+
val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
|
230
|
+
if options[:use_hidden]
|
231
|
+
hidden_html(options[:field_name] || 'day', val, options)
|
232
|
+
else
|
233
|
+
day_options = []
|
234
|
+
1.upto(31) do |day|
|
235
|
+
day_options << ((val == day) ?
|
236
|
+
%(<option value="#{day}" selected="selected">#{day}</option>\n) :
|
237
|
+
%(<option value="#{day}">#{day}</option>\n)
|
238
|
+
)
|
239
|
+
end
|
240
|
+
select_html(options[:field_name] || 'day', day_options, options)
|
170
241
|
end
|
171
|
-
|
172
|
-
select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
173
242
|
end
|
174
243
|
|
175
244
|
# Returns a select tag with options for each of the months January through December with the current month selected.
|
176
245
|
# The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values
|
177
246
|
# (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names --
|
178
247
|
# set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
|
179
|
-
# set the <tt>:add_month_numbers</tt> key in +options+ to true.
|
248
|
+
# set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer to show month names as abbreviations,
|
249
|
+
# set the <tt>:use_short_month</tt> key in +options+ to true. If you want to use your own month names, set the
|
250
|
+
# <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
|
251
|
+
#
|
252
|
+
# Examples:
|
180
253
|
#
|
181
254
|
# select_month(Date.today) # Will use keys like "January", "March"
|
182
255
|
# select_month(Date.today, :use_month_numbers => true) # Will use keys like "1", "3"
|
183
256
|
# select_month(Date.today, :add_month_numbers => true) # Will use keys like "1 - January", "3 - March"
|
257
|
+
# select_month(Date.today, :use_short_month => true) # Will use keys like "Jan", "Mar"
|
258
|
+
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...)) # Will use keys like "Januar", "Marts"
|
184
259
|
#
|
185
260
|
# 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.
|
189
261
|
def select_month(date, options = {})
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
262
|
+
val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
|
263
|
+
if options[:use_hidden]
|
264
|
+
hidden_html(options[:field_name] || 'month', val, options)
|
265
|
+
else
|
266
|
+
month_options = []
|
267
|
+
month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
|
268
|
+
month_names.unshift(nil) if month_names.size < 13
|
269
|
+
1.upto(12) do |month_number|
|
270
|
+
month_name = if options[:use_month_numbers]
|
271
|
+
month_number
|
272
|
+
elsif options[:add_month_numbers]
|
273
|
+
month_number.to_s + ' - ' + month_names[month_number]
|
274
|
+
else
|
275
|
+
month_names[month_number]
|
276
|
+
end
|
201
277
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
278
|
+
month_options << ((val == month_number) ?
|
279
|
+
%(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
|
280
|
+
%(<option value="#{month_number}">#{month_name}</option>\n)
|
281
|
+
)
|
282
|
+
end
|
283
|
+
select_html(options[:field_name] || 'month', month_options, options)
|
206
284
|
end
|
207
|
-
|
208
|
-
select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
209
285
|
end
|
210
286
|
|
211
287
|
# 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
|
@@ -215,37 +291,51 @@ module ActionView
|
|
215
291
|
#
|
216
292
|
# select_year(Date.today, :start_year => 1992, :end_year => 2007) # ascending year values
|
217
293
|
# select_year(Date.today, :start_year => 2005, :end_year => 1900) # descending year values
|
294
|
+
# select_year(2006, :start_year => 2000, :end_year => 2010)
|
218
295
|
#
|
219
296
|
# Override the field name using the <tt>:field_name</tt> option, 'year' by default.
|
220
297
|
def select_year(date, options = {})
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
298
|
+
val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
|
299
|
+
if options[:use_hidden]
|
300
|
+
hidden_html(options[:field_name] || 'year', val, options)
|
301
|
+
else
|
302
|
+
year_options = []
|
303
|
+
y = date ? (date.kind_of?(Fixnum) ? (y = (date == 0) ? Date.today.year : date) : date.year) : Date.today.year
|
304
|
+
|
305
|
+
start_year, end_year = (options[:start_year] || y-5), (options[:end_year] || y+5)
|
306
|
+
step_val = start_year < end_year ? 1 : -1
|
307
|
+
start_year.step(end_year, step_val) do |year|
|
308
|
+
year_options << ((val == year) ?
|
309
|
+
%(<option value="#{year}" selected="selected">#{year}</option>\n) :
|
310
|
+
%(<option value="#{year}">#{year}</option>\n)
|
311
|
+
)
|
312
|
+
end
|
313
|
+
select_html(options[:field_name] || 'year', year_options, options)
|
232
314
|
end
|
233
|
-
|
234
|
-
select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
|
235
315
|
end
|
236
316
|
|
237
317
|
private
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
select_html
|
242
|
-
select_html << %( disabled="disabled") if disabled
|
318
|
+
|
319
|
+
def select_html(type, html_options, options)
|
320
|
+
name_and_id_from_options(options, type)
|
321
|
+
select_html = %(<select id="#{options[:id]}" name="#{options[:name]}")
|
322
|
+
select_html << %( disabled="disabled") if options[:disabled]
|
243
323
|
select_html << %(>\n)
|
244
|
-
select_html << %(<option value=""></option>\n) if include_blank
|
245
|
-
select_html <<
|
324
|
+
select_html << %(<option value=""></option>\n) if options[:include_blank]
|
325
|
+
select_html << html_options.to_s
|
246
326
|
select_html << "</select>\n"
|
247
327
|
end
|
248
328
|
|
329
|
+
def hidden_html(type, value, options)
|
330
|
+
name_and_id_from_options(options, type)
|
331
|
+
hidden_html = %(<input type="hidden" id="#{options[:id]}" name="#{options[:name]}" value="#{value}" />\n)
|
332
|
+
end
|
333
|
+
|
334
|
+
def name_and_id_from_options(options, type)
|
335
|
+
options[:name] = (options[:prefix] || DEFAULT_PREFIX) + (options[:discard_type] ? '' : "[#{type}]")
|
336
|
+
options[:id] = options[:name].gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
|
337
|
+
end
|
338
|
+
|
249
339
|
def leading_zero_on_single_digits(number)
|
250
340
|
number > 9 ? number : "0#{number}"
|
251
341
|
end
|
@@ -255,43 +345,71 @@ module ActionView
|
|
255
345
|
include DateHelper
|
256
346
|
|
257
347
|
def to_date_select_tag(options = {})
|
258
|
-
|
259
|
-
|
260
|
-
options_with_prefix = Proc.new { |position| options.merge(:prefix => "#{@object_name}[#{@method_name}(#{position}i)]") }
|
261
|
-
date = options[:include_blank] ? (value || 0) : (value || Date.today)
|
348
|
+
date_or_time_select options.merge(:discard_hour => true)
|
349
|
+
end
|
262
350
|
|
263
|
-
|
264
|
-
options
|
265
|
-
|
351
|
+
def to_time_select_tag(options = {})
|
352
|
+
date_or_time_select options.merge(:discard_year => true, :discard_month => true)
|
353
|
+
end
|
266
354
|
|
267
|
-
|
355
|
+
def to_datetime_select_tag(options = {})
|
356
|
+
date_or_time_select options
|
357
|
+
end
|
268
358
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
359
|
+
private
|
360
|
+
def date_or_time_select(options)
|
361
|
+
defaults = { :discard_type => true }
|
362
|
+
options = defaults.merge(options)
|
363
|
+
datetime = value(object)
|
364
|
+
datetime ||= Time.now unless options[:include_blank]
|
365
|
+
|
366
|
+
position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }
|
367
|
+
|
368
|
+
order = (options[:order] ||= [:year, :month, :day])
|
369
|
+
|
370
|
+
# Discard explicit and implicit by not being included in the :order
|
371
|
+
discard = {}
|
372
|
+
discard[:year] = true if options[:discard_year] or !order.include?(:year)
|
373
|
+
discard[:month] = true if options[:discard_month] or !order.include?(:month)
|
374
|
+
discard[:day] = true if options[:discard_day] or discard[:month] or !order.include?(:day)
|
375
|
+
discard[:hour] = true if options[:discard_hour]
|
376
|
+
discard[:minute] = true if options[:discard_minute] or discard[:hour]
|
377
|
+
discard[:second] = true unless options[:include_seconds] && !discard[:minute]
|
378
|
+
|
379
|
+
# Maintain valid dates by including hidden fields for discarded elements
|
380
|
+
[:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
|
381
|
+
# Ensure proper ordering of :hour, :minute and :second
|
382
|
+
[:hour, :minute, :second].each { |o| order.delete(o); order.push(o) }
|
383
|
+
|
384
|
+
date_or_time_select = ''
|
385
|
+
order.reverse.each do |param|
|
386
|
+
# Send hidden fields for discarded elements once output has started
|
387
|
+
# This ensures AR can reconstruct valid dates using ParseDate
|
388
|
+
next if discard[param] && date_or_time_select.empty?
|
389
|
+
|
390
|
+
date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param]))))
|
391
|
+
date_or_time_select.insert(0,
|
392
|
+
case param
|
393
|
+
when :hour then (discard[:year] && discard[:day] ? "" : " — ")
|
394
|
+
when :minute then " : "
|
395
|
+
when :second then options[:include_seconds] ? " : " : ""
|
396
|
+
else ""
|
397
|
+
end)
|
273
398
|
|
274
|
-
|
275
|
-
date_select << self.send("select_#{param}", date, options_with_prefix.call(position[param])) unless discard[param]
|
276
|
-
end
|
399
|
+
end
|
277
400
|
|
278
|
-
|
279
|
-
|
401
|
+
date_or_time_select
|
402
|
+
end
|
280
403
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
datetime_select << ' — ' + select_hour(datetime, options_with_prefix.call(4)) unless options[:discard_hour]
|
291
|
-
datetime_select << ' : ' + select_minute(datetime, options_with_prefix.call(5)) unless options[:discard_minute] || options[:discard_hour]
|
292
|
-
|
293
|
-
datetime_select
|
294
|
-
end
|
404
|
+
def options_with_prefix(position, options)
|
405
|
+
prefix = "#{@object_name}"
|
406
|
+
if options[:index]
|
407
|
+
prefix << "[#{options[:index]}]"
|
408
|
+
elsif @auto_index
|
409
|
+
prefix << "[#{@auto_index}]"
|
410
|
+
end
|
411
|
+
options.merge(:prefix => "#{prefix}[#{@method_name}(#{position}i)]")
|
412
|
+
end
|
295
413
|
end
|
296
414
|
|
297
415
|
class FormBuilder
|
@@ -299,6 +417,10 @@ module ActionView
|
|
299
417
|
@template.date_select(@object_name, method, options.merge(:object => @object))
|
300
418
|
end
|
301
419
|
|
420
|
+
def time_select(method, options = {})
|
421
|
+
@template.time_select(@object_name, method, options.merge(:object => @object))
|
422
|
+
end
|
423
|
+
|
302
424
|
def datetime_select(method, options = {})
|
303
425
|
@template.datetime_select(@object_name, method, options.merge(:object => @object))
|
304
426
|
end
|