Add :day_format option to date_select

date_select("article", "written_on", day_format: ->(day) { day.ordinalize })

generates day options like

  <option value="1">1st</option>\n<option value="2">2nd</option>...
This commit is contained in:
Shunichi Ikegami 2021-10-28 13:51:20 +09:00
parent 18922cccd4
commit e9fa24fca5
3 changed files with 72 additions and 1 deletions

View File

@ -1,3 +1,10 @@
* Add `:day_format` option to `date_select`
date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
# generates day options like <option value="1">1st</option>\n<option value="2">2nd</option>...
*Shunichi Ikegami*
* Allow `link_to` helper to infer link name from `Model#to_s` when it
is used with a single argument:

View File

@ -206,6 +206,7 @@ module ActionView
# you are creating new record. While editing existing record, <tt>:end_year</tt> defaults to
# the current selected year plus 5.
# * <tt>:year_format</tt> - Set format of years for year select. Lambda should be passed.
# * <tt>:day_format</tt> - Set format of days for day select. Lambda should be passed.
# * <tt>:discard_day</tt> - Set to true if you don't want to show a day select. This includes the day
# as a hidden field instead of showing a select field. Also note that this implicitly sets the day to be the
# first of the given month in order to not create invalid dates like 31 February.
@ -279,6 +280,9 @@ module ActionView
# # Generates a date select with custom year format.
# date_select("article", "written_on", year_format: ->(year) { "Heisei #{year - 1988}" })
#
# # Generates a date select with custom day format.
# date_select("article", "written_on", day_format: ->(day) { day.ordinalize })
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
#
# 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
@ -811,7 +815,7 @@ module ActionView
if @options[:use_hidden] || @options[:discard_day]
build_hidden(:day, day || 1)
else
build_options_and_select(:day, day, start: 1, end: 31, leading_zeros: false, use_two_digit_numbers: @options[:use_two_digit_numbers])
build_select(:day, build_day_options(day))
end
end
@ -899,6 +903,27 @@ module ActionView
I18n.translate(key, locale: @options[:locale])
end
# Looks up day names by number.
#
# day_name(1) # => 1
#
# If the <tt>use_two_digit_numbers: true</tt> option is passed to DateTimeSelector:
#
# day_name(1) # => "01"
#
# If the <tt>day_format: ->(day) { day.ordinalize }</tt> option is passed to DateTimeSelector:
#
# day_name(1) # => "1st"
def day_name(number)
if day_format_lambda = @options[:day_format]
day_format_lambda.call(number)
elsif @options[:use_two_digit_numbers]
"%02d" % number
else
number
end
end
# Looks up month names by number (1-based):
#
# month_name(1) # => "January"
@ -1011,6 +1036,35 @@ module ActionView
(select_options.join("\n") + "\n").html_safe
end
# Build select option HTML for day.
# build_day_options(2)
# => "<option value="1">1</option>
# <option value="2" selected="selected">2</option>
# <option value="3">3</option>..."
#
# If <tt>day_format: ->(day) { day.ordinalize }</tt> option is passed to DateTimeSelector
# build_day_options(2)
# => "<option value="1">1st</option>
# <option value="2" selected="selected">2nd</option>
# <option value="3">3rd</option>..."
#
# If <tt>use_two_digit_numbers: true</tt> option is passed to DateTimeSelector
# build_day_options(2)
# => "<option value="1">01</option>
# <option value="2" selected="selected">02</option>
# <option value="3">03</option>..."
def build_day_options(selected)
select_options = []
(1..31).each do |value|
tag_options = { value: value }
tag_options[:selected] = "selected" if selected == value
text = day_name(value)
select_options << content_tag("option", text, tag_options)
end
(select_options.join("\n") + "\n").html_safe
end
# Build select option HTML for year.
# If <tt>year_format</tt> option is not passed
# build_year_options(1998, start: 1998, end: 2000)

View File

@ -251,6 +251,16 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, select_day(2, use_two_digit_numbers: true)
end
def test_select_day_with_day_fomat
expected = +%(<select id="date_day" name="date[day]">\n)
expected << %(<option value="1">1st</option>\n<option selected="selected" value="2">2nd</option>\n<option value="3">3rd</option>\n<option value="4">4th</option>\n<option value="5">5th</option>\n<option value="6">6th</option>\n<option value="7">7th</option>\n<option value="8">8th</option>\n<option value="9">9th</option>\n<option value="10">10th</option>\n<option value="11">11th</option>\n<option value="12">12th</option>\n<option value="13">13th</option>\n<option value="14">14th</option>\n<option value="15">15th</option>\n<option value="16">16th</option>\n<option value="17">17th</option>\n<option value="18">18th</option>\n<option value="19">19th</option>\n<option value="20">20th</option>\n<option value="21">21st</option>\n<option value="22">22nd</option>\n<option value="23">23rd</option>\n<option value="24">24th</option>\n<option value="25">25th</option>\n<option value="26">26th</option>\n<option value="27">27th</option>\n<option value="28">28th</option>\n<option value="29">29th</option>\n<option value="30">30th</option>\n<option value="31">31st</option>\n)
expected << "</select>\n"
day_format = ->(day) { ActiveSupport::Inflector.ordinalize(day) }
assert_dom_equal expected, select_day(Time.mktime(2011, 8, 2), day_format: day_format)
assert_dom_equal expected, select_day(2, day_format: day_format)
end
def test_select_day_with_html_options
expected = +%(<select id="date_day" name="date[day]" class="selector">\n)
expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)