aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md3
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb68
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb44
-rw-r--r--actionpack/lib/action_view/helpers/tags.rb4
-rw-r--r--actionpack/lib/action_view/helpers/tags/datetime_field.rb22
-rw-r--r--actionpack/lib/action_view/helpers/tags/datetime_local_field.rb23
-rw-r--r--actionpack/lib/action_view/helpers/tags/month_field.rb22
-rw-r--r--actionpack/lib/action_view/helpers/tags/week_field.rb22
-rw-r--r--actionpack/test/template/form_helper_test.rb140
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb20
-rw-r--r--guides/source/form_helpers.textile12
11 files changed, 378 insertions, 2 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index d6fcae4571..920858d8c0 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,8 @@
## Rails 4.0.0 (unreleased) ##
+* Add `week_field`, `week_field_tag`, `month_field`, `month_field_tag`, `datetime_local_field`,
+ `datetime_local_field_tag`, `datetime_field` and `datetime_field_tag` helpers. *Carlos Galdino*
+
* Add `color_field` and `color_field_tag` helpers. *Carlos Galdino*
* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index c5a9057698..ad8885b708 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -1016,6 +1016,74 @@ module ActionView
Tags::TimeField.new(object_name, method, self, options).render
end
+ # Returns a text_field of type "datetime".
+ #
+ # datetime_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T.%L%z"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 12)
+ # datetime_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime" value="1984-01-12T00:00:00.000+0000" />
+ #
+ def datetime_field(object_name, method, options = {})
+ Tags::DatetimeField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "datetime-local".
+ #
+ # datetime_local_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 12)
+ # datetime_local_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="datetime-local" value="1984-01-12T00:00:00" />
+ #
+ def datetime_local_field(object_name, method, options = {})
+ Tags::DatetimeLocalField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "month".
+ #
+ # month_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="month" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-%m"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 1, 27)
+ # month_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-01" />
+ #
+ def month_field(object_name, method, options = {})
+ Tags::MonthField.new(object_name, method, self, options).render
+ end
+
+ # Returns a text_field of type "week".
+ #
+ # week_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="week" />
+ #
+ # The default value is generated by trying to call +strftime+ with "%Y-W%W"
+ # on the object's value, which makes it behave as expected for instances
+ # of DateTime and ActiveSupport::TimeWithZone.
+ #
+ # @user.born_on = Date.new(1984, 5, 12)
+ # week_field("user", "born_on")
+ # # => <input id="user_born_on" name="user[born_on]" type="date" value="1984-W19" />
+ #
+ def week_field(object_name, method, options = {})
+ Tags::WeekField.new(object_name, method, self, options).render
+ end
+
# Returns a text_field of type "url".
#
# url_field("user", "homepage")
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 7da67cd2f9..1a0019a48c 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -568,6 +568,50 @@ module ActionView
text_field_tag(name, value, options.stringify_keys.update("type" => "time"))
end
+ # Creates a text field of type "datetime".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def datetime_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "datetime"))
+ end
+
+ # Creates a text field of type "datetime-local".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def datetime_local_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "datetime-local"))
+ end
+
+ # Creates a text field of type "month".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def month_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "month"))
+ end
+
+ # Creates a text field of type "week".
+ #
+ # === Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ def week_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "week"))
+ end
+
# Creates a text field of type "url".
#
# ==== Options
diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb
index c56165c769..a05e16979a 100644
--- a/actionpack/lib/action_view/helpers/tags.rb
+++ b/actionpack/lib/action_view/helpers/tags.rb
@@ -11,12 +11,15 @@ module ActionView
autoload :ColorField
autoload :DateField
autoload :DateSelect
+ autoload :DatetimeField
+ autoload :DatetimeLocalField
autoload :DatetimeSelect
autoload :EmailField
autoload :FileField
autoload :GroupedCollectionSelect
autoload :HiddenField
autoload :Label
+ autoload :MonthField
autoload :NumberField
autoload :PasswordField
autoload :RadioButton
@@ -30,6 +33,7 @@ module ActionView
autoload :TimeSelect
autoload :TimeZoneSelect
autoload :UrlField
+ autoload :WeekField
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/datetime_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_field.rb
new file mode 100644
index 0000000000..11d58744fd
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/datetime_field.rb
@@ -0,0 +1,22 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DatetimeField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { format_global_date_time_string(value(object)) }
+ options["min"] = format_global_date_time_string(options["min"])
+ options["max"] = format_global_date_time_string(options["max"])
+ @options = options
+ super
+ end
+
+ private
+
+ def format_global_date_time_string(value)
+ value.try(:strftime, "%Y-%m-%dT%T.%L%z")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb
new file mode 100644
index 0000000000..7593a3c733
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb
@@ -0,0 +1,23 @@
+module ActionView
+ module Helpers
+ module Tags
+ class DatetimeLocalField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["type"] = "datetime-local"
+ options["value"] = @options.fetch("value") { format_local_date_time_string(value(object)) }
+ options["min"] = format_local_date_time_string(options["min"])
+ options["max"] = format_local_date_time_string(options["max"])
+ @options = options
+ super
+ end
+
+ private
+
+ def format_local_date_time_string(value)
+ value.try(:strftime, "%Y-%m-%dT%T")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/month_field.rb b/actionpack/lib/action_view/helpers/tags/month_field.rb
new file mode 100644
index 0000000000..56bd85a90b
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/month_field.rb
@@ -0,0 +1,22 @@
+module ActionView
+ module Helpers
+ module Tags
+ class MonthField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { format_month_string(value(object)) }
+ options["min"] = format_month_string(options["min"])
+ options["max"] = format_month_string(options["max"])
+ @options = options
+ super
+ end
+
+ private
+
+ def format_month_string(value)
+ value.try(:strftime, "%Y-%m")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/tags/week_field.rb b/actionpack/lib/action_view/helpers/tags/week_field.rb
new file mode 100644
index 0000000000..a1265d9928
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/week_field.rb
@@ -0,0 +1,22 @@
+module ActionView
+ module Helpers
+ module Tags
+ class WeekField < TextField #:nodoc:
+ def render
+ options = @options.stringify_keys
+ options["value"] = @options.fetch("value") { format_week_string(value(object)) }
+ options["min"] = format_week_string(options["min"])
+ options["max"] = format_week_string(options["max"])
+ @options = options
+ super
+ end
+
+ private
+
+ def format_week_string(value)
+ value.try(:strftime, "%Y-W%W")
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 76a18fa76a..97c8025db3 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -685,6 +685,146 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal(expected, time_field("post", "written_on"))
end
+ def test_datetime_field
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T00:00:00.000+0000" />}
+ assert_dom_equal(expected, datetime_field("post", "written_on"))
+ end
+
+ def test_datetime_field_with_datetime_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T01:02:03.000+0000" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ assert_dom_equal(expected, datetime_field("post", "written_on"))
+ end
+
+ def test_datetime_field_with_extra_attrs
+ expected = %{<input id="post_written_on" step="60" max="2010-08-15T10:25:00.000+0000" min="2000-06-15T20:45:30.000+0000" name="post[written_on]" type="datetime" value="2004-06-15T01:02:03.000+0000" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ min_value = DateTime.new(2000, 6, 15, 20, 45, 30)
+ max_value = DateTime.new(2010, 8, 15, 10, 25, 00)
+ step = 60
+ assert_dom_equal(expected, datetime_field("post", "written_on", :min => min_value, :max => max_value, :step => step))
+ end
+
+ def test_datetime_field_with_timewithzone_value
+ previous_time_zone, Time.zone = Time.zone, 'UTC'
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" value="2004-06-15T15:30:45.000+0000" />}
+ @post.written_on = Time.zone.parse('2004-06-15 15:30:45')
+ assert_dom_equal(expected, datetime_field("post", "written_on"))
+ ensure
+ Time.zone = previous_time_zone
+ end
+
+ def test_datetime_field_with_nil_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime" />}
+ @post.written_on = nil
+ assert_dom_equal(expected, datetime_field("post", "written_on"))
+ end
+
+ def test_datetime_local_field
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T00:00:00" />}
+ assert_dom_equal(expected, datetime_local_field("post", "written_on"))
+ end
+
+ def test_datetime_local_field_with_datetime_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ assert_dom_equal(expected, datetime_local_field("post", "written_on"))
+ end
+
+ def test_datetime_local_field_with_extra_attrs
+ expected = %{<input id="post_written_on" step="60" max="2010-08-15T10:25:00" min="2000-06-15T20:45:30" name="post[written_on]" type="datetime-local" value="2004-06-15T01:02:03" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ min_value = DateTime.new(2000, 6, 15, 20, 45, 30)
+ max_value = DateTime.new(2010, 8, 15, 10, 25, 00)
+ step = 60
+ assert_dom_equal(expected, datetime_local_field("post", "written_on", :min => min_value, :max => max_value, :step => step))
+ end
+
+ def test_datetime_local_field_with_timewithzone_value
+ previous_time_zone, Time.zone = Time.zone, 'UTC'
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" value="2004-06-15T15:30:45" />}
+ @post.written_on = Time.zone.parse('2004-06-15 15:30:45')
+ assert_dom_equal(expected, datetime_local_field("post", "written_on"))
+ ensure
+ Time.zone = previous_time_zone
+ end
+
+ def test_datetime_local_field_with_nil_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="datetime-local" />}
+ @post.written_on = nil
+ assert_dom_equal(expected, datetime_local_field("post", "written_on"))
+ end
+
+ def test_month_field
+ expected = %{<input id="post_written_on" name="post[written_on]" type="month" value="2004-06" />}
+ assert_dom_equal(expected, month_field("post", "written_on"))
+ end
+
+ def test_month_field_with_nil_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="month" />}
+ @post.written_on = nil
+ assert_dom_equal(expected, month_field("post", "written_on"))
+ end
+
+ def test_month_field_with_datetime_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="month" value="2004-06" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ assert_dom_equal(expected, month_field("post", "written_on"))
+ end
+
+ def test_month_field_with_extra_attrs
+ expected = %{<input id="post_written_on" step="2" max="2010-12" min="2000-02" name="post[written_on]" type="month" value="2004-06" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ min_value = DateTime.new(2000, 2, 13)
+ max_value = DateTime.new(2010, 12, 23)
+ step = 2
+ assert_dom_equal(expected, month_field("post", "written_on", :min => min_value, :max => max_value, :step => step))
+ end
+
+ def test_month_field_with_timewithzone_value
+ previous_time_zone, Time.zone = Time.zone, 'UTC'
+ expected = %{<input id="post_written_on" name="post[written_on]" type="month" value="2004-06" />}
+ @post.written_on = Time.zone.parse('2004-06-15 15:30:45')
+ assert_dom_equal(expected, month_field("post", "written_on"))
+ ensure
+ Time.zone = previous_time_zone
+ end
+
+ def test_week_field
+ expected = %{<input id="post_written_on" name="post[written_on]" type="week" value="2004-W24" />}
+ assert_dom_equal(expected, week_field("post", "written_on"))
+ end
+
+ def test_week_field_with_nil_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="week" />}
+ @post.written_on = nil
+ assert_dom_equal(expected, week_field("post", "written_on"))
+ end
+
+ def test_week_field_with_datetime_value
+ expected = %{<input id="post_written_on" name="post[written_on]" type="week" value="2004-W24" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ assert_dom_equal(expected, week_field("post", "written_on"))
+ end
+
+ def test_week_field_with_extra_attrs
+ expected = %{<input id="post_written_on" step="2" max="2010-W51" min="2000-W06" name="post[written_on]" type="week" value="2004-W24" />}
+ @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3)
+ min_value = DateTime.new(2000, 2, 13)
+ max_value = DateTime.new(2010, 12, 23)
+ step = 2
+ assert_dom_equal(expected, week_field("post", "written_on", :min => min_value, :max => max_value, :step => step))
+ end
+
+ def test_week_field_with_timewithzone_value
+ previous_time_zone, Time.zone = Time.zone, 'UTC'
+ expected = %{<input id="post_written_on" name="post[written_on]" type="week" value="2004-W24" />}
+ @post.written_on = Time.zone.parse('2004-06-15 15:30:45')
+ assert_dom_equal(expected, week_field("post", "written_on"))
+ ensure
+ Time.zone = previous_time_zone
+ end
+
def test_url_field
expected = %{<input id="user_homepage" name="user[homepage]" type="url" />}
assert_dom_equal(expected, url_field("user", "homepage"))
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 195adce180..5d19e3274d 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -469,6 +469,26 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal(expected, time_field_tag("cell"))
end
+ def test_datetime_field_tag
+ expected = %{<input id="appointment" name="appointment" type="datetime" />}
+ assert_dom_equal(expected, datetime_field_tag("appointment"))
+ end
+
+ def test_datetime_local_field_tag
+ expected = %{<input id="appointment" name="appointment" type="datetime-local" />}
+ assert_dom_equal(expected, datetime_local_field_tag("appointment"))
+ end
+
+ def test_month_field_tag
+ expected = %{<input id="birthday" name="birthday" type="month" />}
+ assert_dom_equal(expected, month_field_tag("birthday"))
+ end
+
+ def test_week_field_tag
+ expected = %{<input id="birthday" name="birthday" type="week" />}
+ assert_dom_equal(expected, week_field_tag("birthday"))
+ end
+
def test_url_field_tag
expected = %{<input id="homepage" name="homepage" type="url" />}
assert_dom_equal(expected, url_field_tag("homepage"))
diff --git a/guides/source/form_helpers.textile b/guides/source/form_helpers.textile
index 11d48551c4..8106de6f9d 100644
--- a/guides/source/form_helpers.textile
+++ b/guides/source/form_helpers.textile
@@ -150,7 +150,7 @@ NOTE: Always use labels for checkbox and radio buttons. They associate text with
h4. Other Helpers of Interest
-Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, time fields, color fields, URL fields and email fields:
+Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, time fields, color fields, datetime fields, datetime-local fields, month fields, week fields, URL fields and email fields:
<erb>
<%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %>
@@ -159,6 +159,10 @@ Other form controls worth mentioning are textareas, password fields, hidden fiel
<%= search_field(:user, :name) %>
<%= telephone_field(:user, :phone) %>
<%= date_field(:user, :born_on) %>
+<%= datetime_field(:user, :meeting_time) %>
+<%= datetime_local_field(:user, :graduation_day) %>
+<%= month_field(:user, :birthday_month) %>
+<%= week_field(:user, :birthday_week) %>
<%= url_field(:user, :homepage) %>
<%= email_field(:user, :address) %>
<%= color_field(:user, :favorite_color) %>
@@ -174,6 +178,10 @@ Output:
<input id="user_name" name="user[name]" type="search" />
<input id="user_phone" name="user[phone]" type="tel" />
<input id="user_born_on" name="user[born_on]" type="date" />
+<input id="user_meeting_time" name="user[meeting_time]" type="datetime" />
+<input id="user_graduation_day" name="user[graduation_day]" type="datetime-local" />
+<input id="user_birthday_month" name="user[birthday_month]" type="month" />
+<input id="user_birthday_week" name="user[birthday_week]" type="week" />
<input id="user_homepage" name="user[homepage]" type="url" />
<input id="user_address" name="user[address]" type="email" />
<input id="user_favorite_color" name="user[favorite_color]" type="color" value="#000000" />
@@ -182,7 +190,7 @@ Output:
Hidden inputs are not shown to the user but instead hold data like any textual input. Values inside them can be changed with JavaScript.
-IMPORTANT: The search, telephone, date, time, color, URL, and email inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely "no shortage of solutions for this":https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills, although a couple of popular tools at the moment are "Modernizr":http://www.modernizr.com/ and "yepnope":http://yepnopejs.com/, which provide a simple way to add functionality based on the presence of detected HTML5 features.
+IMPORTANT: The search, telephone, date, time, color, datetime, datetime-local, month, week, URL, and email inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely "no shortage of solutions for this":https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills, although a couple of popular tools at the moment are "Modernizr":http://www.modernizr.com/ and "yepnope":http://yepnopejs.com/, which provide a simple way to add functionality based on the presence of detected HTML5 features.
TIP: If you're using password input fields (for any purpose), you might want to configure your application to prevent those parameters from being logged. You can learn about this in the "Security Guide":security.html#logging.