Friday, December 18, 2009

Web Runtime Widget Tutorial – Part 5: Installing the widget on your Phone

Grab the code!

In this fifth and final part part of the tutorial we look at transferring our widget from our PC based development environment to our phone.

As I said at the end of part 4 of the tutorial, we’ll be using Aptana to prepare our widget for transfer to our phone, but we’ll also need some way of getting a file from the PC to the phone.

Obviously we also need a phone that supports the Nokia WRT. Forum Nokia provide a Device Specifications table that you can filter by feature. I’ve provided a link that filters for WRT enabled devices.

I’ll be installing the widget on a Nokia E71, using a micro USB cable to move the widget from my PC to my phone.

Note: It’s also possible to install your completed widget on your S60 SDK emulator if you wish, however I’m not discussing that in this tutorial.

Packaging the widget up for its journey to your phone

In common with widgets you may have developed for other platforms, a WRT widget is packaged up into what is a standard ZIP file, with a modified file extension.

All of the constituent files of your WRT widget need to be zipped up into a single file, with the extension .wgz.

That’s not a difficult task, but Aptana helps out here turning this simple task into an even easier two-click operation directly within Aptana.

Right click on your project in Aptana, bringing up the context menu shown below:

Project context menu

Now click on the “Package Widget” option in the context menu:

Package your widget

Aptana will create a DiggClient.wgz file for you and add it to your project. The list of files in your project should now look like this:

File list showing packaged widget

Notice that your packaged widget file, DiggClient.wgz, is now shown in the list of files that make up your project.

Copying the widget to your phone

As I said earlier, I’m going to use a USB cable to facilitate transferring my DiggClient.wgz file to my phone. You could use Bluetooth to transfer the file, or any other method with which you are comfortable.

When I connect my phone to my PC via a USB cable, Windows will open an Explorer window showing me the accessible content on my phone:

Explorer window showing phone contents

You can in principle copy any file to any directory presented to you, although it is often suggested that you copy installation files to the “Others” directory shown in the image above.

Now you just need to find the DiggClient.wgz file on your disk and copy it to your phone. Way back in part 1 of the tutorial you will have defined the location that Aptana uses to store your project file. If you can’t remember where that is, no problem, we’ll just let Aptana show us where it has stored your project files.

Right click on the DiggClient.wgz file in your project’s list of files in Aptana to bring up the following context menu:

File context menu

If you click on the “Explore Files” option in the menu, Aptana will open an Explorer window in the directory containing your project files. DiggClient.wgz should be selected in Explorer for you:

 Explorer window showing project files

To copy your packaged widget to your phone, drag DiggClient.wgz from the Explorer window shown above, to the “Others” directory in the Explorer window showing the accessible contents of your phone.

Once you’ve copied the file, be sure to disconnect your phone from your PC before trying to install the widget.

Installing the widget on your phone

Installation is a simple process, although the exact mechanism will vary slightly depending on your phone model.

On the E71 a File Manager application is included in the “Office” application folder. This provides a straightforward route to installing the widget on this phone.

Using the File Manager application UI, navigate to the directory you copied DiggClient.wgz to, making sure to check you are looking at the contents of your memory card and not the phone’s internal memory. Note that although the directory was shown as “Others” in Windows Explorer, it appears as “Other” in the File Manager application UI, at least on the E71.

Once you locate the DiggClient.wgz file, select the file and answer the prompts to confirm that you want to install your widget on your phone.

Once installation is complete, you will find your widget in the “Installations” application folder. Again, the exact folder you will find your widget in will vary slightly between phone models, it may for example be in a folder called “Applications” instead.

Running your widget on your phone

In order to run your widget, you just navigate to it and launch it as you would launch any other application.

Once you’ve entered a topic in the edit field and used tab navigation to select the “Digg it” button, you will get a prompt asking you to confirm that you want your widget to connect to the internet. An internet connection is clearly necessary if we’re going to talk to Digg and retrieve some stories on your chosen topic. However, when deciding whether or not to allow your widget access to the network, bear in mind that you may have to pay for internet access from your phone.

Note that if you do not allow your widget network access, the HTTP request to Digg will fail immediately and your widget will simply show that there are no stories available.

And finally…

Well, that’s it for our tutorial widget. I hope you’ve found it useful and feel confident to go out and experiment with WRT and create some great widgets for your phone and maybe publish them on Ovi Store so others can use them too!

The widget we’ve created isn’t perfect, there are still a couple of rough edges that you could explore – the rough edges I’m thinking of  involve “focus”. Over to you!

Or you could look at extending the widget to use more services provided by the Digg APIs. One idea might be to remove the possibility of typing in a non-existent topic by retrieving a list of topics from Digg and then allowing the user to choose from such a list.

Lastly, please make use of the WRT resources available at Forum Nokia. For example, there is a collection of community provided articles & samples that show how to achieve a large number of tasks using WRT.

Have fun working on your own widgets!

Web Runtime Widget Tutorial – Part 4: Refining the UI

Grab the code!

In this fourth part of the tutorial we smooth off some of the rougher edges in our Widget’s UI.

We will look at using progress notifications to help with the uncertainty over when our request to Digg has completed. We’ll also improve the presentation of the detail view and allow the user to open a link to the full story. Doing this will also cause us to at last make use of our project’s empty CSS file.

As promised, I’ve also got a different icon for our widget. Notice I said “different”, not “better”. At least the new icon is more relevant than the “Hello” speech bubble icon we’ve been using up to now.

Showing Progress

We’ve been using the UIManager object’s showNotification() function since the beginning of this tutorial. Back in part 1 of the tutorial we noted that showNotification() took three parameters:

  • duration (in milliseconds) to show the note
    • If the duration is negative, the note will remain visible until such time as your code explicitly hides the notification
  • type of note (which influences the icon shown in the note dialog)
    • “info” – the type we’ve used up till now, intended for showing general information to the user
    • “warning” – intended for use with errors or similar situations
    • “wait” – this is the type we’ll look at using now because it is intended for use with progress notifications
    • If you pass null as the note type, no icon will be displayed in the notification.
  • message to be shown to the user

If you are using a “wait” notification, a fourth parameter can be passed, which defines the progress of an operation. This fourth parameter should be a floating point number between 0.0 and 1.0, with 0.0 meaning the operation is at 0% and 1.0 meaning the operation is at 100%. Of course, the progress of some operations is difficult to calculate, such as our request to Digg. For these situations, you can pass a negative progress value. The “wait” notification uses slightly different styles depending on whether progress is known or unknown.

Using a “wait” notification is particularly easy if the actual progress over time is not known. You simply need to call UIManager’s showNotification() function as your operation begins and then call the function hideNotification() on your UIManager object when the operation completes.

Displaying the progress notification

