Created
November 11, 2015 19:30
-
-
Save cmacrander/fdacbca907e4d2995d1a to your computer and use it in GitHub Desktop.
queryStringToObject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Read query string parameters as a javascript object. | |
// | |
// Not tested for: | |
// | |
// * Mixing bracketed and non-bracketed keys | |
// * Indexed brackets | |
// * Nested lists | |
// | |
// Some examples (See unit tests below for full details): | |
// | |
// | query string | result | | |
// |--------------|--------------------| | |
// | undefined | uses current URL | | |
// | ? | {} | | |
// | ?a | {a: undefined} | | |
// | ?a= | {a: undefined} | | |
// | ?a=1&b=2 | {a: 1, b: 2} | | |
// | a=1&b=2 | {a: 1, b: 2} | | |
// | ?a[]=1&b=2 | {a: [1], b: 2} | | |
// | ?a=1&a=2 | {a: [1, 2]} | | |
// | ?a[]=1&a[]=2 | {a: [1, 2]} | | |
// | ?a[]=1&a=2 | undefined behavior | | |
// | ?a[1]=1 | undefined behavior | | |
// | ?a[][]=1 | undefined behavior | | |
var queryStringToObject = function (queryString) { | |
var params = {}; | |
// Allow for easy invocation in the default case. | |
if (queryString === undefined) { | |
queryString = window.location.search; | |
} | |
// Leading question mark optional. | |
if (queryString.charAt(0) === '?') { | |
queryString = queryString.substring(1); | |
} | |
// Quick return for empty query string. | |
if (queryString === '') { | |
return params; | |
} | |
// Separate the query string into key-value pairs. | |
// Be careful with split! ''.split('&') gets you [''] | |
var pairStrings = queryString.indexOf('&') === -1 ? | |
[queryString] : queryString.split('&'); | |
// Add each key-value pair to the params object. | |
pairStrings.forEach(function (pairStr) { | |
// Split up the key and value, decoding URL escaping. | |
var pair = pairStr.split('='), | |
key = decodeURIComponent(pair[0]), | |
value = pair[1] ? decodeURIComponent(pair[1]) : undefined, | |
// A key becomes a list if either 1) it repeats or 2) it ends in []. | |
keyIsList = false; | |
// Check for bracket notation. | |
if (key.substr(-2) === '[]') { | |
keyIsList = true; | |
key = key.substr(0, key.length - 2); | |
} | |
// Check for repeats. | |
if (key in params && !(params[key] instanceof Array)) { | |
keyIsList = true; | |
params[key] = [params[key]]; | |
} | |
// Lists keys need to be pushed, not assigned. | |
if (keyIsList) { | |
// Never-before-seen bracketed keys need their list initialized. | |
if (!(key in params)) { | |
params[key] = []; | |
} | |
// Pushing undefined does "set" that index in the array. It's cleaner | |
// to not push it if the key has no value. | |
if (value !== undefined) { | |
params[key].push(value); | |
} | |
} else { | |
// Simple assignment for non-list keys. | |
params[key] = value; | |
} | |
}); | |
return params; | |
}; | |
// Query string unit tests. Returns map of test names to success true/false. | |
(function (f) { | |
var tests = [ | |
function normalNonRepeated() { | |
var p = f('?foo=bar&baz=quz'); | |
return p.foo === 'bar' && p.baz === 'quz'; | |
}, | |
function normalNonRepeatedWithoutQuestionMark() { | |
var p = f('foo=bar&baz=quz'); | |
return p.foo === 'bar' && p.baz === 'quz'; | |
}, | |
function empty() { | |
var p = f('?'); | |
return p !== null && p !== undefined && p.constructor === Object; | |
}, | |
function valuelessWithEquals() { | |
var p = f('?foo=&baz=quz'); | |
return p.foo === undefined && p.baz === 'quz'; | |
}, | |
function valuelessWithEqualsSimple() { | |
var p = f('?foo='); | |
return p.foo === undefined; | |
}, | |
function valuelessWithoutEquals() { | |
var p = f('?foo&baz=quz'); | |
return p.foo === undefined && p.baz === 'quz'; | |
}, | |
function valuelessWithoutEqualsSimple() { | |
var p = f('?foo'); | |
return p.foo === undefined; | |
}, | |
function repeatedWithoutBrackets() { | |
var p = f('?foo=bar1&foo=bar2&baz=quz'); | |
return p.foo[0] === 'bar1' && p.foo[1] === 'bar2' && p.baz === 'quz'; | |
}, | |
function repeatedWithBrackets() { | |
var p = f('?foo[]=bar1&foo[]=bar2&baz=quz'); | |
return p.foo[0] === 'bar1' && p.foo[1] === 'bar2' && p.baz === 'quz'; | |
}, | |
function decodesUrlComponents() { | |
var p = f('?%E3%81%BB%E3%81%92=%E3%81%BB%E3%81%92'); | |
return p['ほげ'] === 'ほげ'; | |
} | |
]; | |
var results = {}; | |
tests.forEach(function (testFn) { | |
var success = false; | |
try { | |
success = testFn(); | |
} catch (e) {} | |
results[testFn.name] = success; | |
if (!success) { | |
console.error("Unit testfailed:", testFn.name); | |
} | |
}); | |
return results; | |
}(queryStringToObject)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment