Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added all the new HTML5 form types as individual form tag methods (se…

…arch, url, number, etc) (Closes #3646) [Stephen Celis]
  • Loading branch information...
commit f8730e5ce6bba4de7639ac09c6c193458038f748 1 parent 40a3e67
@dhh dhh authored
View
3  actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [Edge] (pending)*
+* Added all the new HTML5 form types as individual form tag methods (search, url, number, etc) #3646 [Stephen Celis]
+
* Changed the object used in routing constraints to be an instance of
ActionDispatch::Request rather than Rack::Request
@@ -13,6 +15,7 @@
"HEAD" and #request_method returns "GET" in HEAD requests). This
is for compatibility with Rack::Request
+
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
* #concat is now deprecated in favor of using <%= %> helpers [YK]
View
58 actionpack/lib/action_view/helpers/form_helper.rb
@@ -784,6 +784,56 @@ def check_box(object_name, method, options = {}, checked_value = "1", unchecked_
def radio_button(object_name, method, tag_value, options = {})
InstanceTag.new(object_name, method, self, options.delete(:object)).to_radio_button_tag(tag_value, options)
end
+
+ # Returns a text_field of type "search".
+ def search_field(object_name, method, options = {})
+ options = options.stringify_keys
+
+ if options["autosave"]
+ if options["autosave"] == true
+ options["autosave"] = request.host.split(".").reverse.join(".")
+ end
+ options["results"] ||= 10
+ end
+
+ if options["onsearch"]
+ options["incremental"] = true unless options.has_key?("incremental")
+ end
+
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("search", options)
+ end
+
+ # Returns a text_field of type "tel".
+ def telephone_field(object_name, method, options = {})
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("tel", options)
+ end
+ alias phone_field telephone_field
+
+ # Returns a text_field of type "url".
+ def url_field(object_name, method, options = {})
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("url", options)
+ end
+
+ # Returns a text_field of type "email".
+ def email_field(object_name, method, options = {})
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_input_field_tag("email", options)
+ end
+
+ # Returns an input tag of type "number".
+ #
+ # ==== Options
+ # * Accepts same options as number_field_tag
+ def number_field(object_name, method, options = {})
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_number_field_tag("number", options)
+ end
+
+ # Returns an input tag of type "range".
+ #
+ # ==== Options
+ # * Accepts same options as range_field_tag
+ def range_field(object_name, method, options = {})
+ InstanceTag.new(object_name, method, self, options.delete(:object)).to_number_field_tag("range", options)
+ end
end
module InstanceTagMethods #:nodoc:
@@ -847,6 +897,14 @@ def to_input_field_tag(field_type, options = {})
tag("input", options)
end
+ def to_number_field_tag(field_type, options = {})
+ options = options.stringify_keys
+ if range = options.delete("in") || options.delete("within")
+ options.update("min" => range.min, "max" => range.max)
+ end
+ to_input_field_tag(field_type, options)
+ end
+
def to_radio_button_tag(tag_value, options = {})
options = DEFAULT_RADIO_OPTIONS.merge(options.stringify_keys)
options["type"] = "radio"
View
63 actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -457,6 +457,69 @@ def field_set_tag(legend = nil, options = nil, &block)
output.safe_concat("</fieldset>")
end
+ # Creates a text field of type "search".
+ #
+ # ==== Options
+ # * Accepts the same options as text_field_tag.
+ def search_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "search"))
+ end
+
+ # Creates a text field of type "tel".
+ #
+ # ==== Options
+ # * Accepts the same options as text_field_tag.
+ def telephone_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "tel"))
+ end
+ alias phone_field_tag telephone_field_tag
+
+ # Creates a text field of type "url".
+ #
+ # ==== Options
+ # * Accepts the same options as text_field_tag.
+ def url_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "url"))
+ end
+
+ # Creates a text field of type "email".
+ #
+ # ==== Options
+ # * Accepts the same options as text_field_tag.
+ def email_field_tag(name, value = nil, options = {})
+ text_field_tag(name, value, options.stringify_keys.update("type" => "email"))
+ end
+
+ # Creates a number field.
+ #
+ # ==== Options
+ # * <tt>:min</tt> - The minimum acceptable value.
+ # * <tt>:max</tt> - The maximum acceptable value.
+ # * <tt>:in</tt> - A range specifying the <tt>:min</tt> and
+ # <tt>:max</tt> values.
+ # * <tt>:step</tt> - The acceptable value granularity.
+ # * Otherwise accepts the same options as text_field_tag.
+ #
+ # ==== Examples
+ # number_field_tag 'quantity', nil, :in => 1...10
+ # => <input id="quantity" name="quantity" min="1" max="9" />
+ def number_field_tag(name, value = nil, options = {})
+ options = options.stringify_keys
+ options["type"] ||= "number"
+ if range = options.delete("in") || options.delete("within")
+ options.update("min" => range.min, "max" => range.max)
+ end
+ text_field_tag(name, value, options)
+ end
+
+ # Creates a range form element.
+ #
+ # ==== Options
+ # * Accepts the same options as number_field_tag.
+ def range_field_tag(name, value = nil, options = {})
+ number_field_tag(name, value, options.stringify_keys.update("type" => "range"))
+ end
+
private
def html_options_for_form(url_for_options, options, *parameters_for_url)
returning options.stringify_keys do |html_options|
View
30 actionpack/test/template/form_helper_test.rb
@@ -349,6 +349,36 @@ def test_text_area_with_size_option
)
end
+ def search_field
@pusewicz
pusewicz added a note

