actionview 4.2.11.1 → 7.0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +229 -215
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +116 -43
- data/lib/action_view/buffers.rb +20 -3
- data/lib/action_view/cache_expiry.rb +66 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +21 -122
- data/lib/action_view/digestor.rb +92 -85
- data/lib/action_view/flows.rb +15 -16
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +17 -12
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -101
- data/lib/action_view/helpers/asset_url_helper.rb +180 -74
- data/lib/action_view/helpers/atom_feed_helper.rb +21 -19
- data/lib/action_view/helpers/cache_helper.rb +156 -43
- data/lib/action_view/helpers/capture_helper.rb +21 -14
- data/lib/action_view/helpers/controller_helper.rb +16 -5
- 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 +288 -132
- data/lib/action_view/helpers/debug_helper.rb +9 -6
- data/lib/action_view/helpers/form_helper.rb +956 -173
- data/lib/action_view/helpers/form_options_helper.rb +178 -97
- data/lib/action_view/helpers/form_tag_helper.rb +220 -101
- data/lib/action_view/helpers/javascript_helper.rb +33 -19
- data/lib/action_view/helpers/number_helper.rb +88 -63
- data/lib/action_view/helpers/output_safety_helper.rb +38 -6
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +31 -32
- data/lib/action_view/helpers/tag_helper.rb +332 -71
- data/lib/action_view/helpers/tags/base.rb +123 -99
- data/lib/action_view/helpers/tags/check_box.rb +21 -20
- 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 +5 -3
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- 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 +18 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- 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 +12 -2
- 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 +3 -2
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +80 -51
- data/lib/action_view/helpers/translation_helper.rb +120 -69
- data/lib/action_view/helpers/url_helper.rb +398 -171
- data/lib/action_view/helpers.rb +29 -27
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +137 -113
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +28 -32
- data/lib/action_view/railtie.rb +74 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +152 -15
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +51 -333
- data/lib/action_view/renderer/renderer.rb +68 -11
- data/lib/action_view/renderer/streaming_template_renderer.rb +60 -56
- data/lib/action_view/renderer/template_renderer.rb +87 -74
- data/lib/action_view/rendering.rb +73 -47
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +35 -24
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +151 -41
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +29 -89
- 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 +14 -10
- data/lib/action_view/template/html.rb +12 -13
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +139 -300
- 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 +10 -12
- data/lib/action_view/template/types.rb +28 -26
- data/lib/action_view/template.rb +123 -91
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +70 -53
- data/lib/action_view/testing/resolvers.rb +25 -35
- data/lib/action_view/unbound_template.rb +57 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +16 -11
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +52 -32
- 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 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,16 @@ 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 " : ".
|
201
|
+
# * <tt>:datetime_separator</tt>- Specifies a string to separate the date and time fields. Default is " — ".
|
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.
|
209
|
+
# * <tt>:day_format</tt> - Set format of days for day select. Lambda should be passed.
|
186
210
|
# * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day
|
187
211
|
# as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
|
188
212
|
# first of the given month in order to not create invalid dates like 31 February.
|
@@ -196,15 +220,18 @@ module ActionView
|
|
196
220
|
# the respective locale (e.g. [:year, :month, :day] in the en locale that ships with Rails).
|
197
221
|
# * <tt>:include_blank</tt> - Include a blank option in every select field so it's possible to set empty
|
198
222
|
# dates.
|
199
|
-
# * <tt>:default</tt> - Set a default date if the affected date isn't set or is nil
|
223
|
+
# * <tt>:default</tt> - Set a default date if the affected date isn't set or is +nil+.
|
200
224
|
# * <tt>:selected</tt> - Set a date that overrides the actual value.
|
201
225
|
# * <tt>:disabled</tt> - Set to true if you want show the select fields as disabled.
|
202
226
|
# * <tt>:prompt</tt> - Set to true (for a generic prompt), a prompt string or a hash of prompt strings
|
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
|
#
|
@@ -240,7 +267,7 @@ module ActionView
|
|
240
267
|
# date_select("article", "written_on", default: 3.days.from_now)
|
241
268
|
#
|
242
269
|
# # 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
|
270
|
+
# # which is set in the form with today's date, regardless of the value in the Active Record object.
|
244
271
|
# date_select("article", "written_on", selected: Date.today)
|
245
272
|
#
|
246
273
|
# # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute
|
@@ -250,6 +277,12 @@ module ActionView
|
|
250
277
|
# # Generates a date select with custom prompts.
|
251
278
|
# date_select("article", "written_on", prompt: { day: 'Select day', month: 'Select month', year: 'Select year' })
|
252
279
|
#
|
280
|
+
# # Generates a date select with custom year format.
|
281
|
+
# date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
|
282
|
+
#
|
283
|
+
# # Generates a date select with custom day format.
|
284
|
+
# date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
|
285
|
+
#
|
253
286
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
254
287
|
#
|
255
288
|
# 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 +309,16 @@ module ActionView
|
|
276
309
|
# # the sunrise attribute.
|
277
310
|
# time_select("article", "start_time", include_seconds: true)
|
278
311
|
#
|
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}
|
312
|
+
# # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30, and 45.
|
313
|
+
# time_select 'game', 'game_time', { minute_step: 15 }
|
281
314
|
#
|
282
315
|
# # 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
|
316
|
+
# time_select("article", "written_on", prompt: { hour: 'Choose hour', minute: 'Choose minute', second: 'Choose seconds' })
|
317
|
+
# time_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
|
285
318
|
# time_select("article", "written_on", prompt: true) # generic prompts for all
|
286
319
|
#
|
287
320
|
# # 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}
|
321
|
+
# time_select 'game', 'game_time', { ampm: true }
|
289
322
|
#
|
290
323
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
291
324
|
#
|
@@ -321,8 +354,8 @@ module ActionView
|
|
321
354
|
# datetime_select("article", "written_on", discard_type: true)
|
322
355
|
#
|
323
356
|
# # 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
|
357
|
+
# datetime_select("article", "written_on", prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
358
|
+
# datetime_select("article", "written_on", prompt: { hour: true }) # generic prompt for hours
|
326
359
|
# datetime_select("article", "written_on", prompt: true) # generic prompts for all
|
327
360
|
#
|
328
361
|
# The selects are prepared for multi-parameter assignment to an Active Record object.
|
@@ -372,8 +405,8 @@ module ActionView
|
|
372
405
|
# select_datetime(my_date_time, prefix: 'payday')
|
373
406
|
#
|
374
407
|
# # 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
|
408
|
+
# select_datetime(my_date_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
409
|
+
# select_datetime(my_date_time, prompt: { hour: true }) # generic prompt for hours
|
377
410
|
# select_datetime(my_date_time, prompt: true) # generic prompts for all
|
378
411
|
def select_datetime(datetime = Time.current, options = {}, html_options = {})
|
379
412
|
DateTimeSelector.new(datetime, options, html_options).select_datetime
|
@@ -411,8 +444,8 @@ module ActionView
|
|
411
444
|
# select_date(my_date, prefix: 'payday')
|
412
445
|
#
|
413
446
|
# # 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
|
447
|
+
# select_date(my_date, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
448
|
+
# select_date(my_date, prompt: { hour: true }) # generic prompt for hours
|
416
449
|
# select_date(my_date, prompt: true) # generic prompts for all
|
417
450
|
def select_date(date = Date.current, options = {}, html_options = {})
|
418
451
|
DateTimeSelector.new(date, options, html_options).select_date
|
@@ -451,8 +484,8 @@ module ActionView
|
|
451
484
|
# select_time(my_time, start_hour: 2, end_hour: 14)
|
452
485
|
#
|
453
486
|
# # 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
|
487
|
+
# select_time(my_time, prompt: { day: 'Choose day', month: 'Choose month', year: 'Choose year' })
|
488
|
+
# select_time(my_time, prompt: { hour: true }) # generic prompt for hours
|
456
489
|
# select_time(my_time, prompt: true) # generic prompts for all
|
457
490
|
def select_time(datetime = Time.current, options = {}, html_options = {})
|
458
491
|
DateTimeSelector.new(datetime, options, html_options).select_time
|
@@ -462,7 +495,7 @@ module ActionView
|
|
462
495
|
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
|
463
496
|
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
|
464
497
|
#
|
465
|
-
# my_time = Time.now + 16.
|
498
|
+
# my_time = Time.now + 16.seconds
|
466
499
|
#
|
467
500
|
# # Generates a select field for seconds that defaults to the seconds for the time in my_time.
|
468
501
|
# select_second(my_time)
|
@@ -486,7 +519,7 @@ module ActionView
|
|
486
519
|
# selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
|
487
520
|
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
|
488
521
|
#
|
489
|
-
# my_time = Time.now +
|
522
|
+
# my_time = Time.now + 10.minutes
|
490
523
|
#
|
491
524
|
# # Generates a select field for minutes that defaults to the minutes for the time in my_time.
|
492
525
|
# select_minute(my_time)
|
@@ -643,8 +676,6 @@ module ActionView
|
|
643
676
|
# <time datetime="2010-11-04T17:55:45+01:00">November 04, 2010 17:55</time>
|
644
677
|
# time_tag Date.yesterday, 'Yesterday' # =>
|
645
678
|
# <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
679
|
# time_tag Date.today, datetime: Date.today.strftime('%G-W%V') # =>
|
649
680
|
# <time datetime="2010-W44">November 04, 2010</time>
|
650
681
|
#
|
@@ -655,19 +686,29 @@ module ActionView
|
|
655
686
|
def time_tag(date_or_time, *args, &block)
|
656
687
|
options = args.extract_options!
|
657
688
|
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
|
689
|
+
content = args.first || I18n.l(date_or_time, format: format)
|
660
690
|
|
661
|
-
content_tag(
|
691
|
+
content_tag("time", content, options.reverse_merge(datetime: date_or_time.iso8601), &block)
|
662
692
|
end
|
693
|
+
|
694
|
+
private
|
695
|
+
def normalize_distance_of_time_argument_to_time(value)
|
696
|
+
if value.is_a?(Numeric)
|
697
|
+
Time.at(value)
|
698
|
+
elsif value.respond_to?(:to_time)
|
699
|
+
value.to_time
|
700
|
+
else
|
701
|
+
raise ArgumentError, "#{value.inspect} can't be converted to a Time value"
|
702
|
+
end
|
703
|
+
end
|
663
704
|
end
|
664
705
|
|
665
|
-
class DateTimeSelector
|
706
|
+
class DateTimeSelector # :nodoc:
|
666
707
|
include ActionView::Helpers::TagHelper
|
667
708
|
|
668
|
-
DEFAULT_PREFIX =
|
709
|
+
DEFAULT_PREFIX = "date"
|
669
710
|
POSITION = {
|
670
|
-
:
|
711
|
+
year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6
|
671
712
|
}.freeze
|
672
713
|
|
673
714
|
AMPM_TRANSLATION = Hash[
|
@@ -683,8 +724,8 @@ module ActionView
|
|
683
724
|
@options = options.dup
|
684
725
|
@html_options = html_options.dup
|
685
726
|
@datetime = datetime
|
686
|
-
@options[:datetime_separator] ||=
|
687
|
-
@options[:time_separator] ||=
|
727
|
+
@options[:datetime_separator] ||= " — "
|
728
|
+
@options[:time_separator] ||= " : "
|
688
729
|
end
|
689
730
|
|
690
731
|
def select_datetime
|
@@ -754,7 +795,7 @@ module ActionView
|
|
754
795
|
if @options[:use_hidden] || @options[:discard_minute]
|
755
796
|
build_hidden(:minute, min)
|
756
797
|
else
|
757
|
-
build_options_and_select(:minute, min, :
|
798
|
+
build_options_and_select(:minute, min, step: @options[:minute_step])
|
758
799
|
end
|
759
800
|
end
|
760
801
|
|
@@ -774,7 +815,7 @@ module ActionView
|
|
774
815
|
if @options[:use_hidden] || @options[:discard_day]
|
775
816
|
build_hidden(:day, day || 1)
|
776
817
|
else
|
777
|
-
|
818
|
+
build_select(:day, build_day_options(day))
|
778
819
|
end
|
779
820
|
end
|
780
821
|
|
@@ -784,17 +825,17 @@ module ActionView
|
|
784
825
|
else
|
785
826
|
month_options = []
|
786
827
|
1.upto(12) do |month_number|
|
787
|
-
options = { :
|
828
|
+
options = { value: month_number }
|
788
829
|
options[:selected] = "selected" if month == month_number
|
789
|
-
month_options << content_tag(
|
830
|
+
month_options << content_tag("option", month_name(month_number), options) + "\n"
|
790
831
|
end
|
791
832
|
build_select(:month, month_options.join)
|
792
833
|
end
|
793
834
|
end
|
794
835
|
|
795
836
|
def select_year
|
796
|
-
if
|
797
|
-
val =
|
837
|
+
if !year || @datetime == 0
|
838
|
+
val = "1"
|
798
839
|
middle_year = Date.today.year
|
799
840
|
else
|
800
841
|
val = middle_year = year
|
@@ -814,14 +855,19 @@ module ActionView
|
|
814
855
|
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
856
|
end
|
816
857
|
|
817
|
-
|
858
|
+
build_select(:year, build_year_options(val, options))
|
818
859
|
end
|
819
860
|
end
|
820
861
|
|
821
862
|
private
|
822
863
|
%w( sec min hour day month year ).each do |method|
|
823
864
|
define_method(method) do
|
824
|
-
|
865
|
+
case @datetime
|
866
|
+
when Hash then @datetime[method.to_sym]
|
867
|
+
when Numeric then @datetime
|
868
|
+
when nil then nil
|
869
|
+
else @datetime.send(method)
|
870
|
+
end
|
825
871
|
end
|
826
872
|
end
|
827
873
|
|
@@ -829,12 +875,12 @@ module ActionView
|
|
829
875
|
# valid. Otherwise, February 31st or February 29th, 2011 can be selected, which are invalid.
|
830
876
|
def set_day_if_discarded
|
831
877
|
if @datetime && @options[:discard_day]
|
832
|
-
@datetime = @datetime.change(:
|
878
|
+
@datetime = @datetime.change(day: 1)
|
833
879
|
end
|
834
880
|
end
|
835
881
|
|
836
882
|
# Returns translated month names, but also ensures that a custom month
|
837
|
-
# name array has a leading nil element.
|
883
|
+
# name array has a leading +nil+ element.
|
838
884
|
def month_names
|
839
885
|
@month_names ||= begin
|
840
886
|
month_names = @options[:use_month_names] || translated_month_names
|
@@ -854,7 +900,28 @@ module ActionView
|
|
854
900
|
# "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
855
901
|
def translated_month_names
|
856
902
|
key = @options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
|
857
|
-
I18n.translate(key, :
|
903
|
+
I18n.translate(key, locale: @options[:locale])
|
904
|
+
end
|
905
|
+
|
906
|
+
# Looks up day names by number.
|
907
|
+
#
|
908
|
+
# day_name(1) # => 1
|
909
|
+
#
|
910
|
+
# If the <tt>use_two_digit_numbers: true</tt> option is passed to DateTimeSelector:
|
911
|
+
#
|
912
|
+
# day_name(1) # => "01"
|
913
|
+
#
|
914
|
+
# If the <tt>day_format: ->(day) { day.ordinalize }</tt> option is passed to DateTimeSelector:
|
915
|
+
#
|
916
|
+
# day_name(1) # => "1st"
|
917
|
+
def day_name(number)
|
918
|
+
if day_format_lambda = @options[:day_format]
|
919
|
+
day_format_lambda.call(number)
|
920
|
+
elsif @options[:use_two_digit_numbers]
|
921
|
+
"%02d" % number
|
922
|
+
else
|
923
|
+
number
|
924
|
+
end
|
858
925
|
end
|
859
926
|
|
860
927
|
# Looks up month names by number (1-based):
|
@@ -882,23 +949,38 @@ module ActionView
|
|
882
949
|
if @options[:use_month_numbers]
|
883
950
|
number
|
884
951
|
elsif @options[:use_two_digit_numbers]
|
885
|
-
|
952
|
+
"%02d" % number
|
886
953
|
elsif @options[:add_month_numbers]
|
887
954
|
"#{number} - #{month_names[number]}"
|
888
955
|
elsif format_string = @options[:month_format_string]
|
889
|
-
format_string % {number: number, name: month_names[number]}
|
956
|
+
format_string % { number: number, name: month_names[number] }
|
890
957
|
else
|
891
958
|
month_names[number]
|
892
959
|
end
|
893
960
|
end
|
894
961
|
|
962
|
+
# Looks up year names by number.
|
963
|
+
#
|
964
|
+
# year_name(1998) # => 1998
|
965
|
+
#
|
966
|
+
# If the <tt>:year_format</tt> option is passed:
|
967
|
+
#
|
968
|
+
# year_name(1998) # => "Heisei 10"
|
969
|
+
def year_name(number)
|
970
|
+
if year_format_lambda = @options[:year_format]
|
971
|
+
year_format_lambda.call(number)
|
972
|
+
else
|
973
|
+
number
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
895
977
|
def date_order
|
896
978
|
@date_order ||= @options[:order] || translated_date_order
|
897
979
|
end
|
898
980
|
|
899
981
|
def translated_date_order
|
900
|
-
date_order = I18n.translate(:'date.order', :
|
901
|
-
date_order = date_order.map
|
982
|
+
date_order = I18n.translate(:'date.order', locale: @options[:locale], default: [])
|
983
|
+
date_order = date_order.map(&:to_sym)
|
902
984
|
|
903
985
|
forbidden_elements = date_order - [:year, :month, :day]
|
904
986
|
if forbidden_elements.any?
|
@@ -944,11 +1026,68 @@ module ActionView
|
|
944
1026
|
select_options = []
|
945
1027
|
start.step(stop, step) do |i|
|
946
1028
|
value = leading_zeros ? sprintf("%02d", i) : i
|
947
|
-
tag_options = { :
|
1029
|
+
tag_options = { value: value }
|
948
1030
|
tag_options[:selected] = "selected" if selected == i
|
949
1031
|
text = options[:use_two_digit_numbers] ? sprintf("%02d", i) : value
|
950
1032
|
text = options[:ampm] ? AMPM_TRANSLATION[i] : text
|
951
|
-
select_options << content_tag(
|
1033
|
+
select_options << content_tag("option", text, tag_options)
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
(select_options.join("\n") + "\n").html_safe
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
# Build select option HTML for day.
|
1040
|
+
# build_day_options(2)
|
1041
|
+
# => "<option value="1">1</option>
|
1042
|
+
# <option value="2" selected="selected">2</option>
|
1043
|
+
# <option value="3">3</option>..."
|
1044
|
+
#
|
1045
|
+
# If <tt>day_format: ->(day) { day.ordinalize }</tt> option is passed to DateTimeSelector
|
1046
|
+
# build_day_options(2)
|
1047
|
+
# => "<option value="1">1st</option>
|
1048
|
+
# <option value="2" selected="selected">2nd</option>
|
1049
|
+
# <option value="3">3rd</option>..."
|
1050
|
+
#
|
1051
|
+
# If <tt>use_two_digit_numbers: true</tt> option is passed to DateTimeSelector
|
1052
|
+
# build_day_options(2)
|
1053
|
+
# => "<option value="1">01</option>
|
1054
|
+
# <option value="2" selected="selected">02</option>
|
1055
|
+
# <option value="3">03</option>..."
|
1056
|
+
def build_day_options(selected)
|
1057
|
+
select_options = []
|
1058
|
+
(1..31).each do |value|
|
1059
|
+
tag_options = { value: value }
|
1060
|
+
tag_options[:selected] = "selected" if selected == value
|
1061
|
+
text = day_name(value)
|
1062
|
+
select_options << content_tag("option", text, tag_options)
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
(select_options.join("\n") + "\n").html_safe
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
# Build select option HTML for year.
|
1069
|
+
# If <tt>year_format</tt> option is not passed
|
1070
|
+
# build_year_options(1998, start: 1998, end: 2000)
|
1071
|
+
# => "<option value="1998" selected="selected">1998</option>
|
1072
|
+
# <option value="1999">1999</option>
|
1073
|
+
# <option value="2000">2000</option>"
|
1074
|
+
#
|
1075
|
+
# If <tt>year_format</tt> option is passed
|
1076
|
+
# build_year_options(1998, start: 1998, end: 2000, year_format: ->year { "Heisei #{ year - 1988 }" })
|
1077
|
+
# => "<option value="1998" selected="selected">Heisei 10</option>
|
1078
|
+
# <option value="1999">Heisei 11</option>
|
1079
|
+
# <option value="2000">Heisei 12</option>"
|
1080
|
+
def build_year_options(selected, options = {})
|
1081
|
+
start = options.delete(:start)
|
1082
|
+
stop = options.delete(:end)
|
1083
|
+
step = options.delete(:step)
|
1084
|
+
|
1085
|
+
select_options = []
|
1086
|
+
start.step(stop, step) do |value|
|
1087
|
+
tag_options = { value: value }
|
1088
|
+
tag_options[:selected] = "selected" if selected == value
|
1089
|
+
text = year_name(value)
|
1090
|
+
select_options << content_tag("option", text, tag_options)
|
952
1091
|
end
|
953
1092
|
|
954
1093
|
(select_options.join("\n") + "\n").html_safe
|
@@ -961,48 +1100,65 @@ module ActionView
|
|
961
1100
|
# </select>"
|
962
1101
|
def build_select(type, select_options_as_html)
|
963
1102
|
select_options = {
|
964
|
-
:
|
965
|
-
:
|
1103
|
+
id: input_id_from_type(type),
|
1104
|
+
name: input_name_from_type(type)
|
966
1105
|
}.merge!(@html_options)
|
967
|
-
select_options[:disabled] =
|
968
|
-
select_options[:class] =
|
1106
|
+
select_options[:disabled] = "disabled" if @options[:disabled]
|
1107
|
+
select_options[:class] = css_class_attribute(type, select_options[:class], @options[:with_css_classes]) if @options[:with_css_classes]
|
969
1108
|
|
970
|
-
select_html = "\n"
|
971
|
-
select_html << content_tag(
|
1109
|
+
select_html = +"\n"
|
1110
|
+
select_html << content_tag("option", "", value: "", label: " ") + "\n" if @options[:include_blank]
|
972
1111
|
select_html << prompt_option_tag(type, @options[:prompt]) + "\n" if @options[:prompt]
|
973
1112
|
select_html << select_options_as_html
|
974
1113
|
|
975
|
-
(content_tag(
|
1114
|
+
(content_tag("select", select_html.html_safe, select_options) + "\n").html_safe
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
# Builds the CSS class value for the select element
|
1118
|
+
# css_class_attribute(:year, 'date optional', { year: 'my-year' })
|
1119
|
+
# => "date optional my-year"
|
1120
|
+
def css_class_attribute(type, html_options_class, options) # :nodoc:
|
1121
|
+
css_class = \
|
1122
|
+
case options
|
1123
|
+
when Hash
|
1124
|
+
options[type.to_sym]
|
1125
|
+
else
|
1126
|
+
type
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
[html_options_class, css_class].compact.join(" ")
|
976
1130
|
end
|
977
1131
|
|
978
1132
|
# Builds a prompt option tag with supplied options or from default options.
|
979
1133
|
# prompt_option_tag(:month, prompt: 'Select month')
|
980
1134
|
# => "<option value="">Select month</option>"
|
981
1135
|
def prompt_option_tag(type, options)
|
982
|
-
prompt =
|
1136
|
+
prompt = \
|
1137
|
+
case options
|
983
1138
|
when Hash
|
984
|
-
default_options = {:
|
1139
|
+
default_options = { year: false, month: false, day: false, hour: false, minute: false, second: false }
|
985
1140
|
default_options.merge!(options)[type.to_sym]
|
986
1141
|
when String
|
987
1142
|
options
|
988
1143
|
else
|
989
|
-
I18n.translate(:"datetime.prompts.#{type}", :
|
990
|
-
|
1144
|
+
I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale])
|
1145
|
+
end
|
991
1146
|
|
992
|
-
prompt ? content_tag(
|
1147
|
+
prompt ? content_tag("option", prompt, value: "") : ""
|
993
1148
|
end
|
994
1149
|
|
995
1150
|
# Builds hidden input tag for date part and value.
|
996
1151
|
# build_hidden(:year, 2008)
|
997
|
-
# => "<input id="
|
1152
|
+
# => "<input type="hidden" id="date_year" name="date[year]" value="2008" autocomplete="off" />"
|
998
1153
|
def build_hidden(type, value)
|
999
1154
|
select_options = {
|
1000
|
-
:
|
1001
|
-
:
|
1002
|
-
:
|
1003
|
-
:
|
1155
|
+
type: "hidden",
|
1156
|
+
id: input_id_from_type(type),
|
1157
|
+
name: input_name_from_type(type),
|
1158
|
+
value: value,
|
1159
|
+
autocomplete: "off"
|
1004
1160
|
}.merge!(@html_options.slice(:disabled))
|
1005
|
-
select_options[:disabled] =
|
1161
|
+
select_options[:disabled] = "disabled" if @options[:disabled]
|
1006
1162
|
|
1007
1163
|
tag(:input, select_options) + "\n".html_safe
|
1008
1164
|
end
|
@@ -1013,7 +1169,7 @@ module ActionView
|
|
1013
1169
|
prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
|
1014
1170
|
prefix += "[#{@options[:index]}]" if @options.has_key?(:index)
|
1015
1171
|
|
1016
|
-
field_name = @options[:field_name] || type
|
1172
|
+
field_name = @options[:field_name] || type.to_s
|
1017
1173
|
if @options[:include_position]
|
1018
1174
|
field_name += "(#{ActionView::Helpers::DateTimeSelector::POSITION[type]}i)"
|
1019
1175
|
end
|
@@ -1024,8 +1180,8 @@ module ActionView
|
|
1024
1180
|
# Returns the id attribute for the input tag.
|
1025
1181
|
# => "post_written_on_1i"
|
1026
1182
|
def input_id_from_type(type)
|
1027
|
-
id = input_name_from_type(type).gsub(/([\[
|
1028
|
-
id = @options[:namespace] +
|
1183
|
+
id = input_name_from_type(type).gsub(/([\[(])|(\]\[)/, "_").gsub(/[\])]/, "")
|
1184
|
+
id = @options[:namespace] + "_" + id if @options[:namespace]
|
1029
1185
|
|
1030
1186
|
id
|
1031
1187
|
end
|
@@ -1033,11 +1189,11 @@ module ActionView
|
|
1033
1189
|
# Given an ordering of datetime components, create the selection HTML
|
1034
1190
|
# and join them with their appropriate separators.
|
1035
1191
|
def build_selects_from_types(order)
|
1036
|
-
select =
|
1192
|
+
select = +""
|
1037
1193
|
first_visible = order.find { |type| !@options[:"discard_#{type}"] }
|
1038
1194
|
order.reverse_each do |type|
|
1039
1195
|
separator = separator(type) unless type == first_visible # don't add before first visible field
|
1040
|
-
select.insert(0, separator.to_s +
|
1196
|
+
select.insert(0, separator.to_s + public_send("select_#{type}").to_s)
|
1041
1197
|
end
|
1042
1198
|
select.html_safe
|
1043
1199
|
end
|
@@ -1047,12 +1203,12 @@ module ActionView
|
|
1047
1203
|
return "" if @options[:use_hidden]
|
1048
1204
|
|
1049
1205
|
case type
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1206
|
+
when :year, :month, :day
|
1207
|
+
@options[:"discard_#{type}"] ? "" : @options[:date_separator]
|
1208
|
+
when :hour
|
1209
|
+
(@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator]
|
1210
|
+
when :minute, :second
|
1211
|
+
@options[:"discard_#{type}"] ? "" : @options[:time_separator]
|
1056
1212
|
end
|
1057
1213
|
end
|
1058
1214
|
end
|