My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Sunday, June 08, 2008

JsonTV - JsonML concept to create TreeView components

For those that do not know JsonML, this is a little summary.
JsonML aim is to use JSON to transport layouts, instead of simple data.
Unfortunately, for this purpose the size of the code could be even bigger than regular layout, considering that with a good usage of classes, internal styles, as attributes, are often superfluous.
At the same time, there are still several problems with DOM, for its not standard nature, thanks to those browsers that do not respect W3 or generic predefined guidelines.
For these reasons, and probably others, JsonML has not been widely adopted, as is for his daddy JSON.

An alternative purpose, based on both same concept and grammar


A daily common task in web development, is menu, files and directories, or trees creation, that allow us, as users, to organize data in a better, friendly, and easy to manage, way.
Removing some intermediate step, and thinking about standard data presentation, with useful information and nothing else, it is possible to use the same JsonML grammar to create automatically a DOM based tree.
The schema could be transformed in this way:

element
= '[' name ',' attributes ',' element-list ']'
| '[' name ',' attributes ']'
| '[' name ',' element-list ']'
| '[' name ']'
| json-string
;
name
= json-string
;
attributes
= '{' attribute-list '}'
| '{' '}'
;
attribute-list
= attribute ',' attribute-list
| attribute
;
attribute
= attribute-name ':' attribute-value
;
attribute-name
= json-string
;
attribute-value
= json-string
;
element-list
= element ',' element-list
| element
;

As you can observe, the only difference is with name, instead of tag-name.
The element-list, if present, will be the nested list of informations inside a branch, while name will be the real name of that branch, or leaf, if no element-list is present inside.

The attribute-list will be a dedicated object that will contain, if present, every information we need for that leaf, or branch.
At this point, with a simple piece of code like this one, is possible to create a menu:

["root",
["demo.txt", {size:12345, date:"2008/06/07"}],
["temp",
["file1.tmp"],
["file2.tmp"],
["file3.tmp"]
],
["sound.wav", {size:567, date:"2008/05/07"}]
]

Above code will create automatically a list like this one:

  • root

    • demo.txt

    • temp

      • file1.tmp

      • file2.tmp

      • file3.tmp



    • sound.wav




Every leaf, or branch, will contain at the same time passed information, as object.
In this way, as I wrote before, we are not sending an xhtml or xml structure, but simply a schema of our menu, folder navigator, or whatever we need.

The JsonTV object


This is my JsonTV object implementation. It is truly simple to use and, if you want, raw, but it is only the core which aim is to transport, transform, create, or parse from DOM, every kind of schema that will respect showed grammar.
For example, this is a piece of code that will automatically create above tree, and will hide, or show, internal leafs, if presents, and starting from the root.

onload = function(){
var directory = JsonTV.parseArray(
["root",
["demo.txt", {size:12345, date:"2008/06/07"}],
["temp", ["file1.tmp"], ["file2.tmp"], ["file3.tmp"]],
["sound.wav", {size:456, date:"2008/05/07"}]
]
);
document.body.appendChild(
directory
).onclick = function(e){
var target = (e ? e.target : event.srcElement).parentNode,
ul = target.getElementsByTagName("ul")[0];
if(/li/i.test(target.nodeName)){
if(ul)
ul.style.display = (target.clicked = !target.clicked) ? "none" : "";
else {
var __JSON__ = [];
for(var key in target.__JSON__)
__JSON__.push(key + " = " + target.__JSON__[key]);
if(__JSON__.length)
alert(__JSON__.join("\n"));
};
};
};
directory.className = "directory";

// this is only an assertion like check
setTimeout(function(){
var clone = document.body.appendChild(JsonTV.parseArray(JsonTV.parseDOM(directory)));
if(directory.outerHTML === clone.outerHTML)
document.body.removeChild(clone);
}, 1000);
};


Simplified API


As is for JSON object, JsonTV contains two main public methods: parse, and stringify.
The first one, parse, will convert a JSON string that contains a valid schema Array, a schema Array, into a DOM based Tree.
There is an exception, if you pass a DOM based Tree to parse function, it will convert them into an Array that will respect JsonTV schema.
On the other hand, the stringify method will convert a string, a DOM based Tree, or an Array, into JsonTV string, using, if present, the official JSON.stringify method, or not standard Gecko toSource one, if there is no JSON parser.

Conclusion


This is only my first step inside JsonTV technique, but I am sure that with a good usage of CSS, and few lines of JavaScript, using or not third parts libraries, a common intermediate protocol to manage, send, save, and show tree views, could let us develop truly interesting tree based applcations, making portings from different languages more simple than ever, as it has been for JSON de-facto standard.
Stay tuned for next examples ;)

4 comments:

Anonymous said...

Hi Andrea,

Very interesting to see your approach to the tree building of json, I'm currently finishing up on my json editor so it's refreshing to see how you tackled the 'problem'.

One thing that stood out in your code however is the missing curly brackets on for instance if statements where there's just one line following. This makes minifying your code 'impossible'. You might want to jslint (jslint.com) your code and see what I mean.

Nevertheless, I'm looking forward to the next samples! :)

Regards,
Marc

Andrea Giammarchi said...

Hi Marc,
my code is "perfect" while JSLint, as I said different times, is not perfect :)

You can write my script in a single line and without a single problem.

Indeed, with packed.it you have no problems (try replacing \n with " " and it works perfectly) ;)

If you have a prticular point that is not clear fr you or jslint, please tell me and I'll try to understand why you say that you cannot minify my code (I could miss the brackets problem you are talking about)

Kind Regards

Anonymous said...

Hi Andrea,

That was a stupid comment a made and I can't understand why I wrote it. I have not tried packed.it but I think I really should...

Perhaps it's just not my style to forget the curly brackets when possible.

Hope you are not offended...

Regards,
Marc

Andrea Giammarchi said...

Marc, I am not offended at all, and sorry if my comment let you think about them.

Anyway, Yahoo team created YUI Compressor that has a JSlint compatible mode.

That is because, as they say, JSlint algo is truly simple, and that is why I always say that JSlint is a "developer mood" but not the perfect way to know if your code is good.

For the same reason, I wrote a minifier by myself, and that is part of MyMin project, inside packed.it website :)

P.S. I use curly brackets when I need curly brackets :P