From part 3 of the tutorial, we know that our event handler diggButtonClicked() is the function that initiates the web request to Digg which makes it a good place to present the progress notification, just before we start the web request:

Show wait notification

The code above is identical to the implementation of this function in part 3 of the tutorial, except for the addition of line 207. Here we call showNotification() on our UIManager object, passing a duration of –1 indicating that the notification should not time out, a type of “wait”, a suitable message and a progress of –1, indicating that we can’t tell what the operation’s progress is.

The function then goes on to issue a request for stories to Digg as before. The screenshot below shows the main view with our new “wait” notification visible during a request to Digg:

Screenshot showing wait note

Hiding the progress notification

If we’ve modified the code that creates a request to Digg in order to show a progress notification, it seems sensible that we add code to remove the progress notification in our function that gets called when the request completes.

Hiding the wait notification

The code above is an abridged version of handleDiggResponse() from part 3 of the tutorial. The only difference between the implementation in part 3 and this part of the tutorial is the addition of line 278 – the call to UIManager’s hideNotification() function. We call hideNotification() here  as our last action in handleDiggResponse() because we can be sure that everything has been processed and the UI has been updated as appropriate.

Detail View 2.0

The detail view we’ve been using up to now hasn’t been very interesting. It was fine to prototype our ideas with and demonstrate how we could move data around our views. But if we want to put our widget on our phones and use it, we want something a bit better.

Something like this maybe?

New Detail View

To turn our dull detail view from part 3 of the tutorial into the slightly more interesting view shown above takes just a small amount of code and a bit of CSS. 

Detail View 2.0: Code changes

First up, we need another variable to represent the “Read more” link shown in the screenshot above. This will be a link that opens the browser on the phone and takes the user to a website where they can read more about the particular story displayed in the detail view.

Link label variable

We’ve added the variable linkLabel to represent the link to the full story.

Next we modify the init() function to create a new Label control and assign the reference to the new control to the linkLabel variable.

Label initialisation without captions

We’ve also removed the captions from each of the four labels that will now make up the detail view by passing null as the first parameter to the Label control’s constructor. We don’t need the label captions anymore because we will use differences in style to provide visual cues as to the significance of each label.

We’re going to rely on CSS to improve the appearance of our detail view, but we need to make some more code changes to give our CSS a helping hand; specifically, we need to inject class names into each of the labels we want to style via CSS.

We can set the text of any WRTKit Label control to any arbitrary HTML we like. WRT will render the HTML when it renders the Label control, so provided the HTML is valid, the user should only see the text you intended them to see.

This technique allows us to easily wrap a piece of text intended to be shown to the user in a <div> tag and within the <div> tag we can specify a class attribute. The value of the class attribute can then be used in our CSS to selectively style particular elements in our UI.

Let’s update the implementation of our populateDetailView() function to add class names to our Label controls as appropriate:

Injecting CSS class names to labels

The titleLabel is simply wrapped in a <div> element which defines a class attribute with the value “DiggTitle”.

Similarly, the diggsLabel is wrapped in a <div> element which defines a class attribute with the value “Diggs”. In addition, we also insert a <br/> tag to force a new line; on this new line we add the text “diggs”. This effectively gives us one label which renders it’s content over two lines – the first line renders the number of diggs a story has had with the second line rendering the word “diggs”.

We’ve not changed the storyLabel because the default text styling is fine for the main text of the view.

Our new linkLabel control does require to be styled, in order to make it look like a hyperlink. So we enclose the text of the link in a <div> element with a class attribute which has the value “DiggLink”.

However, we need a little more substance as well as a bit of style in the case of the linkLabel. We need to do something useful when the user clicks the link.

We achieve this by adding a HTML <a> tag to our linkLabel’s text and specifing an href attribute with the value “JavaScript:openStoryLink(…)”.  We are not allowed to open a link directly from our widget’s HTML page, so we can’t just use the URL of the current story’s link property. Instead, by defining the href with the value “JavaScript:openStoryLink(…), WRT will try to invoke a function called openStoryLink() in our JavaScript code. The final thing to notice about the way we define the text of the linkLabel is that we construct the href value in such a way that we pass the numerical id of the story displayed in the detail view when the “Read more” link is clicked. For example, if we were showing the story with id = 3, the <a> tag would look something like this in the HTML of the page:

<a href=”JavaScript:openStoryLink(3)>Read more</a>

The final code change we need to make is to provide an implementation of the function openStoryLink(), otherwise nothing much will happen if the user clicks on the story link in our improved detail view.

As I noted above, we’re not allowed to open a link directly from within our widget’s HTML – the page rendered in your widget must never be replaced with a new page. We get round this by using functionality provided by WRT which allows us to open a link in the phone’s browser instead. The code to achieve this is:

Function to open a URL

If our widget is running in a WRT environment, we call openURL() on our inbuilt widget object, passing it the URL of the story with the id passed as the parameter to our function. openURL() will then launch the relevant link in your phone’s browser. When the user eventually closes the browser, they will be returned to our widget.

If our widget is running in another environment, for example, in a browser environment on your PC, we use JavaScript’s window object, which represents your browser’s window, to open a new window to display the link associated with the story.

That’s all the code changes we require. Now we can turn our attention to our as yet empty CSS file.

Detail View 2.0: Cascading Style Sheet

By implementing the code changes above, we defined three classes that can be referred to by CSS to selectively style content in our new detail view. The classes we defined were:

  • DiggTitle which refers to the title of a story
  • Diggs which refers to the number of Diggs a story has had
  • and DiggLink which refers to the hyperlink to the full story

Styling the title of our story is quite simple. We just need to use bold text, which we’ll centre. We also want the text a bit bigger than the story text, but we don’t want it to dominate our phone’s small screen. We’ll use the following CSS to define a suitable style:

CSS style for story title

This block of CSS starts with the class name to which it applies, preceded by a period. Within the block we specify that the font-weight should be bold, the text should be centred and that the font-size should be 1.25em. We use em as the unit of font size instead of specifying a fixed size because em’s are relative to the default size of the current font. This means that the title should look reasonably in proportion to the text of the story across a range of screen sizes.

Next, we style the number of diggs the current story has had, using the following CSS:

CSS style for number of diggs

We use a font size between normal size and the size used for the story title, which should make the number of diggs the story has had stand out a little. We then define a pale yellow background and centre the text within this element.

Next we define some padding to ensure there is a small gap top and bottom of our diggs element, which just helps to space the content out a little in our detail view. The four values given in the padding property specification define the padding between the element border and the element content in the order top, right, bottom and left. Hence, we’ve defined a 7 pixel gap top and bottom for our diggs element.

