提交 3822a322 编写于 作者: J Justin Schiff

Make disable_with default in submit_tag

Prevents double submission by making disable_with the default.

Default disable_with option will only be applied if user has not
specified her/his own disable_with option, whether that is in the
`data-disable-with` string form or the
`:data => { :disable_with => "Saving..." }` hash form. disable_with
will default to the value attribute.

A configuration option was added to opt out of this functionality if
the user so desires.
`config.action_view.automatically_disable_submit_tag = false`
上级 e69364bc
* Make `disable_with` the default behavior for submit tags. Disables the
button on submit to prevent double submits.
*Justin Schiff*
* Add a break_sequence option to word_wrap so you can specify a custom break.
* Mauricio Gomez *
......
......@@ -161,6 +161,10 @@ class Base
cattr_accessor :raise_on_missing_translations
@@raise_on_missing_translations = false
# Specify whether submit_tag should automatically disable on click
cattr_accessor :automatically_disable_submit_tag
@@automatically_disable_submit_tag = true
class_attribute :_routes
class_attribute :logger
......
......@@ -414,34 +414,48 @@ def radio_button_tag(name, value, checked = false, options = {})
# 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.delete("data-disable-with")
tag_options["data"].delete(:disable_with) if tag_options["data"]
end
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,
......
......@@ -1577,7 +1577,7 @@ def test_form_for
"<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='commit' type='submit' value='Create post' />" +
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" +
"<button name='button' type='submit'>Create post</button>" +
"<button name='button' type='submit'><span>Create post</span></button>"
end
......@@ -1854,7 +1854,7 @@ def test_form_for_with_model_using_relative_model_naming
expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do
"<input name='post[title]' type='text' id='post_title' value='And his name will be forty and four.' />" +
"<input name='commit' type='submit' value='Edit post' />"
"<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
assert_dom_equal expected, output_buffer
......@@ -1875,7 +1875,7 @@ def test_form_for_with_symbol_object_name
"<textarea name='other_name[body]' id='other_name_body'>\nBack to the hill and over it again!</textarea>" +
"<input name='other_name[secret]' value='0' type='hidden' />" +
"<input name='other_name[secret]' checked='checked' id='other_name_secret' value='1' type='checkbox' />" +
"<input name='commit' value='Create post' type='submit' />"
"<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
assert_dom_equal expected, output_buffer
......@@ -2083,7 +2083,7 @@ def test_form_for_label_error_wrapping
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
"<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
"<input name='commit' type='submit' value='Create post' />"
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
......@@ -2101,7 +2101,7 @@ def test_form_for_label_error_wrapping_without_conventional_instance_variable
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
"<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
"<input name='commit' type='submit' value='Create post' />"
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
......@@ -2226,7 +2226,7 @@ def test_submit_with_object_as_new_record_and_locale_strings
end
expected = whole_form('/posts', 'new_post', 'new_post') do
"<input name='commit' type='submit' value='Create Post' />"
"<input name='commit' data-disable-with='Create Post' type='submit' value='Create Post' />"
end
assert_dom_equal expected, output_buffer
......@@ -2240,7 +2240,7 @@ def test_submit_with_object_as_existing_record_and_locale_strings
end
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
"<input name='commit' type='submit' value='Confirm Post changes' />"
"<input name='commit' data-disable-with='Confirm Post changes' type='submit' value='Confirm Post changes' />"
end
assert_dom_equal expected, output_buffer
......@@ -2254,7 +2254,7 @@ def test_submit_without_object_and_locale_strings
end
expected = whole_form do
"<input name='commit' class='extra' type='submit' value='Save changes' />"
"<input name='commit' class='extra' data-disable-with='Save changes' type='submit' value='Save changes' />"
end
assert_dom_equal expected, output_buffer
......@@ -2268,7 +2268,7 @@ def test_submit_with_object_and_nested_lookup
end
expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do
"<input name='commit' type='submit' value='Update your Post' />"
"<input name='commit' data-disable-with='Update your Post' type='submit' value='Update your Post' />"
end
assert_dom_equal expected, output_buffer
......
......@@ -433,6 +433,44 @@ def test_submit_tag
)
end
def test_empty_submit_tag
assert_dom_equal(
%(<input data-disable-with="Save" name='commit' type="submit" value="Save" />),
submit_tag("Save")
)
end
def test_empty_submit_tag_with_opt_out
ActionView::Base.automatically_disable_submit_tag = false
assert_dom_equal(
%(<input name='commit' type="submit" value="Save" />),
submit_tag("Save")
)
ensure
ActionView::Base.automatically_disable_submit_tag = true
end
def test_data_disable_with_string
assert_dom_equal(
%(<input data-disable-with="Processing..." data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" })
)
end
def test_data_disable_with_boolean
assert_dom_equal(
%(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" })
)
end
def test_data_hash_disable_with_boolean
assert_dom_equal(
%(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } })
)
end
def test_submit_tag_with_no_onclick_options
assert_dom_equal(
%(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
......@@ -442,7 +480,7 @@ def test_submit_tag_with_no_onclick_options
def test_submit_tag_with_confirmation
assert_dom_equal(
%(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />),
%(<input name='commit' type='submit' value='Save' data-confirm="Are you sure?" data-disable-with="Save" />),
submit_tag("Save", :data => { :confirm => "Are you sure?" })
)
end
......
......@@ -451,6 +451,9 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`.
* `config.action_view.raise_on_missing_translations` determines whether an
error should be raised for missing translations.
* `config.action_view.automatically_disable_submit_tag` determines whether
submit_tag should automatically disable on click, this defaults to true.
### Configuring Action Mailer
There are a number of settings available on `config.action_mailer`:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册