Statistics
| Branch: | Tag: | Revision:

root / ui / static / json2.js @ 2ee4f989

History | View | Annotate | Download (15.4 kB)

1 d2f03cb3 Mike Muzurakis
/*
2 d2f03cb3 Mike Muzurakis
http://www.JSON.org/json2.js
3 d2f03cb3 Mike Muzurakis
2011-02-23
4 d2f03cb3 Mike Muzurakis

5 d2f03cb3 Mike Muzurakis
Public Domain.
6 d2f03cb3 Mike Muzurakis

7 d2f03cb3 Mike Muzurakis
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 d2f03cb3 Mike Muzurakis

9 d2f03cb3 Mike Muzurakis
See http://www.JSON.org/js.html
10 d2f03cb3 Mike Muzurakis

11 d2f03cb3 Mike Muzurakis

12 d2f03cb3 Mike Muzurakis
This code should be minified before deployment.
13 d2f03cb3 Mike Muzurakis
See http://javascript.crockford.com/jsmin.html
14 d2f03cb3 Mike Muzurakis

15 d2f03cb3 Mike Muzurakis
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
16 d2f03cb3 Mike Muzurakis
NOT CONTROL.
17 d2f03cb3 Mike Muzurakis

18 d2f03cb3 Mike Muzurakis

19 d2f03cb3 Mike Muzurakis
This file creates a global JSON object containing two methods: stringify
20 d2f03cb3 Mike Muzurakis
and parse.
21 d2f03cb3 Mike Muzurakis

22 d2f03cb3 Mike Muzurakis
JSON.stringify(value, replacer, space)
23 d2f03cb3 Mike Muzurakis
value any JavaScript value, usually an object or array.
24 d2f03cb3 Mike Muzurakis

25 d2f03cb3 Mike Muzurakis
replacer an optional parameter that determines how object
26 d2f03cb3 Mike Muzurakis
values are stringified for objects. It can be a
27 d2f03cb3 Mike Muzurakis
function or an array of strings.
28 d2f03cb3 Mike Muzurakis

29 d2f03cb3 Mike Muzurakis
space an optional parameter that specifies the indentation
30 d2f03cb3 Mike Muzurakis
of nested structures. If it is omitted, the text will
31 d2f03cb3 Mike Muzurakis
be packed without extra whitespace. If it is a number,
32 d2f03cb3 Mike Muzurakis
it will specify the number of spaces to indent at each
33 d2f03cb3 Mike Muzurakis
level. If it is a string (such as '\t' or ' '),
34 d2f03cb3 Mike Muzurakis
it contains the characters used to indent at each level.
35 d2f03cb3 Mike Muzurakis

36 d2f03cb3 Mike Muzurakis
This method produces a JSON text from a JavaScript value.
37 d2f03cb3 Mike Muzurakis

38 d2f03cb3 Mike Muzurakis
When an object value is found, if the object contains a toJSON
39 d2f03cb3 Mike Muzurakis
method, its toJSON method will be called and the result will be
40 d2f03cb3 Mike Muzurakis
stringified. A toJSON method does not serialize: it returns the
41 d2f03cb3 Mike Muzurakis
value represented by the name/value pair that should be serialized,
42 d2f03cb3 Mike Muzurakis
or undefined if nothing should be serialized. The toJSON method
43 d2f03cb3 Mike Muzurakis
will be passed the key associated with the value, and this will be
44 d2f03cb3 Mike Muzurakis
bound to the value
45 d2f03cb3 Mike Muzurakis

46 d2f03cb3 Mike Muzurakis
For example, this would serialize Dates as ISO strings.
47 d2f03cb3 Mike Muzurakis

48 d2f03cb3 Mike Muzurakis
Date.prototype.toJSON = function (key) {
49 d2f03cb3 Mike Muzurakis
function f(n) {
50 d2f03cb3 Mike Muzurakis
// Format integers to have at least two digits.
51 d2f03cb3 Mike Muzurakis
return n < 10 ? '0' + n : n;
52 d2f03cb3 Mike Muzurakis
}
53 d2f03cb3 Mike Muzurakis

54 d2f03cb3 Mike Muzurakis
return this.getUTCFullYear() + '-' +
55 d2f03cb3 Mike Muzurakis
f(this.getUTCMonth() + 1) + '-' +
56 d2f03cb3 Mike Muzurakis
f(this.getUTCDate()) + 'T' +
57 d2f03cb3 Mike Muzurakis
f(this.getUTCHours()) + ':' +
58 d2f03cb3 Mike Muzurakis
f(this.getUTCMinutes()) + ':' +
59 d2f03cb3 Mike Muzurakis
f(this.getUTCSeconds()) + 'Z';
60 d2f03cb3 Mike Muzurakis
};
61 d2f03cb3 Mike Muzurakis

62 d2f03cb3 Mike Muzurakis
You can provide an optional replacer method. It will be passed the
63 d2f03cb3 Mike Muzurakis
key and value of each member, with this bound to the containing
64 d2f03cb3 Mike Muzurakis
object. The value that is returned from your method will be
65 d2f03cb3 Mike Muzurakis
serialized. If your method returns undefined, then the member will
66 d2f03cb3 Mike Muzurakis
be excluded from the serialization.
67 d2f03cb3 Mike Muzurakis

68 d2f03cb3 Mike Muzurakis
If the replacer parameter is an array of strings, then it will be
69 d2f03cb3 Mike Muzurakis
used to select the members to be serialized. It filters the results
70 d2f03cb3 Mike Muzurakis
such that only members with keys listed in the replacer array are
71 d2f03cb3 Mike Muzurakis
stringified.
72 d2f03cb3 Mike Muzurakis

73 d2f03cb3 Mike Muzurakis
Values that do not have JSON representations, such as undefined or
74 d2f03cb3 Mike Muzurakis
functions, will not be serialized. Such values in objects will be
75 d2f03cb3 Mike Muzurakis
dropped; in arrays they will be replaced with null. You can use
76 d2f03cb3 Mike Muzurakis
a replacer function to replace those with JSON values.
77 d2f03cb3 Mike Muzurakis
JSON.stringify(undefined) returns undefined.
78 d2f03cb3 Mike Muzurakis

79 d2f03cb3 Mike Muzurakis
The optional space parameter produces a stringification of the
80 d2f03cb3 Mike Muzurakis
value that is filled with line breaks and indentation to make it
81 d2f03cb3 Mike Muzurakis
easier to read.
82 d2f03cb3 Mike Muzurakis

83 d2f03cb3 Mike Muzurakis
If the space parameter is a non-empty string, then that string will
84 d2f03cb3 Mike Muzurakis
be used for indentation. If the space parameter is a number, then
85 d2f03cb3 Mike Muzurakis
the indentation will be that many spaces.
86 d2f03cb3 Mike Muzurakis

87 d2f03cb3 Mike Muzurakis
Example:
88 d2f03cb3 Mike Muzurakis

89 d2f03cb3 Mike Muzurakis
text = JSON.stringify(['e', {pluribus: 'unum'}]);
90 d2f03cb3 Mike Muzurakis
// text is '["e",{"pluribus":"unum"}]'
91 d2f03cb3 Mike Muzurakis

92 d2f03cb3 Mike Muzurakis

93 d2f03cb3 Mike Muzurakis
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
94 d2f03cb3 Mike Muzurakis
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
95 d2f03cb3 Mike Muzurakis

96 d2f03cb3 Mike Muzurakis
text = JSON.stringify([new Date()], function (key, value) {
97 d2f03cb3 Mike Muzurakis
return this[key] instanceof Date ?
98 d2f03cb3 Mike Muzurakis
'Date(' + this[key] + ')' : value;
99 d2f03cb3 Mike Muzurakis
});
100 d2f03cb3 Mike Muzurakis
// text is '["Date(---current time---)"]'
101 d2f03cb3 Mike Muzurakis

102 d2f03cb3 Mike Muzurakis

103 d2f03cb3 Mike Muzurakis
JSON.parse(text, reviver)
104 d2f03cb3 Mike Muzurakis
This method parses a JSON text to produce an object or array.
105 d2f03cb3 Mike Muzurakis
It can throw a SyntaxError exception.
106 d2f03cb3 Mike Muzurakis

107 d2f03cb3 Mike Muzurakis
The optional reviver parameter is a function that can filter and
108 d2f03cb3 Mike Muzurakis
transform the results. It receives each of the keys and values,
109 d2f03cb3 Mike Muzurakis
and its return value is used instead of the original value.
110 d2f03cb3 Mike Muzurakis
If it returns what it received, then the structure is not modified.
111 d2f03cb3 Mike Muzurakis
If it returns undefined then the member is deleted.
112 d2f03cb3 Mike Muzurakis

113 d2f03cb3 Mike Muzurakis
Example:
114 d2f03cb3 Mike Muzurakis

115 d2f03cb3 Mike Muzurakis
// Parse the text. Values that look like ISO date strings will
116 d2f03cb3 Mike Muzurakis
// be converted to Date objects.
117 d2f03cb3 Mike Muzurakis

118 d2f03cb3 Mike Muzurakis
myData = JSON.parse(text, function (key, value) {
119 d2f03cb3 Mike Muzurakis
var a;
120 d2f03cb3 Mike Muzurakis
if (typeof value === 'string') {
121 d2f03cb3 Mike Muzurakis
a =
122 d2f03cb3 Mike Muzurakis
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
123 d2f03cb3 Mike Muzurakis
if (a) {
124 d2f03cb3 Mike Muzurakis
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
125 d2f03cb3 Mike Muzurakis
+a[5], +a[6]));
126 d2f03cb3 Mike Muzurakis
}
127 d2f03cb3 Mike Muzurakis
}
128 d2f03cb3 Mike Muzurakis
return value;
129 d2f03cb3 Mike Muzurakis
});
130 d2f03cb3 Mike Muzurakis

131 d2f03cb3 Mike Muzurakis
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
132 d2f03cb3 Mike Muzurakis
var d;
133 d2f03cb3 Mike Muzurakis
if (typeof value === 'string' &&
134 d2f03cb3 Mike Muzurakis
value.slice(0, 5) === 'Date(' &&
135 d2f03cb3 Mike Muzurakis
value.slice(-1) === ')') {
136 d2f03cb3 Mike Muzurakis
d = new Date(value.slice(5, -1));
137 d2f03cb3 Mike Muzurakis
if (d) {
138 d2f03cb3 Mike Muzurakis
return d;
139 d2f03cb3 Mike Muzurakis
}
140 d2f03cb3 Mike Muzurakis
}
141 d2f03cb3 Mike Muzurakis
return value;
142 d2f03cb3 Mike Muzurakis
});
143 d2f03cb3 Mike Muzurakis

144 d2f03cb3 Mike Muzurakis

145 d2f03cb3 Mike Muzurakis
This is a reference implementation. You are free to copy, modify, or
146 d2f03cb3 Mike Muzurakis
redistribute.
147 d2f03cb3 Mike Muzurakis
*/
148 d2f03cb3 Mike Muzurakis
149 d2f03cb3 Mike Muzurakis
/*jslint evil: true, strict: false, regexp: false */
150 d2f03cb3 Mike Muzurakis
151 d2f03cb3 Mike Muzurakis
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
152 d2f03cb3 Mike Muzurakis
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
153 d2f03cb3 Mike Muzurakis
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
154 d2f03cb3 Mike Muzurakis
lastIndex, length, parse, prototype, push, replace, slice, stringify,
155 d2f03cb3 Mike Muzurakis
test, toJSON, toString, valueOf
156 d2f03cb3 Mike Muzurakis
*/
157 d2f03cb3 Mike Muzurakis
158 d2f03cb3 Mike Muzurakis
159 d2f03cb3 Mike Muzurakis
// Create a JSON object only if one does not already exist. We create the
160 d2f03cb3 Mike Muzurakis
// methods in a closure to avoid creating global variables.
161 d2f03cb3 Mike Muzurakis
162 d2f03cb3 Mike Muzurakis
var JSON;
163 d2f03cb3 Mike Muzurakis
if (!JSON) {
164 d2f03cb3 Mike Muzurakis
    JSON = {};
165 d2f03cb3 Mike Muzurakis
}
166 d2f03cb3 Mike Muzurakis
167 d2f03cb3 Mike Muzurakis
(function () {
168 d2f03cb3 Mike Muzurakis
    "use strict";
169 d2f03cb3 Mike Muzurakis
170 d2f03cb3 Mike Muzurakis
    function f(n) {
171 d2f03cb3 Mike Muzurakis
        // Format integers to have at least two digits.
172 d2f03cb3 Mike Muzurakis
        return n < 10 ? '0' + n : n;
173 d2f03cb3 Mike Muzurakis
    }
174 d2f03cb3 Mike Muzurakis
175 d2f03cb3 Mike Muzurakis
    if (typeof Date.prototype.toJSON !== 'function') {
176 d2f03cb3 Mike Muzurakis
177 d2f03cb3 Mike Muzurakis
        Date.prototype.toJSON = function (key) {
178 d2f03cb3 Mike Muzurakis
179 d2f03cb3 Mike Muzurakis
            return isFinite(this.valueOf()) ?
180 d2f03cb3 Mike Muzurakis
                this.getUTCFullYear() + '-' +
181 d2f03cb3 Mike Muzurakis
                f(this.getUTCMonth() + 1) + '-' +
182 d2f03cb3 Mike Muzurakis
                f(this.getUTCDate()) + 'T' +
183 d2f03cb3 Mike Muzurakis
                f(this.getUTCHours()) + ':' +
184 d2f03cb3 Mike Muzurakis
                f(this.getUTCMinutes()) + ':' +
185 d2f03cb3 Mike Muzurakis
                f(this.getUTCSeconds()) + 'Z' : null;
186 d2f03cb3 Mike Muzurakis
        };
187 d2f03cb3 Mike Muzurakis
188 d2f03cb3 Mike Muzurakis
        String.prototype.toJSON =
189 d2f03cb3 Mike Muzurakis
            Number.prototype.toJSON =
190 d2f03cb3 Mike Muzurakis
            Boolean.prototype.toJSON = function (key) {
191 d2f03cb3 Mike Muzurakis
                return this.valueOf();
192 d2f03cb3 Mike Muzurakis
            };
193 d2f03cb3 Mike Muzurakis
    }
194 d2f03cb3 Mike Muzurakis
195 d2f03cb3 Mike Muzurakis
    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
196 d2f03cb3 Mike Muzurakis
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
197 d2f03cb3 Mike Muzurakis
        gap,
198 d2f03cb3 Mike Muzurakis
        indent,
199 d2f03cb3 Mike Muzurakis
        meta = { // table of character substitutions
200 d2f03cb3 Mike Muzurakis
            '\b': '\\b',
201 d2f03cb3 Mike Muzurakis
            '\t': '\\t',
202 d2f03cb3 Mike Muzurakis
            '\n': '\\n',
203 d2f03cb3 Mike Muzurakis
            '\f': '\\f',
204 d2f03cb3 Mike Muzurakis
            '\r': '\\r',
205 d2f03cb3 Mike Muzurakis
            '"' : '\\"',
206 d2f03cb3 Mike Muzurakis
            '\\': '\\\\'
207 d2f03cb3 Mike Muzurakis
        },
208 d2f03cb3 Mike Muzurakis
        rep;
209 d2f03cb3 Mike Muzurakis
210 d2f03cb3 Mike Muzurakis
211 d2f03cb3 Mike Muzurakis
    function quote(string) {
212 d2f03cb3 Mike Muzurakis
213 d2f03cb3 Mike Muzurakis
// If the string contains no control characters, no quote characters, and no
214 d2f03cb3 Mike Muzurakis
// backslash characters, then we can safely slap some quotes around it.
215 d2f03cb3 Mike Muzurakis
// Otherwise we must also replace the offending characters with safe escape
216 d2f03cb3 Mike Muzurakis
// sequences.
217 d2f03cb3 Mike Muzurakis
218 d2f03cb3 Mike Muzurakis
        escapable.lastIndex = 0;
219 d2f03cb3 Mike Muzurakis
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
220 d2f03cb3 Mike Muzurakis
            var c = meta[a];
221 d2f03cb3 Mike Muzurakis
            return typeof c === 'string' ? c :
222 d2f03cb3 Mike Muzurakis
                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
223 d2f03cb3 Mike Muzurakis
        }) + '"' : '"' + string + '"';
224 d2f03cb3 Mike Muzurakis
    }
