aboutsummaryrefslogtreecommitdiffstats
path: root/actionview/lib/action_view/helpers/form_tag_helper.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionview/lib/action_view/helpers/form_tag_helper.rb')
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb112
1 files changed, 73 insertions, 39 deletions
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index b18f578183..0191064326 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -20,7 +20,7 @@ module ActionView
mattr_accessor :embed_authenticity_token_in_remote_forms
self.embed_authenticity_token_in_remote_forms = false
- # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
+ # Starts a form tag that points the action to a url configured with <tt>url_for_options</tt> just like
# ActionController::Base#url_for. The method for the form defaults to POST.
#
# ==== Options
@@ -35,10 +35,10 @@ module ActionView
# This is helpful when you're fragment-caching the form. Remote forms get the
# authenticity token from the <tt>meta</tt> tag, so embedding is unnecessary unless you
# support browsers without JavaScript.
- # * A list of parameters to feed to the URL the form will be posted to.
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
# submit behavior. By default this behavior is an ajax submit.
# * <tt>:enforce_utf8</tt> - If set to false, a hidden input with name utf8 is not output.
+ # * Any other key creates standard HTML attributes for the tag.
#
# ==== Examples
# form_tag('/posts')
@@ -80,18 +80,17 @@ module ActionView
# associated records. <tt>option_tags</tt> is a string containing the option tags for the select box.
#
# ==== Options
- # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
+ # * <tt>:multiple</tt> - If set to true, the selection will allow multiple choices.
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
# * <tt>:include_blank</tt> - If set to true, an empty option will be created. If set to a string, the string will be used as the option's content and the value will be empty.
# * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something.
- # * <tt>:selected</tt> - Provide a default selected value. It should be of the exact type as the provided options.
# * Any other key creates standard HTML attributes for the tag.
#
# ==== Examples
# select_tag "people", options_from_collection_for_select(@people, "id", "name")
# # <select id="people" name="people"><option value="1">David</option></select>
#
- # select_tag "people", options_from_collection_for_select(@people, "id", "name"), selected: ["1", "David"]
+ # select_tag "people", options_from_collection_for_select(@people, "id", "name", "1")
# # <select id="people" name="people"><option value="1" selected="selected">David</option></select>
#
# select_tag "people", "<option>David</option>".html_safe
@@ -133,15 +132,23 @@ module ActionView
option_tags ||= ""
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
- if options.delete(:include_blank)
- option_tags = content_tag(:option, '', :value => '').safe_concat(option_tags)
+ if options.include?(:include_blank)
+ include_blank = options.delete(:include_blank)
+
+ if include_blank == true
+ include_blank = ''
+ end
+
+ if include_blank
+ option_tags = content_tag("option".freeze, include_blank, value: '').safe_concat(option_tags)
+ end
end
if prompt = options.delete(:prompt)
- option_tags = content_tag(:option, prompt, :value => '').safe_concat(option_tags)
+ option_tags = content_tag("option".freeze, prompt, value: '').safe_concat(option_tags)
end
- content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
+ content_tag "select".freeze, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
end
# Creates a standard text field; use these text fields to input smaller chunks of text like a username
@@ -224,7 +231,7 @@ module ActionView
# # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
# # type="hidden" value="" />
def hidden_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
+ text_field_tag(name, value, options.merge(type: :hidden))
end
# Creates a file upload field. If you are using file uploads then you will also need
@@ -263,7 +270,7 @@ module ActionView
# file_field_tag 'file', accept: 'text/html', class: 'upload', value: 'index.html'
# # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
def file_field_tag(name, options = {})
- text_field_tag(name, nil, options.update("type" => "file"))
+ text_field_tag(name, nil, options.merge(type: :file))
end
# Creates a password field, a masked text field that will hide the users input behind a mask character.
@@ -296,7 +303,7 @@ module ActionView
# password_field_tag 'pin', '1234', maxlength: 4, size: 6, class: "pin_input"
# # => <input class="pin_input" id="pin" maxlength="4" name="pin" size="6" type="password" value="1234" />
def password_field_tag(name = "password", value = nil, options = {})
- text_field_tag(name, value, options.update("type" => "password"))
+ text_field_tag(name, value, options.merge(type: :password))
end
# Creates a text input area; use a textarea for longer text inputs such as blog posts or descriptions.
@@ -407,42 +414,57 @@ module ActionView
# the form is processed normally, otherwise no action is taken.
# * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
# disabled version of the submit button when the form is submitted. This feature is
- # provided by the unobtrusive JavaScript driver.
+ # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
+ # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
#
# ==== Examples
# submit_tag
- # # => <input name="commit" type="submit" value="Save changes" />
+ # # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
#
# submit_tag "Edit this article"
- # # => <input name="commit" type="submit" value="Edit this article" />
+ # # => <input name="commit" data-disable-with="Edit this article" type="submit" value="Edit this article" />
#
# submit_tag "Save edits", disabled: true
- # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
+ # # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
#
- # submit_tag "Complete sale", data: { disable_with: "Please wait..." }
- # # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
+ # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
+ # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
#
# submit_tag nil, class: "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
# submit_tag "Edit", class: "edit_button"
- # # => <input class="edit_button" name="commit" type="submit" value="Edit" />
+ # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
#
# submit_tag "Save", data: { confirm: "Are you sure?" }
- # # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
+ # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
#
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
+ tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options)
+
+ if ActionView::Base.automatically_disable_submit_tag
+ unless tag_options["data-disable-with"] == false || (tag_options["data"] && tag_options["data"][:disable_with] == false)
+ disable_with_text = tag_options["data-disable-with"]
+ disable_with_text ||= tag_options["data"][:disable_with] if tag_options["data"]
+ disable_with_text ||= value.clone
+ tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
+ else
+ tag_options["data"].delete(:disable_with) if tag_options["data"]
+ end
+ tag_options.delete("data-disable-with")
+ end
- tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options)
+ tag :input, tag_options
end
# Creates a button element that defines a <tt>submit</tt> button,
# <tt>reset</tt>button or a generic button which can be used in
# JavaScript, for example. You can use the button tag as a regular
# submit tag but it isn't supported in legacy browsers. However,
- # the button tag allows richer labels such as images and emphasis,
- # so this helper will also accept a block.
+ # the button tag does allow for richer labels such as images and emphasis,
+ # so this helper will also accept a block. By default, it will create
+ # a button tag with type `submit`, if type is not given.
#
# ==== Options
# * <tt>:data</tt> - This option can be used to add custom data attributes.
@@ -465,6 +487,15 @@ module ActionView
# button_tag
# # => <button name="button" type="submit">Button</button>
#
+ # button_tag 'Reset', type: 'reset'
+ # # => <button name="button" type="reset">Reset</button>
+ #
+ # button_tag 'Button', type: 'button'
+ # # => <button name="button" type="button">Button</button>
+ #
+ # button_tag 'Reset', type: 'reset', disabled: true
+ # # => <button name="button" type="reset" disabled="disabled">Reset</button>
+ #
# button_tag(type: 'button') do
# content_tag(:strong, 'Ask me!')
# end
@@ -472,6 +503,9 @@ module ActionView
# # <strong>Ask me!</strong>
# # </button>
#
+ # button_tag "Save", data: { confirm: "Are you sure?" }
+ # # => <button name="button" type="submit" data-confirm="Are you sure?">Save</button>
+ #
# button_tag "Checkout", data: { disable_with: "Please wait..." }
# # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
#
@@ -548,7 +582,7 @@ module ActionView
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
def field_set_tag(legend = nil, options = nil, &block)
output = tag(:fieldset, options, true)
- output.safe_concat(content_tag(:legend, legend)) unless legend.blank?
+ output.safe_concat(content_tag("legend".freeze, legend)) unless legend.blank?
output.concat(capture(&block)) if block_given?
output.safe_concat("</fieldset>")
end
@@ -571,7 +605,7 @@ module ActionView
# color_field_tag 'color', '#DEF726', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="color" name="color" type="color" value="#DEF726" />
def color_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "color"))
+ text_field_tag(name, value, options.merge(type: :color))
end
# Creates a text field of type "search".
@@ -592,7 +626,7 @@ module ActionView
# search_field_tag 'search', 'Enter your search query here', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="search" name="search" type="search" value="Enter your search query here" />
def search_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "search"))
+ text_field_tag(name, value, options.merge(type: :search))
end
# Creates a text field of type "tel".
@@ -613,7 +647,7 @@ module ActionView
# telephone_field_tag 'tel', '0123456789', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="tel" name="tel" type="tel" value="0123456789" />
def telephone_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "tel"))
+ text_field_tag(name, value, options.merge(type: :tel))
end
alias phone_field_tag telephone_field_tag
@@ -635,7 +669,7 @@ module ActionView
# date_field_tag 'date', '01/01/2014', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="date" name="date" type="date" value="01/01/2014" />
def date_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "date"))
+ text_field_tag(name, value, options.merge(type: :date))
end
# Creates a text field of type "time".
@@ -646,7 +680,7 @@ module ActionView
# * <tt>:step</tt> - The acceptable value granularity.
# * Otherwise accepts the same options as text_field_tag.
def time_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "time"))
+ text_field_tag(name, value, options.merge(type: :time))
end
# Creates a text field of type "datetime".
@@ -657,7 +691,7 @@ module ActionView
# * <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"))
+ text_field_tag(name, value, options.merge(type: :datetime))
end
# Creates a text field of type "datetime-local".
@@ -668,7 +702,7 @@ module ActionView
# * <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"))
+ text_field_tag(name, value, options.merge(type: 'datetime-local'))
end
# Creates a text field of type "month".
@@ -679,7 +713,7 @@ module ActionView
# * <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"))
+ text_field_tag(name, value, options.merge(type: :month))
end
# Creates a text field of type "week".
@@ -690,7 +724,7 @@ module ActionView
# * <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"))
+ text_field_tag(name, value, options.merge(type: :week))
end
# Creates a text field of type "url".
@@ -711,7 +745,7 @@ module ActionView
# url_field_tag 'url', 'http://rubyonrails.org', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="url" name="url" type="url" value="http://rubyonrails.org" />
def url_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "url"))
+ text_field_tag(name, value, options.merge(type: :url))
end
# Creates a text field of type "email".
@@ -732,7 +766,7 @@ module ActionView
# email_field_tag 'email', 'email@example.com', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="email" name="email" type="email" value="email@example.com" />
def email_field_tag(name, value = nil, options = {})
- text_field_tag(name, value, options.stringify_keys.update("type" => "email"))
+ text_field_tag(name, value, options.merge(type: :email))
end
# Creates a number field.
@@ -769,10 +803,10 @@ module ActionView
# # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
#
# number_field_tag 'quantity', nil, min: 1, max: 10
- # # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
+ # # => <input id="quantity" name="quantity" min="1" max="10" type="number" />
#
# number_field_tag 'quantity', nil, min: 1, max: 10, step: 2
- # # => <input id="quantity" name="quantity" min="1" max="9" step="2" type="number" />
+ # # => <input id="quantity" name="quantity" min="1" max="10" step="2" type="number" />
#
# number_field_tag 'quantity', '1', class: 'special_input', disabled: true
# # => <input disabled="disabled" class="special_input" id="quantity" name="quantity" type="number" value="1" />
@@ -790,7 +824,7 @@ module ActionView
# ==== 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"))
+ number_field_tag(name, value, options.merge(type: :range))
end
# Creates the hidden UTF8 enforcer tag. Override this method in a helper
@@ -862,7 +896,7 @@ module ActionView
# see http://www.w3.org/TR/html4/types.html#type-name
def sanitize_to_id(name)
- name.to_s.delete(']').gsub(/[^-a-zA-Z0-9:.]/, "_")
+ name.to_s.delete(']').tr('^-a-zA-Z0-9:.', "_")
end
end
end