|
1 /* |
|
2 YUI 3.10.3 (build 2fb5187) |
|
3 Copyright 2013 Yahoo! Inc. All rights reserved. |
|
4 Licensed under the BSD License. |
|
5 http://yuilibrary.com/license/ |
|
6 */ |
|
7 |
|
8 YUI.add('querystring-parse', function (Y, NAME) { |
|
9 |
|
10 /** |
|
11 * The QueryString module adds support for serializing JavaScript objects into |
|
12 * query strings and parsing JavaScript objects from query strings format. |
|
13 * |
|
14 * The QueryString namespace is added to your YUI instance including static methods |
|
15 * `Y.QueryString.parse(..)` and `Y.QueryString.stringify(..)`. |
|
16 * |
|
17 * The `querystring` module is a alias for `querystring-parse` and |
|
18 * `querystring-stringify`. |
|
19 * |
|
20 * As their names suggest, `querystring-parse` adds support for parsing |
|
21 * Query String data (`Y.QueryString.parse`) and `querystring-stringify` for serializing |
|
22 * JavaScript data into Query Strings (`Y.QueryString.stringify`). You may choose to |
|
23 * include either of the submodules individually if you don't need the |
|
24 * complementary functionality, or include the rollup for both. |
|
25 * |
|
26 * @module querystring |
|
27 * @main querystring |
|
28 */ |
|
29 |
|
30 /** |
|
31 * Provides Y.QueryString.parse method to accept Query Strings and return native |
|
32 * JavaScript objects. |
|
33 * |
|
34 * @module querystring |
|
35 * @submodule querystring-parse |
|
36 */ |
|
37 |
|
38 /** |
|
39 * The QueryString module adds support for serializing JavaScript objects into |
|
40 * query strings and parsing JavaScript objects from query strings format. |
|
41 * @class QueryString |
|
42 * @static |
|
43 */ |
|
44 var QueryString = Y.namespace("QueryString"), |
|
45 |
|
46 // Parse a key=val string. |
|
47 // These can get pretty hairy |
|
48 // example flow: |
|
49 // parse(foo[bar][][bla]=baz) |
|
50 // return parse(foo[bar][][bla],"baz") |
|
51 // return parse(foo[bar][], {bla : "baz"}) |
|
52 // return parse(foo[bar], [{bla:"baz"}]) |
|
53 // return parse(foo, {bar:[{bla:"baz"}]}) |
|
54 // return {foo:{bar:[{bla:"baz"}]}} |
|
55 pieceParser = function (eq) { |
|
56 return function parsePiece (key, val) { |
|
57 |
|
58 var sliced, numVal, head, tail, ret; |
|
59 |
|
60 if (arguments.length !== 2) { |
|
61 // key=val, called from the map/reduce |
|
62 key = key.split(eq); |
|
63 return parsePiece( |
|
64 QueryString.unescape(key.shift()), |
|
65 QueryString.unescape(key.join(eq)) |
|
66 ); |
|
67 } |
|
68 key = key.replace(/^\s+|\s+$/g, ''); |
|
69 if (Y.Lang.isString(val)) { |
|
70 val = val.replace(/^\s+|\s+$/g, ''); |
|
71 // convert numerals to numbers |
|
72 if (!isNaN(val)) { |
|
73 numVal = +val; |
|
74 if (val === numVal.toString(10)) { |
|
75 val = numVal; |
|
76 } |
|
77 } |
|
78 } |
|
79 sliced = /(.*)\[([^\]]*)\]$/.exec(key); |
|
80 if (!sliced) { |
|
81 ret = {}; |
|
82 if (key) { |
|
83 ret[key] = val; |
|
84 } |
|
85 return ret; |
|
86 } |
|
87 // ["foo[][bar][][baz]", "foo[][bar][]", "baz"] |
|
88 tail = sliced[2]; |
|
89 head = sliced[1]; |
|
90 |
|
91 // array: key[]=val |
|
92 if (!tail) { |
|
93 return parsePiece(head, [val]); |
|
94 } |
|
95 |
|
96 // obj: key[subkey]=val |
|
97 ret = {}; |
|
98 ret[tail] = val; |
|
99 return parsePiece(head, ret); |
|
100 }; |
|
101 }, |
|
102 |
|
103 // the reducer function that merges each query piece together into one set of params |
|
104 mergeParams = function(params, addition) { |
|
105 return ( |
|
106 // if it's uncontested, then just return the addition. |
|
107 (!params) ? addition |
|
108 // if the existing value is an array, then concat it. |
|
109 : (Y.Lang.isArray(params)) ? params.concat(addition) |
|
110 // if the existing value is not an array, and either are not objects, arrayify it. |
|
111 : (!Y.Lang.isObject(params) || !Y.Lang.isObject(addition)) ? [params].concat(addition) |
|
112 // else merge them as objects, which is a little more complex |
|
113 : mergeObjects(params, addition) |
|
114 ); |
|
115 }, |
|
116 |
|
117 // Merge two *objects* together. If this is called, we've already ruled |
|
118 // out the simple cases, and need to do the for-in business. |
|
119 mergeObjects = function(params, addition) { |
|
120 for (var i in addition) { |
|
121 if (i && addition.hasOwnProperty(i)) { |
|
122 params[i] = mergeParams(params[i], addition[i]); |
|
123 } |
|
124 } |
|
125 return params; |
|
126 }; |
|
127 |
|
128 /** |
|
129 * Accept Query Strings and return native JavaScript objects. |
|
130 * |
|
131 * @method parse |
|
132 * @param qs {String} Querystring to be parsed into an object. |
|
133 * @param sep {String} (optional) Character that should join param k=v pairs together. Default: "&" |
|
134 * @param eq {String} (optional) Character that should join keys to their values. Default: "=" |
|
135 * @public |
|
136 * @static |
|
137 */ |
|
138 QueryString.parse = function (qs, sep, eq) { |
|
139 // wouldn't Y.Array(qs.split()).map(pieceParser(eq)).reduce(mergeParams) be prettier? |
|
140 return Y.Array.reduce( |
|
141 Y.Array.map( |
|
142 qs.split(sep || "&"), |
|
143 pieceParser(eq || "=") |
|
144 ), |
|
145 {}, |
|
146 mergeParams |
|
147 ); |
|
148 }; |
|
149 |
|
150 /** |
|
151 * Provides Y.QueryString.unescape method to be able to override default decoding |
|
152 * method. This is important in cases where non-standard delimiters are used, if |
|
153 * the delimiters would not normally be handled properly by the builtin |
|
154 * (en|de)codeURIComponent functions. |
|
155 * Default: replace "+" with " ", and then decodeURIComponent behavior. |
|
156 * |
|
157 * @method unescape |
|
158 * @param s {String} String to be decoded. |
|
159 * @public |
|
160 * @static |
|
161 **/ |
|
162 QueryString.unescape = function (s) { |
|
163 return decodeURIComponent(s.replace(/\+/g, ' ')); |
|
164 }; |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 }, '3.10.3', {"requires": ["yui-base", "array-extras"]}); |