From 392817cf11e2e840eb564dd4f8713092cff167f8 Mon Sep 17 00:00:00 2001 From: "Erik St. Martin" Date: Sat, 30 Jan 2010 19:44:35 -0600 Subject: updating link_to and button_to to support :remote => true and other options such as :confirm in a unobtrusive manor Signed-off-by: Joshua Peek --- .../lib/action_view/helpers/form_tag_helper.rb | 12 ++-- actionpack/lib/action_view/helpers/url_helper.rb | 77 +++++++++++++--------- actionpack/test/template/form_tag_helper_test.rb | 6 +- actionpack/test/template/url_helper_test.rb | 25 ++++--- 4 files changed, 70 insertions(+), 50 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 048bedc7ba..0e034d781a 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -57,7 +57,7 @@ module ActionView # ==== Examples # select_tag "people", options_from_collection_for_select(@people, "name", "id") # # - # + # # select_tag "people", "" # # => # @@ -128,7 +128,7 @@ module ActionView # Creates a label field # - # ==== Options + # ==== Options # * Creates standard HTML attributes for the tag. # # ==== Examples @@ -367,7 +367,7 @@ module ActionView if disable_with = options.delete("disable_with") disable_with = "this.value='#{disable_with}'" disable_with << ";#{options.delete('onclick')}" if options['onclick'] - + options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }" options["onclick"] << "else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';" options["onclick"] << "hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }" @@ -377,8 +377,7 @@ module ActionView end if confirm = options.delete("confirm") - options["onclick"] ||= 'return true;' - options["onclick"] = "if (!#{confirm_javascript_function(confirm)}) return false; #{options['onclick']}" + add_confirm_to_attributes!(options, confirm) end tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys) @@ -411,8 +410,7 @@ module ActionView options.stringify_keys! if confirm = options.delete("confirm") - options["onclick"] ||= '' - options["onclick"] += "return #{confirm_javascript_function(confirm)};" + add_confirm_to_attributes!(options, confirm) end tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys) diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index d6bfc6d4c9..9e52275537 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -218,11 +218,11 @@ module ActionView html_options = args[2] url = url_for(options) + html_options = convert_options_to_data_attributes(options, html_options) if html_options html_options = html_options.stringify_keys href = html_options['href'] - convert_options_to_javascript!(html_options, url) tag_options = tag_options(html_options) else tag_options = nil @@ -291,14 +291,10 @@ module ActionView request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) end - if confirm = html_options.delete("confirm") - html_options["onclick"] = "return #{confirm_javascript_function(confirm)};" - end - url = options.is_a?(String) ? options : self.url_for(options) name ||= url - convert_options_to_javascript!(html_options, url) + html_options = convert_options_to_data_attributes(options, html_options) html_options.merge!("type" => "submit", "value" => name) @@ -551,46 +547,65 @@ module ActionView end private - def convert_options_to_javascript!(html_options, url = '') + def convert_options_to_data_attributes(options, html_options) + html_options = {} if html_options.nil? + html_options = html_options.stringify_keys + + if (options.is_a?(Hash) && options.key?('remote')) || (html_options.is_a?(Hash) && html_options.key?('remote')) + html_options['data-remote'] = 'true' + options.delete('remote') if options.is_a?(Hash) + html_options.delete('remote') if html_options.is_a?(Hash) + end + confirm = html_options.delete("confirm") - method, href = html_options.delete("method"), html_options['href'] if html_options.key?("popup") ActiveSupport::Deprecation.warn(":popup has been deprecated", caller) end - html_options["onclick"] = case - when confirm && method - "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method, url, href)} };return false;" - when confirm - "return #{confirm_javascript_function(confirm)};" - when method - "#{method_javascript_function(method, url, href)}return false;" - else - html_options["onclick"] + method, href = html_options.delete("method"), html_options['href'] + + if confirm && method + add_confirm_to_attributes!(html_options, confirm) + add_method_to_attributes!(html_options, method) + elsif confirm + add_confirm_to_attributes!(html_options, confirm) + elsif method + add_method_to_attributes!(html_options, method) end + + html_options["data-url"] = options[:url] if options.is_a?(Hash) && options[:url] + + html_options end - def confirm_javascript_function(confirm) - "confirm('#{escape_javascript(confirm)}')" + def add_confirm_to_attributes!(html_options, confirm) + html_options["data-confirm"] = confirm if confirm end - def method_javascript_function(method, url = '', href = nil) - action = (href && url.size > 0) ? "'#{url}'" : 'this.href' - submit_function = - "var f = document.createElement('form'); f.style.display = 'none'; " + - "this.parentNode.appendChild(f); f.method = 'POST'; f.action = #{action};" + def add_method_to_attributes!(html_options, method) + html_options["rel"] = "nofollow" if method && method.to_s.downcase == "delete" + html_options["data-method"] = method if method + end - unless method == :post - submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); " - submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);" + def add_disable_with_to_attributes!(html_options, disable_with) + html_options["data-disable-with"] = disable_with if disable_with + end + + def options_for_javascript(options) + if options.empty? + '{}' + else + "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}" end + end - if protect_against_forgery? - submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); " - submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);" + def array_or_string_for_javascript(option) + if option.kind_of?(Array) + "['#{option.join('\',\'')}']" + elsif !option.nil? + "'#{option}'" end - submit_function << "f.submit();" end # Processes the +html_options+ hash, converting the boolean diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 47462b1237..41ab5c1621 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -299,21 +299,21 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag_with_confirmation assert_dom_equal( - %(), + %(), submit_tag("Save", :confirm => "Are you sure?") ) end def test_submit_tag_with_confirmation_and_with_disable_with assert_dom_equal( - %(), + %(), submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?") ) end def test_image_submit_tag_with_confirmation assert_dom_equal( - %(), + %(), image_submit_tag("save.gif", :confirm => "Are you sure?") ) end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index dd28aec786..6d9384d40b 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -76,7 +76,7 @@ class UrlHelperTest < ActionView::TestCase def test_button_to_with_javascript_confirm assert_dom_equal( - "
", + "
", button_to("Hello", "http://www.example.com", :confirm => "Are you sure?") ) end @@ -170,50 +170,57 @@ class UrlHelperTest < ActionView::TestCase def test_link_tag_with_javascript_confirm assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :confirm => "Are you sure?") ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure, can you?") ) assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :confirm => "You can't possibly be sure,\n can you?") ) end + def test_link_to_with_remote + assert_dom_equal( + "Hello", + link_to("Hello", "http://www.example.com", :remote => true) + ) + end + def test_link_tag_using_post_javascript assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :method => :post) ) end def test_link_tag_using_delete_javascript assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete) ) end def test_link_tag_using_delete_javascript_and_href assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#') ) end def test_link_tag_using_post_javascript_and_confirm assert_dom_equal( - "Hello", + "Hello", link_to("Hello", "http://www.example.com", :method => :post, :confirm => "Are you serious?") ) end def test_link_tag_using_delete_javascript_and_href_and_confirm assert_dom_equal( - "Destroy", + "Destroy", link_to("Destroy", "http://www.example.com", :method => :delete, :href => '#', :confirm => "Are you serious?"), "When specifying url, form should be generated with it, but not this.href" ) -- cgit v1.2.3