If we left it there, what we’d see would be a pale yellow box stretching across the width of our screen, with text centred over two lines. That’s not what we’re looking for. We want the number of diggs to be shown in a small box, similar to the way this information is shown on Digg. We can achieve this by defining a margin for our diggs element, as shown in the CSS block above.

What the margin definition above asks for is that our diggs element is rendered to the screen with 77% of the screen width used as a margin to the right of our element. Admittedly this technique will result in the width of the diggs element changing between devices with different screen widths. As with the padding property, the four values specified for the margin property define the margin around the top, right, bottom and left of the related element respectively.

Having styled the number of diggs a story has had, let’s now look at styling the link that will let users read more about the story. We do this in two parts. First we define some CSS to style the link in its unselected state, then we define a slightly different style for the link in its selected state.

Here’s the CSS for the unselected state:

CSS style for unselected link

This is quite simple, but there is one significant difference to the previous two styles. Rather than applying the style to the whole of the element referred to by the class name “DiggLink”, we only want to style the HTML <a> tag within the element referred to by the “DiggLink” class. We specify this by placing the element we want to apply the style to between the class name and the opening brace of the style definition.

We apply a typical style for hyperlinks, underlining the link, using blue text and rendering it in bold font to make it stand out.

When the user selects the link, we use a different style so the user can see a clear difference between the selected and unselected states:

 CSS style for selected link

As with the CSS for the unselected state, the CSS above defines a style that is applied to <a> tags within elements identified by the class “DiggLink”. However, we only want this style to be applied if the <a> element has focus. The CSS pseudo-class “:focus” is used to specify this constraint on the application of the above style.

The style itself simply inverts the text of the link, using white text on a blue background.

Goodbye “Hello”

We’re almost done. All we need to finish off is replace the “Hello” speech bubble icon we’ve been using since part 1 of the tutorial with something more relevant. Here’s what I’ve come up with:

New improved icon

I know it’s not very exciting, but I’m no graphic artist, so it’ll have to do. Feel free to replace it with something better if you’ve got the graphic ability. The new icon is included in the downloadable package associated with this part of the tutorial.

Coming next…

This concludes the fourth part of our tutorial on creating a Digg client with Nokia WRT & Aptana Studio. Next time we’ll look at getting our widget off our PC and on to our phone. Aptana gives us a helping hand in this task, but you’ll need some means of getting files from your PC to your phone, such as a cable or Bluetooth, or a card reader.

Part 5>

Web Runtime Widget Tutorial – Part 3: Requesting data from Digg and displaying the results

Grab the code!

In this third part of the tutorial we continue the evolution of our widget from a simple Hello World example into a Digg Client widget. We’ve already put together a basic but functional user interface and populated it with some hardcoded data. Now it’s time to hit the web in search of some dynamic content.

In case that sounds like it might be difficult and you’re reaching for your browser’s back button, I’ve got “before and after” screenshots to show you what you get if you stick with this. This is what we had at the end of part 2 of the tutorial:

Before

We had a TextField and a FormButton that didn’t really do anything useful, plus three hardcoded NavigationButtons masquerading as content.

Well, with a bit more code, we end up with this:

After

There’s no hardcoded trickery going on in the screenshot above. That’s genuine content retrieved from Digg.

Digg List Stories API

Digg publish a number of APIs that allow users & partners to interact programmatically with Digg services. I encourage you to read more about the APIs on offer and in particular I’d like to draw your attention to the API License Agreement.

We will be making use of just one of Digg’s APIs, the List Stories API. As you’ll see if you read the documentation provided by Digg, the API is quite extensive and supports responses in several formats, including XML and JSON.

The  request we will send to Digg will be a variant of this form:

http://services.digg.com/stories/topic/sometopic?count=20&appkey=http%3A%2F%2Fgavinmeiklejohn.com&type=xml 

where “sometopic” will be replaced with the topic entered in our widget’s TextField.

I should also draw your attention to the appkey in the above request. Digg require each request sent to them to contain an application key. Digg do not currently issue keys or use keys for authentication, they only monitor application keys for statistical purposes. You may therefore use the key shown in the example request (and used in the code we’ll see later on), or you can define your own. Just make sure that the key you use is valid according to Digg’s application keys rules.

Digg XML Response Example

The XML responses issued by Digg are presented in Digg’s own custom XML format.

You can see an example of the type of XML data our widget should receive by looking at the example XML response on the List Stories API page referenced earlier.

Briefly, the response consists of a <stories> container, within which will be 0..n <story> elements. (In our case, n will be limited to the value of count in the request we send to Digg.) Each <story> contains a number of attributes and further elements that provide information on a given story, such as the title, a short description, thumbnail associated with the story, number of “diggs” a story has and more.

New file

Technically we could write all of the new code we’re going to need in our existing diggclient.js file and our widget would work. However, if we did that the code would be a mess and your widget probably wouldn’t stay working for very much longer if you wanted to add more functionality to it later on. We need to structure our widget with just as much thought as we would structure any other piece of software we might write.

So we’ll create a new file to contain some of the new JavaScript we need to write – we’ll use the new file to handle our web request to Digg.

To add a new JavaScript file to your project, right click on your project in Aptana Studio, select “New” from the context menu, then select “JavaScript File” from the “New” submenu, as shown in the following image:

Create a new file

This will bring up Aptana’s New JavaScript File dialog. The container should be correctly specified as your project and a default file name of “new_file.js” is offered by Aptana. 

New file dialog

Change the file name to “diggweb.js” and click the Finish button.

Name the new file

Your new file should then be created, added to the list of files in your project and opened in the main editor pane. Hopefully you will see something similar to this:

New file open in editor

We’ve just added a new file to our project in Aptana. However, only Aptana understands this. If you wrote code in the new file and tried to call that code or use it in some way from code in diggclient.js, typically nothing much would happen. Why not? Because there is currently nothing in our widget that includes our new JavaScript file at runtime.

There are two ways to resolve this. You can either write a small function to dynamically add a <script> tag to your widget’s DOM document, defining the src attribute of the <script> tag to point to your new file. Or, more simply, you can achieve the same result by modifying your project’s diggclient.html file by hand.

We’ll use the simpler approach as we’ve only got one file to add. Modify your diggclient.html file to match the listing below, by adding the line shown in bold:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />       
        <script type="text/javascript" src="diggclient.js"></script>
        <script type="text/javascript" src="diggweb.js"></script
        <script type="text/javascript" src="WRTKit/WRTKit.js"></script>
        <link rel="stylesheet" href="diggclient.css" type="text/css">
        <META NAME="Generator" CONTENT="Nokia WRT plug-in for Aptana Studio 2.3.0" />
    </head>
    <body onload="init()">
    </body>
</html>

Requesting data from Digg

Let’s get on and write the code to request data from Digg.

In common with virtually all modern browser environments, Nokia WRT supports the XMLHttpRequest API. This API greatly simplifies the work required by web application developers to issue requests to HTTP servers and process any data returned by the server.

XMLHttpRequest does have some shortcomings in so much as it is not an official standard and the implementation of the API tends to vary slightly from browser to browser and from runtime to runtime. More significant though is the difference in security policies between different environments which can make the job of issuing an HTTP request a bit tricky.

The good news is that WRTKit builds on the XMLHttpRequest API to offer an Ajax object, which deals with the differences in underlying API implementation & security policies between browser environments. The Ajax object is a very thin wrapper over the basic XMLHttpRequest but makes the task of issuing a request to an HTTP server about as simple as it can get.

We’ll build another thin wrapper over WRTKit’s Ajax object to help us separate the web request code from the main UI code thereby keeping the UI code as straightforward as possible.

DiggWeb object constructor

We’ll call our web request object DiggWeb. It doesn’t need to do anything special when we create it, so the constructor is just an empty function:

DiggWeb constuctor

DiggWeb properties

Our DiggWeb object needs just two properties. One to hold a reference to the WRTKit Ajax request object we’re wrapping and one to hold a reference to a callback function that we’ll call when our HTTP request completes. The callback function will be implemented in diggclient.js later in this part of the tutorial.

DiggWeb properties

What does DiggWeb.prototype mean?

If you’re new to JavaScript you might be wondering about the syntax I’ve used to add properties to our DiggWeb object, particularly if you normally speak C++, C# or other class based languages. JavaScript doesn’t support classes. There is no distinction between an object and the definition of that object – everything in JavaScript is an object.

Any function in JavaScript can be a constructor. All that distinguishes a constructor in JavaScript from another function is the usage of the new operator before calling your constructor function. This also implies that the role of a constructor is temporary – it is possible to call a “constructor” function on an already existing object.

No classes? Any function can be a constructor? Surely this is chaos! No, there is order and control in the way JavaScript works.

Every JavaScript object has a prototype property which itself is a collection of properties inherited from a base object. At the top of the inheritance tree is the in-built JavaScript Object data type, from which every JavaScript object inherits.

Any object can extend it’s set of properties by adding new properties to it’s prototype property. These new properties can be data properties or new functions, which provides a powerful mechanism to construct complex objects and object inheritance trees.

So, a line of JavaScript such as:

DiggWeb.prototype.ajaxRequest = null;

is saying, add a new property called ajaxRequest to the set of properties contained by DiggWeb’s prototype property.

If you’d like to read more about the object-oriented aspects of JavaScript I suggest you start with the following links:

If you want to go further or if you prefer books, I recommend Douglas Crockford’s “JavaScript: The Good Parts”

Issuing a HTTP request

In addition to two properties, our DiggWeb object needs just two functions. One to issue a HTTP request and one to handle changes in the state of the request. Let’s start looking at how we actually issue a HTTP request.

Requesting data from Digg - 1

We start by defining a function called requestFromDigg that takes two parameters.

  • topic – this will be the text entered by the user in the main view and will be inserted in the correct place in the request URL we construct
  • callback – this will be a reference to a function in diggclient.js that is to be called when the HTTP request completes.

Next, we create a WRTKit Ajax object and assign it to our DiggWeb object’s ajaxRequest property. The reference to the callers callback function is stored in our DiggWeb object’s property of the same name.

The Ajax object that will manage the actual HTTP request to Digg for us also requires a callback function. We handle this in two steps. Firstly, we provide an implementation of XMLHttpRequest’s onreadystatechange() function, like this:

Requesting data from Digg - 2

What we’ve done here is provide a simple implementation for XMLHttpRequest.onreadystatechange() that will call the function readyStateChange() on our DiggWeb object. readyStateChange() is the second of the two functions we will add to our DiggWeb object.

Why have we written self.readyStateChange() rather than this.readyStateChange()? Because when the function XMLHttpRequest.onreadystatechange() runs, this would refer to the XMLHttpRequest object, not our DiggWeb object. We want the function readyStateChange() in our DiggWeb object to be called, so we need to take care to be explicit about which object we’re referring to.

We’re just about ready to issue our request to Digg for some data to show in our UI. We just need to construct the request URL, like this:

Requesting data from Digg - 3

This is just simple string concatenation to build a URL of the form required to request a list of (up to) 20 stories about a specific topic from Digg. Of course, topic is the parameter passed from the caller and will, when we’ve plumbed all of the code together, correspond to the text entered by the user in our widget’s main view.

Finally we can actually transmit our request out on to the web:

Requesting data from Digg - 4

As with typical browsing requests, we’re issuing an HTTP “GET” command, hence the first parameter to the open() function. The second parameter is our string containing the URL to request some stories, with the third parameter indicating that we want the request to be performed asynchronously.

By performing our web request asynchronously we can keep the UI responsive, possibly displaying a progress indication, or if our widget was more powerful, possibly allowing the user to do some other task while the request is processed and data returned from Digg.

The call to open() prepares the XMLHttpRequest object to send the request. Nothing actually gets sent until we call send(). We pass null to send() because we’ve already defined all the data that needs to be sent in the open() function.

All we need to do now is write some code to handle the request state changes and ultimately callback to our caller’s code to tell them when the request is complete.

Dealing with request state changes

XMLHttpRequest has an internal readyState property. Every time the readyState property changes in value, the readystatechange event is fired.

The readyState property can have one of the following values:

readyState value Meaning
0 The XMLHttpRequest object has not yet been used to send any request.
1 The open() function has been called, but no data has yet been sent.
2 The send() function has been called and a request has been sent, but no response has been received yet.
3 Data is now being received by the XMLHttpRequest object.
4 This is the final state which indicates that the request is complete. If data was being returned, it also indicates that all data has now been received by the XMLHttpRequest object.

The readystatechange event is fired once on every state transition, but can also be called multiple times during state 3 if there is a substantial amount of data to be received.

It is the readystatechange event that XMLHttpRequest’s onreadystatechange() function is being called to process. We’ve already seen that we delegate that event handling to a method of our DiggWeb object called readyStateChange().

Ajax callback state check

In our widget we’re only really interested in knowing about completion of our request. We are quite happy to ignore all other states. So we start our event handler by checking the value of the readyState property; if it’s anything other than 4, we return from the function and don’t do any further processing.

If the value of the readyState property is 4, our request is complete and we should call our client’s callback function:

Ajax callback forwarded to client

Recall that we stored a reference to the client’s callback function in our DiggWeb object’s callback property.

We use the callback property to allow us to call the client’s callback function, passing two parameters. The first parameter we pass to the callback function is the numerical HTTP status code.

The second parameter we pass to the callback function varies depending on whether the request completed correctly, or with an error.

If all went well and we have a HTTP status of 200, we pass XMLHttpRequest’s responseXML property as the second parameter to the client’s callback function. XMLHttpRequest detects if valid XML is returned as a result of a request; if so, it stores a XML tree in the responseXML property, ready for parsing.

If something unexpected happened and we did not get a HTTP status of 200, we pass XMLHttpRequest’s statusText property as the second parameter to the client’s callback function. The statusText property contains a human readable textual version of the HTTP status code, such as “Not found” for a status code of 404.

Displaying the data in our widget’s UI

Instead of going through every line of code in diggclient.js as we have done in parts 1 & 2 of the tutorial, I’ll just focus on the new and modified code we need to plumb the XML data received from Digg into our widget’s UI.

More objects, more variables

Let’s start by looking at the new variables we require this time.

Now that we’re getting dynamic data from Digg to display in our UI, we need to allow for the case where there are no stories to show. The most likely reason for this would be that the topic entered by the user does not exist. We’ll cater for this by defining a new Label control that will be shown in the main view, as necessary.

A new label control

The variable noStoriesLabel will hold a reference to this new Label.

We also need one variable to reference our DiggWeb HTTP request object and another variable to reference an array of stories received from Digg, the length of the array being determined by the number of stories we receive. Here are the declarations for these two variables:

Web request & story array variables

The other variables we require are as defined in part 2 of the tutorial.

Initialisation

Our init() function remains almost identical to the code used in part 2 of the tutorial. We just need to remove the code that temporarily added 3 NavigationButtons to the main view and replace it with code that adds a Label to show that there are no stories available yet.

Remove the following code from your init() function…

Out with the old...  and replace it with the following code:

...in with the new

Here we’ve created a new Label control and assigned it to our new noStoriesLabel variable. The Label is constructed in the familiar way, but here we pass null as the second parameter to the Label constructor, signalling that we do not require a caption associated with this Label. Once constructed, the Label is added to our widget’s main view.

We will still use NavigationButton controls to represent each story returned from Digg, but we’ll create the NavigationButton controls as and when they are needed and we’ll also dynamically swap between displaying NavigationButtons when there is data to show and the “No stories available” Label when there is not.

Button Event Handlers

In part 2 of our tutorial we had two button event handler functions:

  • diggButtonClicked() that handled the event fired by the user clicking on the main view’s “Digg it” button.
  • storyClicked() that handled the event fired by the user clicking on one of the NavigationButtons representing stories in the main view

Of these event handlers, only the implementation of diggButtonClicked() changes in this part of the tutorial. The new implementation looks like this:

Digg button event handler

Compared to the implementation in part 2 of the tutorial, it’s only the code within the else clause that is different. Now, instead of just displaying a notification showing the user the text they had entered into the TextField control, we want to do something useful and issue a request to Digg for some stories on the topic entered by the user.

We do this by creating a new Array and assigning the resulting array to our storyArray variable. Array is an inbuilt JavaScript object that allows easy creation, manipulation and removal of data in an array. Next we create one of our own DiggWeb objects and assign that to the webRequest variable.

Finally, we use our DiggWeb object to issue a request to Digg for some stories. As we know, because we wrote the DiggWeb object, we issue a request by calling the requestFromDigg() function of our DiggWeb object. We also know that we need to pass two parameters to requestFromDigg():

  • the topic on which we want some stories
  • a reference to the function we want to be called when the request completes

Therefore, we pass in the topic variable which holds the text the user entered in the TextField control and a reference to a function called handleDiggResponse(), the implementation of which we’ll look at next.

Handling data returned from Digg

You might like to have a look at the example XML data provided by Digg as you follow the implementation of this function.

Also, we’re heavily reliant on the DOM APIs to help process the XML, so if you’re not familiar with them, you might like to take a look at the material on this at the Mozilla Developer Center.

Digg response handler - 1

The first thing we do is check the completion status of the request, which is an HTTP status code. We’re looking for a status of 200 which means the request completed correctly.

If we’ve got an HTTP status of 200, what we want next are all the <story> elements in the XML returned from Digg.

We get all of the <story> elements by calling the DOM API function getElementsByTagName() which returns an array of all elements tagged with a specific string, starting from the root of the XML tree we call the function on.

Now we need to dissect each “story” element in turn and pull out the data we’re interested in.

Digg response handler - 2

We use a for loop to examine each story element in turn. The length property of the array of story elements returned by getElementsByTagName() gives us the number of stories we have received from Digg.

The first thing we need to do when we start processing a story is create some variables in which we can store the parts of the story we are interested in. That’s the purpose of lines 224 – 228. Once we’ve finished getting hold of the individual parts of a story, we’ll use JavaScript Object Notation (JSON) to combine the parts into a single object and add it to our array of stories.

Note: A good introduction to JSON can be found on the msdn site. You don’t have to speak .NET to get something out of the article. Alternatively, if you haven’t already decided to take a look at “JavaScript: The Good Parts”, JSON is another reason to do so.

Some of the data we’re interested in is contained within the attributes of each story element, so we again use the DOM API, this time to gain access to the attributes for the current story.

Having obtained the attributes for the current story, we store the values of the “link” and “diggs” attributes in their namesake variables.

Although there are several other attributes we could look at, I’m more interested in the data to be found in the child nodes of each story element. So let’s look at how we examine the child nodes:

Digg response handler - 3

We use the DOM API once more to retrieve an array of child nodes for the current story. Having got the array of child nodes, we use another for loop to allow us to examine each child node in turn, looking for the data that is of interest to us.

What we want are the parts of the story that have real meaning to the user of our widget – so we’re interested in the title & description of our story together with the thumbnail image associated with the story, if there is one.

In the case of the “title” and “description” child nodes, the actual data, if present, is the value of the first child node of the “title” and “description” child nodes respectively. It is legal for a child node to exist but for there to be no associated value, which is why we need to check the length of the second-level child nodes array rather than assuming we can access the value of the “title” and “description”. When we get the data values we’re interested in, we again store them in their namesake variables, defined earlier in this function.

In the case of the “thumbnail” child node, the data we’re interested in is the URL of the thumbnail image, which is stored in the src attribute. So, just as we did for the story attributes earlier, we get hold of the attributes of the “thumbnail” child node and then retrieve the value of the src attribute. We store the value of the thumbnail’s src attribute in the thumbnail variable defined earlier in this function.

We use JSON to combine the variables declared earlier into a single object which we store in our array of stories by calling the push() function on our storyArray.

Code_7B

JSON provides us with a useful mechanism to create simple data objects on the fly which we can then add to our storyArray.

To construct an object using JSON you write a statement enclosed in braces { }. The JSON statement consists of a comma separated list of property names and values, with a colon used to separate each property name from it’s value.

