From: jaubourg Date: Fri, 13 Jul 2012 07:44:21 +0000 (+0200) Subject: Extracts the serialization code from the ajax module so that alternative ajax impleme... X-Git-Tag: 1.8rc1~40 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ced5e9037a8a1d7306fa6c735ba7f314022c3289;p=jquery.git Extracts the serialization code from the ajax module so that alternative ajax implementations can use it without the need for the whole ajax module to be included in the build. --- diff --git a/grunt.js b/grunt.js index a4e99a3c5..39f999c2f 100644 --- a/grunt.js +++ b/grunt.js @@ -67,6 +67,7 @@ module.exports = function( grunt ) { { flag: "deprecated", src: "src/deprecated.js" }, { flag: "css", src: "src/css.js" }, + "src/serialize.js", { flag: "ajax", src: "src/ajax.js" }, { flag: "ajax/jsonp", src: "src/ajax/jsonp.js", needs: [ "ajax", "ajax/script" ] }, { flag: "ajax/script", src: "src/ajax/script.js", needs: ["ajax"] }, diff --git a/src/ajax.js b/src/ajax.js index 90ac20486..053bd696b 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -3,19 +3,14 @@ var // Document location // Document location segments ajaxLocParts, - r20 = /%20/g, - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, rhash = /#.*$/, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, // #7653, #8125, #8152: local protocol detection rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rquery = /\?/, rscript = /)<[^<]*)*<\/script>/gi, - rselectTextarea = /^(?:select|textarea)/i, rts = /([?&])_=[^&]*/, rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, @@ -148,103 +143,75 @@ function ajaxExtend( target, src ) { } } -jQuery.fn.extend({ - load: function( url, params, callback ) { - if ( typeof url !== "string" && _load ) { - return _load.apply( this, arguments ); - } - - // Don't do a request if no elements are being requested - if ( !this.length ) { - return this; - } +jQuery.fn.load = function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + } - var selector, type, response, - self = this, - off = url.indexOf(" "); + // Don't do a request if no elements are being requested + if ( !this.length ) { + return this; + } - if ( off >= 0 ) { - selector = url.slice( off, url.length ); - url = url.slice( 0, off ); - } + var selector, type, response, + self = this, + off = url.indexOf(" "); - // If it's a function - if ( jQuery.isFunction( params ) ) { + if ( off >= 0 ) { + selector = url.slice( off, url.length ); + url = url.slice( 0, off ); + } - // We assume that it's the callback - callback = params; - params = undefined; + // If it's a function + if ( jQuery.isFunction( params ) ) { - // Otherwise, build a param string - } else if ( typeof params === "object" ) { - type = "POST"; - } + // We assume that it's the callback + callback = params; + params = undefined; - // Request the remote document - jQuery.ajax({ - url: url, + // Otherwise, build a param string + } else if ( typeof params === "object" ) { + type = "POST"; + } - // if "type" variable is undefined, then "GET" method will be used - type: type, - dataType: "html", - data: params, - complete: function( jqXHR, status ) { - if ( callback ) { - self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); - } + // Request the remote document + jQuery.ajax({ + url: url, + + // if "type" variable is undefined, then "GET" method will be used + type: type, + dataType: "html", + data: params, + complete: function( jqXHR, status ) { + if ( callback ) { + self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); } - }).done(function( responseText ) { - - // Save response for use in complete callback - response = arguments; - - // See if a selector was specified - self.html( selector ? + } + }).done(function( responseText ) { - // Create a dummy div to hold the results - jQuery("
") + // Save response for use in complete callback + response = arguments; - // inject the contents of the document in, removing the scripts - // to avoid any 'Permission Denied' errors in IE - .append( responseText.replace( rscript, "" ) ) + // See if a selector was specified + self.html( selector ? - // Locate the specified elements - .find( selector ) : + // Create a dummy div to hold the results + jQuery("
") - // If not, just inject the full result - responseText ); + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append( responseText.replace( rscript, "" ) ) - }); + // Locate the specified elements + .find( selector ) : - return this; - }, + // If not, just inject the full result + responseText ); - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, + }); - serializeArray: function() { - return this.map(function(){ - return this.elements ? jQuery.makeArray( this.elements ) : this; - }) - .filter(function(){ - return this.name && !this.disabled && - ( this.checked || rselectTextarea.test( this.nodeName ) || - rinput.test( this.type ) ); - }) - .map(function( i, elem ){ - var val = jQuery( this ).val(); - - return val == null ? - null : - jQuery.isArray( val ) ? - jQuery.map( val, function( val, i ){ - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }) : - { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - }).get(); - } -}); + return this; +}; // Attach a bunch of functions for handling common AJAX events jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ @@ -753,80 +720,6 @@ jQuery.extend({ return jqXHR; }, - // Serialize an array of form elements or a set of - // key/values into a query string - param: function( a, traditional ) { - var prefix, - s = [], - add = function( key, value ) { - // If value is a function, invoke it and return its value - value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); - s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); - }; - - // Set traditional to true for jQuery <= 1.3.2 behavior. - if ( traditional === undefined ) { - traditional = jQuery.ajaxSettings.traditional; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - }); - - } else { - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ).replace( r20, "+" ); - } -}); - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( jQuery.isArray( obj ) ) { - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - // If array item is non-scalar (array or object), encode its - // numeric index to resolve deserialization ambiguity issues. - // Note that rack (as of 1.0.0) can't currently deserialize - // nested arrays properly, and attempting to do so may cause - // a server error. Possible fixes are to modify rack's - // deserialization algorithm or to provide an option or flag - // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); - } - }); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - // Serialize scalar item. - add( prefix, obj ); - } -} - -// This is still on the jQuery object... for now -// Want to move this to jQuery.ajax some day -jQuery.extend({ - // Counter for holding the number of active queries active: 0, diff --git a/src/serialize.js b/src/serialize.js new file mode 100644 index 000000000..212640cf1 --- /dev/null +++ b/src/serialize.js @@ -0,0 +1,101 @@ +var r20 = /%20/g, + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rselectTextarea = /^(?:select|textarea)/i; + +jQuery.fn.extend({ + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map(function(){ + return this.elements ? jQuery.makeArray( this.elements ) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + ( this.checked || rselectTextarea.test( this.nodeName ) || + rinput.test( this.type ) ); + }) + .map(function( i, elem ){ + var val = jQuery( this ).val(); + + return val == null ? + null : + jQuery.isArray( val ) ? + jQuery.map( val, function( val, i ){ + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }) : + { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + }).get(); + } +}); + +//Serialize an array of form elements or a set of +//key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, value ) { + // If value is a function, invoke it and return its value + value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); + s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); + }; + + // Set traditional to true for jQuery <= 1.3.2 behavior. + if ( traditional === undefined ) { + traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + }); + + } else { + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ).replace( r20, "+" ); +}; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( jQuery.isArray( obj ) ) { + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + // If array item is non-scalar (array or object), encode its + // numeric index to resolve deserialization ambiguity issues. + // Note that rack (as of 1.0.0) can't currently deserialize + // nested arrays properly, and attempting to do so may cause + // a server error. Possible fixes are to modify rack's + // deserialization algorithm or to provide an option or flag + // to force array serialization to be shallow. + buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); + } + }); + + } else if ( !traditional && jQuery.type( obj ) === "object" ) { + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + // Serialize scalar item. + add( prefix, obj ); + } +} diff --git a/test/index.html b/test/index.html index 59dfad62d..aeb9362d6 100644 --- a/test/index.html +++ b/test/index.html @@ -46,6 +46,7 @@ + diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 86d4c9535..85069b482 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -929,138 +929,6 @@ test("jQuery.ajax - dataType html", function() { }); }); -test("serialize()", function() { - expect(5); - - // Add html5 elements only for serialize because selector can't yet find them on non-html5 browsers - jQuery("#search").after( - ""+ - "" - ); - - equal( jQuery("#form").serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3", - "Check form serialization as query string"); - - equal( jQuery("#form :input").serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3", - "Check input serialization as query string"); - - equal( jQuery("#testForm").serialize(), - "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", - "Check form serialization as query string"); - - equal( jQuery("#testForm :input").serialize(), - "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", - "Check input serialization as query string"); - - equal( jQuery("#form, #testForm").serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", - "Multiple form serialization as query string"); - - /* Temporarily disabled. Opera 10 has problems with form serialization. - equal( jQuery("#form, #testForm :input").serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", - "Mixed form/input serialization as query string"); - */ - jQuery("#html5email, #html5number").remove(); -}); - -test("jQuery.param()", function() { - expect(22); - - equal( !jQuery.ajaxSettings.traditional, true, "traditional flag, falsy by default" ); - - var params = {"foo":"bar", "baz":42, "quux":"All your base are belong to us"}; - equal( jQuery.param(params), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); - - params = {"string":"foo","null":null,"undefined":undefined}; - equal( jQuery.param(params), "string=foo&null=&undefined=", "handle nulls and undefineds properly" ); - - params = {"someName": [1, 2, 3], "regularThing": "blah" }; - equal( jQuery.param(params), "someName%5B%5D=1&someName%5B%5D=2&someName%5B%5D=3®ularThing=blah", "with array" ); - - params = {"foo": ["a", "b", "c"]}; - equal( jQuery.param(params), "foo%5B%5D=a&foo%5B%5D=b&foo%5B%5D=c", "with array of strings" ); - - params = {"foo": ["baz", 42, "All your base are belong to us"] }; - equal( jQuery.param(params), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us", "more array" ); - - params = {"foo": { "bar": "baz", "beep": 42, "quux": "All your base are belong to us" } }; - equal( jQuery.param(params), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); - - params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; - equal( decodeURIComponent( jQuery.param(params) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure" ); - - params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, "d": 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; - equal( decodeURIComponent( jQuery.param(params) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" ); - - params = { "a":[1,2], "b":{ "c":3, "d":[4,5], "e":{ "x":[6], "y":7, "z":[8,9] }, "f":true, "g":false, "h":undefined }, "i":[10,11], "j":true, "k":false, "l":[undefined,0], "m":"cowboy hat?" }; - equal( jQuery.param(params,true), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure, forced traditional" ); - - equal( decodeURIComponent( jQuery.param({ "a": [1,2,3], "b[]": [4,5,6], "c[d]": [7,8,9], "e": { "f": [10], "g": [11,12], "h": 13 } }) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." ); - - // #7945 - equal( jQuery.param({"jquery": "1.4.2"}), "jquery=1.4.2", "Check that object with a jQuery property get serialized correctly" ); - - jQuery.ajaxSetup({ traditional: true }); - - params = {"foo":"bar", "baz":42, "quux":"All your base are belong to us"}; - equal( jQuery.param(params), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); - - params = {"someName": [1, 2, 3], "regularThing": "blah" }; - equal( jQuery.param(params), "someName=1&someName=2&someName=3®ularThing=blah", "with array" ); - - params = {"foo": ["a", "b", "c"]}; - equal( jQuery.param(params), "foo=a&foo=b&foo=c", "with array of strings" ); - - params = {"foo[]":["baz", 42, "All your base are belong to us"]}; - equal( jQuery.param(params), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us", "more array" ); - - params = {"foo[bar]":"baz", "foo[beep]":42, "foo[quux]":"All your base are belong to us"}; - equal( jQuery.param(params), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); - - params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; - equal( jQuery.param(params), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure" ); - - params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; - equal( jQuery.param(params), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject+Object%5D&a=17", "nested arrays (not possible when jQuery.param.traditional == true)" ); - - params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; - equal( decodeURIComponent( jQuery.param(params,false) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure, forced not traditional" ); - - params = { "param1": null }; - equal( jQuery.param(params,false), "param1=", "Make sure that null params aren't traversed." ); - - params = {"test": {"length": 3, "foo": "bar"} }; - equal( jQuery.param( params, false ), "test%5Blength%5D=3&test%5Bfoo%5D=bar", "Sub-object with a length property" ); -}); - -test("jQuery.param() Constructed prop values", function() { - expect( 4 ); - - /** @constructor */ - function Record() { - this["prop"] = "val"; - } - - var MyString = String, - MyNumber = Number, - params = { "test": new MyString("foo") }; - - equal( jQuery.param( params, false ), "test=foo", "Do not mistake new String() for a plain object" ); - - params = { "test": new MyNumber(5) }; - equal( jQuery.param( params, false ), "test=5", "Do not mistake new Number() for a plain object" ); - - params = { "test": new Date() }; - ok( jQuery.param( params, false ), "(Non empty string returned) Do not mistake new Date() for a plain object" ); - - // should allow non-native constructed objects - params = { "test": new Record() }; - equal( jQuery.param( params, false ), jQuery.param({ "test": { "prop": "val" } }), "Allow non-native constructed objects" ); -}); - test("synchronous request", function() { expect(1); var response = jQuery.ajax({ diff --git a/test/unit/serialize.js b/test/unit/serialize.js new file mode 100644 index 000000000..ab5d1c427 --- /dev/null +++ b/test/unit/serialize.js @@ -0,0 +1,145 @@ +module("serialize", { teardown: moduleTeardown }); + +test("jQuery.param()", function() { + expect(22); + + equal( !( jQuery.ajaxSettings && jQuery.ajaxSettings.traditional ), true, "traditional flag, falsy by default" ); + + var params = {"foo":"bar", "baz":42, "quux":"All your base are belong to us"}; + equal( jQuery.param(params), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); + + params = {"string":"foo","null":null,"undefined":undefined}; + equal( jQuery.param(params), "string=foo&null=&undefined=", "handle nulls and undefineds properly" ); + + params = {"someName": [1, 2, 3], "regularThing": "blah" }; + equal( jQuery.param(params), "someName%5B%5D=1&someName%5B%5D=2&someName%5B%5D=3®ularThing=blah", "with array" ); + + params = {"foo": ["a", "b", "c"]}; + equal( jQuery.param(params), "foo%5B%5D=a&foo%5B%5D=b&foo%5B%5D=c", "with array of strings" ); + + params = {"foo": ["baz", 42, "All your base are belong to us"] }; + equal( jQuery.param(params), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us", "more array" ); + + params = {"foo": { "bar": "baz", "beep": 42, "quux": "All your base are belong to us" } }; + equal( jQuery.param(params), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); + + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; + equal( decodeURIComponent( jQuery.param(params) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure" ); + + params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, "d": 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; + equal( decodeURIComponent( jQuery.param(params) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" ); + + params = { "a":[1,2], "b":{ "c":3, "d":[4,5], "e":{ "x":[6], "y":7, "z":[8,9] }, "f":true, "g":false, "h":undefined }, "i":[10,11], "j":true, "k":false, "l":[undefined,0], "m":"cowboy hat?" }; + equal( jQuery.param(params,true), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure, forced traditional" ); + + equal( decodeURIComponent( jQuery.param({ "a": [1,2,3], "b[]": [4,5,6], "c[d]": [7,8,9], "e": { "f": [10], "g": [11,12], "h": 13 } }) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." ); + + // #7945 + equal( jQuery.param({"jquery": "1.4.2"}), "jquery=1.4.2", "Check that object with a jQuery property get serialized correctly" ); + + var settings = { traditional: true }; + + if ( jQuery.ajaxSettings ) { + jQuery.ajaxSetup( settings ); + } else { + jQuery.ajaxSettings = settings; + } + + params = {"foo":"bar", "baz":42, "quux":"All your base are belong to us"}; + equal( jQuery.param(params), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); + + params = {"someName": [1, 2, 3], "regularThing": "blah" }; + equal( jQuery.param(params), "someName=1&someName=2&someName=3®ularThing=blah", "with array" ); + + params = {"foo": ["a", "b", "c"]}; + equal( jQuery.param(params), "foo=a&foo=b&foo=c", "with array of strings" ); + + params = {"foo[]":["baz", 42, "All your base are belong to us"]}; + equal( jQuery.param(params), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us", "more array" ); + + params = {"foo[bar]":"baz", "foo[beep]":42, "foo[quux]":"All your base are belong to us"}; + equal( jQuery.param(params), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); + + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; + equal( jQuery.param(params), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure" ); + + params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; + equal( jQuery.param(params), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject+Object%5D&a=17", "nested arrays (not possible when jQuery.param.traditional == true)" ); + + params = { a:[1,2], b:{ c:3, d:[4,5], e:{ x:[6], y:7, z:[8,9] }, f:true, g:false, h:undefined }, i:[10,11], j:true, k:false, l:[undefined,0], m:"cowboy hat?" }; + equal( decodeURIComponent( jQuery.param(params,false) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure, forced not traditional" ); + + params = { "param1": null }; + equal( jQuery.param(params,false), "param1=", "Make sure that null params aren't traversed." ); + + params = {"test": {"length": 3, "foo": "bar"} }; + equal( jQuery.param( params, false ), "test%5Blength%5D=3&test%5Bfoo%5D=bar", "Sub-object with a length property" ); + + if ( jQuery.ajaxSettings === settings ) { + delete jQuery.ajaxSettings; + } else { + jQuery.ajaxSetup({ traditional: false }); + } +}); + +test("jQuery.param() Constructed prop values", function() { + expect( 4 ); + + /** @constructor */ + function Record() { + this["prop"] = "val"; + } + + var MyString = String, + MyNumber = Number, + params = { "test": new MyString("foo") }; + + equal( jQuery.param( params, false ), "test=foo", "Do not mistake new String() for a plain object" ); + + params = { "test": new MyNumber(5) }; + equal( jQuery.param( params, false ), "test=5", "Do not mistake new Number() for a plain object" ); + + params = { "test": new Date() }; + ok( jQuery.param( params, false ), "(Non empty string returned) Do not mistake new Date() for a plain object" ); + + // should allow non-native constructed objects + params = { "test": new Record() }; + equal( jQuery.param( params, false ), jQuery.param({ "test": { "prop": "val" } }), "Allow non-native constructed objects" ); +}); + +test("serialize()", function() { + expect(5); + + // Add html5 elements only for serialize because selector can't yet find them on non-html5 browsers + jQuery("#search").after( + ""+ + "" + ); + + equal( jQuery("#form").serialize(), + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3", + "Check form serialization as query string"); + + equal( jQuery("#form :input").serialize(), + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3", + "Check input serialization as query string"); + + equal( jQuery("#testForm").serialize(), + "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", + "Check form serialization as query string"); + + equal( jQuery("#testForm :input").serialize(), + "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", + "Check input serialization as query string"); + + equal( jQuery("#form, #testForm").serialize(), + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", + "Multiple form serialization as query string"); + + /* Temporarily disabled. Opera 10 has problems with form serialization. + equal( jQuery("#form, #testForm :input").serialize(), + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", + "Mixed form/input serialization as query string"); + */ + jQuery("#html5email, #html5number").remove(); +});