OpenSocial Tutorial
(OpenSocial API v0.8)
Dan Holevoet and Arne Roomann-Kurrik, OpenSocial Team
Novembro 2009
This tutorial will introduce you to gadgets and OpenSocial, and will walk you through the steps required to build a simple social gadget where you can give gifts to your friends. In addition, you will be introduced to some of the more advanced features of the OpenSocial API.
For better understanding of this tutorial, it is suggested to read The Requesting-Data-Tutorial first.
You can find the complete sample code in the opensocial-resources project on Google Code.
Gadget basics
At their core, social gadgets are XML files, sometimes known as gadget specifications. Here is a simple "Hello World" gadget (helloworld.xml), that illustrates the basic sections of a specification:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Hello World!">
<Require feature="opensocial-0.8" />
</ModulePrefs>
<Content type="html">
<![CDATA[
Hello, world!
]]>
</Content>
</Module>
In the "Hello World" example, you can see several sections which control the features and design of the gadget.
<Module>indicates that this XML file contains a gadget.<ModulePrefs>contains information about the gadget, and its author.<Require feature="opensocial-0.8" />denotes a required feature of the gadget — in this case, the OpenSocial API (v0.8).<Content type="html">indicates that the gadget's content type is HTML. This is the recommended content type for OpenSocial containers, but gadgets for other containers such as iGoogle support other content types.<![ CDATA...]>contains the bulk of the gadget, including all of the HTML, CSS, and JavaScript (or references to such files). The content of this section should be treated like the content of thebodytag on a generic HTML page.
Running your first gadget
Set up hosting for your gadget file
It's best to start with a simple gadget while walking through the steps to get up and running. Copy the helloworld.xml example above into a new plain text file on your computer.
To host the gadget externally, you will need a place to upload the file. Fortunately, there are many free places to upload gadget specifications, and Google provides two:
Google Gadget Editor provides a simple interface for editing gadget XML files.
Google Code: Project Hosting provides free open source project hosting, and a convenient way to upload files and handle code versioning.
Using your own hosting is preferred — the flexibility it offers will be greater than free hosting. However, if you don't have your own hosting, and are willing to offer your gadget under an open source license, use Google Code: Project Hosting. Finally, if neither of those options is possible, use the GGE or another alternative.
Setting up the iGoogle environment
Adding the developer tools
Once you've installed your first gadget, there are several other gadgets you should install that will help you with development.
To install a tab containing these gadgets to your iGoogle sandbox, follow this link. A description of each gadget and its purpose can be found in the developer's guide along with installation instructions.
Adding some friends...
The rest of this tutorial relies on having friends available in the sandbox, so take a moment to walk through the process of adding a new friend using the Sandbox Friends gadget. To begin, click on the "Sandbox Friends" link in the left navigation bar. In the contacts manager that is presented, click on the new contact icon on the top left, and enter details for the iGoogle account with which to become friends, and save the details. Next, click on the "Friends" group in the leftmost column, and add your new contact. This contact is now listed as your friend.
An important note is that iGoogle supports asynchronous relationships, so while you may have someone listed as a friend that person might not list you as a "Friends". In order for this relationship to be mutual, the other contact must follow the same process as above to add your account to their "Friends" group. For the purposes of this tutorial, it is best to only include mutual friends in your "Friends" group.
Writing your first social application
Now it's time to bite into something a bit meatier, your first social application. This tutorial will help you write a simple application to give "gifts" to your friends. When the gadget is finished you will be able to:
Give simple gifts to your friends.
See the gifts you have given your friends.
See the gifts friends have given you.
Setting up the basics
If you're starting a new gadget, you should create a new XML file for it — call it gifts.xml. Begin with the usual XML boilerplate, and include the social API. Give the gadget a title as well, "Gifts," something reflective of the purpose of the application (the samples will amend the version number to help you keep track of the iterations in this lab). Here's what your shell of a gadget looks like:
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Gifts part 0 - Boilerplate">
<Require feature="opensocial-0.8"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
]]>
</Content>
</Module>
This gadget doesn't accomplish a lot, and in fact, accomplishes less than the "Hello World" gadget. However, it sets up the basis for the next, important steps.
Complete gadget specification for version 0
Inline JavaScript vs. external JavaScript
For small gadgets, it's often easier to include all the JavaScript calls for a gadget in the same XML file as the HTML. However, for larger gadgets, this can become cumbersome, so it can be helpful to offload JavaScript function definitions into a separate file.
</div>
</div>
Listing friends
gadgets.util.registerOnLoadHandler(init);
function init() {
loadFriends();
}
Now, of course, there needs to be a function to actually load the friend data. The following function creates a new data request object, then populates it with specific types of data that you'll need: the viewer and the viewer's friends. Notice that in order to request friends, the code constructs an IdSpec object. An IdSpec is used when you need to specify one or more people in a group (in this case, the viewer's friends). Then, it sends the request to the server, and gives it the name of a function to call when the data is returned.
function loadFriends() {
var req = opensocial.newDataRequest();
req.add(req.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), 'viewer');
var viewerFriends = opensocial.newIdSpec({ "userId" : "VIEWER", "groupId" : "FRIENDS" });
var opt_params = {};
opt_params[opensocial.DataRequest.PeopleRequestFields.MAX] = 100;
req.add(req.newFetchPeopleRequest(viewerFriends, opt_params), 'viewerFriends');
req.send(onLoadFriends);
}
The callback function, onLoadFriends, will take the data that the server has returned, and display it on the page. The simple check for person.getId() assures that only mutual friends are loaded.
function onLoadFriends(data) {
var viewer = data.get('viewer').getData();
var viewerFriends = data.get('viewerFriends').getData();
html = new Array();
html.push('<ul>');
viewerFriends.each(function(person) {
if (person.getId()) {
html.push('<li>' + person.getDisplayName() + "</li>");
}
});
html.push('</ul>');
document.getElementById('friends').innerHTML = html.join('');
}
Several div elements have been inserted within the gadget specification as entry points for the new HTML.
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Gifts part 1 - Friends">
<Require feature="opensocial-0.8"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
<script type="text/javascript">
/* ... */
</script>
'''<div id='main'>
Your friends:
<div id='friends'></div>
</div>
''']]>
</Content>
</Module>
Complete gadget specification for version 1
Giving gifts
Now it's time to implement the raison d'être of your gadget, giving gifts. In this section, we will modify the gadget to allow the viewer to give a gift to one of their friends.
First, you'll need to modify the basic HTML in the gadget specification so that it can insert new information for gift giving into the layout. The resultant XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Gifts part 2 - Send Gifts">
<Require feature="opensocial-0.8"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
<script type="text/javascript">
/* ... */
</script>
<div id='main'>'''
<div id='give'>
<form id='gift_form'>
Give <span id='gifts'></span> to <span id='friends'></span>. <a href='javascript:void(0);' onclick='giveGift();'>Give!</a>
</form>
</div>'''
</div>
]]>
</Content>
</Module>
Now that there are nice hooks into the HTML, modify the output of the friends list into a set of option tags for use within a select tag. This will allow you to select a friend to receive a gift.
function onLoadFriends(data) {
var viewer = data.get('viewer').getData();
var viewerFriends = data.get('viewerFriends').getData();
html = new Array();
html.push('<select id="person">');
viewerFriends.each(function(person) {
if (person.getId()) {
html.push('<option value="', person.getId(), '">', person.getDisplayName(), '</option>');
}
});
html.push('</select>');
document.getElementById('friends').innerHTML = html.join('');
}
Next, you'll need to create another selection menu of gifts you can give. The sample uses a selection of different types of nuts, but you can feel free to use whatever you like. A small update to the initialization function calls this function when the page loads.
var globalGiftList = ['a cashew nut', 'a peanut', 'a hazelnut', 'a red pistachio nut'];
function makeOptionsMenu() {
var html = new Array();
html.push('<select id="nut">');
for (var i = 0; i < globalGiftList.length; i++) {
html.push('<option value="', i, '">', globalGiftList[i], '</option>');
}
html.push('</select>');
document.getElementById('gifts').innerHTML = html.join('');
}
function init() {
loadFriends();
makeOptionsMenu();
}
To tie all of this together, implement giveGift, the function called when a user clicks the "Give!" button in the gadget. The function loads the gift to be given and the friend to give it to, from the form, updates a global object of gifts, and saves this to the persistent storage.
var globalGivenGifts = {};
function giveGift() {
var nut = document.getElementById('nut').value;
var friend = document.getElementById('person').value;
globalGivenGifts[friend] = nut;
var json = gadgets.json.stringify(globalGivenGifts);
var req = opensocial.newDataRequest();
req.add(req.newUpdatePersonAppDataRequest("VIEWER", 'gifts', json));
req.send();
}