|
|
|
|
|
|
|
|
|
var toString = Object.prototype.toString; |
|
|
|
|
|
|
|
|
|
|
|
var hasOwnProperty = Object.prototype.hasOwnProperty; |
|
|
|
|
|
|
|
|
|
|
|
var indexOf = typeof Array.prototype.indexOf === 'function' |
|
? function(arr, el) { return arr.indexOf(el); } |
|
: function(arr, el) { |
|
for (var i = 0; i < arr.length; i++) { |
|
if (arr[i] === el) return i; |
|
} |
|
return -1; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var isArray = Array.isArray || function(arr) { |
|
return toString.call(arr) == '[object Array]'; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var objectKeys = Object.keys || function(obj) { |
|
var ret = []; |
|
for (var key in obj) { |
|
if (obj.hasOwnProperty(key)) { |
|
ret.push(key); |
|
} |
|
} |
|
return ret; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var forEach = typeof Array.prototype.forEach === 'function' |
|
? function(arr, fn) { return arr.forEach(fn); } |
|
: function(arr, fn) { |
|
for (var i = 0; i < arr.length; i++) fn(arr[i]); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var reduce = function(arr, fn, initial) { |
|
if (typeof arr.reduce === 'function') return arr.reduce(fn, initial); |
|
var res = initial; |
|
for (var i = 0; i < arr.length; i++) res = fn(res, arr[i]); |
|
return res; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var isint = /^[0-9]+$/; |
|
|
|
function promote(parent, key) { |
|
if (parent[key].length == 0) return parent[key] = {} |
|
var t = {}; |
|
for (var i in parent[key]) { |
|
if (hasOwnProperty.call(parent[key], i)) { |
|
t[i] = parent[key][i]; |
|
} |
|
} |
|
parent[key] = t; |
|
return t; |
|
} |
|
|
|
function parse(parts, parent, key, val) { |
|
var part = parts.shift(); |
|
|
|
|
|
if (Object.getOwnPropertyDescriptor(Object.prototype, key)) return; |
|
|
|
|
|
if (!part) { |
|
if (isArray(parent[key])) { |
|
parent[key].push(val); |
|
} else if ('object' == typeof parent[key]) { |
|
parent[key] = val; |
|
} else if ('undefined' == typeof parent[key]) { |
|
parent[key] = val; |
|
} else { |
|
parent[key] = [parent[key], val]; |
|
} |
|
|
|
} else { |
|
var obj = parent[key] = parent[key] || []; |
|
if (']' == part) { |
|
if (isArray(obj)) { |
|
if ('' != val) obj.push(val); |
|
} else if ('object' == typeof obj) { |
|
obj[objectKeys(obj).length] = val; |
|
} else { |
|
obj = parent[key] = [parent[key], val]; |
|
} |
|
|
|
} else if (~indexOf(part, ']')) { |
|
part = part.substr(0, part.length - 1); |
|
if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); |
|
parse(parts, obj, part, val); |
|
|
|
} else { |
|
if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); |
|
parse(parts, obj, part, val); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function merge(parent, key, val){ |
|
if (~indexOf(key, ']')) { |
|
var parts = key.split('[') |
|
, len = parts.length |
|
, last = len - 1; |
|
parse(parts, parent, 'base', val); |
|
|
|
} else { |
|
if (!isint.test(key) && isArray(parent.base)) { |
|
var t = {}; |
|
for (var k in parent.base) t[k] = parent.base[k]; |
|
parent.base = t; |
|
} |
|
set(parent.base, key, val); |
|
} |
|
|
|
return parent; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function compact(obj) { |
|
if ('object' != typeof obj) return obj; |
|
|
|
if (isArray(obj)) { |
|
var ret = []; |
|
|
|
for (var i in obj) { |
|
if (hasOwnProperty.call(obj, i)) { |
|
ret.push(obj[i]); |
|
} |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
for (var key in obj) { |
|
obj[key] = compact(obj[key]); |
|
} |
|
|
|
return obj; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function parseObject(obj){ |
|
var ret = { base: {} }; |
|
|
|
forEach(objectKeys(obj), function(name){ |
|
merge(ret, name, obj[name]); |
|
}); |
|
|
|
return compact(ret.base); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function parseString(str){ |
|
var ret = reduce(String(str).split('&'), function(ret, pair){ |
|
var eql = indexOf(pair, '=') |
|
, brace = lastBraceInKey(pair) |
|
, key = pair.substr(0, brace || eql) |
|
, val = pair.substr(brace || eql, pair.length) |
|
, val = val.substr(indexOf(val, '=') + 1, val.length); |
|
|
|
|
|
if ('' == key) key = pair, val = ''; |
|
if ('' == key) return ret; |
|
|
|
return merge(ret, decode(key), decode(val)); |
|
}, { base: {} }).base; |
|
|
|
return compact(ret); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.parse = function(str){ |
|
if (null == str || '' == str) return {}; |
|
return 'object' == typeof str |
|
? parseObject(str) |
|
: parseString(str); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var stringify = exports.stringify = function(obj, prefix) { |
|
if (isArray(obj)) { |
|
return stringifyArray(obj, prefix); |
|
} else if ('[object Object]' == toString.call(obj)) { |
|
return stringifyObject(obj, prefix); |
|
} else if ('string' == typeof obj) { |
|
return stringifyString(obj, prefix); |
|
} else { |
|
return prefix + '=' + encodeURIComponent(String(obj)); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function stringifyString(str, prefix) { |
|
if (!prefix) throw new TypeError('stringify expects an object'); |
|
return prefix + '=' + encodeURIComponent(str); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function stringifyArray(arr, prefix) { |
|
var ret = []; |
|
if (!prefix) throw new TypeError('stringify expects an object'); |
|
for (var i = 0; i < arr.length; i++) { |
|
ret.push(stringify(arr[i], prefix + '[' + i + ']')); |
|
} |
|
return ret.join('&'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function stringifyObject(obj, prefix) { |
|
var ret = [] |
|
, keys = objectKeys(obj) |
|
, key; |
|
|
|
for (var i = 0, len = keys.length; i < len; ++i) { |
|
key = keys[i]; |
|
if ('' == key) continue; |
|
if (null == obj[key]) { |
|
ret.push(encodeURIComponent(key) + '='); |
|
} else { |
|
ret.push(stringify(obj[key], prefix |
|
? prefix + '[' + encodeURIComponent(key) + ']' |
|
: encodeURIComponent(key))); |
|
} |
|
} |
|
|
|
return ret.join('&'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function set(obj, key, val) { |
|
var v = obj[key]; |
|
if (Object.getOwnPropertyDescriptor(Object.prototype, key)) return; |
|
if (undefined === v) { |
|
obj[key] = val; |
|
} else if (isArray(v)) { |
|
v.push(val); |
|
} else { |
|
obj[key] = [v, val]; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function lastBraceInKey(str) { |
|
var len = str.length |
|
, brace |
|
, c; |
|
for (var i = 0; i < len; ++i) { |
|
c = str[i]; |
|
if (']' == c) brace = false; |
|
if ('[' == c) brace = true; |
|
if ('=' == c && !brace) return i; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function decode(str) { |
|
try { |
|
return decodeURIComponent(str.replace(/\+/g, ' ')); |
|
} catch (err) { |
|
return str; |
|
} |
|
} |
|
|