/** * @class Ext.JSON * Modified version of Douglas Crockford's JSON.js that doesn't * mess with the Object prototype * http://www.json.org/js.html * @singleton */ Ext.JSON = (new(function() { var me = this, encodingFunction, decodingFunction, useNative = null, useHasOwn = !! {}.hasOwnProperty, isNative = function() { if (useNative === null) { useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]'; } return useNative; }, pad = function(n) { return n < 10 ? "0" + n : n; }, doDecode = function(json) { return eval("(" + json + ')'); }, doEncode = function(o, newline) { // http://jsperf.com/is-undefined if (o === null || o === undefined) { return "null"; } else if (Ext.isDate(o)) { return Ext.JSON.encodeDate(o); } else if (Ext.isString(o)) { return encodeString(o); } else if (typeof o == "number") { //don't use isNumber here, since finite checks happen inside isNumber return isFinite(o) ? String(o) : "null"; } else if (Ext.isBoolean(o)) { return String(o); } // Allow custom zerialization by adding a toJSON method to any object type. // Date/String have a toJSON in some environments, so check these first. else if (o.toJSON) { return o.toJSON(); } else if (Ext.isArray(o)) { return encodeArray(o, newline); } else if (Ext.isObject(o)) { return encodeObject(o, newline); } else if (typeof o === "function") { return "null"; } return 'undefined'; }, m = { "\b": '\\b', "\t": '\\t', "\n": '\\n', "\f": '\\f', "\r": '\\r', '"': '\\"', "\\": '\\\\', '\x0b': '\\u000b' //ie doesn't handle \v }, charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g, encodeString = function(s) { return '"' + s.replace(charToReplace, function(a) { var c = m[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"'; }, // encodeArrayPretty = function(o, newline) { var len = o.length, cnewline = newline + ' ', sep = ',' + cnewline, a = ["[", cnewline], // Note newline in case there are no members i; for (i = 0; i < len; i += 1) { a.push(doEncode(o[i], cnewline), sep); } // Overwrite trailing comma (or empty string) a[a.length - 1] = newline + ']'; return a.join(''); }, encodeObjectPretty = function(o, newline) { var cnewline = newline + ' ', sep = ',' + cnewline, a = ["{", cnewline], // Note newline in case there are no members i; for (i in o) { if (!useHasOwn || o.hasOwnProperty(i)) { a.push(doEncode(i) + ': ' + doEncode(o[i], cnewline), sep); } } // Overwrite trailing comma (or empty string) a[a.length - 1] = newline + '}'; return a.join(''); }, // encodeArray = function(o, newline) { // if (newline) { return encodeArrayPretty(o, newline); } // var a = ["[", ""], // Note empty string in case there are no serializable members. len = o.length, i; for (i = 0; i < len; i += 1) { a.push(doEncode(o[i]), ','); } // Overwrite trailing comma (or empty string) a[a.length - 1] = ']'; return a.join(""); }, encodeObject = function(o, newline) { // if (newline) { return encodeObjectPretty(o, newline); } // var a = ["{", ""], // Note empty string in case there are no serializable members. i; for (i in o) { if (!useHasOwn || o.hasOwnProperty(i)) { a.push(doEncode(i), ":", doEncode(o[i]), ','); } } // Overwrite trailing comma (or empty string) a[a.length - 1] = '}'; return a.join(""); }; /** * The function which {@link #encode} uses to encode all javascript values to their JSON representations * when {@link Ext#USE_NATIVE_JSON} is `false`. * * This is made public so that it can be replaced with a custom implementation. * * @param {Object} o Any javascript value to be converted to its JSON representation * @return {String} The JSON representation of the passed value. * @method */ me.encodeValue = doEncode; /** * Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression. * **The returned value includes enclosing double quotation marks.** * * The default return format is "yyyy-mm-ddThh:mm:ss". * * To override this: * Ext.JSON.encodeDate = function(d) { * return Ext.Date.format(d, '"Y-m-d"'); * }; * * @param {Date} d The Date to encode * @return {String} The string literal to use in a JSON string. */ me.encodeDate = function(o) { return '"' + o.getFullYear() + "-" + pad(o.getMonth() + 1) + "-" + pad(o.getDate()) + "T" + pad(o.getHours()) + ":" + pad(o.getMinutes()) + ":" + pad(o.getSeconds()) + '"'; }; /** * Encodes an Object, Array or other value. * * If the environment's native JSON encoding is not being used ({@link Ext#USE_NATIVE_JSON} is not set, or the environment does not support it), then * ExtJS's encoding will be used. This allows the developer to add a `toJSON` method to their classes which need serializing to return a valid * JSON representation of the object. * * @param {Object} o The variable to encode * @return {String} The JSON string */ me.encode = function(o) { if (!encodingFunction) { // setup encoding function on first access encodingFunction = isNative() ? JSON.stringify : me.encodeValue; } return encodingFunction(o); }; /** * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set. * @param {String} json The JSON string * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid. * @return {Object} The resulting object */ me.decode = function(json, safe) { if (!decodingFunction) { // setup decoding function on first access decodingFunction = isNative() ? JSON.parse : doDecode; } try { return decodingFunction(json); } catch (e) { if (safe === true) { return null; } Ext.Error.raise({ sourceClass: "Ext.JSON", sourceMethod: "decode", msg: "You're trying to decode an invalid JSON String: " + json }); } }; })()); /** * Shorthand for {@link Ext.JSON#encode} * @member Ext * @method encode * @inheritdoc Ext.JSON#encode */ Ext.encode = Ext.JSON.encode; /** * Shorthand for {@link Ext.JSON#decode} * @member Ext * @method decode * @inheritdoc Ext.JSON#decode */ Ext.decode = Ext.JSON.decode;