Create a gist now

Instantly share code, notes, and snippets.

jQuery Deparam -- WORK IN PROGRESS -- NOT DONE YET
// jQuery Deparam - v0.1.0 - 6/14/2011
// http://benalman.com/
// Copyright (c) 2011 Ben Alman; Licensed MIT, GPL
(function($) {
// Creating an internal undef value is safer than using undefined, in case it
// was ever overwritten.
var undef;
// A handy reference.
var decode = decodeURIComponent;
// Document $.deparam.
var deparam = $.deparam = function(text, reviver) {
// The object to be returned.
var result = {};
// Iterate over all key=value pairs.
$.each(text.replace(/\+/g, ' ').split('&'), function(index, pair) {
// The key=value pair.
var kv = pair.split('=');
// The key, URI-decoded.
var key = decode(kv[0]);
// Abort if there's no key.
if ( !key ) { return; }
// The value, URI-decoded. If value is missing, use empty string.
var value = decode(kv[1] || '');
// If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
// into its component parts.
var keys = key.split('][');
var last = keys.length - 1;
// Used when key is complex.
var i = 0;
var current = result;
// If the first keys part contains [ and the last ends with ], then []
// are correctly balanced.
if ( keys[0].indexOf('[') >= 0 && /\]$/.test(keys[last]) ) {
// Remove the trailing ] from the last keys part.
keys[last] = keys[last].replace(/\]$/, '');
// Split first keys part into two parts on the [ and add them back onto
// the beginning of the keys array.
keys = keys.shift().split('[').concat(keys);
// Since a key part was added, increment last.
last++;
} else {
// Basic 'foo' style key.
last = 0;
}
if ( $.isFunction(reviver) ) {
// If a reviver function was passed, use that function.
value = reviver(key, value);
} else if ( reviver ) {
// If true was passed, use the built-in $.deparam.reviver function.
value = deparam.reviver(key, value);
}
if ( last ) {
// Complex key, like 'a[]' or 'a[b][c]'. At this point, the keys array
// might look like ['a', ''] (array) or ['a', 'b', 'c'] (object).
for ( ; i <= last; i++ ) {
// If the current key part was specified, use that value as the array
// index or object key. If omitted, assume an array and use the
// array's length (effectively an array push).
key = keys[i] !== '' ? keys[i] : current.length;
if ( i < last ) {
// If not the last key part, update the reference to the current
// object/array, creating it if it doesn't already exist AND there's
// a next key. If the next key is non-numeric and not empty string,
// create an object, otherwise create an array.
current = current[key] = current[key] || (isNaN(keys[i + 1]) ? {} : []);
} else {
// If the last key part, set the value.
current[key] = value;
}
}
} else {
// Simple key.
if ( $.isArray(result[key]) ) {
// If the key already exists, and is an array, push the new value onto
// the array.
result[key].push(value);
} else if ( key in result ) {
// If the key already exists, and is NOT an array, turn it into an
// array, pushing the new value onto it.
result[key] = [result[key], value];
} else {
// Otherwise, just set the value.
result[key] = value;
}
}
});
return result;
};
// Default reviver function, used when true is passed as the second argument
// to $.deparam. Don't like it? Pass your own!
deparam.reviver = function(key, value) {
var specials = {
'true': true,
'false': false,
'null': null,
'undefined': undef
};
return (+value + '') === value ? +value // Number
: value in specials ? specials[value] // true, false, null, undefined
: value; // String
};
}(jQuery));
// jQuery Deparam - v0.1.0 - 6/14/2011
// http://benalman.com/
// Copyright (c) 2011 Ben Alman; Licensed MIT, GPL
(function($){var a,b=decodeURIComponent,c=$.deparam=function(a,d){var e={};$.each(a.replace(/\+/g," ").split("&"),function(a,f){var g=f.split("="),h=b(g[0]);if(!!h){var i=b(g[1]||""),j=h.split("]["),k=j.length-1,l=0,m=e;j[0].indexOf("[")>=0&&/\]$/.test(j[k])?(j[k]=j[k].replace(/\]$/,""),j=j.shift().split("[").concat(j),k++):k=0,$.isFunction(d)?i=d(h,i):d&&(i=c.reviver(h,i));if(k)for(;l<=k;l++)h=j[l]!==""?j[l]:m.length,l<k?m=m[h]=m[h]||(isNaN(j[l+1])?{}:[]):m[h]=i;else $.isArray(e[h])?e[h].push(i):h in e?e[h]=[e[h],i]:e[h]=i}});return e};c.reviver=function(b,c){var d={"true":!0,"false":!1,"null":null,"undefined":a};return+c+""===c?+c:c in d?d[c]:c}})(jQuery)
module('jQuery.deparam');
test('basics', function() {
same($.deparam(''), {}, 'empty string yields empty object');
same($.deparam('a=1&b=2&c=3'), {a: '1', b: '2', c: '3'}, 'all params must exist in the result');
});
test('arrays', function() {
same($.deparam('a=1&a=2&a=3'), {a: ['1', '2', '3']}, 'implicit push');
same($.deparam('a[]=1&a[]=2&a[]=3'), {a: ['1', '2', '3']}, 'explicit push');
same($.deparam('a[0]=1&a[1]=2&a[2]=3'), {a: ['1', '2', '3']}, 'explicit by index');
same($.deparam('a[0]=1&a[2]=2'), {a: ['1', undefined, '2']}, 'explicit by index, skipping indices');
same($.deparam('a[][]=1'), {a: [['1']]}, 'basic nested array');
same($.deparam('a[][]=1&a[][]=2&a[][]=3'), {a: [['1'], ['2'], ['3']]}, 'nested arrays w/o indices is ambiguous');
same($.deparam('a[0][]=1&a[1][]=2&a[2][]=3'), {a: [['1'], ['2'], ['3']]}, 'nested arrays w/indices is not ambiguous');
same($.deparam('a[0][]=1&a[0][]=2&a[0][]=3'), {a: [['1', '2', '3']]}, 'nested arrays w/indices is not ambiguous');
same($.deparam('a[0][]=1&a[0][][]=0&a[1][][]=0&a[1][]=1&a[2][][]=0&a[2][]=1&a[2][][]=0&a[3][][][]=0'), {a: [['1',['0']], [['0'],'1'], [['0'],'1',['0']], [[['0']]]]}, 'a few permutations');
});
test('objects', function() {
same($.deparam('a[b]=1'), {a: {b: '1'}}, 'basic nested object');
same($.deparam('a[b]=1&a[c]=2'), {a: {b: '1', c: '2'}}, 'nested object with multiple params');
same($.deparam('a[b][c]=1'), {a: {b: {c: '1'}}}, 'deep nesting');
});
test('objects and arrays', function() {
same($.deparam('a[b][]=1&a[b][]=2'), {a: {b: ['1', '2']}}, 'nested object with implicit array push');
same($.deparam('a[][b]=1&a[][c]=2'), {a: [{b: '1'}, {c: '2'}]}, 'implicit array push with nested object');
same($.deparam('a[b][0]=1&a[b][2]=2'), {a: {b: ['1', undefined, '2']}}, 'nested object with explicit array indices, skipping indices');
same($.deparam('a[b][0][]=1&a[b][0][]=2'), {a: {b: [['1', '2']]}}, 'nested object with explicit and implicit array indices');
});
test('reviver: none', function() {
same($.deparam('a=foo'), {a: 'foo'}, 'value should be string');
same($.deparam('a='), {a: ''}, 'value should be string');
same($.deparam('a=01234'), {a: '01234'}, 'value should be string');
same($.deparam('a=0x10'), {a: '0x10'}, 'value should be string');
same($.deparam('a=1e3'), {a: '1e3'}, 'value should be string');
same($.deparam('a=-0'), {a: '-0'}, 'value should be string');
same($.deparam('a=true'), {a: 'true'}, 'value should be string');
same($.deparam('a=false'), {a: 'false'}, 'value should be string');
same($.deparam('a=null'), {a: 'null'}, 'value should be string');
same($.deparam('a=undefined'), {a: 'undefined'}, 'value should be string');
same($.deparam('a=123'), {a: '123'}, 'value should be string');
same($.deparam('a=-4.56'), {a: '-4.56'}, 'value should be string');
same($.deparam('a=0.001'), {a: '0.001'}, 'value should be string');
same($.deparam('a=0'), {a: '0'}, 'value should be string');
});
test('reviver: true', function() {
same($.deparam('a=foo', true), {a: 'foo'}, 'value should be string');
same($.deparam('a=', true), {a: ''}, 'value should be string');
same($.deparam('a=01234', true), {a: '01234'}, 'value should be string');
same($.deparam('a=0x10', true), {a: '0x10'}, 'value should be string');
same($.deparam('a=1e3', true), {a: '1e3'}, 'value should be string');
same($.deparam('a=-0', true), {a: '-0'}, 'value should be string');
same($.deparam('a=true', true), {a: true}, 'value should be boolean');
same($.deparam('a=false', true), {a: false}, 'value should be boolean');
same($.deparam('a=null', true), {a: null}, 'value should be null');
same($.deparam('a=undefined', true), {a: undefined}, 'value should be undefined');
same($.deparam('a=123', true), {a: 123}, 'value should be number');
same($.deparam('a=-4.56', true), {a: -4.56}, 'value should be number');
same($.deparam('a=0.001', true), {a: 0.001}, 'value should be number');
same($.deparam('a=0', true), {a: 0}, 'value should be number');
})
test('reviver: custom function', function() {
function fn(key, value) {
return '(' + key + '=' + value + ')';
}
same($.deparam('a=foo', fn), {a: '(a=foo)'}, 'value should be "fancy"');
same($.deparam('a=', fn), {a: '(a=)'}, 'value should be "fancy"');
});
test('jQuery.deparam.reviver', function() {
// \$\.deparam\('a=(.*?)', true\), \{a: (.*?)\}
// $.deparam.reviver('a', '$1'), $2
same($.deparam.reviver('a', 'foo'), 'foo', 'value should be string');
same($.deparam.reviver('a', ''), '', 'value should be string');
same($.deparam.reviver('a', '01234'), '01234', 'value should be string');
same($.deparam.reviver('a', '0x10'), '0x10', 'value should be string');
same($.deparam.reviver('a', '1e3'), '1e3', 'value should be string');
same($.deparam.reviver('a', '-0'), '-0', 'value should be string');
same($.deparam.reviver('a', 'true'), true, 'value should be boolean');
same($.deparam.reviver('a', 'false'), false, 'value should be boolean');
same($.deparam.reviver('a', 'null'), null, 'value should be null');
same($.deparam.reviver('a', 'undefined'), undefined, 'value should be undefined');
same($.deparam.reviver('a', '123'), 123, 'value should be number');
same($.deparam.reviver('a', '-4.56'), -4.56, 'value should be number');
same($.deparam.reviver('a', '0.001'), 0.001, 'value should be number');
same($.deparam.reviver('a', '0'), 0, 'value should be number');
});
test('param', function() {
var obj = {
a: 'foo',
b: '',
c: '01234',
d: '0x10',
e: '1e3',
f: '-0',
g: true,
h: false,
i: null,
j: undefined,
k: 123,
l: -4.56,
m: 0.001,
n: 0,
o: {b: 2, a: 1},
p: [[null], 'foo', '', '01234', '0x10', '1e3', '-0', true, false, null, undefined, 123, -4.56, 0.001, 0, {b: 2, a: 1}, [undefined]],
q: [[1,[0]], [[0],1], [[0],1,[0]], [[[0]]]],
z: {
a: 'foo',
b: '',
c: '01234',
d: '0x10',
e: '1e3',
f: '-0',
g: true,
h: false,
i: null,
j: undefined,
k: 123,
l: -4.56,
m: 0.001,
n: 0,
o: {b: 2, a: 1},
p: [[null], 'foo', '', '01234', '0x10', '1e3', '-0', true, false, null, undefined, 123, -4.56, 0.001, 0, {b: 2, a: 1}, [undefined]],
q: [[1,[0]], [[0],1], [[0],1,[0]], [[[0]]]]
}
};
same($.deparam($.param(obj), true), obj, 'deparam should be able to return $.param to the original object');
});
@cowboy
Owner
cowboy commented Jul 25, 2011

note to self: look into adding something like value.replace(/\+/g, ' ') in reviver function to replace + with space by default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment