www.flickr.com
Michael Kovacs' photos More of Michael Kovacs' photos
Recommend Me Cable Car Software logo

Wednesday, February 20, 2008

Opensocial observations (Part 1 - Data types available in MySpace v0.6 and Orkut v0.7)

For anyone brave enough to dive into the world of opensocial you'll quickly find that there's a lot of stuff around to read but not much in the way of examples and demos showing the lay of the land.

I won't go into great detail here about how opensocial apps are architected but what I will say is that you have to define javascript in any opensocial app just to get the thing off the ground. On some containers you need to do an XML situp as well. I've only experimented on Orkut and MySpace thus far with varying degrees of success and confusion.

Basically if you're using v0.7 and on Orkut you create an XML file that contains your app definition. Here's an example:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Data type inspector">
<Require feature="opensocial-0.7"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
<script src="http://www.pitchwire.com/javascripts/openSocialTestV0.7.js"></script>
<script>
gadgets.util.registerOnLoadHandler(init);
</script>
<div id='snoop'></div>
]]>
</Content>
</Module>


You need to put this XML file somewhere that Orkut can get to it and load it. For example: http://www.pitchwire.com/opensocialTestV0.7.xml In fact you can simply add an app in Orkut and when it asks for the URL simply point to this XML file I have hosted if you don't wish to create these files and host them yourself.

You can see that in the XML file an external javascript file is referenced. That file contains the code I whipped up today that tells you what data types are available in a given container.

This code works for Orkut and any v0.7 opensocial containers:
function inspectEnv() {
var env = opensocial.getEnvironment();
html = new Array();
camera1 = 'b3c7f1';
camera2 = 'fff';
last_camera = camera1;

html.push('<br/>Domain: ' + env.getDomain() );
html.push('<table style="border: 1px solid black;">');
html.push('<tr style="background-color: c8eaa9;"><td>Type</td><td>Field</td><td>Supported?</td></tr>');

var fieldType = opensocial.Environment.ObjectType.ACTIVITY;
var fields = [opensocial.Activity.Field.TITLE,
opensocial.Activity.Field.TITLE_ID,
opensocial.Activity.Field.BODY,
opensocial.Activity.Field.BODY_ID,
opensocial.Activity.Field.EXTERNAL_ID,
opensocial.Activity.Field.ID,
opensocial.Activity.Field.MEDIA_ITEMS,
opensocial.Activity.Field.POSTED_TIME,
opensocial.Activity.Field.PRIORITY,
opensocial.Activity.Field.STREAM_FAVICON_URL,
opensocial.Activity.Field.STREAM_TITLE,
opensocial.Activity.Field.STREAM_SOURCE_URL,
opensocial.Activity.Field.STREAM_URL,
opensocial.Activity.Field.TEMPLATE_PARAMS,
opensocial.Activity.Field.URL,
opensocial.Activity.Field.USER_ID,
opensocial.Activity.Field.APP_ID];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.ACTIVITY_MEDIA_ITEM;
fields = [opensocial.Activity.MediaItem.Field.MIME_TYPE,
opensocial.Activity.MediaItem.Field.TYPE,
opensocial.Activity.MediaItem.Field.URL];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.ADDRESS;
fields = [opensocial.Address.Field.COUNTRY,
opensocial.Address.Field.EXTENDED_ADDRESS,
opensocial.Address.Field.LATITUDE,
opensocial.Address.Field.LOCALITY,
opensocial.Address.Field.LONGITUDE,
opensocial.Address.Field.PO_BOX,
opensocial.Address.Field.POSTAL_CODE,
opensocial.Address.Field.REGION,
opensocial.Address.Field.STREET_ADDRESS,
opensocial.Address.Field.TYPE,
opensocial.Address.Field.UNSTRUCTURED_ADDRESS];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.BODY_TYPE;
fields = [opensocial.BodyType.Field.BUILD,
opensocial.BodyType.Field.EYE_COLOR,
opensocial.BodyType.Field.HAIR_COLOR,
opensocial.BodyType.Field.HEIGHT,
opensocial.BodyType.Field.WEIGHT];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.EMAIL;
fields = [opensocial.Email.Field.ADDRESS,
opensocial.Email.Field.TYPE];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.FILTER_TYPE;
fields = [opensocial.DataRequest.FilterType.ALL,
opensocial.DataRequest.FilterType.HAS_APP];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.MESSAGE;
fields = [opensocial.Message.Field.BODY,
opensocial.Message.Field.TITLE,
opensocial.Message.Field.TYPE];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.MESSAGE_TYPE;
fields = [opensocial.Message.Type.EMAIL,
opensocial.Message.Type.NOTIFICATION,
opensocial.Message.Type.PRIVATE_MESSAGE,
opensocial.Message.Type.PUBLIC_MESSAGE];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.NAME;
fields = [opensocial.Name.Field.ADDITIONAL_NAME,
opensocial.Name.Field.FAMILY_NAME,
opensocial.Name.Field.GIVEN_NAME,
opensocial.Name.Field.HONORIFIC_PREFIX,
opensocial.Name.Field.HONORIFIC_SUFFIX,
opensocial.Name.Field.UNSTRUCTURED];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.ORGANIZATION;
fields = [opensocial.Organization.Field.ADDRESS,
opensocial.Organization.Field.DESCRIPTION,
opensocial.Organization.Field.END_DATE,
opensocial.Organization.Field.FIELD,
opensocial.Organization.Field.NAME,
opensocial.Organization.Field.SALARY,
opensocial.Organization.Field.START_DATE,
opensocial.Organization.Field.SUB_FIELD,
opensocial.Organization.Field.TITLE,
opensocial.Organization.Field.WEBPAGE];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.PERSON;
fields = [opensocial.Person.Field.ABOUT_ME,
opensocial.Person.Field.ACTIVITIES,
opensocial.Person.Field.ADDRESSES,
opensocial.Person.Field.AGE,
opensocial.Person.Field.BODY_TYPE,
opensocial.Person.Field.BOOKS,
opensocial.Person.Field.CARS,
opensocial.Person.Field.CHILDREN,
opensocial.Person.Field.CURRENT_LOCATION,
opensocial.Person.Field.DATE_OF_BIRTH,
opensocial.Person.Field.DRINKER,
opensocial.Person.Field.EMAILS,
opensocial.Person.Field.ETHNICITY,
opensocial.Person.Field.FASHION,
opensocial.Person.Field.FOOD,
opensocial.Person.Field.GENDER,
opensocial.Person.Field.HAPPIEST_WHEN,
opensocial.Person.Field.HEROES,
opensocial.Person.Field.ID,
opensocial.Person.Field.INTERESTS,
opensocial.Person.Field.JOB_INTERESTS,
opensocial.Person.Field.JOBS,
opensocial.Person.Field.LANGUAGES_SPOKEN,
opensocial.Person.Field.LIVING_ARRANGEMENT,
opensocial.Person.Field.LOOKING_FOR,
opensocial.Person.Field.MOVIES,
opensocial.Person.Field.MUSIC,
opensocial.Person.Field.NAME,
opensocial.Person.Field.NICKNAME,
opensocial.Person.Field.PETS,
opensocial.Person.Field.PHONE_NUMBERS,
opensocial.Person.Field.POLITICAL_VIEWS,
opensocial.Person.Field.PROFILE_SONG,
opensocial.Person.Field.PROFILE_URL,
opensocial.Person.Field.PROFILE_VIDEO,
opensocial.Person.Field.QUOTES,
opensocial.Person.Field.RELATIONSHIP_STATUS,
opensocial.Person.Field.RELIGION,
opensocial.Person.Field.ROMANCE,
opensocial.Person.Field.SCARED_OF,
opensocial.Person.Field.SCHOOLS,
opensocial.Person.Field.SEXUAL_ORIENTATION,
opensocial.Person.Field.SMOKER,
opensocial.Person.Field.SPORTS,
opensocial.Person.Field.STATUS,
opensocial.Person.Field.TAGS,
opensocial.Person.Field.THUMBNAIL_URL,
opensocial.Person.Field.TIME_ZONE,
opensocial.Person.Field.TURN_OFFS,
opensocial.Person.Field.TURN_ONS,
opensocial.Person.Field.TV_SHOWS,
opensocial.Person.Field.URLS];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.PHONE;
fields = [opensocial.Phone.Field.NUMBER,
opensocial.Phone.Field.TYPE];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.SORT_ORDER;
fields = [opensocial.DataRequest.SortOrder.NAME,
opensocial.DataRequest.SortOrder.TOP_FRIENDS];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.URL;
fields = [opensocial.Url.Field.ADDRESS,
opensocial.Url.Field.LINK_TEXT,
opensocial.Url.Field.TYPE];
inspectType(env, fieldType, fields);
html.push('</table>');
document.getElementById('snoop').innerHTML = html.join('');
}