Shouldn't it be test_search_field?

@josevalim Owner

Yup. I'm going to fix it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ expected = %{<input id="contact_notes_query" size="30" name="contact[notes_query]" type="search" />}
+ assert_dom_equal(expected, search_field("contact", "notes_query"))
+ end
+
+ def test_telephone_field
+ expected = %{<input id="user_cell" size="30" name="user[cell]" type="tel" />}
+ assert_dom_equal(expected, telephone_field("user", "cell"))
@pusewicz
pusewicz added a note

It should probably test phone_field too?

phone_field is an alias to telephone_field, so this should be fine. :)

@pusewicz
pusewicz added a note

Yeah, but there is not a test that it's result is exactly the same. Say someone changes it, created a method that does something different and you have a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ end
+
+ def test_url_field
+ expected = %{<input id="user_homepage" size="30" name="user[homepage]" type="url" />}
+ assert_dom_equal(expected, url_field("user", "homepage"))
+ end
+
+ def test_email_field
+ expected = %{<input id="user_address" size="30" name="user[address]" type="email" />}
+ assert_dom_equal(expected, email_field("user", "address"))
+ end
+
+ def test_number_field
+ expected = %{<input name="order[quantity]" size="30" max="9" id="order_quantity" type="number" min="1" />}
+ assert_dom_equal(expected, number_field("order", "quantity", :in => 1...10))
+ end
+
+ def test_range_input
+ expected = %{<input name="hifi[volume]" step="0.1" size="30" max="11" id="hifi_volume" type="range" min="0" />}
+ assert_dom_equal(expected, range_field("hifi", "volume", :in => 0..11, :step => 0.1))
+ end
+
def test_explicit_name
assert_dom_equal(
'<input id="post_title" name="dont guess" size="30" type="text" value="Hello World" />', text_field("post", "title", "name" => "dont guess")
View
30 actionpack/test/template/form_tag_helper_test.rb
@@ -335,6 +335,36 @@ def test_image_submit_tag_with_confirmation
)
end
+ def test_search_field_tag
+ expected = %{<input id="query" name="query" type="search" />}
+ assert_dom_equal(expected, search_field_tag("query"))
+ end
+
+ def telephone_field_tag
+ expected = %{<input id="cell" name="cell" type="tel" />}
+ assert_dom_equal(expected, telephone_field_tag("cell"))
+ end
+
+ def test_url_field_tag
+ expected = %{<input id="homepage" name="homepage" type="url" />}
+ assert_dom_equal(expected, url_field_tag("homepage"))
+ end
+
+ def test_email_field_tag
+ expected = %{<input id="address" name="address" type="email" />}
+ assert_dom_equal(expected, email_field_tag("address"))
+ end
+
+ def test_number_field_tag
+ expected = %{<input name="quantity" max="9" id="quantity" type="number" min="1" />}
+ assert_dom_equal(expected, number_field_tag("quantity", nil, :in => 1...10))
+ end
+
+ def test_range_input_tag
+ expected = %{<input name="volume" step="0.1" max="11" id="volume" type="range" min="0" />}
+ assert_dom_equal(expected, range_field_tag("volume", nil, :in => 0..11, :step => 0.1))
+ end
+
def test_pass
assert_equal 1, 1
end

9 comments on commit f8730e5

@radar

You bloody ripper :)

@Aupajo

Nice, been looking out for this commit. :)

@stephencelis

Great! Thanks for handling the merge.

@dmathieu
Collaborator

Nice one :)

@carlosbrando

I really like it.

@pusewicz

Shouldn't it be test_search_field?

@josevalim

Yup. I'm going to fix it, thanks!

@pusewicz

It should probably test phone_field too?

@arthurschreiber

phone_field is an alias to telephone_field, so this should be fine. :)

@pusewicz

Yeah, but there is not a test that it's result is exactly the same. Say someone changes it, created a method that does something different and you have a problem.

@aaronchi

What happened to date type input?

@stephencelis

There are currently a ton of date input types in the HTML5 spec: datetime, datetime-local, date, month, time, week.

The only browser that comes close to supporting them (at the time) is Opera. Till the spec is more finalized, and till more browsers support these input types, it probably makes more sense to just pass it to the :type option.

@dgm

But with a little javascript help, other browsers are becoming supported too, such as jquerytools' dateinput tool.

@matchu

Love.

Please sign in to comment.
Something went wrong with that request. Please try again.