225 d2f03cb3 Mike Muzurakis
226 d2f03cb3 Mike Muzurakis
227 d2f03cb3 Mike Muzurakis
    function str(key, holder) {
228 d2f03cb3 Mike Muzurakis
229 d2f03cb3 Mike Muzurakis
// Produce a string from holder[key].
230 d2f03cb3 Mike Muzurakis
231 d2f03cb3 Mike Muzurakis
        var i, // The loop counter.
232 d2f03cb3 Mike Muzurakis
            k, // The member key.
233 d2f03cb3 Mike Muzurakis
            v, // The member value.
234 d2f03cb3 Mike Muzurakis
            length,
235 d2f03cb3 Mike Muzurakis
            mind = gap,
236 d2f03cb3 Mike Muzurakis
            partial,
237 d2f03cb3 Mike Muzurakis
            value = holder[key];
238 d2f03cb3 Mike Muzurakis
239 d2f03cb3 Mike Muzurakis
// If the value has a toJSON method, call it to obtain a replacement value.
240 d2f03cb3 Mike Muzurakis
241 d2f03cb3 Mike Muzurakis
        if (value && typeof value === 'object' &&
242 d2f03cb3 Mike Muzurakis
                typeof value.toJSON === 'function') {
243 d2f03cb3 Mike Muzurakis
            value = value.toJSON(key);
244 d2f03cb3 Mike Muzurakis
        }
245 d2f03cb3 Mike Muzurakis
246 d2f03cb3 Mike Muzurakis
// If we were called with a replacer function, then call the replacer to
247 d2f03cb3 Mike Muzurakis
// obtain a replacement value.
248 d2f03cb3 Mike Muzurakis
249 d2f03cb3 Mike Muzurakis
        if (typeof rep === 'function') {
250 d2f03cb3 Mike Muzurakis
            value = rep.call(holder, key, value);
251 d2f03cb3 Mike Muzurakis
        }
252 d2f03cb3 Mike Muzurakis
253 d2f03cb3 Mike Muzurakis
// What happens next depends on the value's type.
254 d2f03cb3 Mike Muzurakis
255 d2f03cb3 Mike Muzurakis
        switch (typeof value) {
256 d2f03cb3 Mike Muzurakis
        case 'string':
257 d2f03cb3 Mike Muzurakis
            return quote(value);
258 d2f03cb3 Mike Muzurakis
259 d2f03cb3 Mike Muzurakis
        case 'number':
260 d2f03cb3 Mike Muzurakis
261 d2f03cb3 Mike Muzurakis
// JSON numbers must be finite. Encode non-finite numbers as null.
262 d2f03cb3 Mike Muzurakis
263 d2f03cb3 Mike Muzurakis
            return isFinite(value) ? String(value) : 'null';
264 d2f03cb3 Mike Muzurakis
265 d2f03cb3 Mike Muzurakis
        case 'boolean':
266 d2f03cb3 Mike Muzurakis
        case 'null':
267 d2f03cb3 Mike Muzurakis
268 d2f03cb3 Mike Muzurakis
// If the value is a boolean or null, convert it to a string. Note:
269 d2f03cb3 Mike Muzurakis
// typeof null does not produce 'null'. The case is included here in
270 d2f03cb3 Mike Muzurakis
// the remote chance that this gets fixed someday.
271 d2f03cb3 Mike Muzurakis
272 d2f03cb3 Mike Muzurakis
            return String(value);
273 d2f03cb3 Mike Muzurakis
274 d2f03cb3 Mike Muzurakis
// If the type is 'object', we might be dealing with an object or an array or
275 d2f03cb3 Mike Muzurakis
// null.
276 d2f03cb3 Mike Muzurakis
277 d2f03cb3 Mike Muzurakis
        case 'object':
278 d2f03cb3 Mike Muzurakis
279 d2f03cb3 Mike Muzurakis
// Due to a specification blunder in ECMAScript, typeof null is 'object',
280 d2f03cb3 Mike Muzurakis
// so watch out for that case.
281 d2f03cb3 Mike Muzurakis
282 d2f03cb3 Mike Muzurakis
            if (!value) {
283 d2f03cb3 Mike Muzurakis
                return 'null';
284 d2f03cb3 Mike Muzurakis
            }
285 d2f03cb3 Mike Muzurakis
286 d2f03cb3 Mike Muzurakis
// Make an array to hold the partial results of stringifying this object value.
287 d2f03cb3 Mike Muzurakis
288 d2f03cb3 Mike Muzurakis
            gap += indent;
289 d2f03cb3 Mike Muzurakis
            partial = [];
290 d2f03cb3 Mike Muzurakis
291 d2f03cb3 Mike Muzurakis
// Is the value an array?
292 d2f03cb3 Mike Muzurakis
293 d2f03cb3 Mike Muzurakis
            if (Object.prototype.toString.apply(value) === '[object Array]') {
294 d2f03cb3 Mike Muzurakis
295 d2f03cb3 Mike Muzurakis
// The value is an array. Stringify every element. Use null as a placeholder
296 d2f03cb3 Mike Muzurakis
// for non-JSON values.
297 d2f03cb3 Mike Muzurakis
298 d2f03cb3 Mike Muzurakis
                length = value.length;
299 d2f03cb3 Mike Muzurakis
                for (i = 0; i < length; i += 1) {
300 d2f03cb3 Mike Muzurakis
                    partial[i] = str(i, value) || 'null';
301 d2f03cb3 Mike Muzurakis
                }
302 d2f03cb3 Mike Muzurakis
303 d2f03cb3 Mike Muzurakis
// Join all of the elements together, separated with commas, and wrap them in
304 d2f03cb3 Mike Muzurakis
// brackets.
305 d2f03cb3 Mike Muzurakis
306 d2f03cb3 Mike Muzurakis
                v = partial.length === 0 ? '[]' : gap ?
307 d2f03cb3 Mike Muzurakis
                    '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
308 d2f03cb3 Mike Muzurakis
                    '[' + partial.join(',') + ']';
309 d2f03cb3 Mike Muzurakis
                gap = mind;
310 d2f03cb3 Mike Muzurakis
                return v;
311 d2f03cb3 Mike Muzurakis
            }
312 d2f03cb3 Mike Muzurakis
313 d2f03cb3 Mike Muzurakis
// If the replacer is an array, use it to select the members to be stringified.
314 d2f03cb3 Mike Muzurakis
315 d2f03cb3 Mike Muzurakis
            if (rep && typeof rep === 'object') {
316 d2f03cb3 Mike Muzurakis
                length = rep.length;
317 d2f03cb3 Mike Muzurakis
                for (i = 0; i < length; i += 1) {
318 d2f03cb3 Mike Muzurakis
                    if (typeof rep[i] === 'string') {
319 d2f03cb3 Mike Muzurakis
                        k = rep[i];
320 d2f03cb3 Mike Muzurakis
                        v = str(k, value);
321 d2f03cb3 Mike Muzurakis
                        if (v) {
322 d2f03cb3 Mike Muzurakis
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
323 d2f03cb3 Mike Muzurakis
                        }
324 d2f03cb3 Mike Muzurakis
                    }
325 d2f03cb3 Mike Muzurakis
                }
326 d2f03cb3 Mike Muzurakis
            } else {
327 d2f03cb3 Mike Muzurakis
328 d2f03cb3 Mike Muzurakis
// Otherwise, iterate through all of the keys in the object.
329 d2f03cb3 Mike Muzurakis
330 d2f03cb3 Mike Muzurakis
                for (k in value) {
331 d2f03cb3 Mike Muzurakis
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
332 d2f03cb3 Mike Muzurakis
                        v = str(k, value);
333 d2f03cb3 Mike Muzurakis
                        if (v) {
334 d2f03cb3 Mike Muzurakis
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
335 d2f03cb3 Mike Muzurakis
                        }
336 d2f03cb3 Mike Muzurakis
                    }
337 d2f03cb3 Mike Muzurakis
                }
338 d2f03cb3 Mike Muzurakis
            }
339 d2f03cb3 Mike Muzurakis
340 d2f03cb3 Mike Muzurakis
// Join all of the member texts together, separated with commas,
341 d2f03cb3 Mike Muzurakis
// and wrap them in braces.
342 d2f03cb3 Mike Muzurakis
343 d2f03cb3 Mike Muzurakis
            v = partial.length === 0 ? '{}' : gap ?
344 d2f03cb3 Mike Muzurakis
                '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
345 d2f03cb3 Mike Muzurakis
                '{' + partial.join(',') + '}';
346 d2f03cb3 Mike Muzurakis
            gap = mind;
347 d2f03cb3 Mike Muzurakis
            return v;
348 d2f03cb3 Mike Muzurakis
        }