So our JSON statement creates an object with properties named title, description, diggs, thumbnail and link, giving each of these properties the value of the appropriate data extracted from the XML received from Digg.

The call to push() on our storyArray then adds the object created by our JSON statement to our array of stories. As we’ll see shortly, when we come to access the objects in our storyArray, we can directly reference the properties title, description, diggs, thumbnail and link, even though there is no object defined anywhere in our code that has such properties.

I encourage you to read more about JSON and find out what it can do to make your JavaScript development both easier & more powerful.

Note that the closing brace shown on line 257 above is the closing brace of the outer for loop of our story processing code.

All we need to do now is deal with the case when the request has failed in some way:

Digg response handler - 4

Recall from the implementation of our DiggWeb object that we return the XMLHttpRequest’s xmlResponse property if the request completes correctly, but we return the statusText property if there was a problem which we can use to conveniently present a notification to the user informing them why the request failed.

The code that presents the notification is conditional – we don’t show a notification if the response is 404, which means, of course, that the URL was not found.

By convention, Digg will return a 404 status if the topic we are looking for does not exist. We’ve already said that we will show a textual label in the main view to indicate there are no stories related to the topic entered by the user in this case.

If we also showed the “Not found” notification we’d be duplicating information, and as “Not found” is potentially the most frequent error we are likely to encounter, it is better we deal with this case more gracefully in our widget’s UI.

The last thing we do in our handleDiggResponse() function is call another new function, refreshMainView(), passing it the storyArray. This new function will handle updating the controls visible in the main view to reflect the data received from Digg, including displaying the “No stories available” label if necessary.

Updating the main view

To display the stories received from Digg in our widget’s main view, we need to perform two tasks:

  1. Remove any current content from the view that is no longer relevant.
  2. Add the updated content.
Removing old content

Only two controls in the main view are always relevant – the TextField and the FormButton, so we’ll write code to remove everything apart from these controls from the main view:

Removing old content

We start this function by retrieving an array of the controls in the main view, which we get by calling the function getControls() on the mainView object.

A for loop is then used, which starts with the last control and finishes with the third control which was added to the main view.

Within the for loop we delete each control by calling removeControl() on the mainView object, passing the element of the control array to be deleted. When the for loop exits, the only controls left in the main view will be the TextField and the FormButton.

Note that this code is dependent on the fact that the ListView maintains an array of controls, listed by addition / insertion order. We know therefore that curControls[0] is the TextField control and that curControls[1] is the FormButton control.

Check your references

Beware! If you reversed the direction of the for loop in the code above you would not get the desired result. The call to ListView.getControls() returns a reference to the array of controls contained by the ListView control. When a control is removed from the internal array by calling ListView.removeControl(), the result is visible via the reference we got before we started removing content. Therefore, by advancing the index in the for loop, we effectively skip a possible candidate for deletion. You can of course write code to deal with this, and looping through the array in reverse order is one such mechanism.

Adding new content

The array of stories we received from Digg was passed as the parameter, newStories, to this function. So all we need to do to add fresh content to the main view is construct a NavigationButton for each story, using relevant data from each item in our array of stories.

Adding new content

We start by checking the length of the newStories array because we only want to add NavigationButtons if we’ve got at least one story. For each story, we create a NavigationButton and associate the storyClicked() event handler with it before adding the button to the main view. Notice that the code to do this is very similar to the code we used to add temporary NavigationButtons to the main view in the init() function in part 2 of the tutorial.

The data used to construct each NavigationButton is extracted from the appropriate item in the newStories array.  Notice that we again use a numerical index as the id of the NavigationButton controls and use the title property of our JSON story object as the text on the face of each button. What is interesting is that instead of passing the hardcoded “icon.png” as the image for each button, we use the thumbnail property. This works because behind the scenes the text passed as the third parameter to the NavigationButton constructor becomes the src attribute of an HTML <img> element.

All that’s left to do now is handle the case where there are no stories available. We’ve already created a new Label control and stored a reference to the control in a variable called noStoriesLabel. So we can quite simply deal with this case by adding our noStoriesLabel control to the main view, in lieu of more interesting content:

What to do if there's no content

Updating the detail view

We now need to complete part 3 of our tutorial by updating the code that populates the detail view with content. In part 2 we used the text from the NavigationButton in the main view that corresponded to the story we wanted to read as the title of the story in the detail view. The other data in the detail view was completely hardcoded.

Now we can do a little better by using some of the data we’ve got stored in our story array.

Here’s the new implementation of populateDetailView():

Replacing hardcoded data with dynamic data

The parameter passed to populateDetailView() is still the object which fired the ActionPerformed event, as it was in part 2 of the tutorial. This allows us to get the id of the control which fired the event, which corresponds to the index in our storyArray of the relevant story object.

Given this, we can now populate the three labels in the detail view with relevant content received from Digg.

Additional Notes

You might be wondering why we requested a XML response from Digg when we could have asked for a JSON request, particularly as we then used JSON to coalesce the parts of the XML we were interested in to a single object.

Again I suggest that by using & processing XML to obtain data from Digg and then using a very small part of JSON’s capabilities to simplify the creation of data objects, we’ve been able to cover more in a single tutorial.

We could have formed our request URL to Digg differently and implemented a function to handle a JSON response. Or, sticking with the XML response, we could have created another JavaScript object, say something like DiggStory which might have simply consisted of some data properties. We could then created these new DiggStory objects, populating them with data received from Digg, before adding them to our stories array.

I encourage you to use the code of this tutorial as a basis for your own development and experimentation. Please feel free to re-implement DiggWeb to receive JSON requests or whatever you wish to try!

Coming next…

This concludes the third part of our tutorial on creating a Digg client with Nokia WRT & Aptana Studio. We now have a functional widget which uses HTTP requests to retrieve content from Digg and present it to the user.

Except, there are a few problems:

  • You don’t know whether your request has completed or not, until the UI refreshes with new content. But if there were no stories returned twice in a row, you get no visual indication at all because the UI doesn’t change and keeps saying there are no stories available!
  • The detail view only shows a short description of the story, there’s no way to access the full story!
  • And what’s with the “Hello” icon? Can’t we have something better?

In the next part of this tutorial we will tidy up some of the rough edges in our widget, introduce usage of CSS in WRT widget development and maybe I’ll even get my digital crayons out and create a different icon for our widget!

Part 4>

Web Runtime Widget Tutorial – Part 2: Structuring the Digg Client UI

Grab the code!

In this part of the tutorial we will start to turn our Hello World widget into a Digg Client widget. In a real widget project you would have sat down and considered the use cases that your widget was intended to address and hopefully taken care to design a UI that delivered a good experience to users.

