Working with ExtJs for a long time now (and deliberately avoiding jQuery whenever I could), I finally dumped ExtJs in favor of jQuery with my upcoming Document module for Drupal (mainly for avoiding users from having to download ExtJs separately when Drupal comes bundled with jQuery). And I was really pleased on how easy, flexible and powerful the library was for tasks I thought were best handled with ExtJs. (This should not mean I have abandoned ExtJs, the library is just too powerful and feature-rich to overlook in contemporary web development).
I was surprised to see jQuery’s lack of support for JSON encoding of objects (decoding of JSON serialized string to an object is easily handled by browser’s native eval method).
Quick googling took me to this Google Code project. And when I thought, I have found an easy solution that can be copy-pasted to use, I had a hiccup. The code (written as a jQuery plugin) on the referenced url was not written as per plugin development specifications for jQuery. And it was causing javascript errors in my browser. So, I had to adapt it to make it work. Here’s the adapted code:
{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }/*
* This document is licensed as free software under the terms of the
* MIT License: http://www.opensource.org/licenses/mit-license.php
*
* Adapted by Rahul Singla.
*
* Brantley Harris wrote this plugin. It is based somewhat on the JSON.org
* website’s http://www.json.org/json2.js, which proclaims:
* “NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.”, a sentiment that
* I uphold.
*
* It is also influenced heavily by MochiKit’s serializeJSON, which is
* copyrighted 2005 by Bob Ippolito.
*/
/**
* jQuery.JSON.encode( json-serializble ) Converts the given argument into a
* JSON respresentation.
*
* If an object has a “toJSON” function, that will be used to get the
* representation. Non-integer/string keys are skipped in the object, as are
* keys that point to a function.
*
* json-serializble: The *thing* to be converted.
*/
jQuery.JSON = {
encode: function(o) {
if (typeof (JSON) == ‘object’ && JSON.stringify)
return JSON.stringify(o);
var type = typeof (o);
if (o === null)
return “null”;
if (type == “undefined”)
return undefined;
if (type == “number” || type == “boolean”)
return o + “”;
if (type == “string”)
return this.quoteString(o);
if (type == ‘object’) {
if (typeof o.toJSON == “function”)
return this.encode(o.toJSON());
if (o.constructor === Date) {
var month = o.getUTCMonth() + 1;
if (month < 10)
month = ‘0’ + month;
var day = o.getUTCDate();
if (day < 10)
day = ‘0’ + day;
var year = o.getUTCFullYear();
var hours = o.getUTCHours();
if (hours < 10)
hours = ‘0’ + hours;
var minutes = o.getUTCMinutes();
if (minutes < 10)
minutes = ‘0’ + minutes;
var seconds = o.getUTCSeconds();
if (seconds < 10)
seconds = ‘0’ + seconds;
var milli = o.getUTCMilliseconds();
if (milli < 100)
milli = ‘0’ + milli;
if (milli < 10)
milli = ‘0’ + milli;
return ‘”‘ + year + ‘-‘ + month + ‘-‘ + day + ‘T’ + hours + ‘:’
+ minutes + ‘:’ + seconds + ‘.’ + milli + ‘Z”‘;
}
if (o.constructor === Array) {
var ret = [];
for ( var i = 0; i < o.length; i++)
ret.push(this.encode(o[i]) || “null”);
return “[” + ret.join(“,”) + “]”;
}
var pairs = [];
for ( var k in o) {
var name;
var type = typeof k;
if (type == “number”)
name = ‘”‘ + k + ‘”‘;
else if (type == “string”)
name = this.quoteString(k);
else
continue; // skip non-string or number keys
if (typeof o[k] == “function”)
continue; // skip pairs where the value is a function.
var val = this.encode(o[k]);
pairs.push(name + “:” + val);
}
return “{” + pairs.join(“, “) + “}”;
}
},
/**
* jQuery.JSON.decode(src) Evaluates a given piece of json source.
*/
decode: function(src) {
if (typeof (JSON) == ‘object’ && JSON.parse)
return JSON.parse(src);
return eval(“(” + src + “)”);
},
/**
* jQuery.JSON.decodeSecure(src) Evals JSON in a way that is *more* secure.
*/
decodeSecure: function(src) {
if (typeof (JSON) == ‘object’ && JSON.parse)
return JSON.parse(src);
var filtered = src;
filtered = filtered.replace(/\\[“\\\/bfnrtu]/g, ‘@’);
filtered = filtered
.replace(
/”[^”\\\n\r]*”|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
‘]’);
filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, ”);
if (/^[\],:{}\s]*$/.test(filtered))
return eval(“(” + src + “)”);
else
throw new SyntaxError(“Error parsing JSON, source is not valid.”);
},
/**
* jQuery.JSON.quoteString(string) Returns a string-repr of a string, escaping
* quotes intelligently. Mostly a support function for JSON.encode.
*
* Examples: >>> jQuery.JSON.quoteString(“apple”) “apple”
*
* >>> jQuery.JSON.quoteString(‘”Where are we going?”, she asked.’) “\”Where
* are we going?\”, she asked.”
*/
quoteString: function(string) {
if (string.match(this._escapeable)) {
return ‘”‘ + string.replace(this._escapeable, function(a) {
var c = this._meta[a];
if (typeof c === ‘string’)
return c;
c = a.charCodeAt();
return ‘\\u00’ + Math.floor(c / 16).toString(16)
+ (c % 16).toString(16);
}) + ‘”‘;
}
return ‘”‘ + string + ‘”‘;
},
_escapeable: /[“\\\x00-\x1f\x7f-\x9f]/g,
_meta: {
‘\b’: ‘\\b’,
‘\t’: ‘\\t’,
‘\n’: ‘\\n’,
‘\f’: ‘\\f’,
‘\r’: ‘\\r’,
‘”‘: ‘\\”‘,
‘\\’: ‘\\\\’
}
}{/syntaxhighlighter}
Apart from rewriting the plugin without the $ alias, I have re-organized it to be more object-oriented (call it the ExtJs effect). Here’s how you can use this code:
{syntaxhighlighter brush: as3;fontsize: 100; first-line: 1; }var thing = {plugin: ‘jquery-json’, other: “blah-blah”};
var encoded = $.JSON.encode(thing); //'{“plugin”:”jquery-json”,”other”:blah-blah}’
var decoded = $.JSON.decode(encoded);{/syntaxhighlighter}
You should also be able to easily adapt it to work independently outside jQuery. I fully acknowledge that I have just adapted the code available here and written by Brantley Harris.
You might also be interested in the JSON stringifier available here.
Tanks, nice work
Thanks a lot, was really helpful, using it in my Drupal 7 project (just needs wrapping in (function($){ … })(jQuery); and it’s ready to use) đ
Excellent, I’m pretty much in the same boat, usually use ExtJs and for the project I’m working on needed to be able to encode a object as a string so thanks for putting this together.
Damian
Thanks for the excellent addon. It filled that last little bit with jQuery that makes it able to AJAX objects easily between client-server.
Great job!
Harley
Thank you very much
Just the thing I was looking for, nicely wrapped in a plugin, saved me a lot of work!!!
PS Also an extjs user đ
I get the following error in your code:
‘this_meta’ is null or not an object Line:156
Sorry for duplicate comment. I had some trouble with the captcha.
Hi,
You need to analyze the JSON calls using Wireshark, so you will see if you include the charset in the formation of the JSON page or not, for example:
– If the page is simple if text / html
<pre>
0000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74 .Content -Type: t
0020 65 78 74 2f 68 74 6d 6c 0d 0a 43 61 63 68 65 2d ext/html ..Cache-
0030 43 6f 6e 74 72 6f 6c 3a 20 6e 6f 2d 63 61 63 68 Control: no-cach
</pre>
– If the page is of the type including custom JSON with MIME “charset = ISO-8859-1”
<pre>
0000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010 0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c 3a 20 .Cache-C ontrol:
0020 6e 6f 2d 63 61 63 68 65 0d 0a 43 6f 6e 74 65 6e no-cache ..Conten
0030 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d t-Type: text/htm
0040 6c 3b 20 63 68 61 72 73 65 74 3d 49 53 4f 2d 38 l; chars et=ISO-8
0050 38 35 39 2d 31 0d 0a 43 6f 6e 6e 65 63 74 69 6f 859-1..C onnectio
</pre>
Why is that? because we can not put on the page of JSON a goal like this:
<meta http-equiv=”Content-Type” content=”text/html; charset=iso-8859-1″>
In my case I use the manufacturer Connect Me 9210 Digi:
– I had to use a flag to indicate that one would use non-standard MIME:
p-> theCgiPtr-> = fDataType eRpDataTypeOther;
– It added the new MIME in the variable:
strcpy (p-> theCgiPtr-> fOtherMimeType, “text / html;
charset = ISO-8859-1 “);
**It worked for me** without having to convert the data passed by JSON for UTF-8 and then redo the conversion on the page …
I am too an ExtJS person having to switch over to jQuery. I feel that a lot of things that where taken for granted in ExtJS are missing… This was one of them, thank you!