source: Dev/branches/rest-dojo-ui/client/dojo/json.js @ 263

Last change on this file since 263 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 5.7 KB
Line 
1define(["./has"], function(has){
2        "use strict";
3        var hasJSON = typeof JSON != "undefined";
4        has.add("json-parse", hasJSON); // all the parsers work fine
5                // Firefox 3.5/Gecko 1.9 fails to use replacer in stringify properly https://bugzilla.mozilla.org/show_bug.cgi?id=509184
6        has.add("json-stringify", hasJSON && JSON.stringify({a:0}, function(k,v){return v||1;}) == '{"a":1}');
7        if(has("json-stringify")){
8                return JSON;
9        }
10        else{
11                var escapeString = function(/*String*/str){
12                        //summary:
13                        //              Adds escape sequences for non-visual characters, double quote and
14                        //              backslash and surrounds with double quotes to form a valid string
15                        //              literal.
16                        return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
17                                replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
18                                replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
19                };
20                return {
21                        parse: has("json-parse") ? JSON.parse : function(str, strict){
22                                // summary:
23                                //              Parses a [JSON](http://json.org) string to return a JavaScript object.
24                                // description:
25                                //              This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
26                                //              Throws for invalid JSON strings. This delegates to eval() if native JSON
27                                //              support is not available. By default this will evaluate any valid JS expression.
28                                //              With the strict parameter set to true, the parser will ensure that only
29                                //              valid JSON strings are parsed (otherwise throwing an error). Without the strict
30                                //              parameter, the content passed to this method must come
31                                //              from a trusted source.
32                                // str:
33                                //              a string literal of a JSON item, for instance:
34                                //                      `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
35                                //      strict:
36                                //              When set to true, this will ensure that only valid, secure JSON is ever parsed.
37                                //              Make sure this is set to true for untrusted content. Note that on browsers/engines
38                                //              without native JSON support, setting this to true will run slower.
39                                if(strict && !/^([\s\[\{]*(?:"(?:\\.|[^"])+"|-?\d[\d\.]*(?:[Ee][+-]?\d+)?|null|true|false|)[\s\]\}]*(?:,|:|$))+$/.test(str)){
40                                        throw new SyntaxError("Invalid characters in JSON");
41                                }
42                                return eval('(' + str + ')');
43                        },
44                        stringify: function(value, replacer, spacer){
45                                //      summary:
46                                //              Returns a [JSON](http://json.org) serialization of an object.
47                                //      description:
48                                //              Returns a [JSON](http://json.org) serialization of an object.
49                                //              This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
50                                //              Note that this doesn't check for infinite recursion, so don't do that!
51                                //      value:
52                                //              A value to be serialized.
53                                //      replacer:
54                                //              A replacer function that is called for each value and can return a replacement
55                                //      spacer:
56                                //              A spacer string to be used for pretty printing of JSON
57                                //             
58                                //      example:
59                                //              simple serialization of a trivial object
60                                //              |       define(["dojo/json"], function(JSON){
61                                //              |               var jsonStr = JSON.stringify({ howdy: "stranger!", isStrange: true });
62                                //              |               doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
63                                var undef;
64                                if(typeof replacer == "string"){
65                                        spacer = replacer;
66                                        replacer = null;
67                                }
68                                function stringify(it, indent, key){
69                                        if(replacer){
70                                                it = replacer(key, it);
71                                        }
72                                        var val, objtype = typeof it;
73                                        if(objtype == "number"){
74                                                return isFinite(it) ? it + "" : "null";
75                                        }
76                                        if(objtype == "boolean"){
77                                                return it + "";
78                                        }
79                                        if(it === null){
80                                                return "null";
81                                        }
82                                        if(typeof it == "string"){
83                                                return escapeString(it);
84                                        }
85                                        if(objtype == "function" || objtype == "undefined"){
86                                                return undef; // undefined
87                                        }
88                                        // short-circuit for objects that support "json" serialization
89                                        // if they return "self" then just pass-through...
90                                        if(typeof it.toJSON == "function"){
91                                                return stringify(it.toJSON(key), indent, key);
92                                        }
93                                        if(it instanceof Date){
94                                                return '"{FullYear}-{Month+}-{Date}T{Hours}:{Minutes}:{Seconds}Z"'.replace(/\{(\w+)(\+)?\}/g, function(t, prop, plus){
95                                                        var num = it["getUTC" + prop]() + (plus ? 1 : 0);
96                                                        return num < 10 ? "0" + num : num;
97                                                });
98                                        }
99                                        if(it.valueOf() !== it){
100                                                // primitive wrapper, try again unwrapped:
101                                                return stringify(it.valueOf(), indent, key);
102                                        }
103                                        var nextIndent= spacer ? (indent + spacer) : "";
104                                        /* we used to test for DOM nodes and throw, but FF serializes them as {}, so cross-browser consistency is probably not efficiently attainable */
105                               
106                                        var sep = spacer ? " " : "";
107                                        var newLine = spacer ? "\n" : "";
108                               
109                                        // array
110                                        if(it instanceof Array){
111                                                var itl = it.length, res = [];
112                                                for(key = 0; key < itl; key++){
113                                                        var obj = it[key];
114                                                        val = stringify(obj, nextIndent, key);
115                                                        if(typeof val != "string"){
116                                                                val = "null";
117                                                        }
118                                                        res.push(newLine + nextIndent + val);
119                                                }
120                                                return "[" + res.join(",") + newLine + indent + "]";
121                                        }
122                                        // generic object code path
123                                        var output = [];
124                                        for(key in it){
125                                                var keyStr;
126                                                if(typeof key == "number"){
127                                                        keyStr = '"' + key + '"';
128                                                }else if(typeof key == "string"){
129                                                        keyStr = escapeString(key);
130                                                }else{
131                                                        // skip non-string or number keys
132                                                        continue;
133                                                }
134                                                val = stringify(it[key], nextIndent, key);
135                                                if(typeof val != "string"){
136                                                        // skip non-serializable values
137                                                        continue;
138                                                }
139                                                // At this point, the most non-IE browsers don't get in this branch
140                                                // (they have native JSON), so push is definitely the way to
141                                                output.push(newLine + nextIndent + keyStr + ":" + sep + val);
142                                        }
143                                        return "{" + output.join(",") + newLine + indent + "}"; // String
144                                }
145                                return stringify(value, "", "");
146                        }
147                };
148        }
149});
Note: See TracBrowser for help on using the repository browser.