I’ve been doing some integrations of some of the YUI widgets with Collaboration and I really like it. They have so many useful widgets that are easy to snap in once you get some basic fundamentals down. (YUI2 Examples , YUI3 Examples) I decided to share some of the important things I learned here to give back a little to the blogosphere (I sure get a lot of help from it when I’m doing development work).
For the purposes of this post I’ll walk through some of how I integrated the YUI3 Drag and Drop Portal example with Collaboration. I created an ability to create portlets and page grids that one can drag and drop desired portlets onto very much like one can do with the RSS feeds in that example.
The YUI ( and many of the newer web APIs like JQuery) requires knowledge of working with the JSON format. For those that don’t know it’s a nice way of wrapping lists of objects with key attributes described that can be easily parsed. For example if I wanted to describe a collection of 3 lists of RSS feeds it might look like this:
{"list1":[{"id":"ajaxian","min":false},{"id":"ynews","min":false}], "list2":[{"id":"slashdot","min":false}], "list3":[{"id":"daringfireball","min":false}]}
Each list in the collection has a name (list1, list2 etc), an id, and a minimized state.
My integration required that these JSON formatted text strings get set and read as custom attribute values on objects in Collaboration.
Here are a few key things I learned about working with JSON strings:
1) The JSON object names cannot start with a number NOR contain periods
Because I was associating objects to grid sections, the natural thing that I wanted to use as a name for each item was the OID or object ID which looks like ’1.11.7862′ . I painfully discovered that I could not work with the JSON strings until I replaced the periods with underscores and prefixed the whole thing with non-numeric characters (I used ‘id’)
So I ended up building my ‘feeds’ variable like so:
var feeds = { <ISPECT>while(portletsIt.hasNext()) <ISPECT>TagObject portletObj=(TagObject) portletsIt.next()</ISPECT> <ISPECT>String oid=getOID(portletObj)</ISPECT> <ISPECT>String oidNoDots=oid.replace(".","_")</ISPECT> 'id<ISPECT>showText(oidNoDots)</ISPECT>': { id: 'id<ISPECT>showText(oidNoDots)</ISPECT>', title: '<ISPECT>showName(portletObj)</ISPECT>' }<ISPECT>if(portletsIt.hasNext()),</ISPECT> </ISPECT>
2) You need to URL encode the string before you can set it as a custom attribute value:
I grabbed a handy JavaScript URL encoder/decoder to do this from www.webtoolkit.info
So after my javascript code builds the proper JSON string I set it as an attribute value like so :
var modifyObjUrl="ModifyObject?object=<ISPECT>showOID()</ISPECT> &attrvalue_of_Grid+Mapping="+UrlCoder.encode(feeds);
3) Use the tag method ‘getStringLiteralQuotes()’ to present the string value properly in Javascript code:
var cookie= new String("<ISPECT>showText(getStringLiteralQuotes( getAttributeValue("Grid Mapping")))</ISPECT>");
Iterating over objects defined by JSON on the server side
Yesterday I realized that I wanted to be able to iterate over the objects defined by JSON text in a custom attribute value on the server side. There are no out-of-the-box tag methods for working with JSON so I decided to write a custom one by adding a custom method to the CustomerReport.class extension hook.
The first thing I did was look for a good open source Java utility for working with JSON and I quickly found this nice library at www.json.org . I downloaded it, compiled to a .jar and tried to import it in CustomerReport.java but it kept saying that package org.json did not exist. After a lot of headache I discovered that the real reason it wouldn’t compile is because that same package is already part of the base installation, and it was colliding because my classpath pointed to both. So after getting past that fun, I made a method called ‘getJSONIteratorByKey’ that takes the JSON text and the key as inputs. It looks like this:
public Iterator getJSONIteratorByKey(String JSONText, String key){ Vector v = new Vector(); try{ JSONArray a = new JSONArray(JSONText); JSONObject jo = null; String s = ""; int len = a.length(); for (int i = 0; i < len; i += 1) { if (i > 0) { jo = a.getJSONObject(i); s = jo.getString(key); v.add(s); } } } catch (JSONException e){ v.add(e.toString()); } return v.iterator(); }
So now from a template I can grab a JSON formatted string from a custom attribute value and if one of the object keys is the object id or logical name, I can easily get an iterator for those object ids:
<ISPECT>String jsonText = getAttributeValue("Grid Mapping")</ISPECT> <ISPECT>Iterator it = getJSONIteratorByKey(jsonText,"id")</ISPECT> <ISPECT>while(it.hasNext()) <ISPECT>String s = (String) it.next()</ISPECT> <ISPECT>showText(s)</ISPECT><br> </ISPECT>
I hope someone out there finds this helpful!