From e6a99fdb0ee9e0fd7552d5de8bc4acbe982e98b7 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Sat, 23 Jul 2011 02:10:17 +0200 Subject: [PATCH] Fixes #9887: ajax now supports circular references into objects passed as context. Prefilter and transport developpers should add their own custom option into flatOptions when needed. Unit test added. --- src/ajax.js | 50 ++++++++++++++++++++++++++++++++--------------- test/unit/ajax.js | 16 +++++++++++++++ 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index 087f2febf..77659e118 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -135,6 +135,22 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX return selection; } +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + jQuery.fn.extend({ load: function( url, params, callback ) { if ( typeof url !== "string" && _load ) { @@ -278,23 +294,16 @@ jQuery.extend({ // Creates a full fledged settings object into target // with both ajaxSettings and settings fields. // If target is omitted, writes into ajaxSettings. - ajaxSetup: function ( target, settings ) { - if ( !settings ) { - // Only one parameter, we extend ajaxSettings - settings = target; - target = jQuery.extend( true, jQuery.ajaxSettings, settings ); + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); } else { - // target was provided, we extend into it - jQuery.extend( true, target, jQuery.ajaxSettings, settings ); - } - // Flatten fields we don't want deep extended - for( var field in { context: 1, url: 1 } ) { - if ( field in settings ) { - target[ field ] = settings[ field ]; - } else if( field in jQuery.ajaxSettings ) { - target[ field ] = jQuery.ajaxSettings[ field ]; - } + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; } + ajaxExtend( target, settings ); return target; }, @@ -352,6 +361,15 @@ jQuery.extend({ // Parse text as xml "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true } }, @@ -563,7 +581,7 @@ jQuery.extend({ completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] ); if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] ); + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger( "ajaxStop" ); diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 334339227..6af56db4f 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -2076,6 +2076,22 @@ test( "jQuery.ajax - Location object as url (#7531)", 1, function () { ok( success, "document.location did not generate exception" ); }); +test( "jQuery.ajax - Context with circular references (#9887)", 2, function () { + var success = false, + context = {}; + context.field = context; + try { + success = !jQuery.ajax( "non-existing", { + context: context, + beforeSend: function() { + ok( this === context, "context was not deep extended" ); + return false; + } + }); + } catch (e) { console.log( e ); } + ok( success, "context with circular reference did not generate an exception" ); +}); + test( "jQuery.ajax - statusCode" , function() { var count = 12;