Форк Rambox
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

288 lines
9.1 KiB

/**
* @property {Boolean} [USE_NATIVE_JSON=false]
* @member Ext
* Indicates whether to use native browser parsing for JSON methods.
* This option is ignored if the browser does not support native JSON methods.
*
* **Note:** Native JSON methods will not work with objects that have functions.
* Also, property names must be quoted, otherwise the data will not parse.
*/
Ext.USE_NATIVE_JSON = false;
/**
* Modified version of [Douglas Crockford's JSON.js][dc] that doesn't
* mess with the Object prototype.
*
* [dc]: http://www.json.org/js.html
*
* @class Ext.JSON
* @singleton
*/
Ext.JSON = (new(function() {
// @define Ext.JSON
// @require Ext
// @require Ext.Error
var me = this,
hasNative = window.JSON && JSON.toString() === '[object JSON]',
useHasOwn = !! {}.hasOwnProperty,
pad = function(n) {
return n < 10 ? "0" + n : n;
},
doDecode = function(json) {
return eval("(" + json + ')'); // jshint ignore:line
},
doEncode = function(o, newline) {
// http://jsperf.com/is-undefined
if (o === null || o === undefined) {
return "null";
} else if (Ext.isDate(o)) {
return me.encodeDate(o);
} else if (Ext.isString(o)) {
if (Ext.isMSDate(o)) {
return me.encodeMSDate(o);
} else {
return me.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);
}) + '"';
},
encodeMSDate = function(o) {
return '"' + o + '"';
},
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(me.encodeValue(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, val;
for (i in o) {
val = o[i];
if (!useHasOwn || o.hasOwnProperty(i)) {
// To match JSON.stringify, we shouldn't encode functions or undefined
if (typeof val === 'function' || val === undefined) {
continue;
}
a.push(me.encodeValue(i) + ': ' + me.encodeValue(val, 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(me.encodeValue(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, val;
for (i in o) {
val = o[i];
if (!useHasOwn || o.hasOwnProperty(i)) {
// To match JSON.stringify, we shouldn't encode functions or undefined
if (typeof val === 'function' || val === undefined) {
continue;
}
a.push(me.encodeValue(i), ":", me.encodeValue(val), ',');
}
}
// Overwrite trailing comma (or empty string)
a[a.length - 1] = '}';
return a.join("");
};
/**
* Encodes a String. This returns the actual string which is inserted into the JSON string as the literal
* expression. **The returned value includes enclosing double quotation marks.**
*
* To override this:
*
* Ext.JSON.encodeString = function(s) {
* return 'Foo' + s;
* };
*
* @param {String} s The String to encode
* @return {String} The string literal to use in a JSON string.
* @method
*/
me.encodeString = encodeString;
/**
* 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) {
// check USE_NATIVE_JSON here so it can be changed if needed
if (hasNative && Ext.USE_NATIVE_JSON) {
return JSON.stringify(o);
}
return me.encodeValue(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=false] `true` to return null, otherwise throw an exception
* if the JSON is invalid.
* @return {Object} The resulting object.
*/
me.decode = function(json, safe) {
try {
// check USE_NATIVE_JSON here so it can be changed if needed
if (hasNative && Ext.USE_NATIVE_JSON) {
return JSON.parse(json);
}
return doDecode(json);
} catch (e) {
if (safe) {
return null;
}
Ext.Error.raise({
sourceClass: "Ext.JSON",
sourceMethod: "decode",
msg: "You're trying to decode an invalid JSON String: " + json
});
}
};
me.encodeMSDate = encodeMSDate;
//@private Alias for backwards compatibility
if (!Ext.util) {
Ext.util = {};
}
Ext.util.JSON = me;
/**
* Shorthand for {@link Ext.JSON#encode}
* @member Ext
* @method encode
* @inheritdoc Ext.JSON#encode
*/
Ext.encode = me.encode;
/**
* Shorthand for {@link Ext.JSON#decode}
* @member Ext
* @method decode
* @inheritdoc Ext.JSON#decode
*/
Ext.decode = me.decode;
})());