In the case of our Digg Client widget, I’ve designed a UI that takes the essence of Scott Guthrie’s Silverlight Digg Client UI and transposes it to its closest WRTKit equivalent. The result is a UI that some might argue is more complex than it needs to be, but I’d argue that it allows us to examine more possibilities in this tutorial than a minimalist functional UI might do.

Let’s start by looking at the target UI. I’ve designed a widget consisting of three views.

Main View

The first view the user will see is the main view which will allow them to enter a topic on which they would like to retrieve stories Digg. It looks like this:

Main view

The view consists of a ListView, a TextField, a FormButton and a set of NavigationButtons representing the stories received from Digg.

The content of the NavigationButtons – the icon & text – are temporary, as is the number of buttons included in the view. Later in the tutorial real data returned from Digg will be used to dynamically populate the list of stories. I could have omitted the NavigationButtons and simply used a text label saying there were no results available, but by creating temporary results we’re able to write and test the code that glues the views together and create a functional UI prototype of our widget.

About View

The about view is basically identical to the equivalent view in our Hello World widget. A small update to the text shown by the label is all that has changed.

About view

Detail View

The detail view is new in this part of the tutorial. Here we can provide more information about a story selected by the user from the list of stories displayed in the main view.

Detail view

This view is quite simple and consists of just three Label controls. Each Label control is populated with a different piece of text – the title of the story, the number of “Diggs” this story has had and last but not least, the text of the story itself.

Three times the UI… three times the code?

Thankfully not! We’ve got more views and more controls to think about, so there are quite a few more UI objects to construct and set up. We also need some more logic to handle navigation between the three views, but it’s all quite straightforward.

All of the work we need to do is confined to the diggclient.js file. Every other file in the project remains as it was in part 1 of the tutorial.

More objects, more variables

Let’s start with all these new UI objects and the variables we’ll use to represent them:

Global variables

As in part 1 of the tutorial, we declare a variable for our WRTKit uiManager and then one variable for each of our three views – mainView, detailView & aboutView.

Next there are three sets of variable declarations, each set declaring the variables needed to represent the UI objects specific to a given view.

For the main view we need a TextField and a FormButton, so we declare two variables to represent them. Notice that there are no variables declared to represent the stories.

For the detail view, we need three Label controls, so we declare three variables to represent them.

As in part 1 of the tutorial, the about view only requires a single variable to represent a Label control.

The next variable declaration – viewFunc – helps to support the logic needed to navigate between the three views of our widget. It  is used to reference one of the functions that we call to show a specific view.

In part 1 of the tutorial we only had two views – the main view & the about view - and we always returned to the main view when we dismissed the about view. However this approach will not work now that we have three views. This time, prior to showing the about view, we will set viewFunc to refer to the appropriate showXXX() function to ensure the correct view is displayed when the user closes the about view.

Finally, as before, we declare MENU_ITEM_ABOUT, which defines the position of the “About” option in the widget’s option menu.

Initialisation

Because every other file in the project except diggclient.js remains the same between parts 1 & 2 of this tutorial, you know from part 1 that the JavaScript method called when our widget starts up is init().

The first block of code in init() should look familiar:

Initialisation

If you can’t remember what this code does, refer back to the explanation given in part 1 of this tutorial.

The next block of code creates the WRTKit UIManager object and the three ListView objects we need:

Initialisation - core UI variables

Again, this code is almost identical to the code in part 1 of the tutorial. The only difference is that we’re creating three views this time instead of two.

Now it’s time to add come controls to the three views. This code is a mixture of old and new:

Initialisation - main view controls

First we create the controls needed for the main view. If you refer back to the UI screenshots earlier in this part of the tutorial, you can see we need a TextField, a FormButton and a set of NavigationButtons that will represent a list of stories.

The code to create the TextField and FormButton controls will again look familiar to you from part 1 of the tutorial. The TextField’s prompt and the FormButton’s text have changed to suit the needs of our UI, and the function that will be called when the FormButton is clicked has been given a new name, to keep it consistent with the name of the object who’s event it is handling.

Next we have some new code. What we need to help demonstrate that our UI works as designed is something to represent some stories. Then we’ll need some code to let us read the stories and go back and choose another story to read. I’m using a for loop to create three objects that will represent stories in our main view.

Initialisation - temporary content

The for loop creates three NavigationButton controls and adds each one to the main view. A NavigationButton is another WRTKit control which is intended to be used to allow users to navigate between views in a widget. The icon & text on the face of the NavigationButton should make it clear to the user which view they will be taken to if they were to click the button. In our case we don’t have any real data yet so we’ll have to cheat!

We create each NavigationButton by passing three parameters to the NavigationButton constructor. First is the familiar object id. Previously we’ve used null for all our object id’s because we haven’t yet needed to refer to them other than through the variable to which the objects are assigned. Now however we’re going to need to know which story the user wants to read, so we pass the integer i as the id of each object; obviously i has a different value each time round the for loop, so each NavigationButton object gets a unique id. Notice that the constructor actually requires a string for the object id; we’re relying on JavaScript converting i from an integer to a string for us, which it does.

The second parameter passed to NavigationButton’s constructor should be an image to be displayed on the face of the button. For the time being we’ll use the widget’s icon as the image for each button. The image on each button will eventually be retrieved via a URL contained within the story data we receive from Digg.

Lastly the constructor needs some text to display on the face of the button. Here we construct a string, again using the integer i to give each button a different string. This string will be the title of a story in our finished widget.

NavigationButtons and FormButtons both derive from the abstract base class ActionControl, which fires the ActionPerformed event whenever the user clicks a button derived from ActionControl. So just as we did with the FormButton control on the main view, we add an event listener to each NavigationButton we create. The same function, storyClicked(), is passed as the event listener for each button because we want the same work to be performed regardless of the story the user wants to read, all that changes is the data that makes up the story.

Moving on to our new detail view, we need to create three Label controls to represent the title of a story, an indication of the number of “Diggs” the story has and finally, the body of the story itself.

Initialisation - detail view controls

The code above shows that we simply create three Label controls, giving each one a self-explanatory caption, and then add the three Label’s to our new detail view.

The code to create the Label control for the about view is once again the same as we used in part 1 of the tutorial:

Initialisation - about view control

We close the init() function by telling the WRTKit UIManager object which view to use initially:

Initialisation complete

Button Event Handlers

At this point we’ve completed all the preparation needed. We have three views, each of which is populated with some controls to allow the user to interact with the widget and allow the widget to present information to the user. Now we need to write some code to handle the various events, such as the user clicking on the “Digg it” button or on any of the NavigationButtons that represent stories returned from Digg.com.

Let’s start with some more familiar code – diggButtonClicked() – which is called, not surprisingly, when the user clicks on the “Digg it” button:

Digg button event handler

