From d6c35ec37875d8aa73497b6e1f43e1919d30801e Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Wed, 15 Jun 2011 18:20:00 -0400 Subject: [PATCH 001/226] Fixed intermittently failing test in FF. --- test/public/test/call-remote-callbacks.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/public/test/call-remote-callbacks.js b/test/public/test/call-remote-callbacks.js index 126c9bb3..c15b078e 100644 --- a/test/public/test/call-remote-callbacks.js +++ b/test/public/test/call-remote-callbacks.js @@ -235,6 +235,7 @@ asyncTest('"ajax:beforeSend", "ajax:error" and "ajax:complete" are triggered on }); }); +// IF THIS TEST IS FAILING, TRY INCREASING THE TIMEOUT AT THE BOTTOM TO > 100 asyncTest('binding to ajax callbacks via .live() triggers handlers properly', 3, function() { $('form[data-remote]') .live('ajax:beforeSend', function() { @@ -250,7 +251,7 @@ asyncTest('binding to ajax callbacks via .live() triggers handlers properly', 3, setTimeout(function() { start(); - }, 13); + }, 63); }); })(); From 4188a64eeca650935d0aeaa1cec181f926c99b4e Mon Sep 17 00:00:00 2001 From: Ciaran Lee Date: Fri, 27 May 2011 17:45:37 +0100 Subject: [PATCH 002/226] fixing cross domain AJAX for jQuery > 1.5 --- src/rails.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rails.js b/src/rails.js index 5f726be0..f2eb83ad 100644 --- a/src/rails.js +++ b/src/rails.js @@ -95,6 +95,7 @@ // Submits "remote" forms and links with ajax handleRemote: function(element) { var method, url, data, + crossDomain = element.data('cross-domain') || false, dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); if (rails.fire(element, 'ajax:before')) { @@ -116,7 +117,7 @@ } rails.ajax({ - url: url, type: method || 'GET', data: data, dataType: dataType, + url: url, type: method || 'GET', data: data, dataType: dataType, crossDomain: crossDomain, // stopping the "ajax:beforeSend" event will cancel the ajax request beforeSend: function(xhr, settings) { if (settings.dataType === undefined) { @@ -244,7 +245,7 @@ // ajaxPrefilter is a jQuery 1.5 feature if ('ajaxPrefilter' in $) { - $.ajaxPrefilter(function(options, originalOptions, xhr){ rails.CSRFProtection(xhr); }); + $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); } else { $(document).ajaxSend(function(e, xhr){ rails.CSRFProtection(xhr); }); } From 616e4fe354ce0ae5137636f9b5475782a7c9e896 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Wed, 15 Jun 2011 18:02:25 -0400 Subject: [PATCH 003/226] Created test for CSRF token being excluded when data-cross-domain=true. Fixed token-header-exclusion for jquery 1.4.4. Also created test for intelligently guessing cross-domain behavior when target url is on a different domain, and fixed behavior for this case. See Issue #167 for all relevant discussion. --- src/rails.js | 4 ++-- test/public/test/call-remote.js | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/rails.js b/src/rails.js index f2eb83ad..5397d669 100644 --- a/src/rails.js +++ b/src/rails.js @@ -95,7 +95,7 @@ // Submits "remote" forms and links with ajax handleRemote: function(element) { var method, url, data, - crossDomain = element.data('cross-domain') || false, + crossDomain = element.data('cross-domain') || null, dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); if (rails.fire(element, 'ajax:before')) { @@ -247,7 +247,7 @@ if ('ajaxPrefilter' in $) { $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); } else { - $(document).ajaxSend(function(e, xhr){ rails.CSRFProtection(xhr); }); + $(document).ajaxSend(function(e, xhr, options){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); } $(rails.linkClickSelector).live('click.rails', function(e) { diff --git a/test/public/test/call-remote.js b/test/public/test/call-remote.js index 33f5c59d..b2373695 100644 --- a/test/public/test/call-remote.js +++ b/test/public/test/call-remote.js @@ -92,4 +92,41 @@ asyncTest('sends CSRF token in custom header', 1, function() { }); }); +asyncTest('does not send CSRF token in custom header if crossDomain', 1, function() { + build_form({ 'data-cross-domain': 'true' }); + $('#qunit-fixture').append(''); + + // Manually set request header to be XHR, since setting crossDomain: true in .ajax() + // causes jQuery to skip setting the request header, to prevent our test/server.rb from + // raising an an error (when request.xhr? is false). + $('#qunit-fixture').find('form').bind('ajax:beforeSend', function(e, xhr) { + xhr.setRequestHeader('X-Requested-With', "XMLHttpRequest"); + }); + + submit(function(e, data, status, xhr) { + equal(data.HTTP_X_CSRF_TOKEN, undefined, 'X-CSRF-Token header should NOT be sent'); + }); +}); + +asyncTest('intelligently guesses crossDomain behavior when target URL is a different domain', 1, function(e, xhr) { + + // Don't set data-cross-domain here, just set action to be a different domain than localhost + build_form({ action: 'http://www.alfajango.com' }); + $('#qunit-fixture').append(''); + + $('#qunit-fixture').find('form') + .bind('ajax:beforeSend', function(e, xhr, settings) { + + // crossDomain doesn't work with jquery 1.4, because it wasn't added until 1.5 + if (jQuery().jquery.indexOf('1.4') === 0) strictEqual(settings.crossDomain, null) + else equal(settings.crossDomain, true, 'crossDomain should be set to true'); + + // prevent request from actually getting sent off-domain + return false; + }) + .trigger('submit'); + + setTimeout(function() { start(); }, 13); +}); + })(); From e33f3f7a156709949d8ec7db99fbff4ac9b8f5dd Mon Sep 17 00:00:00 2001 From: Otavio Medeiros Date: Tue, 7 Jun 2011 23:24:04 -0300 Subject: [PATCH 004/226] added remote => true to on change event in select option --- src/rails.js | 18 +++++++++++++++++- test/public/test/data-remote.js | 25 ++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/rails.js b/src/rails.js index a129ef4a..44e097f3 100644 --- a/src/rails.js +++ b/src/rails.js @@ -51,6 +51,9 @@ // Link elements bound by jquery-ujs linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]', + // Select elements bound by jquery-ujs + selectChangeSelector: 'select[data-remote]', + // Form elements bound by jquery-ujs formSubmitSelector: 'form', @@ -109,7 +112,12 @@ data.push(button); element.data('ujs:submit-button', null); } - } else { + } else if (element.is('select')) { + method = element.data('method'); + url = element.data('url'); + data = element.serialize(); + if (element.data('params')) data = data + "&" + element.data('params'); + } else { method = element.data('method'); url = element.attr('href'); data = element.data('params') || null; @@ -262,6 +270,14 @@ } }); + $(rails.selectChangeSelector).live('change.rails', function(e) { + var link = $(this); + if (!rails.allowAction(link)) return rails.stopEverything(e); + + rails.handleRemote(link); + return false; + }); + $(rails.formSubmitSelector).live('submit.rails', function(e) { var form = $(this), remote = form.data('remote') !== undefined, diff --git a/test/public/test/data-remote.js b/test/public/test/data-remote.js index a498cf5f..19bdcbca 100644 --- a/test/public/test/data-remote.js +++ b/test/public/test/data-remote.js @@ -12,7 +12,16 @@ module('data-remote', { 'data-remote': 'true', method: 'post' })) - .find('form').append($('')); + .find('form').append($('')) + .append($('')) - .append($('')); + } }); @@ -39,6 +31,18 @@ asyncTest('clicking on a link with data-remote attribute', 5, function() { }); asyncTest('changing a select option with data-remote attribute', 5, function() { + $('form') + .append( + $('')) + .attr("novalidate", "novalidate") + .bind('ajax:beforeSend', function() { + ok(true, 'ajax:beforeSend should run'); + }) + .bind('ajax:complete', function() { + ok(true, 'ajax:complete should run') + }) + .trigger('submit'); + + setTimeout(function() { + start(); + }, 13); +}); + +asyncTest('blank required form input for non-remote form with "novalidate" attribute should not abort normal submission', 1, function() { + var form = $('form[data-remote]') + .append($('')) + .removeAttr('data-remote') + .attr("novalidate","novalidate") + .bind('iframe:loading', function() { + ok(true, 'form should get submitted'); + }) + .trigger('submit'); + + setTimeout(function() { + start(); + }, 13); +}); + function skipIt() { // This test cannot work due to the security feature in browsers which makes the value // attribute of file input fields readonly, so it cannot be set with default value. From 36a81a3e9a44246391b554f105e7e83f86a66c75 Mon Sep 17 00:00:00 2001 From: Rafael Barbosa Date: Sat, 30 Jul 2011 14:52:33 -0300 Subject: [PATCH 013/226] Changing the order of evaluation so the abort:required event won't be fired on forms with the novalidate attribute. --- src/rails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rails.js b/src/rails.js index 5da48602..b17d5e79 100644 --- a/src/rails.js +++ b/src/rails.js @@ -287,7 +287,7 @@ if (!rails.allowAction(form)) return rails.stopEverything(e); // skip other logic when required values are missing or file upload is present - if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs]) && form.attr("novalidate") == undefined) { + if (blankRequiredInputs && form.attr("novalidate") == undefined && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { return rails.stopEverything(e); } From cd619df9f0daad3303aacd4f992fff19158b1e5d Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Wed, 10 Aug 2011 16:27:01 -0400 Subject: [PATCH 014/226] Fixed up test for novalidate attribute --- test/public/test/call-remote-callbacks.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/test/public/test/call-remote-callbacks.js b/test/public/test/call-remote-callbacks.js index 57d4f59c..939f523f 100644 --- a/test/public/test/call-remote-callbacks.js +++ b/test/public/test/call-remote-callbacks.js @@ -120,7 +120,7 @@ asyncTest('form should be submitted with blank required fields if handler is bou }, 13); }); -asyncTest('disabled fields should not be included in blank required check', 1, function() { +asyncTest('disabled fields should not be included in blank required check', 2, function() { var form = $('form[data-remote]') .append($('')) .append($('')) @@ -129,12 +129,9 @@ asyncTest('disabled fields should not be included in blank required check', 1, f }) .bind('ajax:aborted:required', function() { ok(false, 'ajax:aborted:required should not run'); - }) - .trigger('submit'); + }); - setTimeout(function() { - start(); - }, 13); + submit(); }); asyncTest('form should be submitted with blank required fields if it has the "novalidate" attribute', 2, function(){ @@ -144,14 +141,11 @@ asyncTest('form should be submitted with blank required fields if it has the "no .bind('ajax:beforeSend', function() { ok(true, 'ajax:beforeSend should run'); }) - .bind('ajax:complete', function() { - ok(true, 'ajax:complete should run') - }) - .trigger('submit'); + .bind('ajax:aborted:required', function() { + ok(false, 'ajax:aborted:required should not run'); + }); - setTimeout(function() { - start(); - }, 13); + submit(); }); asyncTest('blank required form input for non-remote form with "novalidate" attribute should not abort normal submission', 1, function() { From 4bf967e8daa0421287af1bf9242eb4ce41b5c469 Mon Sep 17 00:00:00 2001 From: Radoslav Stankov Date: Tue, 16 Aug 2011 15:06:16 +0300 Subject: [PATCH 015/226] Prevent global variable leak --- src/rails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rails.js b/src/rails.js index b17d5e79..017f32b7 100644 --- a/src/rails.js +++ b/src/rails.js @@ -124,7 +124,7 @@ data = element.data('params') || null; } - options = { + var options = { type: method || 'GET', data: data, dataType: dataType, crossDomain: crossDomain, // stopping the "ajax:beforeSend" event will cancel the ajax request beforeSend: function(xhr, settings) { From b4e3e1a3f8aba47b4d456ccf38c973ca90e8d3b8 Mon Sep 17 00:00:00 2001 From: Radoslav Stankov Date: Tue, 16 Aug 2011 15:07:06 +0300 Subject: [PATCH 016/226] Minor optimization --- src/rails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rails.js b/src/rails.js index 017f32b7..236cfa40 100644 --- a/src/rails.js +++ b/src/rails.js @@ -144,7 +144,7 @@ } }; // Do not pass url to `ajax` options if blank - if (url) { $.extend(options, { url: url }); } + if (url) { options.url = url; } rails.ajax(options); } From 296815268b4469ccdd2f23970cc2efe985fa6fa3 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Mon, 29 Aug 2011 18:59:46 -0400 Subject: [PATCH 017/226] Updated options var --- src/rails.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rails.js b/src/rails.js index 236cfa40..d6e585fa 100644 --- a/src/rails.js +++ b/src/rails.js @@ -99,7 +99,8 @@ handleRemote: function(element) { var method, url, data, crossDomain = element.data('cross-domain') || null, - dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); + dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType), + options; if (rails.fire(element, 'ajax:before')) { @@ -124,7 +125,7 @@ data = element.data('params') || null; } - var options = { + options = { type: method || 'GET', data: data, dataType: dataType, crossDomain: crossDomain, // stopping the "ajax:beforeSend" event will cancel the ajax request beforeSend: function(xhr, settings) { @@ -143,7 +144,7 @@ element.trigger('ajax:error', [xhr, status, error]); } }; - // Do not pass url to `ajax` options if blank + // Only pass url to `ajax` options if not blank if (url) { options.url = url; } rails.ajax(options); From d9f55ec9ee66504ab17959fee3cb14a9afadfc52 Mon Sep 17 00:00:00 2001 From: Akzhan Abdulin Date: Wed, 31 Aug 2011 17:02:37 +0400 Subject: [PATCH 018/226] GitHub syntax highlighting in README --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8e50a82c..5e13d998 100644 --- a/README.md +++ b/README.md @@ -61,15 +61,17 @@ For Rails 2, you will need to manually implement the `csrf_meta_tag` helper and The `csrf_meta_tags` (Rails 3.1) and `csrf_meta_tag` (Rails 3.0) helpers generate two meta tags containing values necessary for the [cross-site request forgery protection][csrf] built into Rails. Here is how to implement that helper in Rails 2: - # app/helpers/application_helper.rb - def csrf_meta_tag - if protect_against_forgery? - out = %(\n) - out << %() - out % [ Rack::Utils.escape_html(request_forgery_protection_token), - Rack::Utils.escape_html(form_authenticity_token) ] - end +```ruby + # app/helpers/application_helper.rb + def csrf_meta_tag + if protect_against_forgery? + out = %(\n) + out << %() + out % [ Rack::Utils.escape_html(request_forgery_protection_token), + Rack::Utils.escape_html(form_authenticity_token) ] end + end +``` [data]: http://dev.w3.org/html5/spec/elements.html#embedding-custom-non-visible-data-with-the-data-attributes "Embedding custom non-visible data with the data-* attributes" [wiki]: https://github.com/rails/jquery-ujs/wiki From 9b8af35a817517e1f7158ba0e7eb61d219e168a5 Mon Sep 17 00:00:00 2001 From: Akzhan Abdulin Date: Wed, 31 Aug 2011 17:05:10 +0400 Subject: [PATCH 019/226] more syntax highlights --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5e13d998..0a200d8e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,9 @@ Installation For automated installation in Rails, use the "jquery-rails" gem. Place this in your Gemfile: - gem 'jquery-rails', '>= 1.0.12' +```ruby +gem 'jquery-rails', '>= 1.0.12' +``` And run: @@ -35,8 +37,10 @@ This next step depends on your version of Rails. a. For Rails 3.1, add these lines to the top of your app/assets/javascripts/application.js file: - //= require jquery - //= require jquery_ujs +```javascript +//= require jquery +//= require jquery_ujs +``` b. For Rails 3.0, run this command (add `--ui` if you want jQuery UI): @@ -53,7 +57,9 @@ Choose to overwrite jquery_ujs.js if prompted.* Configure the following in your application startup file: - config.action_view.javascript_expansions[:defaults] = %w(jquery rails) +```ruby + config.action_view.javascript_expansions[:defaults] = %w(jquery rails) +``` Now the template helper `javascript_include_tag :defaults` will generate SCRIPT tags to load jQuery and rails.js. From ee275d15342c41f9088137829b1a9b9c0cf304be Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Wed, 31 Aug 2011 10:44:17 -0400 Subject: [PATCH 020/226] Fixed blank url test for jquery 1.6.2 --- test/public/test/call-remote.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/public/test/call-remote.js b/test/public/test/call-remote.js index 0a420b13..b5e3a8d3 100644 --- a/test/public/test/call-remote.js +++ b/test/public/test/call-remote.js @@ -98,7 +98,7 @@ asyncTest('allow empty form "action"', 1, function() { } // Actual location (strip out settings.data that jQuery serializes and appends) - ajaxLocation = settings.url.replace(settings.data,"").replace(/&$/, ""); + ajaxLocation = settings.url.replace(settings.data,"").replace(/&$/, "").replace(/\?$/, ""); equal(ajaxLocation.match(/^(.*)/)[1], currentLocation, 'URL should be current page by default'); // Prevent the request from actually getting sent to the current page and From 840ab6ac76b2d5ab931841bc3d8567e5b57f183e Mon Sep 17 00:00:00 2001 From: Akzhan Abdulin Date: Fri, 2 Sep 2011 12:05:59 +0400 Subject: [PATCH 021/226] Add jQuery version 1.6.3 to tests, and use it by default --- test/server.rb | 8 +++++++- test/views/index.erb | 10 ++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/test/server.rb b/test/server.rb index 095eed0e..8a9bc259 100644 --- a/test/server.rb +++ b/test/server.rb @@ -1,6 +1,8 @@ require 'sinatra' require 'json' +JQUERY_VERSIONS = %w[ 1.6 1.6.1 1.6.2 1.6.3 ].freeze + use Rack::Static, :urls => ["/src"], :root => File.expand_path('..', settings.root) helpers do @@ -39,10 +41,14 @@ def script_tag src src = "/test/#{src}.js" unless src.index('/') %() end + + def jquery_versions + JQUERY_VERSIONS + end end get '/' do - params[:version] ||= '1.6.2' + params[:version] ||= JQUERY_VERSIONS.last params[:cdn] ||= 'jquery' erb :index end diff --git a/test/views/index.erb b/test/views/index.erb index 3ec4c6f2..21c7bc6c 100644 --- a/test/views/index.erb +++ b/test/views/index.erb @@ -10,10 +10,12 @@
jQuery version: - <%= jquery_link '1.6' %> • - <%= jquery_link '1.6.1' %> • - <%= jquery_link '1.6.2' %> • - <%= jquery_link 'edge' if File.exist?(settings.root + '/public/vendor/jquery.js') %> + + <% jquery_versions.each do |v| %> + <%= ' • ' if v != jquery_versions.first %> + <%= jquery_link v %> + <% end %> + <%= (' • ' + jquery_link('edge')) if File.exist?(settings.root + '/public/vendor/jquery.js') %>

From ba5808e73111fb65e91610b078577bb014d9b6d8 Mon Sep 17 00:00:00 2001 From: Surendra Singhi Date: Fri, 2 Sep 2011 16:40:23 +0530 Subject: [PATCH 022/226] add checkboxes support to jquery-ujs --- src/rails.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rails.js b/src/rails.js index d6e585fa..1d5ba64a 100644 --- a/src/rails.js +++ b/src/rails.js @@ -52,7 +52,7 @@ linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]', // Select elements bound by jquery-ujs - selectChangeSelector: 'select[data-remote]', + selectChangeSelector: 'select[data-remote], input[type="checkbox"][data-remote]', // Form elements bound by jquery-ujs formSubmitSelector: 'form', @@ -114,15 +114,15 @@ data.push(button); element.data('ujs:submit-button', null); } - } else if (element.is('select')) { + } else if (element.is('select') || element.is("input[type='checkbox']")) { method = element.data('method'); url = element.data('url'); data = element.serialize(); - if (element.data('params')) data = data + "&" + element.data('params'); + if (element.data('params')) data = data + "&" + element.data('params'); } else { method = element.data('method'); url = element.attr('href'); - data = element.data('params') || null; + data = element.data('params') || null; } options = { @@ -277,7 +277,7 @@ rails.handleRemote(link); return false; - }); + }); $(rails.formSubmitSelector).live('submit.rails', function(e) { var form = $(this), From 6e9a06d45eaf2da1036d4c2ead25ff57d0127d03 Mon Sep 17 00:00:00 2001 From: Markus Doits Date: Mon, 29 Aug 2011 12:35:16 +0200 Subject: [PATCH 023/226] Allow 'data-disable-with' to work on links - Simple element's inner html substitution by what is in 'data-disable-with' - Element is reenabled after a possible remote call - Element is not disabled if a confirmation returns false - Test tdb --- src/rails.js | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/rails.js b/src/rails.js index b17d5e79..ed3c252f 100644 --- a/src/rails.js +++ b/src/rails.js @@ -49,7 +49,7 @@ $.rails = rails = { // Link elements bound by jquery-ujs - linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]', + linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]', // Select elements bound by jquery-ujs selectChangeSelector: 'select[data-remote]', @@ -72,6 +72,9 @@ // Form file input elements fileInputSelector: 'input:file', + // Link onClick disable selector with possible reenable after remote submission + linkDisableSelector: 'a[data-disable-with]', + // Make sure that every Ajax request sends the CSRF token CSRFProtection: function(xhr) { var token = $('meta[name="csrf-token"]').attr('content'); @@ -252,15 +255,41 @@ }); } return continuePropagation; + }, + + // replace element's html with the 'data-disable-with' after storing original html + // and prevent clicking on it + disableElement: function(element) { + element.data('ujs:enable-with', element.html()); // store enabled state + element.html(element.data('disable-with')); // set to disabled state + element.bind('click.railsDisable', function(e) { // prevent further clicking + return rails.stopEverything(e) + }); + }, + + // restore element to its original state which was disabled by 'disableElement' above + enableElement: function(element) { + if (element.data('ujs:enable-with') !== undefined) { + element.html(element.data('ujs:enable-with')); // set to old enabled state + element.removeData('ujs:enable-with'); // clean up cache + } + element.unbind('click.railsDisable'); // enable element } + }; $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); + $(rails.linkDisableSelector).live('ajax:complete', function() { + rails.enableElement($(this)); + }); + $(rails.linkClickSelector).live('click.rails', function(e) { var link = $(this); if (!rails.allowAction(link)) return rails.stopEverything(e); + if (link.is(rails.linkDisableSelector)) rails.disableElement(link); + if (link.data('remote') !== undefined) { rails.handleRemote(link); return false; From dd9384f6332d450721354dbab6f959d961b06bc9 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Sun, 4 Sep 2011 17:45:05 -0400 Subject: [PATCH 024/226] Fixed up blank form action test. Kept jquery 1.6.2 as default until 1.6.3 is fixed. --- test/public/test/call-remote.js | 1 + test/server.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/public/test/call-remote.js b/test/public/test/call-remote.js index b5e3a8d3..37ba0a2c 100644 --- a/test/public/test/call-remote.js +++ b/test/public/test/call-remote.js @@ -96,6 +96,7 @@ asyncTest('allow empty form "action"', 1, function() { currentLocation.href = ""; currentLocation = currentLocation.href; } + currentLocation = currentLocation.replace(/\?$/, ''); // Actual location (strip out settings.data that jQuery serializes and appends) ajaxLocation = settings.url.replace(settings.data,"").replace(/&$/, "").replace(/\?$/, ""); diff --git a/test/server.rb b/test/server.rb index 8a9bc259..a0a71873 100644 --- a/test/server.rb +++ b/test/server.rb @@ -48,7 +48,7 @@ def jquery_versions end get '/' do - params[:version] ||= JQUERY_VERSIONS.last + params[:version] ||= '1.6.2' params[:cdn] ||= 'jquery' erb :index end From 89396108ce574080f9b877cad74573c5d1ae9aa2 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Sun, 4 Sep 2011 18:10:36 -0400 Subject: [PATCH 025/226] Added change selector handling for all remote inputs, selects, and textareas. Closes #199 --- src/rails.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rails.js b/src/rails.js index 1d5ba64a..262d43ba 100644 --- a/src/rails.js +++ b/src/rails.js @@ -52,7 +52,7 @@ linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]', // Select elements bound by jquery-ujs - selectChangeSelector: 'select[data-remote], input[type="checkbox"][data-remote]', + inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]', // Form elements bound by jquery-ujs formSubmitSelector: 'form', @@ -114,7 +114,7 @@ data.push(button); element.data('ujs:submit-button', null); } - } else if (element.is('select') || element.is("input[type='checkbox']")) { + } else if (element.is(rails.inputChangeSelector)) { method = element.data('method'); url = element.data('url'); data = element.serialize(); @@ -271,7 +271,7 @@ } }); - $(rails.selectChangeSelector).live('change.rails', function(e) { + $(rails.inputChangeSelector).live('change.rails', function(e) { var link = $(this); if (!rails.allowAction(link)) return rails.stopEverything(e); From 3af83ecf4670202abe81f2e817fcef6b35f137d9 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Sun, 4 Sep 2011 20:04:12 -0400 Subject: [PATCH 026/226] formatting --- src/rails.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rails.js b/src/rails.js index 262d43ba..39efde25 100644 --- a/src/rails.js +++ b/src/rails.js @@ -120,9 +120,9 @@ data = element.serialize(); if (element.data('params')) data = data + "&" + element.data('params'); } else { - method = element.data('method'); - url = element.attr('href'); - data = element.data('params') || null; + method = element.data('method'); + url = element.attr('href'); + data = element.data('params') || null; } options = { From eb732f4ea15f854ccf874d4936cbbdfdbbf7c180 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Sun, 4 Sep 2011 22:06:43 -0400 Subject: [PATCH 027/226] Created tests for disabling links. Fixed removing data for bug in jquery --- src/rails.js | 4 ++- test/public/test/data-disable.js | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/rails.js b/src/rails.js index 98c5c9ad..1504a183 100644 --- a/src/rails.js +++ b/src/rails.js @@ -272,7 +272,9 @@ enableElement: function(element) { if (element.data('ujs:enable-with') !== undefined) { element.html(element.data('ujs:enable-with')); // set to old enabled state - element.removeData('ujs:enable-with'); // clean up cache + // this should be element.removeData('ujs:enable-with') + // but, there is currently a bug in jquery which makes hyphenated data attributes not get removed + element.data('ujs:enable-with', false); // clean up cache } element.unbind('click.railsDisable'); // enable element } diff --git a/test/public/test/data-disable.js b/test/public/test/data-disable.js index 2fa04b1a..9f5a802e 100644 --- a/test/public/test/data-disable.js +++ b/test/public/test/data-disable.js @@ -15,6 +15,12 @@ module('data-disable', { .find('form:last') // WEEIRDD: the form won't submit to an iframe if the button is name="submit" (??!) .append($('')); + + $('#qunit-fixture').append($('', { + text: 'Click me', + href: '/echo', + 'data-disable-with': 'clicking...' + })); } }); @@ -133,3 +139,44 @@ asyncTest('form textarea with "data-disable-with" attribute', 3, function() { ok(textarea.is(':disabled'), 'textarea should be disabled'); equal(textarea.val(), 'processing ...', 'textarea should have disabled value given to it'); }); + +asyncTest('link with "data-disable-with" attribute disables', 4, function() { + var link = $('a[data-disable-with]'); + + ok(!link.data('ujs:enable-with'), 'link should not be disabled'); + equal(link.html(), 'Click me', 'link should have value given to it'); + + function checkDisabledLink() { + ok(link.data('ujs:enable-with'), 'link should be disabled'); + equal(link.html(), 'clicking...'); + } + + link.trigger('click'); + checkDisabledLink(); + start(); +}); + +asyncTest('remote link with "data-disable-with" attribute disables and re-enables', 6, function() { + var link = $('a[data-disable-with]').attr('data-remote', true); + + function checkEnabledLink() { + ok(!link.data('ujs:enable-with'), 'link should not be disabled'); + equal(link.html(), 'Click me', 'link should have value given to it'); + } + checkEnabledLink(); + + function checkDisabledLink() { + ok(link.data('ujs:enable-with'), 'link should be disabled'); + equal(link.html(), 'clicking...'); + } + + link + .bind('ajax:beforeSend', function() { + checkDisabledLink(); + }) + .live('ajax:complete', function() { + checkEnabledLink(); + start(); + }) + .trigger('click'); +}); From c01215c3d48ebb9f9f1059f26efa0c0c9092da2b Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Mon, 12 Sep 2011 22:37:29 -0400 Subject: [PATCH 028/226] Added jquery 1.6.4 to test suite --- test/server.rb | 2 +- test/views/layout.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/server.rb b/test/server.rb index a0a71873..d33cbc57 100644 --- a/test/server.rb +++ b/test/server.rb @@ -1,7 +1,7 @@ require 'sinatra' require 'json' -JQUERY_VERSIONS = %w[ 1.6 1.6.1 1.6.2 1.6.3 ].freeze +JQUERY_VERSIONS = %w[ 1.6 1.6.1 1.6.2 1.6.3 1.6.4 ].freeze use Rack::Static, :urls => ["/src"], :root => File.expand_path('..', settings.root) diff --git a/test/views/layout.erb b/test/views/layout.erb index ec9a7540..28041d92 100644 --- a/test/views/layout.erb +++ b/test/views/layout.erb @@ -8,7 +8,7 @@ color: #8699A4; text-align: right; font-family: sans-serif; line-height: 1; margin-top: -1.8em; padding: 0 2em .8em 0; } - #jquery-cdn { margin-right: 300px; } + #jquery-cdn { margin-right: 375px; } #jquery-cdn a, #jquery-version a { color: white; text-decoration: underline; } From 44df81adbb31b83f77ec59b4e616a4183861688e Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Thu, 15 Sep 2011 12:06:27 -0400 Subject: [PATCH 029/226] Updated formInputClickSelector for button[type] IE7 issue. Closes #206. --- src/rails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rails.js b/src/rails.js index 67d4f58d..40223c0b 100644 --- a/src/rails.js +++ b/src/rails.js @@ -58,7 +58,7 @@ formSubmitSelector: 'form', // Form input elements bound by jquery-ujs - formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])', + formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not(button[type])', // Form input elements disabled during form submission disableSelector: 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]', From 888be8adcb7d609f442b3883dc722c5427e49354 Mon Sep 17 00:00:00 2001 From: Steve Schwartz Date: Mon, 3 Oct 2011 00:25:55 -0400 Subject: [PATCH 030/226] Carry over target attribute for a[data-method] links to form. Closes --- src/rails.js | 3 +++ test/public/test/data-method.js | 23 +++++++++++++++++------ test/public/test/settings.js | 5 +++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/rails.js b/src/rails.js index 40223c0b..6ef7f777 100644 --- a/src/rails.js +++ b/src/rails.js @@ -159,6 +159,7 @@ handleMethod: function(link) { var href = link.attr('href'), method = link.data('method'), + target = link.attr('target'), csrf_token = $('meta[name=csrf-token]').attr('content'), csrf_param = $('meta[name=csrf-param]').attr('content'), form = $('
'), @@ -168,6 +169,8 @@ metadata_input += ''; } + if (target) { form.attr('target', target); } + form.hide().append(metadata_input).appendTo('body'); form.submit(); }, diff --git a/test/public/test/data-method.js b/test/public/test/data-method.js index 34c282e0..ef50500f 100644 --- a/test/public/test/data-method.js +++ b/test/public/test/data-method.js @@ -1,11 +1,15 @@ (function(){ -module('data-method'); +module('data-method', { + setup: function() { + $('#qunit-fixture').append($('
', { + href: '/echo', 'data-method': 'delete', text: 'destroy!' + })); + } +}); -function submit(fn) { - $('#qunit-fixture'). - append($('', { href: '/echo', 'data-method': 'delete', text: 'destroy!' })) - .find('a') +function submit(fn, options) { + $('#qunit-fixture').find('a') .bind('iframe:loaded', function(e, data) { fn(data); start(); @@ -31,4 +35,11 @@ asyncTest('link with "data-method" and CSRF', 1, function() { }); }); -})(); \ No newline at end of file +asyncTest('link "target" should be carried over to generated form', 1, function() { + $('a[data-method]').attr('target', 'super-special-frame'); + submit(function(data) { + equal(data.params._target, 'super-special-frame'); + }); +}); + +})(); diff --git a/test/public/test/settings.js b/test/public/test/settings.js index c58734d7..e23bf7ed 100644 --- a/test/public/test/settings.js +++ b/test/public/test/settings.js @@ -26,10 +26,11 @@ $(document).bind('submit', function(e) { if (!e.isDefaultPrevented()) { var form = $(e.target), action = form.attr('action'), name = 'form-frame' + jQuery.guid++, - iframe = $('