mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Added :post option to UrlHelper#link_to that makes it possible to do POST requests through normal ahref links using Javascript
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2149 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
2f66e873b0
commit
7e3dc807df
3 changed files with 62 additions and 22 deletions
|
@ -1,5 +1,7 @@
|
||||||
*SVN*
|
*SVN*
|
||||||
|
|
||||||
|
* Added :post option to UrlHelper#link_to that makes it possible to do POST requests through normal ahref links using Javascript
|
||||||
|
|
||||||
* Fixed overwrite_params
|
* Fixed overwrite_params
|
||||||
|
|
||||||
* Added ActionController::Base.benchmark and ActionController::Base.silence to allow for easy benchmarking and turning off the log
|
* Added ActionController::Base.benchmark and ActionController::Base.silence to allow for easy benchmarking and turning off the log
|
||||||
|
|
|
@ -20,16 +20,22 @@ module ActionView
|
||||||
# link:classes/ActionController/Base.html#M000021. It's also possible to pass a string instead of an options hash to
|
# link:classes/ActionController/Base.html#M000021. It's also possible to pass a string instead of an options hash to
|
||||||
# get a link tag that just points without consideration. If nil is passed as a name, the link itself will become the name.
|
# get a link tag that just points without consideration. If nil is passed as a name, the link itself will become the name.
|
||||||
#
|
#
|
||||||
# The html_options has two special features. One for creating javascript confirm alerts where if you pass :confirm => 'Are you sure?',
|
# The html_options has three special features. One for creating javascript confirm alerts where if you pass :confirm => 'Are you sure?',
|
||||||
# the link will be guarded with a JS popup asking that question. If the user accepts, the link is processed, otherwise not.
|
# the link will be guarded with a JS popup asking that question. If the user accepts, the link is processed, otherwise not.
|
||||||
#
|
#
|
||||||
# The other for creating a popup window, which is done by either passing :popup with true or the options of the window in
|
# Another for creating a popup window, which is done by either passing :popup with true or the options of the window in
|
||||||
# Javascript form.
|
# Javascript form.
|
||||||
#
|
#
|
||||||
|
# And a third for making the link do a POST request (instead of the regular GET) through a dynamically added form element that
|
||||||
|
# is instantly submitted. Note that if the user has turned off Javascript, the request will fall back on the GET. So its
|
||||||
|
# your responsibility to determine what the action should be once it arrives at the controller. The POST form is turned on by
|
||||||
|
# passing :post as true. Note, it's not possible to use POST requests and popup targets at the same time (an exception will be thrown).
|
||||||
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?"
|
# link_to "Delete this page", { :action => "destroy", :id => @page.id }, :confirm => "Are you sure?"
|
||||||
# link_to "Help", { :action => "help" }, :popup => true
|
# link_to "Help", { :action => "help" }, :popup => true
|
||||||
# link_to "Busy loop", { :action => "busy" }, :popup => ['new_window', 'height=300,width=600']
|
# link_to "Busy loop", { :action => "busy" }, :popup => ['new_window', 'height=300,width=600']
|
||||||
|
# link_to "Destroy account", { :action => "destroy" }, :confirm => "Are you sure?", :post => true
|
||||||
def link_to(name, options = {}, html_options = nil, *parameters_for_method_reference)
|
def link_to(name, options = {}, html_options = nil, *parameters_for_method_reference)
|
||||||
html_options = (html_options || {}).stringify_keys
|
html_options = (html_options || {}).stringify_keys
|
||||||
convert_options_to_javascript!(html_options)
|
convert_options_to_javascript!(html_options)
|
||||||
|
@ -90,15 +96,20 @@ module ActionView
|
||||||
# +td+ element or in between +p+ elements, but not in the middle of
|
# +td+ element or in between +p+ elements, but not in the middle of
|
||||||
# a run of text, nor can you place a form within another form.
|
# a run of text, nor can you place a form within another form.
|
||||||
# (Bottom line: Always validate your HTML before going public.)
|
# (Bottom line: Always validate your HTML before going public.)
|
||||||
|
|
||||||
def button_to(name, options = {}, html_options = nil)
|
def button_to(name, options = {}, html_options = nil)
|
||||||
html_options = (html_options || {}).stringify_keys
|
html_options = (html_options || {}).stringify_keys
|
||||||
convert_boolean_attributes!(html_options, %w( disabled ))
|
convert_boolean_attributes!(html_options, %w( disabled ))
|
||||||
convert_confirm_option_to_javascript!(html_options)
|
|
||||||
url, name = options.is_a?(String) ?
|
if confirm = html_options.delete("confirm")
|
||||||
|
html_options["onclick"] = "return #{confirm_javascript_function(confirm)};"
|
||||||
|
end
|
||||||
|
|
||||||
|
url, name = options.is_a?(String) ?
|
||||||
[ options, name || options ] :
|
[ options, name || options ] :
|
||||||
[ url_for(options), name || url_for(options) ]
|
[ url_for(options), name || url_for(options) ]
|
||||||
|
|
||||||
html_options.merge!("type" => "submit", "value" => name)
|
html_options.merge!("type" => "submit", "value" => name)
|
||||||
|
|
||||||
"<form method=\"post\" action=\"#{h url}\" class=\"button-to\"><div>" +
|
"<form method=\"post\" action=\"#{h url}\" class=\"button-to\"><div>" +
|
||||||
tag("input", html_options) + "</div></form>"
|
tag("input", html_options) + "</div></form>"
|
||||||
end
|
end
|
||||||
|
@ -227,26 +238,37 @@ module ActionView
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def convert_confirm_option_to_javascript!(html_options)
|
def convert_options_to_javascript!(html_options)
|
||||||
if confirm = html_options.delete("confirm")
|
confirm, popup, post = html_options.delete("confirm"), html_options.delete("popup"), html_options.delete("post")
|
||||||
html_options["onclick"] = "return confirm('#{escape_javascript(confirm)}');"
|
|
||||||
return confirm
|
html_options["onclick"] = case
|
||||||
|
when popup && post
|
||||||
|
raise ActionView::ActionViewError, "You can't use :popup and :post in the same link"
|
||||||
|
when confirm && popup
|
||||||
|
"if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;"
|
||||||
|
when confirm && post
|
||||||
|
"if (#{confirm_javascript_function(confirm)}) { #{post_javascript_function} };return false;"
|
||||||
|
when confirm
|
||||||
|
"return #{confirm_javascript_function(confirm)};"
|
||||||
|
when post
|
||||||
|
"#{post_javascript_function}return false;"
|
||||||
|
when popup
|
||||||
|
popup_javascript_function(popup) + 'return false;'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def convert_popup_option_to_javascript!(html_options, confirm_message = false)
|
def confirm_javascript_function(confirm)
|
||||||
if popup = html_options.delete("popup")
|
"confirm('#{escape_javascript(confirm)}')"
|
||||||
popup_js = popup.is_a?(Array) ? "window.open(this.href,'#{popup.first}','#{popup.last}');" : "window.open(this.href);"
|
|
||||||
html_options["onclick"] = popup_js + 'return false;' unless confirm_message
|
|
||||||
html_options["onclick"] = "if (confirm('#{escape_javascript(confirm_message)}')) { #{popup_js} };return false;" if confirm_message
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def convert_options_to_javascript!(html_options)
|
|
||||||
confirm_message = convert_confirm_option_to_javascript!(html_options)
|
|
||||||
convert_popup_option_to_javascript!(html_options, confirm_message)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def popup_javascript_function(popup)
|
||||||
|
popup.is_a?(Array) ? "window.open(this.href,'#{popup.first}','#{popup.last}');" : "window.open(this.href);"
|
||||||
|
end
|
||||||
|
|
||||||
|
def post_javascript_function
|
||||||
|
"f = document.createElement('form'); document.body.appendChild(f); f.method = 'POST'; f.action = url; f.submit();"
|
||||||
|
end
|
||||||
|
|
||||||
# Processes the _html_options_ hash, converting the boolean
|
# Processes the _html_options_ hash, converting the boolean
|
||||||
# attributes from true/false form into the form required by
|
# attributes from true/false form into the form required by
|
||||||
# HTML/XHTML. (An attribute is considered to be boolean if
|
# HTML/XHTML. (An attribute is considered to be boolean if
|
||||||
|
@ -270,12 +292,10 @@ module ActionView
|
||||||
#
|
#
|
||||||
# convert_boolean_attributes!( html_options,
|
# convert_boolean_attributes!( html_options,
|
||||||
# %w( checked disabled readonly ) )
|
# %w( checked disabled readonly ) )
|
||||||
|
|
||||||
def convert_boolean_attributes!(html_options, bool_attrs)
|
def convert_boolean_attributes!(html_options, bool_attrs)
|
||||||
bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
|
bool_attrs.each { |x| html_options[x] = x if html_options.delete(x) }
|
||||||
html_options
|
html_options
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -88,6 +88,24 @@ class UrlHelperTest < Test::Unit::TestCase
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_link_tag_using_post_javascript
|
||||||
|
assert_equal(
|
||||||
|
"<a href=\"http://www.example.com\" onclick=\"f = document.createElement('form'); document.body.appendChild(f); f.method = 'POST'; f.action = url; f.submit();return false;\">Hello</a>",
|
||||||
|
link_to("Hello", "http://www.example.com", :post => true)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_link_tag_using_post_javascript_and_confirm
|
||||||
|
assert_equal(
|
||||||
|
"<a href=\"http://www.example.com\" onclick=\"if (confirm('Are you serious?')) { f = document.createElement('form'); document.body.appendChild(f); f.method = 'POST'; f.action = url; f.submit(); };return false;\">Hello</a>",
|
||||||
|
link_to("Hello", "http://www.example.com", :post => true, :confirm => "Are you serious?")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_link_tag_using_post_javascript_and_popup
|
||||||
|
assert_raises(ActionView::ActionViewError) { link_to("Hello", "http://www.example.com", :popup => true, :post => true, :confirm => "Are you serious?") }
|
||||||
|
end
|
||||||
|
|
||||||
def test_link_to_unless
|
def test_link_to_unless
|
||||||
assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog")
|
assert_equal "Showing", link_to_unless(true, "Showing", :action => "show", :controller => "weblog")
|
||||||
assert "<a href=\"http://www.example.com\">Listing</a>", link_to_unless(false, "Listing", :action => "list", :controller => "weblog")
|
assert "<a href=\"http://www.example.com\">Listing</a>", link_to_unless(false, "Listing", :action => "list", :controller => "weblog")
|
||||||
|
|
Loading…
Reference in a new issue