Although the variable names are different, you should be able to spot the same pattern of code here as we used to handle the click on the “Say Hello!” button in part 1 of this tutorial.

We get the topic the user would like to search Digg.com for by retrieving the text held in the topicField. If the topic to be searched for is empty, we pop up a notification suggesting the user enters a topic.

If there is text in the topic field, we also pop up a notification, however this is temporary code. Eventually we will send a request to Digg.com for a list of stories about the topic the user entered. For now we just let the user know that we are aware of the topic they would like stories about.

Now let’s look at how we deal with a click on any one of the NavigationButtons that represent stories:

Story button event handler

Here we call a function that sounds like it might be adding content to the detail view controls after which we call another function which looks like it will change the view to show the new detail view. Indeed, that’s exactly what this code does. But why have we done this when we could have just added the relevant text to the Label controls in showDetailView()?

We can’t wait until we’re inside showDetailView() to add the relevant content to the view’s Label controls because showDetailView() can be called from two places:

  1. as a result of clicking on a story from the main view.
  2. on return from the about view, if the about view was called from the detail view.

We don’t really want the different views to understand much about what each others purpose is. It is better that we separate the code that puts the correct content into the detail view’s controls from the code that handles setting up the softkeys and activating the view. This is why we have two functions where previously we might just have used one function.

What about the parameter we pass to populateDetailView()?

Event Message

The parameter passed to event handlers is a JavaScript object which contains three properties you can access in your event handler code:

  • type – this is a string that tells you the type of the event your code has been called to handle, for example, ActionPerformed.
  • source – this is a reference to the object that fired the event, typically a view or a control. In our event handlers, the source will either be our FormButton object, or one of our NavigationButton objects.
  • value – this contains additional data specific to the type of event. We don’t currently use this in our code.

So, when populateDetailView() is called from storyClicked() with a parameter of event.source, we’re calling populateDetailView() with the object that fired the event – the NavigationButton representing the story the user now wants to read.

Populating the Detail view

Here’s the code of populateDetailView():

Populating the detail view

We now know that the story parameter passed to populateDetailView() is the source property of the event message that was passed to storyClicked(). We also now know that this means populateDetailView() is being passed a reference to the NavigationButton that fired the event which resulted in storyClicked() being called.

When we created the controls for the main view, we said that the caption of each NavigationButton would hold the title of a story in our completed widget. We can get hold of the title of the story the user wants to read by calling story.getText() and use that text as the content of detail view’s titleLabel.

The other Label controls are assigned hardcoded text which we will dynamically populate in the next part of this tutorial.

Look at the views!

Let’s start our look at the code used to display each view by looking at what we need to do to present the details of a story:

Showing the detail view

Having implemented the function populateDetailView() to prepare the content of the detail view and ensured that the storyClicked() event handler calls populateDetailView() before calling showDetailView(), it should be no surprise to see that showDetailView() is very simple.

Both the detail and about views need the same softkeys – Options & Back – so it would be good to use the same function to prepare the softkeys for both views. We achieve this through the use of a new function,  setSubViewSoftkeys().

What differs between the needs of the detail and about views is what function they should call to return to the previous view. We handle this by passing setSubViewSoftkeys() the function which should be called when the “Back” softkey is pressed.

Having set the softkeys, we ask the UIManager to show the detail view.

Setting common softkeys & remembering where we were

Before going on to look at the methods used to show the main and about views, let’s take a closer look at setSubViewSoftkeys():

Setting softkeys for detail & about views

As you can see, the right softkey is always set to “Back” by this function. However, depending on the value of the parameter, func, the function that will be called when the user selects the “Back” softkey is different.

The parameter func is assumed to be a reference to a function, rather than a reference to a control or view or any other object.

If func contains a value (func is not null), func is used as the second parameter to menu.setRightSoftkeyLabel(), meaning that when the “Back” softkey is selected by the user, the function referred to by func will be called.

If func is null we pass another the variable viewFunc to menu.setRightSoftkeyLabel(). So in this case when the “Back” softkey is selected by the user, the function referred to by viewFunc will be called.

Showing the About view

So what is viewFunc? To answer that, we need to look at how we display the about view, which we do with this code:

Showing the about view

Earlier in this part of the tutorial while discussing the variables we said  that prior to showing the about view, we will set viewFunc to refer to the appropriate function to ensure the correct view is displayed when the user closes the about view. That’s exactly what the first part of this function is doing.

First we get a reference to the current view from the UIManager object. We then compare that reference to our view variables to determine which view is currently being displayed.

If the current view is either the main view or the detail view, we set viewFunc to refer to the function used to show that view. However, if the current view is actually the about view, we don’t set viewFunc, or, more accurately, we don’t change the value of viewFunc.

In this way we ensure that viewFunc always refers to the function needed to display the view the user was in prior to displaying the about view, even if they try to trick us by selecting Options –> About while already in the about view.

Once viewFunc is correctly set, it’s a simple matter of putting the appropriate text in the aboutLabel control, calling setSubViewSoftkeys() to ensure we get “Back” as our right softkey and then asking the UIManager object to show the about view. Notice that we don’t pass any parameter to setSubViewSoftkeys(). This means that the value of the func parameter that setSubViewSoftkeys() expects will be null, and the value of viewFunc will be used as the function to be called when the right softkey is selected by the user.

Showing the Main view

The function, showMainView(), should be familiar to you as it is exactly as it was in part 1 of the tutorial:

Showing the main view

Menu Event Handling

The code used to handle selections from the options menu is also the same as we used in part 1 of the tutorial. No changes were necessary here because we didn’t introduce any new options.

Menu event handler

Additional Notes

WRTKit offers an alternative control that could have removed the need for the new detail view. We could have used a ContentPanel object to represent each story. The ContentPanel is an expandable UI element that supports a caption that could represent the title of a story, and additional content that could represent the text of a story. The user can expand and collapse each panel to read whichever story they wish. If we used ContentPanel controls instead of NavigationButton controls we could remove the detail view.

I chose to use NavigationButtons to illustrate the use of another view and the work needed to navigate between them. You can of course use the tutorial code as the basis for your own work. Feel free to re-write the widget to use ContentPanel controls rather than NavigationButton controls & remove the detail view.

It is also worth noting that we could have simplified some of the view switching logic if we had ensured that the user could not select Options –> About while they were already in the about view. If you want to try rewriting the code to achieve this, think about use of the menu object’s remove() function to help you.

Coming next…

This concludes the second part of our tutorial on creating a Digg client with Nokia WRT & Aptana Studio. Now we have a functional UI, involving three views and all the logic needed to navigate between them. We have used a mixture of temporary code and hardcoded data to simulate some stories.

In the next part of this tutorial we will get real data into our widget from the internet.

Part 3>