function inspectType(env, fieldType, fields) {
for(j = 0; j < fields.length; j++) {
supports = env.supportsField(fieldType, fields[j]);
display = supports ? 'style="font-weight: bold;"' : ''
html.push('<tr style="background-color: ' + last_camera + '"><td>' + fieldType + '</td><td>' + fields[j] + '</td><td ' + display + '>' + supports + '</td></tr>');
last_camera = last_camera == camera1 ? camera2 : camera1
}
}

function init() {
inspectEnv();
}


Not so bad once you get your bearings and understand how things work. I will say that it hasn't been the smoothest development environment in the world but compared to MySpace it's a dream. Speaking of MySpace the current situation there is so awful at the moment it's almost as if they don't want people to write apps for their platform.

The current state of affairs there is that they expect you to paste your HTML and javascript code into a textarea on their developer site. They too suffer from some of the same confusion that Orkut does where it's not clear what the oder of operations are and where key links are missing when trying to navigate around the sandbox. Also on MySpace your app has a MySpace profile as if it's another user. It can have friends, etc. Yeah.. that seems about right for MySpace :-)

Because I'm apparently a glutton for punishment I decided to try and run my container introspection code on MySpace. Turns out V0.6 is much smaller in terms of data types than V0.7 with only 3 defined.

Here's the code that you can paste into your canvas textarea once you've created an app on MySpace:

<div id='snoop' style='height: 500px; overflow: scroll;'></div>
<script type="text/javascript" language="javascript">
function init() {
inspectEnv();
}

