Archive for June, 2007

Building a Twitter widget, part 5: publishing data to your account through authentication

Friday, June 8th, 2007

We’ve been through a lot of things since we started this series of articles, but the part we are entering now is what will make a difference in your widget. Many widget are able to display public data, and others can display private data just fine, but being able to also publish data directly from one’s Netvibes page (and on different account for each instance of the widget, even) is what will drive users to your widget.

Twitter 05: GET and POST

Of course, being able to publish data (or, in HTTP lingo, to POST data) requires the adequate API method. Twitter provides it, and it’s simply named update. This way, we can display our friend’s statuses using one method (friends_timeline, as seen in the previous part), and publish our statuses using another one. For publishing, we will use the JSON data format, so the URL to retrieve a JSON feed from that API method will be http://twitter.com/statuses/update.json.

To follow along, grab the code from the previous version.

Expanding the HTML code

This new feature of our widget will require us to have two different parts in our HTML display: one that will feature a form, which will send our text to Twitter, and another part where we will display the data feed we are getting from our account. We will create static HTML tags that we will access and update using their CSS classes and the widget.getElementsByClassName method. We will also have to rework a bit of our JavaScript code to make these new HTML elements fit in.

Previously, our HTML code only featured a single p element. Now it will look like this:

</head>
<body>
  <form method="post"
    action="http://twitter.com/statuses/update.json">
    <textarea rows="2" name="status"></textarea>
    <input type="submit" class="submit" value="Update" />
  </form>
  <div class="messages"><p>Twitter is loading ...</p></div>
  <div class="paging"></div>
</body>
</html>

Note that the form is directly pointing its action attribute to the API method’s URL.

Because those elements are hand-created, they don’t have access to UWA’s DOM method, like addContent or hide. Only dynamically-created elements, using widget.createElement() for instance, are UWA-extended. Luckily, UWA provides a method to extend our elements, and apply DOM methods to them: UWA.$element.

Because we will need to access those elements using DOM method throughout our code, we will gather their references in an object: widget.elements[]. Extension has to be done at loading time, so this is how our new Twitter.onLoad method looks like:

Twitter.onLoad = function() {
  widget.setValue('offset', 0);

  widget.setTitle('Twitter');

  widget.elements['form'] = UWA.$element(
    widget.body.getElementsByTagName('form')[0] );
  widget.elements['messages'] = UWA.$element(
    widget.body.getElementsByClassName('messages')[0] );
  widget.elements['paging'] = UWA.$element(
    widget.body.getElementsByClassName('paging')[0] );
  widget.elements['textarea'] = UWA.$element(
    widget.elements['form'].getElementsByTagName('textarea')[0]);

  widget.elements['textarea'].value = '';

  if ( widget.getValue('username') )  {
    widget.elements['form'].show();
    widget.elements['form'].onsubmit = Twitter.submit;
    Twitter.loadTimeline();
  } else {
    widget.elements['form'].hide();
    widget.elements['messages']
      .setHTML('Please authenticate.');
    widget.callback("onEdit");
  }

  widget.callback('onUpdateBody');
}

Incidentally, we have updated our if..else block to reflect these changes. Note that we are already “hijacking” the form onsubmit event in order to handle it ourselves. The rest should be pretty self explanatory.

Likewise, Twitter.loadTimeline() will get a little update to use our new HTML elements:

