From d6b26a6040db97a55e23a7f10f2e9ba859eb11dc Mon Sep 17 00:00:00 2001 From: Olek Janiszewski Date: Sun, 12 Feb 2012 13:32:53 +0100 Subject: [PATCH] Add HTML5 input[type="date"] helper --- actionpack/CHANGELOG.md | 2 ++ .../lib/action_view/helpers/form_helper.rb | 18 +++++++++++++ .../action_view/helpers/form_tag_helper.rb | 8 ++++++ actionpack/lib/action_view/helpers/tags.rb | 1 + .../lib/action_view/helpers/tags/base.rb | 2 +- .../action_view/helpers/tags/date_field.rb | 15 +++++++++++ actionpack/test/template/form_helper_test.rb | 26 +++++++++++++++++++ .../test/template/form_tag_helper_test.rb | 7 ++++- railties/guides/source/form_helpers.textile | 8 +++--- 9 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 actionpack/lib/action_view/helpers/tags/date_field.rb diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 3487c96414..459f5b90e4 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Add `date_field` and `date_field_tag` helpers which render an `input[type="date"]` tag *Olek Janiszewski* + * Adds `image_url`, `javascript_url`, `stylesheet_url`, `audio_url`, `video_url`, and `font_url` to assets tag helper. These URL helpers will return the full path to your assets. This is useful when you are going to reference this asset from external host. *Prem Sichanugrist* diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index bdfef920c5..44e24fecd1 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -889,6 +889,24 @@ module ActionView end alias phone_field telephone_field + # Returns a text_field of type "date". + # + # date_field("user", "born_on") + # # => + # + # The default value is generated by trying to call "to_date" + # on the object's value, which makes it behave as expected for instances + # of DateTime and ActiveSupport::TimeWithZone. You can still override that + # by passing the "value" option explicitly, e.g. + # + # @user.born_on = Date.new(1984, 1, 27) + # date_field("user", "born_on", value: "1984-05-12") + # # => + # + def date_field(object_name, method, options = {}) + Tags::DateField.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 e97f602728..53fd189c39 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -549,6 +549,14 @@ module ActionView end alias phone_field_tag telephone_field_tag + # Creates a text field of type "date". + # + # ==== Options + # * Accepts the same options as text_field_tag. + def date_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "date")) + 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 c480799fe3..3cf762877f 100644 --- a/actionpack/lib/action_view/helpers/tags.rb +++ b/actionpack/lib/action_view/helpers/tags.rb @@ -8,6 +8,7 @@ module ActionView autoload :CollectionCheckBoxes autoload :CollectionRadioButtons autoload :CollectionSelect + autoload :DateField autoload :DateSelect autoload :DatetimeSelect autoload :EmailField diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb index e22612ccd0..1ece0ad2fc 100644 --- a/actionpack/lib/action_view/helpers/tags/base.rb +++ b/actionpack/lib/action_view/helpers/tags/base.rb @@ -36,7 +36,7 @@ module ActionView object.respond_to?(method_before_type_cast) ? object.send(method_before_type_cast) : - object.send(@method_name) + value(object) end end diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb new file mode 100644 index 0000000000..bb968e9f39 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/date_field.rb @@ -0,0 +1,15 @@ +module ActionView + module Helpers + module Tags + class DateField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["value"] = @options.fetch("value") { value(object).try(:to_date) } + options["size"] = nil + @options = options + super + end + end + end + end +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 9366960caa..d072d3bce0 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -514,6 +514,32 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal(expected, telephone_field("user", "cell")) end + def test_date_field + expected = %{} + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_date_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_date_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, date_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_date_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, date_field("post", "written_on")) + end + def test_url_field expected = %{} 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 2f2546aed2..809102e5c2 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -457,11 +457,16 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal(expected, search_field_tag("query")) end - def telephone_field_tag + def test_telephone_field_tag expected = %{} assert_dom_equal(expected, telephone_field_tag("cell")) end + def test_date_field_tag + expected = %{} + assert_dom_equal(expected, date_field_tag("cell")) + end + def test_url_field_tag expected = %{} assert_dom_equal(expected, url_field_tag("homepage")) diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile index 9758b639cf..2de4d49cf2 100644 --- a/railties/guides/source/form_helpers.textile +++ b/railties/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, URL fields and email fields: +Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, URL fields and email fields: <%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %> @@ -158,6 +158,7 @@ Other form controls worth mentioning are textareas, password fields, hidden fiel <%= hidden_field_tag(:parent_id, "5") %> <%= search_field(:user, :name) %> <%= telephone_field(:user, :phone) %> +<%= date_field(:user, :born_on) %> <%= url_field(:user, :homepage) %> <%= email_field(:user, :address) %> @@ -170,13 +171,14 @@ 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, 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, 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. @@ -467,7 +469,7 @@ Rails _used_ to have a +country_select+ helper for choosing countries, but this h3. Using Date and Time Form Helpers -The date and time helpers differ from all the other form helpers in two important respects: +You can choose not to use the form helpers generating HTML5 date input fields and use the alternative date and time helpers. These date and time helpers differ from all the other form helpers in two important respects: # Dates and times are not representable by a single input element. Instead you have several, one for each component (year, month, day etc.) and so there is no single value in your +params+ hash with your date or time. # Other helpers use the +_tag+ suffix to indicate whether a helper is a barebones helper or one that operates on model objects. With dates and times, +select_date+, +select_time+ and +select_datetime+ are the barebones helpers, +date_select+, +time_select+ and +datetime_select+ are the equivalent model object helpers.