2004-11-23 20:04:44 -05:00
require " date "
2008-02-19 23:23:18 -05:00
require 'action_view/helpers/tag_helper'
2004-11-23 20:04:44 -05:00
module ActionView
module Helpers
# The Date Helper primarily creates select/option tags for different kinds of dates and date elements. All of the select-type methods
# share a number of common options that are as follows:
#
2005-03-06 06:50:41 -05:00
# * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday" would give
2004-11-23 20:04:44 -05:00
# birthday[month] instead of date[month] if passed to the select_month method.
# * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date.
# * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true, the select_month
# method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of "date[month]".
module DateHelper
2008-02-19 23:23:18 -05:00
include ActionView :: Helpers :: TagHelper
2005-07-02 14:38:22 -04:00
DEFAULT_PREFIX = 'date' unless const_defined? ( 'DEFAULT_PREFIX' )
2004-11-23 20:04:44 -05:00
2006-09-04 13:00:37 -04:00
# Reports the approximate distance in time between two Time or Date objects or integers as seconds.
# Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
2008-03-15 16:00:41 -04:00
# Distances are reported based on the following table:
2005-06-17 09:42:23 -04:00
#
2008-03-15 16:00:41 -04:00
# 0 <-> 29 secs # => less than a minute
# 30 secs <-> 1 min, 29 secs # => 1 minute
# 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
# 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
# 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
# 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
# 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
# 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
# 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
# 1 yr <-> 2 yrs minus 1 secs # => about 1 year
# 2 yrs <-> max time or date # => over [2..X] years
2005-06-17 09:42:23 -04:00
#
2008-03-15 16:00:41 -04:00
# With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds:
# 0-4 secs # => less than 5 seconds
# 5-9 secs # => less than 10 seconds
# 10-19 secs # => less than 20 seconds
# 20-39 secs # => half a minute
# 40-59 secs # => less than a minute
# 60-89 secs # => 1 minute
2006-09-04 13:00:37 -04:00
#
2007-06-23 13:49:18 -04:00
# ==== Examples
2006-09-04 13:00:37 -04:00
# from_time = Time.now
2007-06-23 13:49:18 -04:00
# distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
# distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
# distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
# distance_of_time_in_words(from_time, from_time + 15.seconds, true) # => less than 20 seconds
# distance_of_time_in_words(from_time, 3.years.from_now) # => over 3 years
# distance_of_time_in_words(from_time, from_time + 60.hours) # => about 3 days
# distance_of_time_in_words(from_time, from_time + 45.seconds, true) # => less than a minute
# distance_of_time_in_words(from_time, from_time - 45.seconds, true) # => less than a minute
# distance_of_time_in_words(from_time, 76.seconds.from_now) # => 1 minute
2007-10-07 23:46:23 -04:00
# distance_of_time_in_words(from_time, from_time + 1.year + 3.days) # => about 1 year
2007-06-23 13:49:18 -04:00
# distance_of_time_in_words(from_time, from_time + 4.years + 15.days + 30.minutes + 5.seconds) # => over 4 years
#
# to_time = Time.now + 6.years + 19.days
# distance_of_time_in_words(from_time, to_time, true) # => over 6 years
# distance_of_time_in_words(to_time, from_time, true) # => over 6 years
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
2006-09-04 13:00:37 -04:00
#
2008-06-19 10:25:27 -04:00
def distance_of_time_in_words ( from_time , to_time = 0 , include_seconds = false , options = { } )
2005-06-17 09:42:23 -04:00
from_time = from_time . to_time if from_time . respond_to? ( :to_time )
to_time = to_time . to_time if to_time . respond_to? ( :to_time )
distance_in_minutes = ( ( ( to_time - from_time ) . abs ) / 60 ) . round
distance_in_seconds = ( ( to_time - from_time ) . abs ) . round
2005-03-06 06:50:41 -05:00
2008-06-23 08:37:50 -04:00
I18n . with_options :locale = > options [ :locale ] , :scope = > :'datetime.distance_in_words' do | locale |
2008-06-19 10:25:27 -04:00
case distance_in_minutes
when 0 .. 1
return distance_in_minutes == 0 ?
locale . t ( :less_than_x_minutes , :count = > 1 ) :
locale . t ( :x_minutes , :count = > distance_in_minutes ) unless include_seconds
case distance_in_seconds
when 0 .. 4 then locale . t :less_than_x_seconds , :count = > 5
when 5 .. 9 then locale . t :less_than_x_seconds , :count = > 10
when 10 .. 19 then locale . t :less_than_x_seconds , :count = > 20
when 20 .. 39 then locale . t :half_a_minute
when 40 .. 59 then locale . t :less_than_x_minutes , :count = > 1
else locale . t :x_minutes , :count = > 1
end
when 2 .. 44 then locale . t :x_minutes , :count = > distance_in_minutes
when 45 .. 89 then locale . t :about_x_hours , :count = > 1
when 90 .. 1439 then locale . t :about_x_hours , :count = > ( distance_in_minutes . to_f / 60 . 0 ) . round
when 1440 .. 2879 then locale . t :x_days , :count = > 1
when 2880 .. 43199 then locale . t :x_days , :count = > ( distance_in_minutes / 1440 ) . round
when 43200 .. 86399 then locale . t :about_x_months , :count = > 1
when 86400 .. 525599 then locale . t :x_months , :count = > ( distance_in_minutes / 43200 ) . round
when 525600 .. 1051199 then locale . t :about_x_years , :count = > 1
else locale . t :over_x_years , :count = > ( distance_in_minutes / 525600 ) . round
end
2004-11-23 20:04:44 -05:00
end
2008-06-19 10:25:27 -04:00
end
2006-12-06 14:15:24 -05:00
2004-11-23 20:04:44 -05:00
# Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
2007-06-23 13:49:18 -04:00
#
# ==== Examples
# time_ago_in_words(3.minutes.from_now) # => 3 minutes
# time_ago_in_words(Time.now - 15.hours) # => 15 hours
# time_ago_in_words(Time.now) # => less than a minute
#
# from_time = Time.now - 3.days - 14.minutes - 25.seconds # => 3 days
2005-03-30 08:06:19 -05:00
def time_ago_in_words ( from_time , include_seconds = false )
2005-03-26 17:00:23 -05:00
distance_of_time_in_words ( from_time , Time . now , include_seconds )
2004-11-23 20:04:44 -05:00
end
2006-12-06 14:15:24 -05:00
2005-03-30 08:06:19 -05:00
alias_method :distance_of_time_in_words_to_now , :time_ago_in_words
2004-11-23 20:04:44 -05:00
# Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
2005-02-19 13:26:37 -05:00
# +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
2008-05-02 09:45:23 -04:00
# which accepts all the keys that each of the individual select builders do (like <tt>:use_month_numbers</tt> for select_month) as well as a range of
2005-02-19 13:26:37 -05:00
# discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
# drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
# set the order of the tags using the <tt>:order</tt> option with an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in
# the desired order. Symbols may be omitted and the respective select is not included.
#
2008-05-02 09:45:23 -04:00
# Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, and <tt>:second</tt>.
2007-01-28 11:44:44 -05:00
#
2008-05-02 09:45:23 -04:00
# Passing <tt>:disabled => true</tt> as part of the +options+ will make elements inaccessible for change.
2005-09-11 01:58:00 -04:00
#
2008-05-02 09:45:23 -04:00
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
2008-03-01 23:40:54 -05:00
#
2005-02-19 13:26:37 -05:00
# NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
2004-11-23 20:04:44 -05:00
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
2004-11-23 20:04:44 -05:00
# date_select("post", "written_on")
2007-06-23 13:49:18 -04:00
#
# # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
# # with the year in the year drop down box starting at 1995.
2004-11-23 20:04:44 -05:00
# date_select("post", "written_on", :start_year => 1995)
2007-06-23 13:49:18 -04:00
#
# # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
# # with the year in the year drop down box starting at 1995, numbers used for months instead of words,
# # and without a day select box.
2005-03-06 06:50:41 -05:00
# date_select("post", "written_on", :start_year => 1995, :use_month_numbers => true,
2004-11-23 20:04:44 -05:00
# :discard_day => true, :include_blank => true)
2007-06-23 13:49:18 -04:00
#
# # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
# # with the fields ordered as day, month, year rather than month, day, year.
2005-02-19 13:26:37 -05:00
# date_select("post", "written_on", :order => [:day, :month, :year])
2004-11-23 20:04:44 -05:00
#
2007-06-23 13:49:18 -04:00
# # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
# # lacking a year field.
# date_select("user", "birthday", :order => [:month, :day])
#
# # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
# # which is initially set to the date 3 days from the current date
2007-01-28 11:44:44 -05:00
# date_select("post", "written_on", :default => 3.days.from_now)
2007-06-23 13:49:18 -04:00
#
# # Generates a date select that when POSTed is stored in the credit_card variable, in the bill_due attribute
# # that will have a default day of 20.
2007-01-28 11:44:44 -05:00
# date_select("credit_card", "bill_due", :default => { :day => 20 })
#
2004-11-23 20:04:44 -05:00
# The selects are prepared for multi-parameter assignment to an Active Record object.
2007-05-31 12:38:36 -04:00
#
# 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 all month
# choices are valid.
2008-03-01 23:40:54 -05:00
def date_select ( object_name , method , options = { } , html_options = { } )
InstanceTag . new ( object_name , method , self , nil , options . delete ( :object ) ) . to_date_select_tag ( options , html_options )
2004-11-23 20:04:44 -05:00
end
2006-12-06 14:15:24 -05:00
# Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
# time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
# You can include the seconds with <tt>:include_seconds</tt>.
2007-06-23 13:49:18 -04:00
#
2008-03-01 23:40:54 -05:00
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
2006-12-06 14:15:24 -05:00
# time_select("post", "sunrise")
2007-06-23 13:49:18 -04:00
#
# # Creates a time select tag that, when POSTed, will be stored in the order variable in the submitted attribute
# time_select("order", "submitted")
#
# # Creates a time select tag that, when POSTed, will be stored in the mail variable in the sent_at attribute
# time_select("mail", "sent_at")
#
# # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in
# # the sunrise attribute.
2006-12-06 14:15:24 -05:00
# time_select("post", "start_time", :include_seconds => true)
#
2007-06-23 13:49:18 -04:00
# # Creates a time select tag with a seconds field that, when POSTed, will be stored in the entry variables in
# # the submission_time attribute.
# time_select("entry", "submission_time", :include_seconds => true)
#
2007-11-06 18:00:15 -05:00
# # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45.
# time_select 'game', 'game_time', {:minute_step => 15}
#
2006-12-06 14:15:24 -05:00
# The selects are prepared for multi-parameter assignment to an Active Record object.
2007-05-31 12:38:36 -04:00
#
# 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 all month
# choices are valid.
2008-03-01 23:40:54 -05:00
def time_select ( object_name , method , options = { } , html_options = { } )
InstanceTag . new ( object_name , method , self , nil , options . delete ( :object ) ) . to_time_select_tag ( options , html_options )
2006-12-06 14:15:24 -05:00
end
2004-11-23 20:04:44 -05:00
# Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
# attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples:
#
2008-03-01 23:40:54 -05:00
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute
2004-11-23 20:04:44 -05:00
# datetime_select("post", "written_on")
2007-06-23 13:49:18 -04:00
#
# # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
# # post variable in the written_on attribute.
2004-11-23 20:04:44 -05:00
# datetime_select("post", "written_on", :start_year => 1995)
#
2007-06-23 13:49:18 -04:00
# # Generates a datetime select with a default value of 3 days from the current time that, when POSTed, will be stored in the
# # trip variable in the departing attribute.
# datetime_select("trip", "departing", :default => 3.days.from_now)
#
# # Generates a datetime select that discards the type that, when POSTed, will be stored in the post variable as the written_on
# # attribute.
# datetime_select("post", "written_on", :discard_type => true)
#
2004-11-23 20:04:44 -05:00
# The selects are prepared for multi-parameter assignment to an Active Record object.
2008-03-01 23:40:54 -05:00
def datetime_select ( object_name , method , options = { } , html_options = { } )
InstanceTag . new ( object_name , method , self , nil , options . delete ( :object ) ) . to_datetime_select_tag ( options , html_options )
2004-11-23 20:04:44 -05:00
end
2006-12-06 14:15:24 -05:00
# Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
# It's also possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
# symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
2007-12-05 13:54:41 -05:00
# will be appended onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt> and <tt>:time_separator</tt>
2006-12-06 14:15:24 -05:00
# keys to the +options+ to control visual display of the elements.
2007-06-23 13:49:18 -04:00
#
2008-03-01 23:40:54 -05:00
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# my_date_time = Time.now + 4.days
#
# # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
# select_datetime(my_date_time)
#
# # Generates a datetime select that defaults to today (no specified datetime)
# select_datetime()
#
# # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
2007-12-05 13:54:41 -05:00
# # with the fields ordered year, month, day rather than month, day, year.
2007-06-23 13:49:18 -04:00
# select_datetime(my_date_time, :order => [:year, :month, :day])
#
# # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
# # with a '/' between each date field.
# select_datetime(my_date_time, :date_separator => '/')
#
# # Generates a datetime select that discards the type of the field and defaults to the datetime in
# # my_date_time (four days after today)
# select_datetime(my_date_time, :discard_type => true)
#
# # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
# # prefixed with 'payday' rather than 'date'
# select_datetime(my_date_time, :prefix => 'payday')
#
2008-04-21 01:40:04 -04:00
def select_datetime ( datetime = Time . current , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
separator = options [ :datetime_separator ] || ''
2008-03-01 23:40:54 -05:00
select_date ( datetime , options , html_options ) + separator + select_time ( datetime , options , html_options )
2006-12-06 14:15:24 -05:00
end
2004-11-23 20:04:44 -05:00
# Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
2006-12-06 14:15:24 -05:00
# It's possible to explicitly set the order of the tags using the <tt>:order</tt> option with an array of
# symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
2007-12-05 13:54:41 -05:00
# will be appended onto the <tt>:order</tt> passed in.
2007-06-23 13:49:18 -04:00
#
2008-03-01 23:40:54 -05:00
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# my_date = Time.today + 6.days
#
# # Generates a date select that defaults to the date in my_date (six days after today)
# select_date(my_date)
#
# # Generates a date select that defaults to today (no specified date)
# select_date()
#
# # Generates a date select that defaults to the date in my_date (six days after today)
2007-12-05 13:54:41 -05:00
# # with the fields ordered year, month, day rather than month, day, year.
2007-06-23 13:49:18 -04:00
# select_date(my_date, :order => [:year, :month, :day])
#
# # Generates a date select that discards the type of the field and defaults to the date in
# # my_date (six days after today)
# select_datetime(my_date_time, :discard_type => true)
#
# # Generates a date select that defaults to the datetime in my_date (six days after today)
# # prefixed with 'payday' rather than 'date'
# select_datetime(my_date_time, :prefix => 'payday')
#
2008-05-08 23:48:47 -04:00
def select_date ( date = Date . current , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
options [ :order ] || = [ ]
[ :year , :month , :day ] . each { | o | options [ :order ] . push ( o ) unless options [ :order ] . include? ( o ) }
2004-11-23 20:04:44 -05:00
2006-12-06 14:15:24 -05:00
select_date = ''
options [ :order ] . each do | o |
2008-03-01 23:40:54 -05:00
select_date << self . send ( " select_ #{ o } " , date , options , html_options )
2006-12-06 14:15:24 -05:00
end
select_date
2004-11-23 20:04:44 -05:00
end
2005-01-02 10:32:01 -05:00
# Returns a set of html select-tags (one for hour and minute)
2007-06-23 13:49:18 -04:00
# You can set <tt>:time_separator</tt> key to format the output, and
# the <tt>:include_seconds</tt> option to include an input for seconds.
#
2008-03-01 23:40:54 -05:00
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds
#
# # Generates a time select that defaults to the time in my_time
# select_time(my_time)
#
# # Generates a time select that defaults to the current time (no specified time)
# select_time()
#
# # Generates a time select that defaults to the time in my_time,
# # which has fields separated by ':'
# select_time(my_time, :time_separator => ':')
#
# # Generates a time select that defaults to the time in my_time,
# # that also includes an input for seconds
# select_time(my_time, :include_seconds => true)
#
# # Generates a time select that defaults to the time in my_time, that has fields
# # separated by ':' and includes an input for seconds
# select_time(my_time, :time_separator => ':', :include_seconds => true)
#
2008-04-21 01:40:04 -04:00
def select_time ( datetime = Time . current , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
separator = options [ :time_separator ] || ''
2008-03-01 23:40:54 -05:00
select_hour ( datetime , options , html_options ) + separator + select_minute ( datetime , options , html_options ) + ( options [ :include_seconds ] ? separator + select_second ( datetime , options , html_options ) : '' )
2005-01-02 10:32:01 -05:00
end
# Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
# The <tt>second</tt> can also be substituted for a second number.
2005-07-02 14:38:22 -04:00
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
2007-06-23 13:49:18 -04:00
#
# ==== Examples
# my_time = Time.now + 16.minutes
#
# # Generates a select field for seconds that defaults to the seconds for the time in my_time
# select_second(my_time)
#
# # Generates a select field for seconds that defaults to the number given
# select_second(33)
#
# # Generates a select field for seconds that defaults to the seconds for the time in my_time
# # that is named 'interval' rather than 'second'
# select_second(my_time, :field_name => 'interval')
#
2008-03-01 23:40:54 -05:00
def select_second ( datetime , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
val = datetime ? ( datetime . kind_of? ( Fixnum ) ? datetime : datetime . sec ) : ''
if options [ :use_hidden ]
options [ :include_seconds ] ? hidden_html ( options [ :field_name ] || 'second' , val , options ) : ''
else
second_options = [ ]
0 . upto ( 59 ) do | second |
second_options << ( ( val == second ) ?
2008-02-19 23:23:18 -05:00
content_tag ( :option , leading_zero_on_single_digits ( second ) , :value = > leading_zero_on_single_digits ( second ) , :selected = > " selected " ) :
content_tag ( :option , leading_zero_on_single_digits ( second ) , :value = > leading_zero_on_single_digits ( second ) )
2006-12-06 14:15:24 -05:00
)
2008-02-19 23:23:18 -05:00
second_options << " \n "
2006-12-06 14:15:24 -05:00
end
2008-03-01 23:40:54 -05:00
select_html ( options [ :field_name ] || 'second' , second_options . join , options , html_options )
2005-01-02 10:32:01 -05:00
end
end
2004-11-23 20:04:44 -05:00
# Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
2005-04-13 01:15:41 -04:00
# Also can return a select tag with options by <tt>minute_step</tt> from 0 through 59 with the 00 minute selected
2004-11-23 20:04:44 -05:00
# The <tt>minute</tt> can also be substituted for a minute number.
2005-07-02 14:38:22 -04:00
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
2007-06-23 13:49:18 -04:00
#
# ==== Examples
# my_time = Time.now + 6.hours
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
# select_minute(my_time)
#
# # Generates a select field for minutes that defaults to the number given
# select_minute(14)
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
# # that is named 'stride' rather than 'second'
# select_minute(my_time, :field_name => 'stride')
#
2008-03-01 23:40:54 -05:00
def select_minute ( datetime , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
val = datetime ? ( datetime . kind_of? ( Fixnum ) ? datetime : datetime . min ) : ''
if options [ :use_hidden ]
hidden_html ( options [ :field_name ] || 'minute' , val , options )
else
minute_options = [ ]
0 . step ( 59 , options [ :minute_step ] || 1 ) do | minute |
minute_options << ( ( val == minute ) ?
2008-02-19 23:23:18 -05:00
content_tag ( :option , leading_zero_on_single_digits ( minute ) , :value = > leading_zero_on_single_digits ( minute ) , :selected = > " selected " ) :
content_tag ( :option , leading_zero_on_single_digits ( minute ) , :value = > leading_zero_on_single_digits ( minute ) )
2006-12-06 14:15:24 -05:00
)
2008-02-19 23:23:18 -05:00
minute_options << " \n "
2006-12-06 14:15:24 -05:00
end
2008-03-01 23:40:54 -05:00
select_html ( options [ :field_name ] || 'minute' , minute_options . join , options , html_options )
2006-12-06 14:15:24 -05:00
end
2004-11-23 20:04:44 -05:00
end
# Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
# The <tt>hour</tt> can also be substituted for a hour number.
2005-07-02 14:38:22 -04:00
# Override the field name using the <tt>:field_name</tt> option, 'hour' by default.
2007-06-23 13:49:18 -04:00
#
# ==== Examples
# my_time = Time.now + 6.hours
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
# select_minute(my_time)
#
# # Generates a select field for minutes that defaults to the number given
# select_minute(14)
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
# # that is named 'stride' rather than 'second'
# select_minute(my_time, :field_name => 'stride')
#
2008-03-01 23:40:54 -05:00
def select_hour ( datetime , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
val = datetime ? ( datetime . kind_of? ( Fixnum ) ? datetime : datetime . hour ) : ''
if options [ :use_hidden ]
hidden_html ( options [ :field_name ] || 'hour' , val , options )
else
hour_options = [ ]
0 . upto ( 23 ) do | hour |
hour_options << ( ( val == hour ) ?
2008-02-19 23:23:18 -05:00
content_tag ( :option , leading_zero_on_single_digits ( hour ) , :value = > leading_zero_on_single_digits ( hour ) , :selected = > " selected " ) :
content_tag ( :option , leading_zero_on_single_digits ( hour ) , :value = > leading_zero_on_single_digits ( hour ) )
2006-12-06 14:15:24 -05:00
)
2008-02-19 23:23:18 -05:00
hour_options << " \n "
2006-12-06 14:15:24 -05:00
end
2008-03-01 23:40:54 -05:00
select_html ( options [ :field_name ] || 'hour' , hour_options . join , options , html_options )
2004-11-23 20:04:44 -05:00
end
end
# Returns a select tag with options for each of the days 1 through 31 with the current day selected.
# The <tt>date</tt> can also be substituted for a hour number.
2005-07-02 14:38:22 -04:00
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
2007-06-23 13:49:18 -04:00
#
# ==== Examples
# my_date = Time.today + 2.days
#
# # Generates a select field for days that defaults to the day for the date in my_date
# select_day(my_time)
#
# # Generates a select field for days that defaults to the number given
# select_day(5)
#
# # Generates a select field for days that defaults to the day for the date in my_date
# # that is named 'due' rather than 'day'
# select_day(my_time, :field_name => 'due')
#
2008-03-01 23:40:54 -05:00
def select_day ( date , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
val = date ? ( date . kind_of? ( Fixnum ) ? date : date . day ) : ''
if options [ :use_hidden ]
hidden_html ( options [ :field_name ] || 'day' , val , options )
else
day_options = [ ]
1 . upto ( 31 ) do | day |
day_options << ( ( val == day ) ?
2008-02-19 23:23:18 -05:00
content_tag ( :option , day , :value = > day , :selected = > " selected " ) :
content_tag ( :option , day , :value = > day )
2006-12-06 14:15:24 -05:00
)
2008-02-19 23:23:18 -05:00
day_options << " \n "
2006-12-06 14:15:24 -05:00
end
2008-03-01 23:40:54 -05:00
select_html ( options [ :field_name ] || 'day' , day_options . join , options , html_options )
2004-11-23 20:04:44 -05:00
end
end
2005-03-06 06:50:41 -05:00
2004-11-23 20:04:44 -05:00
# Returns a select tag with options for each of the months January through December with the current month selected.
# The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values
# (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names --
2005-03-06 06:50:41 -05:00
# set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
2006-12-06 14:15:24 -05:00
# set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer to show month names as abbreviations,
# set the <tt>:use_short_month</tt> key in +options+ to true. If you want to use your own month names, set the
2007-06-23 13:49:18 -04:00
# <tt>:use_month_names</tt> key in +options+ to an array of 12 month names. Override the field name using the
# <tt>:field_name</tt> option, 'month' by default.
2006-12-06 14:15:24 -05:00
#
2007-06-23 13:49:18 -04:00
# ==== Examples
# # Generates a select field for months that defaults to the current month that
# # will use keys like "January", "March".
# select_month(Date.today)
2004-11-23 20:04:44 -05:00
#
2007-06-23 13:49:18 -04:00
# # Generates a select field for months that defaults to the current month that
# # is named "start" rather than "month"
# select_month(Date.today, :field_name => 'start')
#
# # Generates a select field for months that defaults to the current month that
# # will use keys like "1", "3".
# select_month(Date.today, :use_month_numbers => true)
#
# # Generates a select field for months that defaults to the current month that
# # will use keys like "1 - January", "3 - March".
# select_month(Date.today, :add_month_numbers => true)
#
# # Generates a select field for months that defaults to the current month that
# # will use keys like "Jan", "Mar".
# select_month(Date.today, :use_short_month => true)
#
# # Generates a select field for months that defaults to the current month that
# # will use keys like "Januar", "Marts."
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
2005-07-02 14:38:22 -04:00
#
2008-03-01 23:40:54 -05:00
def select_month ( date , options = { } , html_options = { } )
2008-06-19 10:25:27 -04:00
locale = options [ :locale ]
2008-06-22 07:49:38 -04:00
locale || = self . locale if respond_to? ( :locale )
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
val = date ? ( date . kind_of? ( Fixnum ) ? date : date . month ) : ''
if options [ :use_hidden ]
hidden_html ( options [ :field_name ] || 'month' , val , options )
else
month_options = [ ]
2008-06-19 10:25:27 -04:00
month_names = options [ :use_month_names ] || begin
2008-07-02 13:21:07 -04:00
key = options [ :use_short_month ] ? :'date.abbr_month_names' : :'date.month_names'
I18n . translate key , locale
2008-06-19 10:25:27 -04:00
end
2006-12-06 14:15:24 -05:00
month_names . unshift ( nil ) if month_names . size < 13
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
1 . upto ( 12 ) do | month_number |
month_name = if options [ :use_month_numbers ]
month_number
elsif options [ :add_month_numbers ]
month_number . to_s + ' - ' + month_names [ month_number ]
else
month_names [ month_number ]
end
2004-11-23 20:04:44 -05:00
2006-12-06 14:15:24 -05:00
month_options << ( ( val == month_number ) ?
2008-02-19 23:23:18 -05:00
content_tag ( :option , month_name , :value = > month_number , :selected = > " selected " ) :
content_tag ( :option , month_name , :value = > month_number )
2006-12-06 14:15:24 -05:00
)
2008-02-19 23:23:18 -05:00
month_options << " \n "
2006-12-06 14:15:24 -05:00
end
2008-03-01 23:40:54 -05:00
select_html ( options [ :field_name ] || 'month' , month_options . join , options , html_options )
2004-11-23 20:04:44 -05:00
end
2008-06-19 10:25:27 -04:00
end
2005-03-06 06:50:41 -05:00
2004-11-23 20:04:44 -05:00
# Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
2005-05-19 13:40:02 -04:00
# can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. Both ascending and descending year
# lists are supported by making <tt>:start_year</tt> less than or greater than <tt>:end_year</tt>. The <tt>date</tt> can also be
2007-06-23 13:49:18 -04:00
# substituted for a year given as a number. Override the field name using the <tt>:field_name</tt> option, 'year' by default.
#
# ==== Examples
# # Generates a select field for years that defaults to the current year that
# # has ascending year values
# select_year(Date.today, :start_year => 1992, :end_year => 2007)
#
# # Generates a select field for years that defaults to the current year that
# # is named 'birth' rather than 'year'
# select_year(Date.today, :field_name => 'birth')
#
# # Generates a select field for years that defaults to the current year that
# # has descending year values
# select_year(Date.today, :start_year => 2005, :end_year => 1900)
2004-11-23 20:04:44 -05:00
#
2007-06-23 13:49:18 -04:00
# # Generates a select field for years that defaults to the year 2006 that
# # has ascending year values
2006-12-06 14:15:24 -05:00
# select_year(2006, :start_year => 2000, :end_year => 2010)
2005-07-02 14:38:22 -04:00
#
2008-03-01 23:40:54 -05:00
def select_year ( date , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
val = date ? ( date . kind_of? ( Fixnum ) ? date : date . year ) : ''
if options [ :use_hidden ]
hidden_html ( options [ :field_name ] || 'year' , val , options )
else
year_options = [ ]
y = date ? ( date . kind_of? ( Fixnum ) ? ( y = ( date == 0 ) ? Date . today . year : date ) : date . year ) : Date . today . year
start_year , end_year = ( options [ :start_year ] || y - 5 ) , ( options [ :end_year ] || y + 5 )
step_val = start_year < end_year ? 1 : - 1
start_year . step ( end_year , step_val ) do | year |
year_options << ( ( val == year ) ?
2008-02-19 23:23:18 -05:00
content_tag ( :option , year , :value = > year , :selected = > " selected " ) :
content_tag ( :option , year , :value = > year )
2006-12-06 14:15:24 -05:00
)
2008-02-19 23:23:18 -05:00
year_options << " \n "
2006-12-06 14:15:24 -05:00
end
2008-03-01 23:40:54 -05:00
select_html ( options [ :field_name ] || 'year' , year_options . join , options , html_options )
2004-11-23 20:04:44 -05:00
end
end
2005-03-06 06:50:41 -05:00
2004-11-23 20:04:44 -05:00
private
2006-12-06 14:15:24 -05:00
2008-03-01 23:40:54 -05:00
def select_html ( type , html_options , options , select_tag_options = { } )
2006-12-06 14:15:24 -05:00
name_and_id_from_options ( options , type )
2008-02-19 23:23:18 -05:00
select_options = { :id = > options [ :id ] , :name = > options [ :name ] }
select_options . merge! ( :disabled = > 'disabled' ) if options [ :disabled ]
2008-03-01 23:40:54 -05:00
select_options . merge! ( select_tag_options ) unless select_tag_options . empty?
2008-02-19 23:23:18 -05:00
select_html = " \n "
select_html << content_tag ( :option , '' , :value = > '' ) + " \n " if options [ :include_blank ]
2006-12-06 14:15:24 -05:00
select_html << html_options . to_s
2008-02-19 23:23:18 -05:00
content_tag ( :select , select_html , select_options ) + " \n "
2004-11-23 20:04:44 -05:00
end
2005-03-06 06:50:41 -05:00
2006-12-06 14:15:24 -05:00
def hidden_html ( type , value , options )
name_and_id_from_options ( options , type )
2008-02-19 23:23:18 -05:00
hidden_html = tag ( :input , :type = > " hidden " , :id = > options [ :id ] , :name = > options [ :name ] , :value = > value ) + " \n "
2006-12-06 14:15:24 -05:00
end
def name_and_id_from_options ( options , type )
options [ :name ] = ( options [ :prefix ] || DEFAULT_PREFIX ) + ( options [ :discard_type ] ? '' : " [ #{ type } ] " )
options [ :id ] = options [ :name ] . gsub ( / ([ \ [ \ (])|( \ ] \ [) / , '_' ) . gsub ( / [ \ ] \ )] / , '' )
end
2004-11-23 20:04:44 -05:00
def leading_zero_on_single_digits ( number )
number > 9 ? number : " 0 #{ number } "
end
end
class InstanceTag #:nodoc:
include DateHelper
2008-03-01 23:40:54 -05:00
def to_date_select_tag ( options = { } , html_options = { } )
date_or_time_select ( options . merge ( :discard_hour = > true ) , html_options )
2006-12-06 14:15:24 -05:00
end
2004-11-23 20:04:44 -05:00
2008-03-01 23:40:54 -05:00
def to_time_select_tag ( options = { } , html_options = { } )
date_or_time_select ( options . merge ( :discard_year = > true , :discard_month = > true ) , html_options )
2006-12-06 14:15:24 -05:00
end
2005-02-19 13:26:37 -05:00
2008-03-01 23:40:54 -05:00
def to_datetime_select_tag ( options = { } , html_options = { } )
date_or_time_select ( options , html_options )
2006-12-06 14:15:24 -05:00
end
2005-03-06 06:50:41 -05:00
2006-12-06 14:15:24 -05:00
private
2008-03-01 23:40:54 -05:00
def date_or_time_select ( options , html_options = { } )
2008-06-19 10:25:27 -04:00
locale = options [ :locale ]
2006-12-06 14:15:24 -05:00
defaults = { :discard_type = > true }
options = defaults . merge ( options )
datetime = value ( object )
2007-01-28 11:44:44 -05:00
datetime || = default_time_from_options ( options [ :default ] ) unless options [ :include_blank ]
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
position = { :year = > 1 , :month = > 2 , :day = > 3 , :hour = > 4 , :minute = > 5 , :second = > 6 }
2008-07-02 13:21:07 -04:00
order = options [ :order ] || = I18n . translate ( :'date.order' , locale )
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
# Discard explicit and implicit by not being included in the :order
discard = { }
discard [ :year ] = true if options [ :discard_year ] or ! order . include? ( :year )
discard [ :month ] = true if options [ :discard_month ] or ! order . include? ( :month )
discard [ :day ] = true if options [ :discard_day ] or discard [ :month ] or ! order . include? ( :day )
discard [ :hour ] = true if options [ :discard_hour ]
discard [ :minute ] = true if options [ :discard_minute ] or discard [ :hour ]
discard [ :second ] = true unless options [ :include_seconds ] && ! discard [ :minute ]
2008-06-19 10:25:27 -04:00
2007-05-31 12:38:36 -04:00
# If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are valid
# (otherwise it could be 31 and february wouldn't be a valid date)
2007-06-14 21:58:32 -04:00
if datetime && discard [ :day ] && ! discard [ :month ]
2007-05-31 12:38:36 -04:00
datetime = datetime . change ( :day = > 1 )
end
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
# Maintain valid dates by including hidden fields for discarded elements
[ :day , :month , :year ] . each { | o | order . unshift ( o ) unless order . include? ( o ) }
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
# Ensure proper ordering of :hour, :minute and :second
[ :hour , :minute , :second ] . each { | o | order . delete ( o ) ; order . push ( o ) }
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
date_or_time_select = ''
order . reverse . each do | param |
# Send hidden fields for discarded elements once output has started
# This ensures AR can reconstruct valid dates using ParseDate
next if discard [ param ] && date_or_time_select . empty?
2008-03-01 23:40:54 -05:00
date_or_time_select . insert ( 0 , self . send ( " select_ #{ param } " , datetime , options_with_prefix ( position [ param ] , options . merge ( :use_hidden = > discard [ param ] ) ) , html_options ) )
2006-12-06 14:15:24 -05:00
date_or_time_select . insert ( 0 ,
case param
when :hour then ( discard [ :year ] && discard [ :day ] ? " " : " — " )
when :minute then " : "
when :second then options [ :include_seconds ] ? " : " : " "
else " "
end )
end
2008-06-19 10:25:27 -04:00
2006-12-06 14:15:24 -05:00
date_or_time_select
end
2005-03-06 06:50:41 -05:00
2006-12-06 14:15:24 -05:00
def options_with_prefix ( position , options )
prefix = " #{ @object_name } "
if options [ :index ]
prefix << " [ #{ options [ :index ] } ] "
elsif @auto_index
prefix << " [ #{ @auto_index } ] "
end
options . merge ( :prefix = > " #{ prefix } [ #{ @method_name } ( #{ position } i)] " )
end
2007-01-28 11:44:44 -05:00
def default_time_from_options ( default )
case default
when nil
2008-04-21 01:08:45 -04:00
Time . current
2007-01-28 11:44:44 -05:00
when Date , Time
default
else
# Rename :minute and :second to :min and :sec
default [ :min ] || = default [ :minute ]
default [ :sec ] || = default [ :second ]
2008-05-09 00:40:25 -04:00
time = Time . current
2007-01-28 11:44:44 -05:00
[ :year , :month , :day , :hour , :min , :sec ] . each do | key |
2008-05-09 00:40:25 -04:00
default [ key ] || = time . send ( key )
2007-01-28 11:44:44 -05:00
end
2008-05-18 11:59:24 -04:00
Time . utc_time ( default [ :year ] , default [ :month ] , default [ :day ] , default [ :hour ] , default [ :min ] , default [ :sec ] )
2007-01-28 11:44:44 -05:00
end
end
2004-11-23 20:04:44 -05:00
end
2005-11-13 06:13:11 -05:00
class FormBuilder
2008-03-01 23:40:54 -05:00
def date_select ( method , options = { } , html_options = { } )
2005-11-13 06:13:11 -05:00
@template . date_select ( @object_name , method , options . merge ( :object = > @object ) )
end
2008-03-01 23:40:54 -05:00
def time_select ( method , options = { } , html_options = { } )
2006-12-06 14:15:24 -05:00
@template . time_select ( @object_name , method , options . merge ( :object = > @object ) )
end
2008-03-01 23:40:54 -05:00
def datetime_select ( method , options = { } , html_options = { } )
2005-11-13 06:13:11 -05:00
@template . datetime_select ( @object_name , method , options . merge ( :object = > @object ) )
end
end
2004-11-23 20:04:44 -05:00
end
2005-05-19 13:40:02 -04:00
end