Twitter.loadTimeline = function() {
  widget.elements['form'].show();
  UWA.Data.request(
    'http://twitter.com/statuses/friends_timeline.json',
    { method: 'get', type: 'json', cache: 600,
    onComplete: Twitter.display,
    authentication: Twitter.getAuthentication() }
  );
  widget.elements['messages'].setHTML(
    '<div class="loading">Fetching messages from Twitter<br />
    (be patient, Twitter can be slow !)</div>');
  widget.callback('onUpdateBody');
}

The Twitter.display method also gets the widget.elements[] treatment in a few places:
widget.setBody(''); is replaced with widget.elements['messages'].empty();
widget.body.appendChild(p); becomes widget.elements['messages'].appendChild(p);
widget.body.addContent('<div class="paging"></div>'); is removed, since the div is now static in the HTML code
var pagerContainer = UWA.$element( widget.body.getElementsByClassName('paging')[0] ); is also removed, since pagerContainer can be replaced by widget.elements['paging']
pagerContainer.setContent( pager.getContent() ); thus becomes widget.elements['paging'].setContent( pager.getContent() );

That’s it for our rewriting of our HTML around our new HTML code, and the related JavaScript code.

Submitting data: the methods around the form

Thanks to our if..else block in the onLoad method, our form is only displayed when the user is logged-in. Once he is, we have to handle it, and its Submit button, in the most elegant way possible – that is, not by opening a new browser page where the answer data will be displayed, but by passing the data to our Ajax method. That method is called Twitter.submit, as defined in our if..else block, using this line of code: widget.elements['form'].onsubmit = Twitter.submit;. Here’s how we’ll write it:

Twitter.submit = function() {
  var status = widget.elements['textarea'].value;
  UWA.Data.request(
   this.action,
    {
    method: this.method, proxy: 'ajax',
    onComplete: Twitter.onSubmitOk,
    parameters: 'status=' +  status,
    authentication: Twitter.getAuthentication()
    }
  );
  widget.elements['textarea'].setAttribute('disabled', 'disabled');
  return false;
  }

Notice how the URL of our Ajax request is directly taken from the form action attribute, using this.action. Also, we disable the form’s text area, to prevent more text from being entered while the request is being sent. Finally, return false; prevents the form itself from being submitted: the whole submission is done through Ajax.
Twitter’s update method requires a parameter, status, which contains the status’ text. We provide it using the parameters setting of the Ajax request.
We already have the Twitter.getAuthentication method in place (it’s the same as in the previous parts of the widget), but we need the define Twitter.onSubmitOk(), which will decide what is to be done if the request is successful. Here, we will simply erase the message we submitted, and re-enable the textarea for further Twitting.

Twitter.onSubmitOk = function() {
  widget.elements['textarea'].value = '';
  widget.elements['textarea'].removeAttribute('disabled');
  Twitter.loadTimeline();
}

And this is it for data submission through authentication!

Styling the form

Twitter 05: unstyled form

As it is, the form isn’t really pretty: the textarea and the input button are next to each other, which prevents the textarea from being larger. A bit of CSS will make it more appealing:

<style type="text/css">
(..)

textarea {
  width:98%;
  display:block;
  padding:2px 1%;
  margin:auto;
  font-size:1em;
  }

input.submit {
  margin:auto;
  display:block;
  font-weight:bold;
  }
</style>

Our Twitter widget is now fully functional for handling private data, in and out of the API.

Check out the code for that new version of our Twitter widget!

Building a Twitter widget, part 4: getting your private data through authentication

Thursday, June 7th, 2007

So far, this series of articles have focused on getting and displaying public data, like Twitter public timeline in the previous part of this series of tutorials.

Public data is what most of the current web services will let you play with, but the more interesting services are those that let you manipulate your private data. This requires authentication, that is establishing a privileged connection with it. As the Netvibes proxy will not allow the passing of identities and states through classic authentication tools like cookies or sessions, we devised our own UWA authentication methods.

Twitter 04: authentication

These methods require two new preference fields, and the use of a new authentication setting in your Ajax request. Read up the whole documentation to get a better idea of how it works. We will follow it along and expand from it in this fourth part of our series.

As usual, you can follow along by using the previous version of the widget.

Putting the login form in place

Twitter 04: login

This is trivial: just add the necessary preferences to the widget code. Here’s our new preferences block:

<widget:preferences>
  <preference name="username" type="text" label="Username" />
  <preference name="pass" type="password" label="Password" />
  <preference name="limit" type="range"
    label="Number of items to display" defaultValue="10"
    step="1" min="1" max="20" onchange="reParse" />
  <preference name="offset" type="hidden" defaultValue="0" />
</widget:preferences>

We advise you to place it at the top of the preferences, but you can place them as you see fit.

Building the foundation

Now that we are getting exclusively private content, we cannot expect the widget to work without the user being logged-in. Since he is by default, we can’t directly fetch the data feed and display it, we have to first tell the user that he needs to enter his username and password before he can see anything.

That simply requires to change the Twitter.onLoad method, and build a if..else block in it: this checks whether the user is logged-in or not, and depending on the result, we ask him to log-in or launch the authentication/display code.

if ( widget.getValue('username') )  {
  widget.body.setHTML(
    '<div class="loading">Fetching messages from Twitter<br />
     (be patient, Twitter can be slow !)</div>');
  widget.callback('onUpdateBody');
  Twitter.loadTimeline();
} else {
  widget.body.setHTML('Please authenticate.');
  widget.callback("onEdit");
}

Since we never know how long the request can take (some servers can be quite slow), we first print a “please be patient” kind of message before launching the request, with the Twitter.loadTimeline method (presented in the next section). We trigger the onUpdateBody callback method in order for the widget to resize according to the content we just added to the body.
If the user is not logged-in, we ask him to, and open the preference form by triggering the onEdit callback method.

Making the Ajax request

We are going to switch data source. We’re not interested in the public timeline anymore, now we only want to get the statuses from our friends. Luckily Twitter provides a source just for that: friends_timeline, which “Returns the 20 most recent statuses posted in the last 24 hours from the authenticating user and that user’s friends”. The new feed to use is therefore this one:

http://twitter.com/statuses/friends_timeline.json

We integrate it into the Ajax request, which will now use UWA.Data.request() instead of UWA.getJson(). Here the code for our new Twitter.loadTimeline() method, for now:

Twitter.loadTimeline = function() {
  UWA.Data.request(
    'http://twitter.com/statuses/friends_timeline.json',
    { method: 'get', type: 'json', cache: 600,
    onComplete: Twitter.display,
    authentication: Twitter.getAuthentication() }
  );
}

Why are we using UWA.Data.request() instead of the simpler UWA.getJson() ? Because the later cannot deal with authentication, which requires an new setting: authentication.
The authentication object requested by the authentication setting is built by the new getAuthentication method, as given in the documentation. Note that unlike the onComplete setting, which has to reference a method and therefore not use the final (), authentication has to be set to an object, created by that getAuthentication method, and so has to feature the final ().

Twitter.getAuthentication = function() {
  var authentication = { moduleId: widget.id,
    username: widget.getValue('username'), type: 'http_basic' }
  // enable authentication outside of Netvibes
  if (widget.data.pass)
    authentication.password = widget.data.pass;
  return authentication;
  }

widget.data.pass references the content of the pass preference. If you change the name of the preference, remember to also do it in the getAuthentication method.

This being done, the other methods, like Twitter.display shouldn't need a change in order to parse and display all your friends' (and your own) statuses...

Testing the authentication

Authentication doesn't work too well in standalone mode, and it works in Netvibes only if the widget is set inline. To test authentication, you have to first put the UWA Test Widget in your Netvibes page, then edit its preferences, where you will put the URL of your own widget, and tick the Inline checkbox. If you don't tick that box, the widget's authentication won't work. Once you validate that, the UWA Test Widget is effectively replaced by your widget, and you can start fiddling with its own preferences.

Twitter 04: test widget

Here is the code for this new version. The next part will show you how to send message to filter through authentication.

Building a Twitter widget, part 3: paging and automatic preferences

Wednesday, June 6th, 2007

The first part of this series saw us build a widget that displayed a single Twitter status. The second part built upon the first on, and expanded the widget to display the whole public timeline feed, all the while learning UWA techniques and good practices.

Techniques and best practices are the central elements of the present third part: we will introduce paging, through the Pager control, and automatic preferences updates. Those two, once built into our widget, will immensely enhance its ease of use, and should be seen as best practices.

Twitter 03: paging

As usual, you can download and work with the previous version if you want to follow along.

Using the Pager control

Our previous version of the widget downloaded the public timeline feed, and let the user choose how many items to display. That imposed a limitation: if the user chose to display less than 20 items, he had no access to the remaining items: they were in effect hidden from view. This is why paging is much needed.

UWA provides a handful of controls, which are JavaScript objects that generate the proper HTML to use UWA templates (that is, CSS rules). Using templates and controls rather than one’s own recreation ensures that the widget is always well integrated into the user’s Netvibes theme.

The Pager control is available using the UWA.Controls.Pager object, which you have to set to a few data sources using a JSON object, like so:

Twitter.display = function(json) {
(...)
  var pager = new UWA.Controls.Pager(
    {
    module: widget,
    limit: widget.getValue('limit'),
    offset: widget.getValue('offset'),
    dataArray: json
    }
  );
}

module must be a reference to the widget. Most of the time, widget will suffice.
limit must be set to the number of displayed items. We here retrieve the content of our Range preference.
offset must be set to the number of the page itself (starting with zero). We here make use of a new, hidden preference, which acts as a global variable. We add right after the limit preference that we put in place in the previous version.

<preference name="offset" type="hidden" defaultValue="0" />

dataArray, at last, must be set to the array returned by the feed source. Here, that’s the json array, which we got from our Ajax request on the Twitter API method http://twitter.com/statuses/public_timeline.json.

In order to deal with page-changing, we then set an onChange event to the Pager object, and use to update the widget accordingly – for instance, setting the new value of the offset preference, and re-displaying the whole content based on that new offset:

pager.onChange = function(newOffset) {
  widget.setValue('offset', newOffset);
  Twitter.display();
}

Once all the JavaScript code is set up, we need to place a target div in the HTML code, where we want the paging to appear. Since our HTML is still dynamically generated using the setHTML method, we add that new element at the end of setHTML’s arguments in Twitter.display():

(...)
p.setHTML(
  (...)
  + ')<div class="paging"></div>'
)
widget.body.appendChild(p);
(...)

…and then properly put the generated paging in, at the end of Twitter.display

var pagerContainer = UWA.$element(
  widget.body.getElementsByClassName('paging')[0] );
pagerContainer.setContent( pager.getContent() );

In these last two lines, we use the UWA.$element() method, which extends any hand-created element with UWA’s DOM methods. Remember that elements created through the standard createElement() are already extended. We then call the pager’s getContent(), which will take in charge the generation of the whole pager HTML code.

The generated code gives you one or two bottom links, depending on where in the paging you are: ‘prev’ and ‘next’. Each link features an automatic onclick event, which calculates the newOffset value for the pager.onChange method: offset - limit for ‘prev’, offset + limit for ‘next’.

Once the new offset is set, the next line of our pager.onchange method triggers Twitter.display(), which creates the whole code around the JSON representation of the requested data – which was already downloaded. This is why it is useful to separate data downloading (in Twitter.onLoad) and data displaying (in Twitter.display): so that we can change the display without reloading the whole data every time.

Still, two last changes are necessary in order for our pager to work properly. First, change the loop that parses through our data feed. It was written this way:

for (var i = 0; i < json.length; i++ ) {

But since we take pages into account, we have to include our current offset in the equation. Therefore:

for (var i = widget.getValue('offset'); i < json.length; i++ ) {

Second and last change: since our offset is stored as a preference, it will saved for your next connection. This is not what we will want here, because that would imply that reloading the widget will directly get you to the previous offset, but with new content. So we have to reset it at each reloading, just in case:

Twitter.onLoad = function() {
  widget.setValue('offset', 0);
  widget.setTitle('Twitter public timeline');
  UWA.Data.getJson(
    'http://twitter.com/statuses/public_timeline.json',
    Twitter.display
  );
}

Paging is now working as expected.

Automatic preference update

By default, preferences do not impact the widget until the preference form is closed, using the ‘OK’ button or the ‘Close Edit’ text link. This can make preference-testing quite long for the user. You are therefore encouraged to add the onchange attribute to some of your preferences, making them point to a method that will redisplay the content according to the new setting. This is very quickly done.

First, add the onchange attribude, and make it point to a method:

<preference name="limit" type="range"
  label="Number of items to display" defaultValue="10"
  step="1" min="1" max="20" onchange="reParse" />

The method pointed by onchange will be called within the widget namespace. Therefore, you must define that method as widget.reParse.

You can make whatever you want of it: make it point directly to widget.onLoad, or having a real code block, like so:

widget.reParse = function() {
  if (Twitter.json) Twitter.display(Twitter.json);
  else widget.onLoad();
}

To make that if() line work properly, we just have to add a small line around the beginning of our Twitter.display method:

if (json) Twitter.json = json;

This will make our JSON data available to all the other methods.

And we’re now done with this thirs part of our series. Here is our new version of the widget. Check the code to fully understand the changes since the previous version.

Building a Twitter widget, part 2: displaying the public timeline

Tuesday, June 5th, 2007

This is part 2 of our series of articles on building a complete Twitter widget, all the while exploring the functionalities of UWA and learning some good practices of widget developing. If you haven’t already, read the first part, where we set up the basic widget code, and customize it to display a single, known Twitter status.

That first example had its limits, starting with the fact that you had to know the status ID beforehand, and that displaying only one status remains a tad useless. That’s why we’ll start from that first code, and change it to display the content of the whole feed for the public timeline, using Twitter’s timeline method. This way, we will discover how to use the UWA.Data.getFeed method, how to add CSS styles and how to use templates.

Twitter 02: the public timeline

If you want to follow along, download and work with our previous version of the widget.

Changing the preferences

The previous version of the widget dealt with a single status. The preference was as simple as this:

<preference name="id" type="text" label="Status ID"
  defaultValue="44739202" />

Since we won’t directly target a single status anymore, we can remove this line. But that doesn’t mean we can’t let the user decide how to display the content. For now, we will let the user simply choose how many entries to display. To that effect, we’ll use a preference of the range type, since we know the feed features 20 items:

<preference name="limit" type="range"
  label="Number of items to display" defaultValue="10"
  step="1" min="1" max="20" />

This code is directly lifted and adapted from our basic RSSReader sample widget. You can see the available preference types on the documentation site.

The HTML code won’t need much of a change for now, we’ll keep it as is.

Adapting the Ajax request code

We’re not displaying a single status anymore, but a series of statuses. That implies some more thoughts on the JavaScript code.

First, the feed URL is obviously changing. Our new Twitter.onLoad method now looks like this:

Twitter.onLoad = function() {
  UWA.Data.getJson(
    'http://twitter.com/statuses/public_timeline.json',
    Twitter.display);
}

We’ve decided to use the JSON feed, since it’s easier to work with in JavaScript. That being said, it’s format is less predictable (each service uses its own variation: Twitter, Flickr, del.icio.us…), so those who would rather know what they can expect should use the RSS 2.0 or Atom 1.0 version of the feed (just replace the .json file extension by .rss or .atom), and use the UWA.Data.getFeed method rather than the UWA.Data.getJson one. Check out the various ways of accessing data using UWA’s Ajax methods.

Revamping the display code

Twitter.display() is next in line in our data processing. Since we don’t display one status, but a series of them, we have to parse the JSON feed with a proper loop. That loop should stop parsing when it reaches the number of items requested by the user in his preference setting.

Thanks to JSON, this loop is very intuitively built: items are just part of a JavaScript array, ready to be parsed. We know what the item names are because we took the time to study the default JSON output’s format (using the cURL tool or directly within the browser, using the url http://twitter.com/statuses/public_timeline.json):

[
  {
  "created_at":"Tue Jun 05 14:28:57 +0000 2007",
  "text":"bla bla bla bla bla",
  "id":123456789,
  "user":
    {
    "name":"John Doe",
    "description":"My description",
    "location":"City, Country",
    "url":"http:\/\/www.example.com\/",
    "id":123456,
    "protected":false,
    "profile_image_url":"http:\/\/assets3.twitter.com\...",
    "screen_name":"MyUsername"
    }
  }
,
  {
  "created_at":"Tue Jun 05 14:28:57 +0000 2007",
  "text":"patati et patata et patati",
  "id":123456790,
(...20 items in the feed...)
    }
  }
]

The basic code turns out like this:

Twitter.display = function(json) {
  var count = 0;
  for (var i = 0; i < json.length; i++) {
    var status = json[i];
    var p = widget.createElement('p');
    p.setHTML(
      '<img width="32" height="32" src="'
      + status.user.profile_image_url + '" /> '
      + ''
      + status.user.screen_name + ': '
      + status.text
    )
    widget.body.appendChild(p);
    count++;
    if (count == widget.getValue('limit')) break;
  }
  widget.callback('onUpdateBody');
}

The Ajax request returns an array, which contains the JSON data. We can directly parse every item using var status = json[i]. Each status is an JavaScript object, which you can easily access the properties of, like status.text or status.user.profile_image_url.
The date, available at status.created_at, uses a non-standard format, so we pass that data to a custom function, Twitter.date, to get a true Date object that we can use in our code.
All of these data are put in a dynamically-created p tag. Note that only dynamically-created tags, using widget.createElement() for instance, are UWA-extanded by default. Hand-created elements can be extended through the UWA.$elements(elementTagName) method, as we will see in another part.

Right after the loop has entirely parsed the wanted content, we set up a call on the onUpdateBody callback method, which indicates that the body content has been updated, and that it should try and resize itself in order to display it all correctly.

The complete code features a bit more code, notably for handling the timestamp display.

Styling it all

Displayed as is, the result is not very pretty: images and texts are not aligned correctly, and it’s hard to tell the difference between two statuses. This is where we can make good use of CSS classes.

Twitter 02: no CSS style

We first have to add classes to the p element that we created dynamically. This is how we do it, directly in the loop:

(...)
var p = widget.createElement('p');
p.setAttribute('class', 'status');
if (count % 2 == 0)
  p.addClassName('odd');
else
  p.addClassName('even');
p.setHTML('<img ...
(...)

In order to differentiate statuses, we add a second class, 'odd' or 'even', depending on the count variable.

Classes being in place, the only thing left is to set the style-sheet. This is done directly in the HTML code:

<style>
p.status {
  margin: 5px 0;
  padding: 5px;
  min-height: 36px;
  clear: both;
  }

p.status img {
  float: left;
  margin-right: 5px;
  }
</style>

The even and odd classes are dealt with by UWA’s CSS, so you don’t have to set those yourself, they will automatically adapt to the current theme. That being said, you can overload them with your own CSS rules.

Every designer is free to choose how to style his data. Note that if you want to conform to the user’s current theme, you might prefer to use a UWA template, like the Thumbnailed List one.

We’re done for now, the public timeline displays in a nice way, and that was our aim. Check out the code for this new version of our Twitter widget. The next part will focus on paging and automatic preference handling.

Building a Twitter widget, part 1: setting-up the code and displaying a single status

Monday, June 4th, 2007

With the introduction of authentication methods in UWA (see the complete documentation) comes the ability to build some much more interesting widgets, ones that can access private data securely, both in read and write mode (HTTP GET and POST).

In order to present authentication to you, we’ve built a Twitter widget able to access your own status feed, and post new stuffs to your account. In this short series of articles, we’ll re-build it pieces by pieces, starting with a simple widget displaying specific statuses and the public timeline, to adding more complex functionalities like posting messages to your private widget account.

Note that in order to get the authenticated part to work, you will of course need to have a proper Twitter account. Those who don’t know Twitter yet might better understand the widget by learning about the service provided by the Twitter site

Twitter

This series of article are also aimed at introducing UWA development good practices, answering frequent questions and pointing to information in the numerous documentation pages we provide. For this reason, this first part will be quite long, as we will take the time to introduce details and pointers during the process of creating the widget.

Hopefully it will help you getting better at understanding how to work with UWA.

Gathering documentation

Before we start writing any code, we need to understand fully the service we want to UWA-fy. That means gathering information about the service’s ins-and-outs, how it is supposed to handle feeds, connections, users… You cannot expect to build a good widget if you don’t know how to use the service’s resources properly.

Our widget will provide access to Twitter. That service, luckily for us, not only has an ad-hoc API, but also a good documentation to help developers get acquainted with that API.

What we are looking for in this documentation is data feeds that we can access, whether freely or through authentication. At first we will focus on public data – we’ll keep the feeds that require authentication for later.

We quickly learn that Twitter conforms to the REST design principles for a web services, which roughly means it leverages the HTTP protocol’s methods, like GET, POST, PUT, etc. The Twitter feeds are available in XML, JSON, RSS 2.0 and Atom 1.0, respectively through the .xml, .json, .rss and .atom file extensions of the chosen feed.

Twitter provides a handful of public methods, among which are show() which returns a single status, and also public_timeline() which returns “the 20 most recent statuses from non-protected users who have set a custom user icon”. Those two methods are accessible through the following URLs:

http://twitter.com/statuses/show/[status id].[xml|json|rss|atom]
http://twitter.com/statuses/public_timeline.[xml|json|rss|atom]

With this knowledge in hand, we will first build a widget that will only display one specific status. Not really useful as-is, obviously: this is just a way to get us started on how UWA uses feeds.

Building the widget’s skeleton

Instead of starting from scratch, the documentation provides a simple HTML skeleton to which you can add your code. We’ll start from there, section by section. We encourage you to directly copy/paste that skeleton, and to modify it to suit your needs.
As a convention, try to give your widget’s file a meaningful name. For this series, we’ll name it, obviously, twitter.html.

Starting with the file’s HEAD section

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:widget="http://www.netvibes.com/ns/"  >
  <head>

Our file is in XHTML 1.0 Strict, with the usual headers. The only UWA-specific line is the one that points to the Netvibes namespace for the custom widget:preference element.

Adding the metadata

Here’s our modification to the metadata part of the skeleton. Make sure you change every line to properly describe you and your widget.

    <meta name="author" content="Xavier Borderie" />
    <meta name="website" content="http://dev.netvibes.com/blog/" />
    <meta name="description" content="Access Twitter data" />
    <meta name="version" content="0.1" />
    <meta name="keywords" content="twitter" />

    <meta name="apiVersion" content="1.0" />
    <meta name="inline" content="false" />
    <meta name="autoRefresh" content="300" />
    <meta name="debugMode" content="true" />

Building the preferences

If the service you point to accepts variables, you are very much encouraged to allow the user to change them, rather than to simply display the data feed content. Even if the service doesn’t accept variables, you can still let the user decide how many entries he wants displayed, how often to update the content, etc. This is all done in the widget:preferences element.

For now, we simply use Twitter’s show method for now, which displays a single ID based on the ID number we send. We will only provide one preference, with a default value: the ID number the user wants displayed.

    <widget:preferences>
      <preference name="id" type="text" label="Status ID"
        defaultValue="44739202" />
    </widget:preferences>

Preferences are accessible to JavaScript using the widget.getValue(prefName) method – here, widget.getValue('id').

Putting the CSS and JavaScript in place

CSS and JavaScript are to be added in the standard style and script tags. We will only use JavaScript for now, so let’s adapt the skeleton’s code:

    <script type="text/javascript">
      var Twitter = {}

      Twitter.onLoad = function() {
        var url = 'http://twitter.com/statuses/show/'
          + widget.getValue('id') + '.json';
        UWA.Data.getJson(url, Twitter.display);
      }

      Twitter.date = function(date) {
      	var dateArray = date.split(' ');
      	return new Date(
          Date.parse( dateArray[0] + ', ' + dateArray[2] + ' '
             + dateArray[1] + ' ' + dateArray[3] + ' '
             + dateArray[5].substring(0,4) )
        );
      }

      Twitter.display = function(json) {
      	widget.setTitle('Status from ' + json.user.name);

      	var when = Twitter.date(json.created_at);
        var month = when.getMonth()+1;
        month = (month < 10) ? '0'+month : month;

        widget.setBody(
          "<p>From: " + json.user.name + "</p>" +
          "<p>Date: " + when.getFullYear() +'-'+ month
             +'-'+ when.getDate() +' at '+ when.getHours()
             +':'+ when.getMinutes()
             +':'+ when.getSeconds() + "</p>" +
          "<p>Message: " + json.text + "</p>"
        );
      }

      widget.onLoad = Twitter.onLoad;
      widget.onRefresh = Twitter.onLoad;
    </script>

We chose to use the JSON representation of the status’ data. Whatever the data format chosen, we need to know which form it has been given by the service, in order to handle it properly. This can be done by viewing directly the feed using the cURL tool, or simply using your browser, with the full URL of the API method. This will display the data’s content, from which you can learn what are the available data fields.
As for the code itself, the one used above is lifted and heavily adapted from the Ajax Examples pages.

In this example, we are using an alternative function syntax: WidgetName.functionName = function(functionArgs) { ...}. While this might help some developers to group sibling functions under the same notation, it could also bring confusion to others. Fear not, as nothing forces you to use this convention in your code ; you can just as well use the usual syntax: function WidgetName.functionName(functionArgs) { ... } .

If you want your JavaScript code to be launched as soon as your widget is loaded, you need to set the widget.onLoad method, whether by making it point to the JavaScript function to trigger (without the ending (), or else widget.onLoad will be set to that method’s result), or filling its code block with the needed code lines.
widget.onRefresh is the equivalent of widget.onLoad, but is triggered when the widget is refreshed – that is, when its preferences are modified. We here simply set it to our own Twitter.onLoad method.

Twitter.onLoad is set to fetch the JSON feed, using the UWA.Data.getJson method, and directing to the Twitter.display method (again, without the final ()) if the request is successful. The Ajax request is here relaunched every time we change the id preference and validate the preference form.

Because JSON is very easy to handle in JavaScript, the Twitter.display method can be very small, simply putting the right JSON content in the right HTML tag. We’ve therefore added another method, Twitter.date(), that will help us display Twitter’s custom date format in a more readable way.

Adding the static HTML

The HTML code used to display the content can be entirely changed and rewritten through JavaScript & DOM. You can therefore put whatever you wish in here for now, but a good practices is to warn the user that the content is loading, and thus that he may have a few seconds to wait until he sees the whole interface. In this case, we encourage the following:

</head>
<body>
  <p>Twitter is loading ...</p>
</body>
</html>

However, there are times when you’d rather not have to build the whole interface using JavaScript – which will be the case for us when our widget gets more complex. Nothing keeps you from directly setting up the HTML code, maybe hiding it using CSS while the content is loading, and targetting the HTML elements using their unique tagnames/CSS classes and the DOM (remember that getElementById() is not available for now in UWA).

This is it for now. Here is the full code. The next part will deal with full RSS displaying, using public_timeline().