actionview 4.2.11.1 → 6.0.4
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 +4 -4
- data/CHANGELOG.md +201 -192
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +144 -37
- data/lib/action_view/buffers.rb +18 -1
- data/lib/action_view/cache_expiry.rb +53 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker.rb +54 -20
- data/lib/action_view/digestor.rb +88 -85
- data/lib/action_view/flows.rb +11 -12
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +16 -11
- data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
- data/lib/action_view/helpers/asset_url_helper.rb +171 -67
- data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
- data/lib/action_view/helpers/cache_helper.rb +112 -42
- data/lib/action_view/helpers/capture_helper.rb +20 -13
- data/lib/action_view/helpers/controller_helper.rb +15 -4
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +230 -129
- data/lib/action_view/helpers/debug_helper.rb +7 -6
- data/lib/action_view/helpers/form_helper.rb +755 -129
- data/lib/action_view/helpers/form_options_helper.rb +130 -75
- data/lib/action_view/helpers/form_tag_helper.rb +116 -71
- data/lib/action_view/helpers/javascript_helper.rb +30 -14
- data/lib/action_view/helpers/number_helper.rb +84 -59
- data/lib/action_view/helpers/output_safety_helper.rb +36 -4
- data/lib/action_view/helpers/rendering_helper.rb +11 -8
- data/lib/action_view/helpers/sanitize_helper.rb +30 -31
- data/lib/action_view/helpers/tag_helper.rb +201 -75
- data/lib/action_view/helpers/tags/base.rb +138 -98
- data/lib/action_view/helpers/tags/check_box.rb +20 -19
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +2 -1
- data/lib/action_view/helpers/tags/date_select.rb +37 -36
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +3 -2
- data/lib/action_view/helpers/tags/month_field.rb +2 -1
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +2 -1
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +2 -1
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/text_helper.rb +56 -38
- data/lib/action_view/helpers/translation_helper.rb +91 -47
- data/lib/action_view/helpers/url_helper.rb +160 -105
- data/lib/action_view/helpers.rb +5 -3
- data/lib/action_view/layouts.rb +65 -61
- data/lib/action_view/log_subscriber.rb +61 -10
- data/lib/action_view/lookup_context.rb +147 -89
- data/lib/action_view/model_naming.rb +3 -1
- data/lib/action_view/path_set.rb +28 -23
- data/lib/action_view/railtie.rb +62 -6
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/renderer/abstract_renderer.rb +71 -13
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
- data/lib/action_view/renderer/partial_renderer.rb +239 -225
- data/lib/action_view/renderer/renderer.rb +22 -8
- data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
- data/lib/action_view/renderer/template_renderer.rb +79 -73
- data/lib/action_view/rendering.rb +68 -44
- data/lib/action_view/routing_url_for.rb +33 -22
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +44 -29
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
- data/lib/action_view/template/handlers/erb.rb +24 -86
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +38 -8
- data/lib/action_view/template/html.rb +19 -10
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +28 -0
- data/lib/action_view/template/resolver.rb +217 -193
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +11 -10
- data/lib/action_view/template/types.rb +18 -18
- data/lib/action_view/template.rb +146 -90
- data/lib/action_view/test_case.rb +52 -32
- data/lib/action_view/testing/resolvers.rb +46 -34
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +48 -31
- data/lib/action_view.rb +11 -8
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +38 -29
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,12 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "action_view/helpers/tag_helper"
|
5
|
+
require "active_support/core_ext/array/extract_options"
|
6
|
+
require "active_support/core_ext/date/conversions"
|
7
|
+
require "active_support/core_ext/hash/slice"
|
8
|
+
require "active_support/core_ext/object/acts_like"
|
9
|
+
require "active_support/core_ext/object/with_options"
|
7
10
|
|
8
11
|
module ActionView
|
9
|
-
module Helpers
|
12
|
+
module Helpers #:nodoc:
|
10
13
|
# = Action View Date Helpers
|
11
14
|
#
|
12
15
|
# The Date Helper primarily creates select/option tags for different kinds of dates and times or date and time
|
@@ -68,71 +71,88 @@ module ActionView
|
|
68
71
|
# distance_of_time_in_words(from_time, to_time, include_seconds: true) # => about 6 years
|
69
72
|
# distance_of_time_in_words(to_time, from_time, include_seconds: true) # => about 6 years
|
70
73
|
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
|
74
|
+
#
|
75
|
+
# With the <tt>scope</tt> option, you can define a custom scope for Rails
|
76
|
+
# to look up the translation.
|
77
|
+
#
|
78
|
+
# For example you can define the following in your locale (e.g. en.yml).
|
79
|
+
#
|
80
|
+
# datetime:
|
81
|
+
# distance_in_words:
|
82
|
+
# short:
|
83
|
+
# about_x_hours:
|
84
|
+
# one: 'an hour'
|
85
|
+
# other: '%{count} hours'
|
86
|
+
#
|
87
|
+
# See https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/en.yml
|
88
|
+
# for more examples.
|
89
|
+
#
|
90
|
+
# Which will then result in the following:
|
91
|
+
#
|
92
|
+
# from_time = Time.now
|
93
|
+
# distance_of_time_in_words(from_time, from_time + 50.minutes, scope: 'datetime.distance_in_words.short') # => "an hour"
|
94
|
+
# distance_of_time_in_words(from_time, from_time + 3.hours, scope: 'datetime.distance_in_words.short') # => "3 hours"
|
71
95
|
def distance_of_time_in_words(from_time, to_time = 0, options = {})
|
72
96
|
options = {
|
73
97
|
scope: :'datetime.distance_in_words'
|
74
98
|
}.merge!(options)
|
75
99
|
|
76
|
-
from_time = from_time
|
77
|
-
to_time =
|
100
|
+
from_time = normalize_distance_of_time_argument_to_time(from_time)
|
101
|
+
to_time = normalize_distance_of_time_argument_to_time(to_time)
|
78
102
|
from_time, to_time = to_time, from_time if from_time > to_time
|
79
|
-
distance_in_minutes = ((to_time - from_time)/60.0).round
|
103
|
+
distance_in_minutes = ((to_time - from_time) / 60.0).round
|
80
104
|
distance_in_seconds = (to_time - from_time).round
|
81
105
|
|
82
|
-
I18n.with_options :
|
106
|
+
I18n.with_options locale: options[:locale], scope: options[:scope] do |locale|
|
83
107
|
case distance_in_minutes
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
108
|
+
when 0..1
|
109
|
+
return distance_in_minutes == 0 ?
|
110
|
+
locale.t(:less_than_x_minutes, count: 1) :
|
111
|
+
locale.t(:x_minutes, count: distance_in_minutes) unless options[:include_seconds]
|
112
|
+
|
113
|
+
case distance_in_seconds
|
114
|
+
when 0..4 then locale.t :less_than_x_seconds, count: 5
|
115
|
+
when 5..9 then locale.t :less_than_x_seconds, count: 10
|
116
|
+
when 10..19 then locale.t :less_than_x_seconds, count: 20
|
117
|
+
when 20..39 then locale.t :half_a_minute
|
118
|
+
when 40..59 then locale.t :less_than_x_minutes, count: 1
|
119
|
+
else locale.t :x_minutes, count: 1
|
120
|
+
end
|
121
|
+
|
122
|
+
when 2...45 then locale.t :x_minutes, count: distance_in_minutes
|
123
|
+
when 45...90 then locale.t :about_x_hours, count: 1
|
100
124
|
# 90 mins up to 24 hours
|
101
|
-
|
125
|
+
when 90...1440 then locale.t :about_x_hours, count: (distance_in_minutes.to_f / 60.0).round
|
102
126
|
# 24 hours up to 42 hours
|
103
|
-
|
127
|
+
when 1440...2520 then locale.t :x_days, count: 1
|
104
128
|
# 42 hours up to 30 days
|
105
|
-
|
129
|
+
when 2520...43200 then locale.t :x_days, count: (distance_in_minutes.to_f / 1440.0).round
|
106
130
|
# 30 days up to 60 days
|
107
|
-
|
131
|
+
when 43200...86400 then locale.t :about_x_months, count: (distance_in_minutes.to_f / 43200.0).round
|
108
132
|
# 60 days up to 365 days
|
109
|
-
|
133
|
+
when 86400...525600 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round
|
134
|
+
else
|
135
|
+
from_year = from_time.year
|
136
|
+
from_year += 1 if from_time.month >= 3
|
137
|
+
to_year = to_time.year
|
138
|
+
to_year -= 1 if to_time.month < 3
|
139
|
+
leap_years = (from_year > to_year) ? 0 : (from_year..to_year).count { |x| Date.leap?(x) }
|
140
|
+
minute_offset_for_leap_year = leap_years * 1440
|
141
|
+
# Discount the leap year days when calculating year distance.
|
142
|
+
# e.g. if there are 20 leap year days between 2 dates having the same day
|
143
|
+
# and month then the based on 365 days calculation
|
144
|
+
# the distance in years will come out to over 80 years when in written
|
145
|
+
# English it would read better as about 80 years.
|
146
|
+
minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
|
147
|
+
remainder = (minutes_with_offset % MINUTES_IN_YEAR)
|
148
|
+
distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR)
|
149
|
+
if remainder < MINUTES_IN_QUARTER_YEAR
|
150
|
+
locale.t(:about_x_years, count: distance_in_years)
|
151
|
+
elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR
|
152
|
+
locale.t(:over_x_years, count: distance_in_years)
|
110
153
|
else
|
111
|
-
|
112
|
-
|
113
|
-
fyear += 1 if from_time.month >= 3
|
114
|
-
tyear = to_time.year
|
115
|
-
tyear -= 1 if to_time.month < 3
|
116
|
-
leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
|
117
|
-
minute_offset_for_leap_year = leap_years * 1440
|
118
|
-
# Discount the leap year days when calculating year distance.
|
119
|
-
# e.g. if there are 20 leap year days between 2 dates having the same day
|
120
|
-
# and month then the based on 365 days calculation
|
121
|
-
# the distance in years will come out to over 80 years when in written
|
122
|
-
# English it would read better as about 80 years.
|
123
|
-
minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
|
124
|
-
else
|
125
|
-
minutes_with_offset = distance_in_minutes
|
126
|
-
end
|
127
|
-
remainder = (minutes_with_offset % MINUTES_IN_YEAR)
|
128
|
-
distance_in_years = (minutes_with_offset.div MINUTES_IN_YEAR)
|
129
|
-
if remainder < MINUTES_IN_QUARTER_YEAR
|
130
|
-
locale.t(:about_x_years, :count => distance_in_years)
|
131
|
-
elsif remainder < MINUTES_IN_THREE_QUARTERS_YEAR
|
132
|
-
locale.t(:over_x_years, :count => distance_in_years)
|
133
|
-
else
|
134
|
-
locale.t(:almost_x_years, :count => distance_in_years + 1)
|
135
|
-
end
|
154
|
+
locale.t(:almost_x_years, count: distance_in_years + 1)
|
155
|
+
end
|
136
156
|
end
|
137
157
|
end
|
138
158
|
end
|
@@ -177,12 +197,15 @@ module ActionView
|
|
177
197
|
# and +:name+ (string). A format string would be something like "%{name} (%<number>02d)" for example.
|
178
198
|
# See <tt>Kernel.sprintf</tt> for documentation on format sequences.
|
179
199
|
# * <tt>:date_separator</tt> - Specifies a string to separate the date fields. Default is "" (i.e. nothing).
|
200
|
+
# * <tt>:time_separator</tt> - Specifies a string to separate the time fields. Default is "" (i.e. nothing).
|
201
|
+
# * <tt>:datetime_separator</tt>- Specifies a string to separate the date and time fields. Default is "" (i.e. nothing).
|
180
202
|
# * <tt>:start_year</tt> - Set the start year for the year select. Default is <tt>Date.today.year - 5</tt> if
|
181
203
|
# you are creating new record. While editing existing record, <tt>:start_year</tt> defaults to
|
182
204
|
# the current selected year minus 5.
|
183
205
|
# * <tt>:end_year</tt> - Set the end year for the year select. Default is <tt>Date.today.year + 5</tt> if
|
184
206
|
# you are creating new record. While editing existing record, <tt>:end_year</tt> defaults to
|
185
207
|
# the current selected year plus 5.
|
208
|
+
# * <tt>:year_format</tt> - Set format of years for year select. Lambda should be passed.
|
186
209
|
# * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day
|
187
210
|
# as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
|
188
211
|
# first of the given month in order to not create invalid dates like 31 February.
|
@@ -196,15 +219,18 @@ module ActionView
|
|
196
219
|
# the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).
|
197
220
|
# * <tt>:include_blank</tt> - Include a blank option in every select field so it's possible to set empty
|
198
221
|
# dates.
|
199
|
-
# * <tt>:default</tt> - Set a default date if the affected date isn't set or is nil
|
222
|
+
# * <tt>:default</tt> - Set a default date if the affected date isn't set or is +nil+.
|
200
223
|
# * <tt>:selected</tt> - Set a date that overrides the actual value.
|
201
224
|
# * <tt>:disabled</tt> - Set to true if you want show the select fields as disabled.
|
202
225
|
# * <tt>:prompt</tt> - Set to true (for a generic prompt), a prompt string or a hash of prompt strings
|
203
226
|
# for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
|
204
227
|
# Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
|
205
228
|
# or the given prompt string.
|
206
|
-
# * <tt>:with_css_classes</tt>
|
207
|
-
# automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second'
|
229
|
+
# * <tt>:with_css_classes</tt> - Set to true or a hash of strings. Use true if you want to assign generic styles for
|
230
|
+
# select tags. This automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second'. A hash of
|
231
|
+
# strings for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, <tt>:second</tt>
|
232
|
+
# will extend the select type with the given value. Use +html_options+ to modify every select tag in the set.
|
233
|
+
# * <tt>:use_hidden</tt> - Set to true if you only want to generate hidden input tags.
|
208
234
|
#
|
209
235
|
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
|
210
236
|
#
|
@@ -240,7 +266,7 @@ module ActionView
|
|
240
266
|
# date_select("article", "written_on", default: 3.days.from_now)
|
241
267
|
#
|
242
268
|
# # Generates a date select that when POSTed is stored in the article variable, in the written_on attribute
|
243
|
-
# # which is set in the form with
|
269
|
+
# # which is set in the form with today's date, regardless of the value in the Active Record object.
|
244
270
|
# date_select("article", "written_on", selected: Date.today)
|
245
271
|
#
|
246
272
|
# # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute
|
@@ -250,6 +276,9 @@ module ActionView
|
|
250
276
|
# # Generates a date select with custom prompts.
|
251
277
|
# date_select("article", "written_on", prompt: { day: 'Select day', month: 'Select month', year: 'Select year' })
|
252
278
|
#
|
279
|
+
# # Generates a date select with custom year format.
|
280
|
+
# date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
|
281
|
+
#
|
253
282
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
254
283
|
#
|
255
284
|
# Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that
|
@@ -276,16 +305,16 @@ module ActionView
|
|
276
305
|
# # the sunrise attribute.
|
277
306
|
# time_select("article", "start_time", include_seconds: true)
|
278
307
|
#
|
279
|
-
# # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45.
|
280
|
-
# time_select 'game', 'game_time', {minute_step: 15}
|
308
|
+
# # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30, and 45.
|
309
|
+
# time_select 'game', 'game_time', { minute_step: 15 }
|
281
310
|
#
|
282
311
|
# # Creates a time select tag with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
|
283
|
-
# time_select("article", "written_on", prompt: {hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds'})
|
284
|
-
# time_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
|
312
|
+
# time_select("article", "written_on", prompt: { hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds' })
|
313
|
+
# time_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
|
285
314
|
# time_select("article", "written_on", prompt: true) # generic prompts for all
|
286
315
|
#
|
287
316
|
# # You can set :ampm option to true which will show the hours as: 12 PM, 01 AM .. 11 PM.
|
288
|
-
# time_select 'game', 'game_time', {ampm: true}
|
317
|
+
# time_select 'game', 'game_time', { ampm: true }
|
289
318
|
#
|
290
319
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
291
320
|
#
|
@@ -321,8 +350,8 @@ module ActionView
|
|
321
350
|
# datetime_select("article", "written_on", discard_type: true)
|
322
351
|
#
|
323
352
|
# # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
|
324
|
-
# datetime_select("article", "written_on", prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
|
325
|
-
# datetime_select("article", "written_on", prompt: {hour: true}) # generic prompt for hours
|
353
|
+
# datetime_select("article", "written_on", prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
354
|
+
# datetime_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
|
326
355
|
# datetime_select("article", "written_on", prompt: true) # generic prompts for all
|
327
356
|
#
|
328
357
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
@@ -372,8 +401,8 @@ module ActionView
|
|
372
401
|
# select_datetime(my_date_time, prefix: 'payday')
|
373
402
|
#
|
374
403
|
# # Generates a datetime select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
|
375
|
-
# select_datetime(my_date_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
|
376
|
-
# select_datetime(my_date_time, prompt: {hour: true}) # generic prompt for hours
|
404
|
+
# select_datetime(my_date_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
405
|
+
# select_datetime(my_date_time, prompt: { hour: true }) # generic prompt for hours
|
377
406
|
# select_datetime(my_date_time, prompt: true) # generic prompts for all
|
378
407
|
def select_datetime(datetime = Time.current, options = {}, html_options = {})
|
379
408
|
DateTimeSelector.new(datetime, options, html_options).select_datetime
|
@@ -411,8 +440,8 @@ module ActionView
|
|
411
440
|
# select_date(my_date, prefix: 'payday')
|
412
441
|
#
|
413
442
|
# # Generates a date select with a custom prompt. Use <tt>prompt: true</tt> for generic prompts.
|
414
|
-
# select_date(my_date, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
|
415
|
-
# select_date(my_date, prompt: {hour: true}) # generic prompt for hours
|
443
|
+
# select_date(my_date, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
444
|
+
# select_date(my_date, prompt: { hour: true }) # generic prompt for hours
|
416
445
|
# select_date(my_date, prompt: true) # generic prompts for all
|
417
446
|
def select_date(date = Date.current, options = {}, html_options = {})
|
418
447
|
DateTimeSelector.new(date, options, html_options).select_date
|
@@ -451,8 +480,8 @@ module ActionView
|
|
451
480
|
# select_time(my_time, start_hour: 2, end_hour: 14)
|
452
481
|
#
|
453
482
|
# # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
|
454
|
-
# select_time(my_time, prompt: {day: 'Choose day', month: 'Choose month', year: 'Choose year'})
|
455
|
-
# select_time(my_time, prompt: {hour: true}) # generic prompt for hours
|
483
|
+
# select_time(my_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
484
|
+
# select_time(my_time, prompt: { hour: true }) # generic prompt for hours
|
456
485
|
# select_time(my_time, prompt: true) # generic prompts for all
|
457
486
|
def select_time(datetime = Time.current, options = {}, html_options = {})
|
458
487
|
DateTimeSelector.new(datetime, options, html_options).select_time
|
@@ -462,7 +491,7 @@ module ActionView
|
|
462
491
|
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
|
463
492
|
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
|
464
493
|
#
|
465
|
-
# my_time = Time.now + 16.
|
494
|
+
# my_time = Time.now + 16.seconds
|
466
495
|
#
|
467
496
|
# # Generates a select field for seconds that defaults to the seconds for the time in my_time.
|
468
497
|
# select_second(my_time)
|
@@ -486,7 +515,7 @@ module ActionView
|
|
486
515
|
# selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
|
487
516
|
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
|
488
517
|
#
|
489
|
-
# my_time = Time.now +
|
518
|
+
# my_time = Time.now + 10.minutes
|
490
519
|
#
|
491
520
|
# # Generates a select field for minutes that defaults to the minutes for the time in my_time.
|
492
521
|
# select_minute(my_time)
|
@@ -643,8 +672,6 @@ module ActionView
|
|
643
672
|
# <time datetime="2010-11-04T17:55:45+01:00">November 04, 2010 17:55</time>
|
644
673
|
# time_tag Date.yesterday, 'Yesterday' # =>
|
645
674
|
# <time datetime="2010-11-03">Yesterday</time>
|
646
|
-
# time_tag Date.today, pubdate: true # =>
|
647
|
-
# <time datetime="2010-11-04" pubdate="pubdate">November 04, 2010</time>
|
648
675
|
# time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # =>
|
649
676
|
# <time datetime="2010-W44">November 04, 2010</time>
|
650
677
|
#
|
@@ -655,19 +682,29 @@ module ActionView
|
|
655
682
|
def time_tag(date_or_time, *args, &block)
|
656
683
|
options = args.extract_options!
|
657
684
|
format = options.delete(:format) || :long
|
658
|
-
content = args.first || I18n.l(date_or_time, :
|
659
|
-
datetime = date_or_time.acts_like?(:time) ? date_or_time.xmlschema : date_or_time.iso8601
|
685
|
+
content = args.first || I18n.l(date_or_time, format: format)
|
660
686
|
|
661
|
-
content_tag(
|
687
|
+
content_tag("time", content, options.reverse_merge(datetime: date_or_time.iso8601), &block)
|
662
688
|
end
|
689
|
+
|
690
|
+
private
|
691
|
+
def normalize_distance_of_time_argument_to_time(value)
|
692
|
+
if value.is_a?(Numeric)
|
693
|
+
Time.at(value)
|
694
|
+
elsif value.respond_to?(:to_time)
|
695
|
+
value.to_time
|
696
|
+
else
|
697
|
+
raise ArgumentError, "#{value.inspect} can't be converted to a Time value"
|
698
|
+
end
|
699
|
+
end
|
663
700
|
end
|
664
701
|
|
665
702
|
class DateTimeSelector #:nodoc:
|
666
703
|
include ActionView::Helpers::TagHelper
|
667
704
|
|
668
|
-
DEFAULT_PREFIX =
|
705
|
+
DEFAULT_PREFIX = "date"
|
669
706
|
POSITION = {
|
670
|
-
:
|
707
|
+
year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6
|
671
708
|
}.freeze
|
672
709
|
|
673
710
|
AMPM_TRANSLATION = Hash[
|
@@ -683,8 +720,8 @@ module ActionView
|
|
683
720
|
@options = options.dup
|
684
721
|
@html_options = html_options.dup
|
685
722
|
@datetime = datetime
|
686
|
-
@options[:datetime_separator] ||=
|
687
|
-
@options[:time_separator] ||=
|
723
|
+
@options[:datetime_separator] ||= " — "
|
724
|
+
@options[:time_separator] ||= " : "
|
688
725
|
end
|
689
726
|
|
690
727
|
def select_datetime
|
@@ -754,7 +791,7 @@ module ActionView
|
|
754
791
|
if @options[:use_hidden] || @options[:discard_minute]
|
755
792
|
build_hidden(:minute, min)
|
756
793
|
else
|
757
|
-
build_options_and_select(:minute, min, :
|
794
|
+
build_options_and_select(:minute, min, step: @options[:minute_step])
|
758
795
|
end
|
759
796
|
end
|
760
797
|
|
@@ -774,7 +811,7 @@ module ActionView
|
|
774
811
|
if @options[:use_hidden] || @options[:discard_day]
|
775
812
|
build_hidden(:day, day || 1)
|
776
813
|
else
|
777
|
-
build_options_and_select(:day, day, :
|
814
|
+
build_options_and_select(:day, day, start: 1, end: 31, leading_zeros: false, use_two_digit_numbers: @options[:use_two_digit_numbers])
|
778
815
|
end
|
779
816
|
end
|
780
817
|
|
@@ -784,17 +821,17 @@ module ActionView
|
|
784
821
|
else
|
785
822
|
month_options = []
|
786
823
|
1.upto(12) do |month_number|
|
787
|
-
options = { :
|
824
|
+
options = { value: month_number }
|
788
825
|
options[:selected] = "selected" if month == month_number
|
789
|
-
month_options << content_tag(
|
826
|
+
month_options << content_tag("option", month_name(month_number), options) + "\n"
|
790
827
|
end
|
791
828
|
build_select(:month, month_options.join)
|
792
829
|
end
|
793
830
|
end
|
794
831
|
|
795
832
|
def select_year
|
796
|
-
if
|
797
|
-
val =
|
833
|
+
if !year || @datetime == 0
|
834
|
+
val = "1"
|
798
835
|
middle_year = Date.today.year
|
799
836
|
else
|
800
837
|
val = middle_year = year
|
@@ -814,14 +851,19 @@ module ActionView
|
|
814
851
|
raise ArgumentError, "There are too many years options to be built. Are you sure you haven't mistyped something? You can provide the :max_years_allowed parameter."
|
815
852
|
end
|
816
853
|
|
817
|
-
|
854
|
+
build_select(:year, build_year_options(val, options))
|
818
855
|
end
|
819
856
|
end
|
820
857
|
|
821
858
|
private
|
822
859
|
%w( sec min hour day month year ).each do |method|
|
823
860
|
define_method(method) do
|
824
|
-
|
861
|
+
case @datetime
|
862
|
+
when Hash then @datetime[method.to_sym]
|
863
|
+
when Numeric then @datetime
|
864
|
+
when nil then nil
|
865
|
+
else @datetime.send(method)
|
866
|
+
end
|
825
867
|
end
|
826
868
|
end
|
827
869
|
|
@@ -829,12 +871,12 @@ module ActionView
|
|
829
871
|
# valid. Otherwise, February 31st or February 29th, 2011 can be selected, which are invalid.
|
830
872
|
def set_day_if_discarded
|
831
873
|
if @datetime && @options[:discard_day]
|
832
|
-
@datetime = @datetime.change(:
|
874
|
+
@datetime = @datetime.change(day: 1)
|
833
875
|
end
|
834
876
|
end
|
835
877
|
|
836
878
|
# Returns translated month names, but also ensures that a custom month
|
837
|
-
# name array has a leading nil element.
|
879
|
+
# name array has a leading +nil+ element.
|
838
880
|
def month_names
|
839
881
|
@month_names ||= begin
|
840
882
|
month_names = @options[:use_month_names] || translated_month_names
|
@@ -854,7 +896,7 @@ module ActionView
|
|
854
896
|
# "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
855
897
|
def translated_month_names
|
856
898
|
key = @options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
|
857
|
-
I18n.translate(key, :
|
899
|
+
I18n.translate(key, locale: @options[:locale])
|
858
900
|
end
|
859
901
|
|
860
902
|
# Looks up month names by number (1-based):
|
@@ -882,23 +924,38 @@ module ActionView
|
|
882
924
|
if @options[:use_month_numbers]
|
883
925
|
number
|
884
926
|
elsif @options[:use_two_digit_numbers]
|
885
|
-
|
927
|
+
"%02d" % number
|
886
928
|
elsif @options[:add_month_numbers]
|
887
929
|
"#{number} - #{month_names[number]}"
|
888
930
|
elsif format_string = @options[:month_format_string]
|
889
|
-
format_string % {number: number, name: month_names[number]}
|
931
|
+
format_string % { number: number, name: month_names[number] }
|
890
932
|
else
|
891
933
|
month_names[number]
|
892
934
|
end
|
893
935
|
end
|
894
936
|
|
937
|
+
# Looks up year names by number.
|
938
|
+
#
|
939
|
+
# year_name(1998) # => 1998
|
940
|
+
#
|
941
|
+
# If the <tt>:year_format</tt> option is passed:
|
942
|
+
#
|
943
|
+
# year_name(1998) # => "Heisei 10"
|
944
|
+
def year_name(number)
|
945
|
+
if year_format_lambda = @options[:year_format]
|
946
|
+
year_format_lambda.call(number)
|
947
|
+
else
|
948
|
+
number
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
895
952
|
def date_order
|
896
953
|
@date_order ||= @options[:order] || translated_date_order
|
897
954
|
end
|
898
955
|
|
899
956
|
def translated_date_order
|
900
|
-
date_order = I18n.translate(:'date.order', :
|
901
|
-
date_order = date_order.map
|
957
|
+
date_order = I18n.translate(:'date.order', locale: @options[:locale], default: [])
|
958
|
+
date_order = date_order.map(&:to_sym)
|
902
959
|
|
903
960
|
forbidden_elements = date_order - [:year, :month, :day]
|
904
961
|
if forbidden_elements.any?
|
@@ -944,11 +1001,39 @@ module ActionView
|
|
944
1001
|
select_options = []
|
945
1002
|
start.step(stop, step) do |i|
|
946
1003
|
value = leading_zeros ? sprintf("%02d", i) : i
|
947
|
-
tag_options = { :
|
1004
|
+
tag_options = { value: value }
|
948
1005
|
tag_options[:selected] = "selected" if selected == i
|
949
1006
|
text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value
|
950
1007
|
text = options[:ampm] ? AMPM_TRANSLATION[i] : text
|
951
|
-
select_options << content_tag(
|
1008
|
+
select_options << content_tag("option", text, tag_options)
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
(select_options.join("\n") + "\n").html_safe
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
# Build select option HTML for year.
|
1015
|
+
# If <tt>year_format</tt> option is not passed
|
1016
|
+
# build_year_options(1998, start: 1998, end: 2000)
|
1017
|
+
# => "<option value="1998" selected="selected">1998</option>
|
1018
|
+
# <option value="1999">1999</option>
|
1019
|
+
# <option value="2000">2000</option>"
|
1020
|
+
#
|
1021
|
+
# If <tt>year_format</tt> option is passed
|
1022
|
+
# build_year_options(1998, start: 1998, end: 2000, year_format: ->year { "Heisei #{ year - 1988 }" })
|
1023
|
+
# => "<option value="1998" selected="selected">Heisei 10</option>
|
1024
|
+
# <option value="1999">Heisei 11</option>
|
1025
|
+
# <option value="2000">Heisei 12</option>"
|
1026
|
+
def build_year_options(selected, options = {})
|
1027
|
+
start = options.delete(:start)
|
1028
|
+
stop = options.delete(:end)
|
1029
|
+
step = options.delete(:step)
|
1030
|
+
|
1031
|
+
select_options = []
|
1032
|
+
start.step(stop, step) do |value|
|
1033
|
+
tag_options = { value: value }
|
1034
|
+
tag_options[:selected] = "selected" if selected == value
|
1035
|
+
text = year_name(value)
|
1036
|
+
select_options << content_tag("option", text, tag_options)
|
952
1037
|
end
|
953
1038
|
|
954
1039
|
(select_options.join("\n") + "\n").html_safe
|
@@ -961,35 +1046,51 @@ module ActionView
|
|
961
1046
|
# </select>"
|
962
1047
|
def build_select(type, select_options_as_html)
|
963
1048
|
select_options = {
|
964
|
-
:
|
965
|
-
:
|
1049
|
+
id: input_id_from_type(type),
|
1050
|
+
name: input_name_from_type(type)
|
966
1051
|
}.merge!(@html_options)
|
967
|
-
select_options[:disabled] =
|
968
|
-
select_options[:class] =
|
1052
|
+
select_options[:disabled] = "disabled" if @options[:disabled]
|
1053
|
+
select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes]
|
969
1054
|
|
970
|
-
select_html = "\n"
|
971
|
-
select_html << content_tag(
|
1055
|
+
select_html = +"\n"
|
1056
|
+
select_html << content_tag("option", "", value: "") + "\n" if @options[:include_blank]
|
972
1057
|
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
|
973
1058
|
select_html << select_options_as_html
|
974
1059
|
|
975
|
-
(content_tag(
|
1060
|
+
(content_tag("select", select_html.html_safe, select_options) + "\n").html_safe
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# Builds the css class value for the select element
|
1064
|
+
# css_class_attribute(:year, 'date optional', { year: 'my-year' })
|
1065
|
+
# => "date optional my-year"
|
1066
|
+
def css_class_attribute(type, html_options_class, options) # :nodoc:
|
1067
|
+
css_class = \
|
1068
|
+
case options
|
1069
|
+
when Hash
|
1070
|
+
options[type.to_sym]
|
1071
|
+
else
|
1072
|
+
type
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
[html_options_class, css_class].compact.join(" ")
|
976
1076
|
end
|
977
1077
|
|
978
1078
|
# Builds a prompt option tag with supplied options or from default options.
|
979
1079
|
# prompt_option_tag(:month, prompt: 'Select month')
|
980
1080
|
# => "<option value="">Select month</option>"
|
981
1081
|
def prompt_option_tag(type, options)
|
982
|
-
prompt =
|
1082
|
+
prompt = \
|
1083
|
+
case options
|
983
1084
|
when Hash
|
984
|
-
default_options = {:
|
1085
|
+
default_options = { year: false, month: false, day: false, hour: false, minute: false, second: false }
|
985
1086
|
default_options.merge!(options)[type.to_sym]
|
986
1087
|
when String
|
987
1088
|
options
|
988
1089
|
else
|
989
|
-
I18n.translate(:"datetime.prompts.#{type}", :
|
990
|
-
|
1090
|
+
I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale])
|
1091
|
+
end
|
991
1092
|
|
992
|
-
prompt ? content_tag(
|
1093
|
+
prompt ? content_tag("option", prompt, value: "") : ""
|
993
1094
|
end
|
994
1095
|
|
995
1096
|
# Builds hidden input tag for date part and value.
|
@@ -997,12 +1098,12 @@ module ActionView
|
|
997
1098
|
# => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />"
|
998
1099
|
def build_hidden(type, value)
|
999
1100
|
select_options = {
|
1000
|
-
:
|
1001
|
-
:
|
1002
|
-
:
|
1003
|
-
:
|
1101
|
+
type: "hidden",
|
1102
|
+
id: input_id_from_type(type),
|
1103
|
+
name: input_name_from_type(type),
|
1104
|
+
value: value
|
1004
1105
|
}.merge!(@html_options.slice(:disabled))
|
1005
|
-
select_options[:disabled] =
|
1106
|
+
select_options[:disabled] = "disabled" if @options[:disabled]
|
1006
1107
|
|
1007
1108
|
tag(:input, select_options) + "\n".html_safe
|
1008
1109
|
end
|
@@ -1013,7 +1114,7 @@ module ActionView
|
|
1013
1114
|
prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
|
1014
1115
|
prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
|
1015
1116
|
|
1016
|
-
field_name = @options[:field_name] || type
|
1117
|
+
field_name = @options[:field_name] || type.to_s
|
1017
1118
|
if @options[:include_position]
|
1018
1119
|
field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
|
1019
1120
|
end
|
@@ -1024,8 +1125,8 @@ module ActionView
|
|
1024
1125
|
# Returns the id attribute for the input tag.
|
1025
1126
|
# => "post_written_on_1i"
|
1026
1127
|
def input_id_from_type(type)
|
1027
|
-
id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/,
|
1028
|
-
id = @options[:namespace] +
|
1128
|
+
id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, "_").gsub(/[\]\)]/, "")
|
1129
|
+
id = @options[:namespace] + "_" + id if @options[:namespace]
|
1029
1130
|
|
1030
1131
|
id
|
1031
1132
|
end
|
@@ -1033,7 +1134,7 @@ module ActionView
|
|
1033
1134
|
# Given an ordering of datetime components, create the selection HTML
|
1034
1135
|
# and join them with their appropriate separators.
|
1035
1136
|
def build_selects_from_types(order)
|
1036
|
-
select =
|
1137
|
+
select = +""
|
1037
1138
|
first_visible = order.find { |type| !@options[:"discard_#{type}"] }
|
1038
1139
|
order.reverse_each do |type|
|
1039
1140
|
separator = separator(type) unless type == first_visible # don't add before first visible field
|
@@ -1047,12 +1148,12 @@ module ActionView
|
|
1047
1148
|
return "" if @options[:use_hidden]
|
1048
1149
|
|
1049
1150
|
case type
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1151
|
+
when :year, :month, :day
|
1152
|
+
@options[:"discard_#{type}"] ? "" : @options[:date_separator]
|
1153
|
+
when :hour
|
1154
|
+
(@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
|
1155
|
+
when :minute, :second
|
1156
|
+
@options[:"discard_#{type}"] ? "" : @options[:time_separator]
|
1056
1157
|
end
|
1057
1158
|
end
|
1058
1159
|
end
|