349 d2f03cb3 Mike Muzurakis
    }
350 d2f03cb3 Mike Muzurakis
351 d2f03cb3 Mike Muzurakis
// If the JSON object does not yet have a stringify method, give it one.
352 d2f03cb3 Mike Muzurakis
353 d2f03cb3 Mike Muzurakis
    if (typeof JSON.stringify !== 'function') {
354 d2f03cb3 Mike Muzurakis
        JSON.stringify = function (value, replacer, space) {
355 d2f03cb3 Mike Muzurakis
356 d2f03cb3 Mike Muzurakis
// The stringify method takes a value and an optional replacer, and an optional
357 d2f03cb3 Mike Muzurakis
// space parameter, and returns a JSON text. The replacer can be a function
358 d2f03cb3 Mike Muzurakis
// that can replace values, or an array of strings that will select the keys.
359 d2f03cb3 Mike Muzurakis
// A default replacer method can be provided. Use of the space parameter can
360 d2f03cb3 Mike Muzurakis
// produce text that is more easily readable.
361 d2f03cb3 Mike Muzurakis
362 d2f03cb3 Mike Muzurakis
            var i;
363 d2f03cb3 Mike Muzurakis
            gap = '';
364 d2f03cb3 Mike Muzurakis
            indent = '';
365 d2f03cb3 Mike Muzurakis
366 d2f03cb3 Mike Muzurakis
// If the space parameter is a number, make an indent string containing that
367 d2f03cb3 Mike Muzurakis
// many spaces.
368 d2f03cb3 Mike Muzurakis
369 d2f03cb3 Mike Muzurakis
            if (typeof space === 'number') {
370 d2f03cb3 Mike Muzurakis
                for (i = 0; i < space; i += 1) {
371 d2f03cb3 Mike Muzurakis
                    indent += ' ';
372 d2f03cb3 Mike Muzurakis
                }
373 d2f03cb3 Mike Muzurakis
374 d2f03cb3 Mike Muzurakis
// If the space parameter is a string, it will be used as the indent string.
375 d2f03cb3 Mike Muzurakis
376 d2f03cb3 Mike Muzurakis
            } else if (typeof space === 'string') {
377 d2f03cb3 Mike Muzurakis
                indent = space;
378 d2f03cb3 Mike Muzurakis
            }
379 d2f03cb3 Mike Muzurakis
380 d2f03cb3 Mike Muzurakis
// If there is a replacer, it must be a function or an array.
381 d2f03cb3 Mike Muzurakis
// Otherwise, throw an error.
382 d2f03cb3 Mike Muzurakis
383 d2f03cb3 Mike Muzurakis
            rep = replacer;
384 d2f03cb3 Mike Muzurakis
            if (replacer && typeof replacer !== 'function' &&
385 d2f03cb3 Mike Muzurakis
                    (typeof replacer !== 'object' ||
386 d2f03cb3 Mike Muzurakis
                    typeof replacer.length !== 'number')) {
387 d2f03cb3 Mike Muzurakis
                throw new Error('JSON.stringify');
388 d2f03cb3 Mike Muzurakis
            }
389 d2f03cb3 Mike Muzurakis
390 d2f03cb3 Mike Muzurakis
// Make a fake root object containing our value under the key of ''.
391 d2f03cb3 Mike Muzurakis
// Return the result of stringifying the value.
392 d2f03cb3 Mike Muzurakis
393 d2f03cb3 Mike Muzurakis
            return str('', {'': value});
394 d2f03cb3 Mike Muzurakis
        };
395 d2f03cb3 Mike Muzurakis
    }