function inspectEnv() {
var env = opensocial.getEnvironment();
html = new Array();
camera1 = 'b3c7f1';
camera2 = 'fff';
last_camera = camera1;

html.push('<br/>Domain: ' + env.getDomain() );
html.push('<table style="border: 1px solid black;">');
html.push('<tr style="background-color: c8eaa9;"><td>Type</td><td>Field</td><td>Supported?</td></tr>');

var fieldType = opensocial.Environment.ObjectType.ACTIVITY;
var fields = [opensocial.Activity.Field.TITLE,
opensocial.Activity.Field.TITLE_ID,
opensocial.Activity.Field.BODY,
opensocial.Activity.Field.BODY_ID,
opensocial.Activity.Field.EXTERNAL_ID,
opensocial.Activity.Field.ID,
opensocial.Activity.Field.MEDIA_ITEMS,
opensocial.Activity.Field.POSTED_TIME,
opensocial.Activity.Field.PRIORITY,
opensocial.Activity.Field.STREAM_FAVICON_URL,
opensocial.Activity.Field.STREAM_TITLE,
opensocial.Activity.Field.STREAM_SOURCE_URL,
opensocial.Activity.Field.STREAM_URL,
opensocial.Activity.Field.TEMPLATE_PARAMS,
opensocial.Activity.Field.URL,
opensocial.Activity.Field.USER_ID,
opensocial.Activity.Field.APP_ID];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.ACTIVITY_MEDIA_ITEM;
fields = [opensocial.Activity.MediaItem.Field.MIME_TYPE,
opensocial.Activity.MediaItem.Field.TYPE,
opensocial.Activity.MediaItem.Field.URL];
inspectType(env, fieldType, fields);

fieldType = opensocial.Environment.ObjectType.PERSON;
fields = [opensocial.Person.Field.ABOUT_ME,
opensocial.Person.Field.ACTIVITIES,
opensocial.Person.Field.ADDRESSES,
opensocial.Person.Field.AGE,
opensocial.Person.Field.BODY_TYPE,
opensocial.Person.Field.BOOKS,
opensocial.Person.Field.CARS,
opensocial.Person.Field.CHILDREN,
opensocial.Person.Field.CURRENT_LOCATION,
opensocial.Person.Field.DATE_OF_BIRTH,
opensocial.Person.Field.DRINKER,
opensocial.Person.Field.EMAILS,
opensocial.Person.Field.ETHNICITY,
opensocial.Person.Field.FASHION,
opensocial.Person.Field.FOOD,
opensocial.Person.Field.GENDER,
opensocial.Person.Field.HAPPIEST_WHEN,
opensocial.Person.Field.HEROES,
opensocial.Person.Field.ID,
opensocial.Person.Field.INTERESTS,
opensocial.Person.Field.JOB_INTERESTS,
opensocial.Person.Field.JOBS,
opensocial.Person.Field.LANGUAGES_SPOKEN,
opensocial.Person.Field.LIVING_ARRANGEMENT,
opensocial.Person.Field.LOOKING_FOR,
opensocial.Person.Field.MOVIES,
opensocial.Person.Field.MUSIC,
opensocial.Person.Field.NAME,
opensocial.Person.Field.NICKNAME,
opensocial.Person.Field.PETS,
opensocial.Person.Field.PHONE_NUMBERS,
opensocial.Person.Field.POLITICAL_VIEWS,
opensocial.Person.Field.PROFILE_SONG,
opensocial.Person.Field.PROFILE_URL,
opensocial.Person.Field.PROFILE_VIDEO,
opensocial.Person.Field.QUOTES,
opensocial.Person.Field.RELATIONSHIP_STATUS,
opensocial.Person.Field.RELIGION,
opensocial.Person.Field.ROMANCE,
opensocial.Person.Field.SCARED_OF,
opensocial.Person.Field.SCHOOLS,
opensocial.Person.Field.SEXUAL_ORIENTATION,
opensocial.Person.Field.SMOKER,
opensocial.Person.Field.SPORTS,
opensocial.Person.Field.STATUS,
opensocial.Person.Field.TAGS,
opensocial.Person.Field.THUMBNAIL_URL,
opensocial.Person.Field.TIME_ZONE,
opensocial.Person.Field.TURN_OFFS,
opensocial.Person.Field.TURN_ONS,
opensocial.Person.Field.TV_SHOWS,
opensocial.Person.Field.URLS];
inspectType(env, fieldType, fields);
html.push('>/table>');
document.getElementById('snoop').innerHTML = html.join('');
}

function inspectType(env, fieldType, fields) {
for(j = 0; j < fields.length; j++) {
supports = env.supportsField(fieldType, fields[j]);
display = supports ? 'style="font-weight: bold;"' : ''
html.push('>tr style="background-color: ' + last_camera + '">>td>' + fieldType + '>/td>>td>' + fields[j] + '>/td>>td ' + display + '>' + supports + '>/td>>/tr>');
last_camera = last_camera == camera1 ? camera2 : camera1
}
}
init();
</script>


Mind you this only shows you the supported datatypes for what's in the opensocial V0.6 spec. MySpace has a few extension of their own that are available for you to use. I won't cover that here, you can go check out their API docs for that. The word is that they'll be upgrading to V0.7 soon. I sure hope so but I also wish that Orkut would implement the full spec too. You'll see how much is still missing when you install the inspector app.

That's it for now. I'm sure I'll have lots more I could post about on this topic as well as Facebook development.

Enjoy!

This page is powered by Blogger. Isn't yours?