actionview 4.2.11 → 5.0.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +304 -184
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +14 -2
- data/lib/action_view/dependency_tracker.rb +51 -18
- data/lib/action_view/digestor.rb +83 -81
- data/lib/action_view/flows.rb +4 -5
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +15 -5
- data/lib/action_view/helpers/asset_url_helper.rb +51 -12
- data/lib/action_view/helpers/atom_feed_helper.rb +6 -5
- data/lib/action_view/helpers/cache_helper.rb +62 -21
- data/lib/action_view/helpers/capture_helper.rb +5 -4
- data/lib/action_view/helpers/controller_helper.rb +11 -2
- data/lib/action_view/helpers/date_helper.rb +59 -13
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +74 -72
- data/lib/action_view/helpers/form_options_helper.rb +79 -39
- data/lib/action_view/helpers/form_tag_helper.rb +74 -44
- data/lib/action_view/helpers/javascript_helper.rb +4 -4
- data/lib/action_view/helpers/number_helper.rb +28 -13
- data/lib/action_view/helpers/output_safety_helper.rb +32 -2
- data/lib/action_view/helpers/record_tag_helper.rb +12 -99
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +1 -2
- data/lib/action_view/helpers/tag_helper.rb +19 -11
- data/lib/action_view/helpers/tags/base.rb +45 -29
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -28
- data/lib/action_view/helpers/tags/collection_helpers.rb +32 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -9
- data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
- data/lib/action_view/helpers/tags/label.rb +1 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
- data/lib/action_view/helpers/tags/search_field.rb +12 -9
- data/lib/action_view/helpers/tags/text_field.rb +0 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +27 -11
- data/lib/action_view/helpers/translation_helper.rb +56 -26
- data/lib/action_view/helpers/url_helper.rb +108 -79
- data/lib/action_view/layouts.rb +11 -10
- data/lib/action_view/log_subscriber.rb +35 -1
- data/lib/action_view/lookup_context.rb +69 -48
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +9 -0
- data/lib/action_view/railtie.rb +18 -3
- data/lib/action_view/record_identifier.rb +45 -19
- data/lib/action_view/renderer/abstract_renderer.rb +7 -3
- data/lib/action_view/renderer/partial_renderer.rb +38 -37
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +49 -0
- data/lib/action_view/renderer/renderer.rb +2 -6
- data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
- data/lib/action_view/renderer/template_renderer.rb +11 -10
- data/lib/action_view/rendering.rb +15 -7
- data/lib/action_view/routing_url_for.rb +18 -6
- data/lib/action_view/tasks/{dependencies.rake → cache_digests.rake} +2 -2
- data/lib/action_view/template.rb +36 -12
- data/lib/action_view/template/error.rb +20 -9
- data/lib/action_view/template/handlers.rb +6 -4
- data/lib/action_view/template/handlers/html.rb +9 -0
- data/lib/action_view/template/handlers/raw.rb +1 -3
- data/lib/action_view/template/resolver.rb +49 -42
- data/lib/action_view/template/types.rb +14 -16
- data/lib/action_view/test_case.rb +15 -9
- data/lib/action_view/testing/resolvers.rb +1 -2
- data/lib/action_view/view_paths.rb +6 -24
- metadata +16 -20
@@ -31,26 +31,33 @@ module ActionView
|
|
31
31
|
# stylesheet_link_tag("application")
|
32
32
|
# # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
|
33
33
|
#
|
34
|
-
# Browsers
|
35
|
-
# host
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
34
|
+
# Browsers open a limited number of simultaneous connections to a single
|
35
|
+
# host. The exact number varies by browser and version. This limit may cause
|
36
|
+
# some asset downloads to wait for previous assets to finish before they can
|
37
|
+
# begin. You can use the <tt>%d</tt> wildcard in the +asset_host+ to
|
38
|
+
# distribute the requests over four hosts. For example,
|
39
|
+
# <tt>assets%d.example.com<tt> will spread the asset requests over
|
40
|
+
# "assets0.example.com", ..., "assets3.example.com".
|
41
41
|
#
|
42
42
|
# image_tag("rails.png")
|
43
43
|
# # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" />
|
44
44
|
# stylesheet_link_tag("application")
|
45
45
|
# # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
|
46
46
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
47
|
+
# This may improve the asset loading performance of your application.
|
48
|
+
# It is also possible the combination of additional connection overhead
|
49
|
+
# (DNS, SSL) and the overall browser connection limits may result in this
|
50
|
+
# solution being slower. You should be sure to measure your actual
|
51
|
+
# performance across targeted browsers both before and after this change.
|
52
|
+
#
|
53
|
+
# To implement the corresponding hosts you can either setup four actual
|
54
|
+
# hosts or use wildcard DNS to CNAME the wildcard to a single asset host.
|
55
|
+
# You can read more about setting up your DNS CNAME records from your ISP.
|
50
56
|
#
|
51
57
|
# Note: This is purely a browser performance optimization and is not meant
|
52
58
|
# for server load balancing. See http://www.die.net/musings/page_load_time/
|
53
|
-
# for background.
|
59
|
+
# for background and http://www.browserscope.org/?category=network for
|
60
|
+
# connection limit data.
|
54
61
|
#
|
55
62
|
# Alternatively, you can exert more control over the asset host by setting
|
56
63
|
# +asset_host+ to a proc like this:
|
@@ -121,11 +128,13 @@ module ActionView
|
|
121
128
|
# asset_path "application", type: :stylesheet # => /assets/application.css
|
122
129
|
# asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
|
123
130
|
def asset_path(source, options = {})
|
131
|
+
raise ArgumentError, "nil is not a valid asset source" if source.nil?
|
132
|
+
|
124
133
|
source = source.to_s
|
125
134
|
return "" unless source.present?
|
126
135
|
return source if source =~ URI_REGEXP
|
127
136
|
|
128
|
-
tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '')
|
137
|
+
tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, ''.freeze)
|
129
138
|
|
130
139
|
if extname = compute_asset_extname(source, options)
|
131
140
|
source = "#{source}#{extname}"
|
@@ -248,6 +257,11 @@ module ActionView
|
|
248
257
|
|
249
258
|
# Computes the full URL to a JavaScript asset in the public javascripts directory.
|
250
259
|
# This will use +javascript_path+ internally, so most of their behaviors will be the same.
|
260
|
+
# Since +javascript_url+ is based on +asset_url+ method you can set :host options. If :host
|
261
|
+
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
262
|
+
#
|
263
|
+
# javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/dir/xmlhr.js
|
264
|
+
#
|
251
265
|
def javascript_url(source, options = {})
|
252
266
|
url_to_asset(source, {type: :javascript}.merge!(options))
|
253
267
|
end
|
@@ -270,6 +284,11 @@ module ActionView
|
|
270
284
|
|
271
285
|
# Computes the full URL to a stylesheet asset in the public stylesheets directory.
|
272
286
|
# This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
|
287
|
+
# Since +stylesheet_url+ is based on +asset_url+ method you can set :host options. If :host
|
288
|
+
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
289
|
+
#
|
290
|
+
# stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/css/style.css
|
291
|
+
#
|
273
292
|
def stylesheet_url(source, options = {})
|
274
293
|
url_to_asset(source, {type: :stylesheet}.merge!(options))
|
275
294
|
end
|
@@ -295,6 +314,11 @@ module ActionView
|
|
295
314
|
|
296
315
|
# Computes the full URL to an image asset.
|
297
316
|
# This will use +image_path+ internally, so most of their behaviors will be the same.
|
317
|
+
# Since +image_url+ is based on +asset_url+ method you can set :host options. If :host
|
318
|
+
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
319
|
+
#
|
320
|
+
# image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/edit.png
|
321
|
+
#
|
298
322
|
def image_url(source, options = {})
|
299
323
|
url_to_asset(source, {type: :image}.merge!(options))
|
300
324
|
end
|
@@ -316,6 +340,11 @@ module ActionView
|
|
316
340
|
|
317
341
|
# Computes the full URL to a video asset in the public videos directory.
|
318
342
|
# This will use +video_path+ internally, so most of their behaviors will be the same.
|
343
|
+
# Since +video_url+ is based on +asset_url+ method you can set :host options. If :host
|
344
|
+
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
345
|
+
#
|
346
|
+
# video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/hd.avi
|
347
|
+
#
|
319
348
|
def video_url(source, options = {})
|
320
349
|
url_to_asset(source, {type: :video}.merge!(options))
|
321
350
|
end
|
@@ -337,6 +366,11 @@ module ActionView
|
|
337
366
|
|
338
367
|
# Computes the full URL to an audio asset in the public audios directory.
|
339
368
|
# This will use +audio_path+ internally, so most of their behaviors will be the same.
|
369
|
+
# Since +audio_url+ is based on +asset_url+ method you can set :host options. If :host
|
370
|
+
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
371
|
+
#
|
372
|
+
# audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/horse.wav
|
373
|
+
#
|
340
374
|
def audio_url(source, options = {})
|
341
375
|
url_to_asset(source, {type: :audio}.merge!(options))
|
342
376
|
end
|
@@ -357,6 +391,11 @@ module ActionView
|
|
357
391
|
|
358
392
|
# Computes the full URL to a font asset.
|
359
393
|
# This will use +font_path+ internally, so most of their behaviors will be the same.
|
394
|
+
# Since +font_url+ is based on +asset_url+ method you can set :host options. If :host
|
395
|
+
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
396
|
+
#
|
397
|
+
# font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/font.ttf
|
398
|
+
#
|
360
399
|
def font_url(source, options = {})
|
361
400
|
url_to_asset(source, {type: :font}.merge!(options))
|
362
401
|
end
|
@@ -16,7 +16,7 @@ module ActionView
|
|
16
16
|
# end
|
17
17
|
#
|
18
18
|
# app/controllers/posts_controller.rb:
|
19
|
-
# class PostsController < ApplicationController
|
19
|
+
# class PostsController < ApplicationController
|
20
20
|
# # GET /posts.html
|
21
21
|
# # GET /posts.atom
|
22
22
|
# def index
|
@@ -51,7 +51,7 @@ module ActionView
|
|
51
51
|
# * <tt>:language</tt>: Defaults to "en-US".
|
52
52
|
# * <tt>:root_url</tt>: The HTML alternative that this feed is doubling for. Defaults to / on the current host.
|
53
53
|
# * <tt>:url</tt>: The URL for this feed. Defaults to the current URL.
|
54
|
-
# * <tt>:id</tt>: The id for this feed. Defaults to "tag
|
54
|
+
# * <tt>:id</tt>: The id for this feed. Defaults to "tag:localhost,2005:/posts", in this case.
|
55
55
|
# * <tt>:schema_date</tt>: The date at which the tag scheme for the feed was first used. A good default is the year you
|
56
56
|
# created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified,
|
57
57
|
# 2005 is used (as an "I don't care" value).
|
@@ -132,7 +132,7 @@ module ActionView
|
|
132
132
|
end
|
133
133
|
|
134
134
|
private
|
135
|
-
# Delegate to xml builder, first wrapping the element in
|
135
|
+
# Delegate to xml builder, first wrapping the element in an xhtml
|
136
136
|
# namespaced div element if the method and arguments indicate
|
137
137
|
# that an xhtml_block? is desired.
|
138
138
|
def method_missing(method, *arguments, &block)
|
@@ -174,7 +174,7 @@ module ActionView
|
|
174
174
|
#
|
175
175
|
# * <tt>:published</tt>: Time first published. Defaults to the created_at attribute on the record if one such exists.
|
176
176
|
# * <tt>:updated</tt>: Time of update. Defaults to the updated_at attribute on the record if one such exists.
|
177
|
-
# * <tt>:url</tt>: The URL for this entry. Defaults to the polymorphic_url for the record.
|
177
|
+
# * <tt>:url</tt>: The URL for this entry or false or nil for not having a link tag. Defaults to the polymorphic_url for the record.
|
178
178
|
# * <tt>:id</tt>: The ID for this entry. Defaults to "tag:#{@view.request.host},#{@feed_options[:schema_date]}:#{record.class}/#{record.id}"
|
179
179
|
# * <tt>:type</tt>: The TYPE for this entry. Defaults to "text/html".
|
180
180
|
def entry(record, options = {})
|
@@ -191,7 +191,8 @@ module ActionView
|
|
191
191
|
|
192
192
|
type = options.fetch(:type, 'text/html')
|
193
193
|
|
194
|
-
|
194
|
+
url = options.fetch(:url) { @view.polymorphic_url(record) }
|
195
|
+
@xml.link(:rel => 'alternate', :type => type, :href => url) if url
|
195
196
|
|
196
197
|
yield AtomBuilder.new(@xml)
|
197
198
|
end
|
@@ -39,7 +39,7 @@ module ActionView
|
|
39
39
|
# This will include both records as part of the cache key and updating either of them will
|
40
40
|
# expire the cache.
|
41
41
|
#
|
42
|
-
# ==== Template digest
|
42
|
+
# ==== \Template digest
|
43
43
|
#
|
44
44
|
# The template digest that's added to the cache key is computed by taking an md5 of the
|
45
45
|
# contents of the entire template file. This ensures that your caches will automatically
|
@@ -75,7 +75,8 @@ module ActionView
|
|
75
75
|
# render(topics) => render("topics/topic")
|
76
76
|
# render(message.topics) => render("topics/topic")
|
77
77
|
#
|
78
|
-
# It's not possible to derive all render calls like that, though.
|
78
|
+
# It's not possible to derive all render calls like that, though.
|
79
|
+
# Here are a few examples of things that can't be derived:
|
79
80
|
#
|
80
81
|
# render group_of_attachments
|
81
82
|
# render @project.documents.where(published: true).order('created_at')
|
@@ -97,22 +98,61 @@ module ActionView
|
|
97
98
|
# <%# Template Dependency: todolists/todolist %>
|
98
99
|
# <%= render_sortable_todolists @project.todolists %>
|
99
100
|
#
|
100
|
-
#
|
101
|
+
# In some cases, like a single table inheritance setup, you might have
|
102
|
+
# a bunch of explicit dependencies. Instead of writing every template out,
|
103
|
+
# you can use a wildcard to match any template in a directory:
|
104
|
+
#
|
105
|
+
# <%# Template Dependency: events/* %>
|
106
|
+
# <%= render_categorizable_events @person.events %>
|
107
|
+
#
|
108
|
+
# This marks every template in the directory as a dependency. To find those
|
109
|
+
# templates, the wildcard path must be absolutely defined from app/views or paths
|
110
|
+
# otherwise added with +prepend_view_path+ or +append_view_path+.
|
111
|
+
# This way the wildcard for `app/views/recordings/events` would be `recordings/events/*` etc.
|
112
|
+
#
|
113
|
+
# The pattern used to match explicit dependencies is <tt>/# Template Dependency: (\S+)/</tt>,
|
114
|
+
# so it's important that you type it out just so.
|
101
115
|
# You can only declare one template dependency per line.
|
102
116
|
#
|
103
117
|
# === External dependencies
|
104
118
|
#
|
105
|
-
# If you use a helper method, for example, inside
|
106
|
-
# you'll have to bump the cache as well.
|
119
|
+
# If you use a helper method, for example, inside a cached block and
|
120
|
+
# you then update that helper, you'll have to bump the cache as well.
|
121
|
+
# It doesn't really matter how you do it, but the md5 of the template file
|
107
122
|
# must change. One recommendation is to simply be explicit in a comment, like:
|
108
123
|
#
|
109
124
|
# <%# Helper Dependency Updated: May 6, 2012 at 6pm %>
|
110
125
|
# <%= some_helper_method(person) %>
|
111
126
|
#
|
112
|
-
# Now all you
|
113
|
-
|
127
|
+
# Now all you have to do is change that timestamp when the helper method changes.
|
128
|
+
#
|
129
|
+
# === Collection Caching
|
130
|
+
#
|
131
|
+
# When rendering a collection of objects that each use the same partial, a `cached`
|
132
|
+
# option can be passed.
|
133
|
+
# For collections rendered such:
|
134
|
+
#
|
135
|
+
# <%= render partial: 'notifications/notification', collection: @notifications, cached: true %>
|
136
|
+
#
|
137
|
+
# The `cached: true` will make Action View's rendering read several templates
|
138
|
+
# from cache at once instead of one call per template.
|
139
|
+
#
|
140
|
+
# Templates in the collection not already cached are written to cache.
|
141
|
+
#
|
142
|
+
# Works great alongside individual template fragment caching.
|
143
|
+
# For instance if the template the collection renders is cached like:
|
144
|
+
#
|
145
|
+
# # notifications/_notification.html.erb
|
146
|
+
# <% cache notification do %>
|
147
|
+
# <%# ... %>
|
148
|
+
# <% end %>
|
149
|
+
#
|
150
|
+
# Any collection renders will find those cached templates when attempting
|
151
|
+
# to read multiple templates at once.
|
152
|
+
def cache(name = {}, options = {}, &block)
|
114
153
|
if controller.respond_to?(:perform_caching) && controller.perform_caching
|
115
|
-
|
154
|
+
name_options = options.slice(:skip_digest, :virtual_path)
|
155
|
+
safe_concat(fragment_for(cache_fragment_name(name, name_options), options, &block))
|
116
156
|
else
|
117
157
|
yield
|
118
158
|
end
|
@@ -126,7 +166,7 @@ module ActionView
|
|
126
166
|
# <b>All the topics on this project</b>
|
127
167
|
# <%= render project.topics %>
|
128
168
|
# <% end %>
|
129
|
-
def cache_if(condition, name = {}, options =
|
169
|
+
def cache_if(condition, name = {}, options = {}, &block)
|
130
170
|
if condition
|
131
171
|
cache(name, options, &block)
|
132
172
|
else
|
@@ -142,33 +182,34 @@ module ActionView
|
|
142
182
|
# <b>All the topics on this project</b>
|
143
183
|
# <%= render project.topics %>
|
144
184
|
# <% end %>
|
145
|
-
def cache_unless(condition, name = {}, options =
|
185
|
+
def cache_unless(condition, name = {}, options = {}, &block)
|
146
186
|
cache_if !condition, name, options, &block
|
147
187
|
end
|
148
188
|
|
149
189
|
# This helper returns the name of a cache key for a given fragment cache
|
150
|
-
# call. By supplying skip_digest
|
190
|
+
# call. By supplying +skip_digest:+ true to cache, the digestion of cache
|
151
191
|
# fragments can be manually bypassed. This is useful when cache fragments
|
152
192
|
# cannot be manually expired unless you know the exact key which is the
|
153
193
|
# case when using memcached.
|
154
|
-
|
155
|
-
|
156
|
-
|
194
|
+
#
|
195
|
+
# The digest will be generated using +virtual_path:+ if it is provided.
|
196
|
+
#
|
197
|
+
def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
|
157
198
|
if skip_digest
|
158
199
|
name
|
159
200
|
else
|
160
|
-
fragment_name_with_digest(name)
|
201
|
+
fragment_name_with_digest(name, virtual_path)
|
161
202
|
end
|
162
203
|
end
|
163
204
|
|
164
205
|
private
|
165
206
|
|
166
|
-
def fragment_name_with_digest(name) #:nodoc:
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
[
|
207
|
+
def fragment_name_with_digest(name, virtual_path) #:nodoc:
|
208
|
+
virtual_path ||= @virtual_path
|
209
|
+
if virtual_path
|
210
|
+
name = controller.url_for(name).split("://").last if name.is_a?(Hash)
|
211
|
+
digest = Digestor.digest name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies
|
212
|
+
[ name, digest ]
|
172
213
|
else
|
173
214
|
name
|
174
215
|
end
|
@@ -9,8 +9,8 @@ module ActionView
|
|
9
9
|
# It provides a method to capture blocks into variables through capture and
|
10
10
|
# a way to capture a block of markup for use in a layout through content_for.
|
11
11
|
module CaptureHelper
|
12
|
-
# The capture method
|
13
|
-
#
|
12
|
+
# The capture method extracts part of a template as a String object.
|
13
|
+
# You can then use this object anywhere in your templates, layout, or helpers.
|
14
14
|
#
|
15
15
|
# The capture method can be used in ERB templates...
|
16
16
|
#
|
@@ -31,7 +31,8 @@ module ActionView
|
|
31
31
|
# <head><title><%= @greeting %></title></head>
|
32
32
|
# <body>
|
33
33
|
# <b><%= @greeting %></b>
|
34
|
-
# </body
|
34
|
+
# </body>
|
35
|
+
# </html>
|
35
36
|
#
|
36
37
|
def capture(*args)
|
37
38
|
value = nil
|
@@ -114,7 +115,7 @@ module ActionView
|
|
114
115
|
# <li><%= link_to 'Home', action: 'index' %></li>
|
115
116
|
# <% end %>
|
116
117
|
#
|
117
|
-
# And in
|
118
|
+
# And in another place:
|
118
119
|
#
|
119
120
|
# <% content_for :navigation do %>
|
120
121
|
# <li><%= link_to 'Login', action: 'login' %></li>
|
@@ -7,19 +7,28 @@ module ActionView
|
|
7
7
|
module ControllerHelper #:nodoc:
|
8
8
|
attr_internal :controller, :request
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
CONTROLLER_DELEGATES = [:request_forgery_protection_token, :params,
|
11
|
+
:session, :cookies, :response, :headers, :flash, :action_name,
|
12
|
+
:controller_name, :controller_path]
|
13
|
+
|
14
|
+
delegate *CONTROLLER_DELEGATES, to: :controller
|
12
15
|
|
13
16
|
def assign_controller(controller)
|
14
17
|
if @_controller = controller
|
15
18
|
@_request = controller.request if controller.respond_to?(:request)
|
16
19
|
@_config = controller.config.inheritable_copy if controller.respond_to?(:config)
|
20
|
+
@_default_form_builder = controller.default_form_builder if controller.respond_to?(:default_form_builder)
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def logger
|
21
25
|
controller.logger if controller.respond_to?(:logger)
|
22
26
|
end
|
27
|
+
|
28
|
+
def respond_to?(method_name, include_private = false)
|
29
|
+
return controller.respond_to?(method_name) if CONTROLLER_DELEGATES.include?(method_name.to_sym)
|
30
|
+
super
|
31
|
+
end
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|
@@ -3,6 +3,7 @@ require 'action_view/helpers/tag_helper'
|
|
3
3
|
require 'active_support/core_ext/array/extract_options'
|
4
4
|
require 'active_support/core_ext/date/conversions'
|
5
5
|
require 'active_support/core_ext/hash/slice'
|
6
|
+
require 'active_support/core_ext/object/acts_like'
|
6
7
|
require 'active_support/core_ext/object/with_options'
|
7
8
|
|
8
9
|
module ActionView
|
@@ -68,6 +69,27 @@ module ActionView
|
|
68
69
|
# distance_of_time_in_words(from_time, to_time, include_seconds: true) # => about 6 years
|
69
70
|
# distance_of_time_in_words(to_time, from_time, include_seconds: true) # => about 6 years
|
70
71
|
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
|
72
|
+
#
|
73
|
+
# With the <tt>scope</tt> option, you can define a custom scope for Rails
|
74
|
+
# to look up the translation.
|
75
|
+
#
|
76
|
+
# For example you can define the following in your locale (e.g. en.yml).
|
77
|
+
#
|
78
|
+
# datetime:
|
79
|
+
# distance_in_words:
|
80
|
+
# short:
|
81
|
+
# about_x_hours:
|
82
|
+
# one: 'an hour'
|
83
|
+
# other: '%{count} hours'
|
84
|
+
#
|
85
|
+
# See https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml
|
86
|
+
# for more examples.
|
87
|
+
#
|
88
|
+
# Which will then result in the following:
|
89
|
+
#
|
90
|
+
# from_time = Time.now
|
91
|
+
# distance_of_time_in_words(from_time, from_time + 50.minutes, scope: 'datetime.distance_in_words.short') # => "an hour"
|
92
|
+
# distance_of_time_in_words(from_time, from_time + 3.hours, scope: 'datetime.distance_in_words.short') # => "3 hours"
|
71
93
|
def distance_of_time_in_words(from_time, to_time = 0, options = {})
|
72
94
|
options = {
|
73
95
|
scope: :'datetime.distance_in_words'
|
@@ -177,6 +199,8 @@ module ActionView
|
|
177
199
|
# and +:name+ (string). A format string would be something like "%{name} (%<number>02d)" for example.
|
178
200
|
# See <tt>Kernel.sprintf</tt> for documentation on format sequences.
|
179
201
|
# * <tt>:date_separator</tt> - Specifies a string to separate the date fields. Default is "" (i.e. nothing).
|
202
|
+
# * <tt>:time_separator</tt> - Specifies a string to separate the time fields. Default is "" (i.e. nothing).
|
203
|
+
# * <tt>:datetime_separator</tt>- Specifies a string to separate the date and time fields. Default is "" (i.e. nothing).
|
180
204
|
# * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Date.today.year - 5</tt> if
|
181
205
|
# you are creating new record. While editing existing record, <tt>:start_year</tt> defaults to
|
182
206
|
# the current selected year minus 5.
|
@@ -203,8 +227,11 @@ module ActionView
|
|
203
227
|
# for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
|
204
228
|
# Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
|
205
229
|
# or the given prompt string.
|
206
|
-
# * <tt>:with_css_classes</tt>
|
207
|
-
# automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second'
|
230
|
+
# * <tt>:with_css_classes</tt> - Set to true or a hash of strings. Use true if you want to assign generic styles for
|
231
|
+
# select tags. This automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second'. A hash of
|
232
|
+
# strings for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, <tt>:second</tt>
|
233
|
+
# will extend the select type with the given value. Use +html_options+ to modify every select tag in the set.
|
234
|
+
# * <tt>:use_hidden</tt> - Set to true if you only want to generate hidden input tags.
|
208
235
|
#
|
209
236
|
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
|
210
237
|
#
|
@@ -462,7 +489,7 @@ module ActionView
|
|
462
489
|
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
|
463
490
|
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
|
464
491
|
#
|
465
|
-
# my_time = Time.now + 16.
|
492
|
+
# my_time = Time.now + 16.seconds
|
466
493
|
#
|
467
494
|
# # Generates a select field for seconds that defaults to the seconds for the time in my_time.
|
468
495
|
# select_second(my_time)
|
@@ -486,7 +513,7 @@ module ActionView
|
|
486
513
|
# selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
|
487
514
|
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
|
488
515
|
#
|
489
|
-
# my_time = Time.now +
|
516
|
+
# my_time = Time.now + 10.minutes
|
490
517
|
#
|
491
518
|
# # Generates a select field for minutes that defaults to the minutes for the time in my_time.
|
492
519
|
# select_minute(my_time)
|
@@ -658,7 +685,7 @@ module ActionView
|
|
658
685
|
content = args.first || I18n.l(date_or_time, :format => format)
|
659
686
|
datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
|
660
687
|
|
661
|
-
content_tag(
|
688
|
+
content_tag("time".freeze, content, options.reverse_merge(:datetime => datetime), &block)
|
662
689
|
end
|
663
690
|
end
|
664
691
|
|
@@ -786,7 +813,7 @@ module ActionView
|
|
786
813
|
1.upto(12) do |month_number|
|
787
814
|
options = { :value => month_number }
|
788
815
|
options[:selected] = "selected" if month == month_number
|
789
|
-
month_options << content_tag(
|
816
|
+
month_options << content_tag("option".freeze, month_name(month_number), options) + "\n"
|
790
817
|
end
|
791
818
|
build_select(:month, month_options.join)
|
792
819
|
end
|
@@ -821,7 +848,12 @@ module ActionView
|
|
821
848
|
private
|
822
849
|
%w( sec min hour day month year ).each do |method|
|
823
850
|
define_method(method) do
|
824
|
-
|
851
|
+
case @datetime
|
852
|
+
when Hash then @datetime[method.to_sym]
|
853
|
+
when Numeric then @datetime
|
854
|
+
when nil then nil
|
855
|
+
else @datetime.send(method)
|
856
|
+
end
|
825
857
|
end
|
826
858
|
end
|
827
859
|
|
@@ -898,7 +930,7 @@ module ActionView
|
|
898
930
|
|
899
931
|
def translated_date_order
|
900
932
|
date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => [])
|
901
|
-
date_order = date_order.map
|
933
|
+
date_order = date_order.map(&:to_sym)
|
902
934
|
|
903
935
|
forbidden_elements = date_order - [:year, :month, :day]
|
904
936
|
if forbidden_elements.any?
|
@@ -948,7 +980,7 @@ module ActionView
|
|
948
980
|
tag_options[:selected] = "selected" if selected == i
|
949
981
|
text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value
|
950
982
|
text = options[:ampm] ? AMPM_TRANSLATION[i] : text
|
951
|
-
select_options << content_tag(
|
983
|
+
select_options << content_tag("option".freeze, text, tag_options)
|
952
984
|
end
|
953
985
|
|
954
986
|
(select_options.join("\n") + "\n").html_safe
|
@@ -965,14 +997,28 @@ module ActionView
|
|
965
997
|
:name => input_name_from_type(type)
|
966
998
|
}.merge!(@html_options)
|
967
999
|
select_options[:disabled] = 'disabled' if @options[:disabled]
|
968
|
-
select_options[:class] =
|
1000
|
+
select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes]
|
969
1001
|
|
970
1002
|
select_html = "\n"
|
971
|
-
select_html << content_tag(
|
1003
|
+
select_html << content_tag("option".freeze, '', :value => '') + "\n" if @options[:include_blank]
|
972
1004
|
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
|
973
1005
|
select_html << select_options_as_html
|
974
1006
|
|
975
|
-
(content_tag(
|
1007
|
+
(content_tag("select".freeze, select_html.html_safe, select_options) + "\n").html_safe
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
# Builds the css class value for the select element
|
1011
|
+
# css_class_attribute(:year, 'date optional', { year: 'my-year' })
|
1012
|
+
# => "date optional my-year"
|
1013
|
+
def css_class_attribute(type, html_options_class, options) # :nodoc:
|
1014
|
+
css_class = case options
|
1015
|
+
when Hash
|
1016
|
+
options[type.to_sym]
|
1017
|
+
else
|
1018
|
+
type
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
[html_options_class, css_class].compact.join(' ')
|
976
1022
|
end
|
977
1023
|
|
978
1024
|
# Builds a prompt option tag with supplied options or from default options.
|
@@ -989,7 +1035,7 @@ module ActionView
|
|
989
1035
|
I18n.translate(:"datetime.prompts.#{type}", :locale => @options[:locale])
|
990
1036
|
end
|
991
1037
|
|
992
|
-
prompt ? content_tag(
|
1038
|
+
prompt ? content_tag("option".freeze, prompt, :value => '') : ''
|
993
1039
|
end
|
994
1040
|
|
995
1041
|
# Builds hidden input tag for date part and value.
|