396 d2f03cb3 Mike Muzurakis
397 d2f03cb3 Mike Muzurakis
398 d2f03cb3 Mike Muzurakis
// If the JSON object does not yet have a parse method, give it one.
399 d2f03cb3 Mike Muzurakis
400 d2f03cb3 Mike Muzurakis
    if (typeof JSON.parse !== 'function') {
401 d2f03cb3 Mike Muzurakis
        JSON.parse = function (text, reviver) {
402 d2f03cb3 Mike Muzurakis
403 d2f03cb3 Mike Muzurakis
// The parse method takes a text and an optional reviver function, and returns
404 d2f03cb3 Mike Muzurakis
// a JavaScript value if the text is a valid JSON text.
405 d2f03cb3 Mike Muzurakis
406 d2f03cb3 Mike Muzurakis
            var j;
407 d2f03cb3 Mike Muzurakis
408 d2f03cb3 Mike Muzurakis
            function walk(holder, key) {
409 d2f03cb3 Mike Muzurakis
410 d2f03cb3 Mike Muzurakis
// The walk method is used to recursively walk the resulting structure so
411 d2f03cb3 Mike Muzurakis
// that modifications can be made.
412 d2f03cb3 Mike Muzurakis
413 d2f03cb3 Mike Muzurakis
                var k, v, value = holder[key];
414 d2f03cb3 Mike Muzurakis
                if (value && typeof value === 'object') {
415 d2f03cb3 Mike Muzurakis
                    for (k in value) {
416 d2f03cb3 Mike Muzurakis
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
417 d2f03cb3 Mike Muzurakis
                            v = walk(value, k);
418 d2f03cb3 Mike Muzurakis
                            if (v !== undefined) {
419 d2f03cb3 Mike Muzurakis
                                value[k] = v;
420 d2f03cb3 Mike Muzurakis
                            } else {
421 d2f03cb3 Mike Muzurakis
                                delete value[k];
422 d2f03cb3 Mike Muzurakis
                            }
423 d2f03cb3 Mike Muzurakis
                        }
424 d2f03cb3 Mike Muzurakis
                    }
425 d2f03cb3 Mike Muzurakis
                }
426 d2f03cb3 Mike Muzurakis
                return reviver.call(holder, key, value);
427 d2f03cb3 Mike Muzurakis
            }
428 d2f03cb3 Mike Muzurakis
429 d2f03cb3 Mike Muzurakis
430 d2f03cb3 Mike Muzurakis
// Parsing happens in four stages. In the first stage, we replace certain
431 d2f03cb3 Mike Muzurakis
// Unicode characters with escape sequences. JavaScript handles many characters
432 d2f03cb3 Mike Muzurakis
// incorrectly, either silently deleting them, or treating them as line endings.
433 d2f03cb3 Mike Muzurakis
434 d2f03cb3 Mike Muzurakis
            text = String(text);
435 d2f03cb3 Mike Muzurakis
            cx.lastIndex = 0;
436 d2f03cb3 Mike Muzurakis
            if (cx.test(text)) {
437 d2f03cb3 Mike Muzurakis
                text = text.replace(cx, function (a) {
438 d2f03cb3 Mike Muzurakis
                    return '\\u' +
439 d2f03cb3 Mike Muzurakis
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
440 d2f03cb3 Mike Muzurakis
                });
441 d2f03cb3 Mike Muzurakis
            }
442 d2f03cb3 Mike Muzurakis
443 d2f03cb3 Mike Muzurakis
// In the second stage, we run the text against regular expressions that look
444 d2f03cb3 Mike Muzurakis
// for non-JSON patterns. We are especially concerned with '()' and 'new'
445 d2f03cb3 Mike Muzurakis
// because they can cause invocation, and '=' because it can cause mutation.
446 d2f03cb3 Mike Muzurakis
// But just to be safe, we want to reject all unexpected forms.
447 d2f03cb3 Mike Muzurakis
448 d2f03cb3 Mike Muzurakis
// We split the second stage into 4 regexp operations in order to work around
449 d2f03cb3 Mike Muzurakis
// crippling inefficiencies in IE's and Safari's regexp engines. First we
450 d2f03cb3 Mike Muzurakis
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
451 d2f03cb3 Mike Muzurakis
// replace all simple value tokens with ']' characters. Third, we delete all
452 d2f03cb3 Mike Muzurakis
// open brackets that follow a colon or comma or that begin the text. Finally,
453 d2f03cb3 Mike Muzurakis
// we look to see that the remaining characters are only whitespace or ']' or
454 d2f03cb3 Mike Muzurakis
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
455 d2f03cb3 Mike Muzurakis
456 d2f03cb3 Mike Muzurakis
            if (/^[\],:{}\s]*$/
457 d2f03cb3 Mike Muzurakis
                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
458 d2f03cb3 Mike Muzurakis
                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
459 d2f03cb3 Mike Muzurakis
                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
460 d2f03cb3 Mike Muzurakis
461 d2f03cb3 Mike Muzurakis
// In the third stage we use the eval function to compile the text into a
462 d2f03cb3 Mike Muzurakis
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
463 d2f03cb3 Mike Muzurakis
// in JavaScript: it can begin a block or an object literal. We wrap the text
464 d2f03cb3 Mike Muzurakis
// in parens to eliminate the ambiguity.
465 d2f03cb3 Mike Muzurakis
466 d2f03cb3 Mike Muzurakis
                j = eval('(' + text + ')');
467 d2f03cb3 Mike Muzurakis
468 d2f03cb3 Mike Muzurakis
// In the optional fourth stage, we recursively walk the new structure, passing
469 d2f03cb3 Mike Muzurakis
// each name/value pair to a reviver function for possible transformation.
470 d2f03cb3 Mike Muzurakis
471 d2f03cb3 Mike Muzurakis
                return typeof reviver === 'function' ?
472 d2f03cb3 Mike Muzurakis
                    walk({'': j}, '') : j;
473 d2f03cb3 Mike Muzurakis
            }
474 d2f03cb3 Mike Muzurakis
475 d2f03cb3 Mike Muzurakis
// If the text is not JSON parseable, then a SyntaxError is thrown.
476 d2f03cb3 Mike Muzurakis
477 d2f03cb3 Mike Muzurakis
            throw new SyntaxError('JSON.parse');
478 d2f03cb3 Mike Muzurakis
        };
479 d2f03cb3 Mike Muzurakis
    }
480 d2f03cb3 Mike Muzurakis
}());
481 d2f03cb3 Mike Muzurakis