<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7181454077103467897</id><updated>2011-11-27T23:29:39.158Z</updated><category term='Aptana'/><category term='Acer'/><category term='WRTKit'/><category term='Tutorial'/><category term='open source'/><category term='WRT'/><category term='Digg'/><category term='foundation'/><category term='symbian'/><category term='XP mode'/><category term='Windows 7'/><title type='text'>Refactored Thoughts</title><subtitle type='html'>Occasional thoughts and comments on software development and architecture &amp;amp; other topics.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-4716087133075875810</id><published>2009-12-18T17:49:00.002Z</published><updated>2009-12-18T18:14:06.946Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WRTKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WRT'/><category scheme='http://www.blogger.com/atom/ns#' term='Aptana'/><category scheme='http://www.blogger.com/atom/ns#' term='Digg'/><title type='text'>Web Runtime Widget Tutorial – Part 5: Installing the widget on your Phone</title><content type='html'>&lt;h2&gt;&lt;font color="#800080"&gt;&lt;a href="http://cid-41c47f6e8baac5b4.skydrive.live.com/self.aspx/.Public/DiggClient%20-%20Part%205.zip" target="_blank"&gt;Grab the code!&lt;/a&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;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 &lt;a href="http://www.forum.nokia.com/devices/matrix_webruntime_1.html" target="_blank"&gt;WRT enabled devices&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;&lt;em&gt;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.&lt;/em&gt;&lt;/p&gt;&lt;h5&gt;Packaging the widget up for its journey to your phone&lt;/h5&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;All of the constituent files of your WRT widget need to be zipped up into a single file, with the extension .wgz.&lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;Right click on your project in Aptana, bringing up the context menu shown below:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvAiHkt3pI/AAAAAAAAAOQ/elO2ZHgYUqY/s1600-h/Click12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Project context menu" border="0" alt="Project context menu" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAikTdqAI/AAAAAAAAAOU/HlfE7tVvnIA/Click1_thumb.png?imgmax=800" width="340" height="824" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Now click on the “Package Widget” option in the context menu: &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAi393WUI/AAAAAAAAAOY/pfuexpmpyHY/s1600-h/Click22.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Package your widget" border="0" alt="Package your widget" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAjFEA9jI/AAAAAAAAAOc/iACMbYTHlEc/Click2_thumb.png?imgmax=800" width="290" height="117" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAjiKcyrI/AAAAAAAAAOg/3quh-gcVHMg/s1600-h/FileList2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="File list showing packaged widget" border="0" alt="File list showing packaged widget" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAjwGw3mI/AAAAAAAAAOk/lKP9MBBbXOM/FileList_thumb.png?imgmax=800" width="342" height="384" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Notice that your packaged widget file, DiggClient.wgz, is now shown in the list of files that make up your project.&lt;/p&gt;&lt;h5&gt;Copying the widget to your phone&lt;/h5&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvAknrv5zI/AAAAAAAAAOo/kx4ppjD4blc/s1600-h/Copy_12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Explorer window showing phone contents" border="0" alt="Explorer window showing phone contents" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAlPvjmVI/AAAAAAAAAOs/PJ9o9hdmzRE/Copy_1_thumb.png?imgmax=800" width="647" height="370" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Right click on the DiggClient.wgz file in your project’s list of files in Aptana to bring up the following context menu:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAlmgtAmI/AAAAAAAAAO0/O_Xw7pouUBU/s1600-h/Copy_22.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="File context menu" border="0" alt="File context menu" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAl3cv3xI/AAAAAAAAAO4/3GlfRrDM6Tw/Copy_2_thumb.png?imgmax=800" width="320" height="674" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAmkXKCdI/AAAAAAAAAO8/s8DRzLGw4s4/s1600-h/Copy_32.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Explorer window showing project files" border="0" alt="Explorer window showing project files" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAnV4vwJI/AAAAAAAAAPA/hHumYP9kTtg/Copy_3_thumb.png?imgmax=800" width="907" height="391" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;Once you’ve copied the file, be sure to disconnect your phone from your PC before trying to install the widget.&lt;/p&gt;&lt;h5&gt;Installing the widget on your phone&lt;/h5&gt;&lt;p&gt;Installation is a simple process, although the exact mechanism will vary slightly depending on your phone model.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;h5&gt;Running your widget on your phone&lt;/h5&gt;&lt;p&gt;In order to run your widget, you just navigate to it and launch it as you would launch any other application. &lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;h3&gt;And finally…&lt;/h3&gt;&lt;p&gt;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 &lt;a href="https://store.ovi.com/" target="_blank"&gt;Ovi Store&lt;/a&gt; so others can use them too!&lt;/p&gt;&lt;p&gt;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&amp;#160; involve “focus”. Over to you! &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Lastly, please make use of the &lt;a href="http://www.forum.nokia.com/Tools_Docs_and_Code/Documentation/Web_Technologies/Web_Runtime.xhtml" target="_blank"&gt;WRT resources&lt;/a&gt; available at &lt;a href="http://www.forum.nokia.com/" target="_blank"&gt;Forum Nokia&lt;/a&gt;. For example, there is a collection of &lt;a href="http://wiki.forum.nokia.com/index.php/Category:Web_Runtime_(WRT)" target="_blank"&gt;community provided articles &amp;amp; samples&lt;/a&gt; that show how to achieve a large number of tasks using WRT.&lt;/p&gt;&lt;p&gt;Have fun working on your own widgets! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-4716087133075875810?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/4716087133075875810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-5.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/4716087133075875810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/4716087133075875810'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-5.html' title='Web Runtime Widget Tutorial – Part 5: Installing the widget on your Phone'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAikTdqAI/AAAAAAAAAOU/HlfE7tVvnIA/s72-c/Click1_thumb.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-1294884786913368241</id><published>2009-12-18T17:48:00.002Z</published><updated>2009-12-18T18:13:11.238Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WRTKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WRT'/><category scheme='http://www.blogger.com/atom/ns#' term='Aptana'/><category scheme='http://www.blogger.com/atom/ns#' term='Digg'/><title type='text'>Web Runtime Widget Tutorial – Part 4: Refining the UI</title><content type='html'>&lt;h2&gt;&lt;font color="#800080"&gt;&lt;a href="http://cid-41c47f6e8baac5b4.skydrive.live.com/self.aspx/.Public/DiggClient%20-%20Part%204.zip" target="_blank"&gt;Grab the code!&lt;/a&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p&gt;In this fourth part of the tutorial we smooth off some of the rougher edges in our Widget’s UI.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;h4&gt;Showing Progress&lt;/h4&gt;&lt;p&gt;We’ve been using the &lt;font face="Courier New"&gt;UIManager&lt;/font&gt; object’s &lt;font face="Courier New"&gt;showNotification()&lt;/font&gt; function since the beginning of this tutorial. Back in part 1 of the tutorial we noted that &lt;font face="Courier New"&gt;showNotification()&lt;/font&gt; took three parameters:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;duration (in milliseconds) to show the note      &lt;ul&gt;&lt;li&gt;If the duration is negative, the note will remain visible until such time as your code explicitly hides the notification &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;type of note (which influences the icon shown in the note dialog)      &lt;ul&gt;&lt;li&gt;“info” – the type we’ve used up till now, intended for showing general information to the user &lt;/li&gt;
&lt;li&gt;“warning” – intended for use with errors or similar situations &lt;/li&gt;
&lt;li&gt;“wait” – this is the type we’ll look at using now because it is intended for use with progress notifications &lt;/li&gt;
&lt;li&gt;If you pass null as the note type, no icon will be displayed in the notification. &lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;message to be shown to the user &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Using a “wait” notification is particularly easy if the actual progress over time is not known. You simply need to call &lt;font face="Courier New"&gt;UIManager&lt;/font&gt;’s &lt;font face="Courier New"&gt;showNotification()&lt;/font&gt; function as your operation begins and then call the function &lt;font face="Courier New"&gt;hideNotification()&lt;/font&gt; on your &lt;font face="Courier New"&gt;UIManager&lt;/font&gt; object when the operation completes. &lt;/p&gt;&lt;h5&gt;Displaying the progress notification&lt;/h5&gt;&lt;p&gt;From part 3 of the tutorial, we know that our event handler &lt;font face="Courier New"&gt;diggButtonClicked()&lt;/font&gt; 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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAQwtfyeI/AAAAAAAAAMo/YuVn7LkgvNM/s1600-h/Code_15.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Show wait notification" border="0" alt="Show wait notification" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvARNlZ_KI/AAAAAAAAAMs/BJo7d19nk8I/Code_1_thumb1.png?imgmax=800" width="665" height="255" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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 &lt;font face="Courier New"&gt;showNotification()&lt;/font&gt; on our &lt;font face="Courier New"&gt;UIManager&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvARup4C_I/AAAAAAAAAMw/Vt0K2Gz5M4I/s1600-h/WaitNote2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Screenshot showing wait note" border="0" alt="Screenshot showing wait note" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvASLgbtnI/AAAAAAAAAM0/ttsHHYIoF-c/WaitNote_thumb.png?imgmax=800" width="402" height="536" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h5&gt;Hiding the progress notification&lt;/h5&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvASvjBayI/AAAAAAAAAM4/3CWdpEGJ86s/s1600-h/Code_25.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Hiding the wait notification" border="0" alt="Hiding the wait notification" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAS3lISPI/AAAAAAAAAM8/JpEr-fWxQ9Q/Code_2_thumb1.png?imgmax=800" width="651" height="368" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The code above is an abridged version of &lt;font face="Courier New"&gt;handleDiggResponse()&lt;/font&gt; 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 &lt;font face="Courier New"&gt;UIManager&lt;/font&gt;’s &lt;font face="Courier New"&gt;hideNotification()&lt;/font&gt; function. We call &lt;font face="Courier New"&gt;hideNotification()&lt;/font&gt; here&amp;#160; as our last action in &lt;font face="Courier New"&gt;handleDiggResponse()&lt;/font&gt; because we can be sure that everything has been processed and the UI has been updated as appropriate.&lt;/p&gt;&lt;h4&gt;Detail View 2.0&lt;/h4&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Something like this maybe?&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvATn2eAYI/AAAAAAAAANA/VzEvILgG-4Q/s1600-h/DetailView2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="New Detail View" border="0" alt="New Detail View" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAUFFDnxI/AAAAAAAAANE/w6r3xyGssVE/DetailView_thumb.png?imgmax=800" width="413" height="540" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;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.&amp;#160; &lt;/p&gt;&lt;h5&gt;Detail View 2.0: Code changes&lt;/h5&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAUYERZEI/AAAAAAAAANI/9m7e-mlAdww/s1600-h/Code_32.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Link label variable" border="0" alt="Link label variable" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAUrOgD4I/AAAAAAAAANM/PozgD0-qCSo/Code_3_thumb.png?imgmax=800" width="410" height="120" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We’ve added the variable &lt;font face="Courier New"&gt;linkLabel&lt;/font&gt; to represent the link to the full story.&lt;/p&gt;&lt;p&gt;Next we modify the &lt;font face="Courier New"&gt;init()&lt;/font&gt; function to create a new &lt;font face="Courier New"&gt;Label&lt;/font&gt; control and assign the reference to the new control to the &lt;font face="Courier New"&gt;linkLabel&lt;/font&gt; variable. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvAUwwqS9I/AAAAAAAAANQ/QyWhPhVJLDE/s1600-h/Code_45.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Label initialisation without captions" border="0" alt="Label initialisation without captions" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAVa1v_sI/AAAAAAAAANU/z5yOWoQcgps/Code_4_thumb1.png?imgmax=800" width="426" height="187" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We’ve also removed the captions from each of the four labels that will now make up the detail view by passing &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt; as the first parameter to the &lt;font face="Courier New"&gt;Label&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;We can set the text of any WRTKit &lt;font face="Courier New"&gt;Label&lt;/font&gt; control to any arbitrary HTML we like. WRT will render the HTML when it renders the &lt;font face="Courier New"&gt;Label&lt;/font&gt; control, so provided the HTML is valid, the user should only see the text you intended them to see.&lt;/p&gt;&lt;p&gt;This technique allows us to easily wrap a piece of text intended to be shown to the user in a &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;div&lt;/font&gt;&amp;gt;&lt;/font&gt; tag and within the &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;div&lt;/font&gt;&amp;gt;&lt;/font&gt; tag we can specify a &lt;font color="#ff0000" face="Courier New"&gt;class&lt;/font&gt; attribute. The value of the &lt;font color="#ff0000" face="Courier New"&gt;class&lt;/font&gt; attribute can then be used in our CSS to selectively style particular elements in our UI.&lt;/p&gt;&lt;p&gt;Let’s update the implementation of our &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; function to add class names to our &lt;font face="Courier New"&gt;Label&lt;/font&gt; controls as appropriate:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAVvDh9QI/AAAAAAAAANY/a5pxd3EhVQM/s1600-h/Code_52.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Injecting CSS class names to labels" border="0" alt="Injecting CSS class names to labels" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAWCKyBNI/AAAAAAAAANc/6hPQ3e26agE/Code_5_thumb.png?imgmax=800" width="1027" height="153" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The &lt;font face="Courier New"&gt;titleLabel&lt;/font&gt; is simply wrapped in a &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;div&lt;/font&gt;&amp;gt;&lt;/font&gt; element which defines a &lt;font color="#ff0000" face="Courier New"&gt;class&lt;/font&gt; attribute with the value “DiggTitle”.&lt;/p&gt;&lt;p&gt;Similarly, the &lt;font face="Courier New"&gt;diggsLabel&lt;/font&gt; is wrapped in a &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;div&lt;/font&gt;&amp;gt;&lt;/font&gt; element which defines a &lt;font color="#ff0000" face="Courier New"&gt;class&lt;/font&gt; attribute with the value “Diggs”. In addition, we also insert a &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;br&lt;/font&gt;/&amp;gt;&lt;/font&gt; 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”.&lt;/p&gt;&lt;p&gt;We’ve not changed the storyLabel because the default text styling is fine for the main text of the view.&lt;/p&gt;&lt;p&gt;Our new &lt;font face="Courier New"&gt;linkLabel&lt;/font&gt; 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 &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;div&lt;/font&gt;&amp;gt;&lt;/font&gt; element with a &lt;font color="#ff0000" face="Courier New"&gt;class&lt;/font&gt; attribute which has the value “DiggLink”. &lt;/p&gt;&lt;p&gt;However, we need a little more substance as well as a bit of style in the case of the &lt;font face="Courier New"&gt;linkLabel&lt;/font&gt;. We need to do something useful when the user clicks the link. &lt;/p&gt;&lt;p&gt;We achieve this by adding a HTML &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;a&lt;/font&gt;&amp;gt;&lt;/font&gt; tag to our &lt;font face="Courier New"&gt;linkLabel&lt;/font&gt;’s text and specifing an &lt;font color="#ff0000" face="Courier New"&gt;href&lt;/font&gt; attribute with the value “JavaScript:openStoryLink(…)”.&amp;#160; 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 &lt;font color="#ff0000" face="Courier New"&gt;href&lt;/font&gt; with the value “JavaScript:openStoryLink(…), WRT will try to invoke a function called &lt;font face="Courier New"&gt;openStoryLink()&lt;/font&gt; in our JavaScript code. The final thing to notice about the way we define the text of the &lt;font face="Courier New"&gt;linkLabel&lt;/font&gt; is that we construct the &lt;font color="#ff0000" face="Courier New"&gt;href&lt;/font&gt; 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 &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;a&lt;/font&gt;&amp;gt;&lt;/font&gt; tag would look something like this in the HTML of the page:&lt;/p&gt;&lt;p&gt;&lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;a &lt;font color="#800000"&gt;href&lt;/font&gt;&lt;font color="#000000"&gt;=”&lt;/font&gt;JavaScript:openStoryLink(3)&lt;font color="#000000"&gt;”&lt;/font&gt;&amp;gt;&lt;/font&gt;Read more&lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;/&lt;font color="#800000"&gt;a&lt;/font&gt;&amp;gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;The final code change we need to make is to provide an implementation of the function &lt;font face="Courier New"&gt;openStoryLink()&lt;/font&gt;, otherwise nothing much will happen if the user clicks on the story link in our improved detail view.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAWW6-BLI/AAAAAAAAANg/wt6hRwKCiVo/s1600-h/Code_62.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Function to open a URL" border="0" alt="Function to open a URL" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAWhOaeNI/AAAAAAAAANk/7fY_Beoeu4U/Code_6_thumb.png?imgmax=800" width="471" height="169" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;If our widget is running in a WRT environment, we call &lt;font face="Courier New"&gt;openURL()&lt;/font&gt; on our inbuilt &lt;font face="Courier New"&gt;widget&lt;/font&gt; object, passing it the URL of the story with the id passed as the parameter to our function. &lt;font face="Courier New"&gt;openURL()&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;If our widget is running in another environment, for example, in a browser environment on your PC, we use JavaScript’s &lt;font face="Courier New"&gt;window&lt;/font&gt; object, which represents your browser’s window, to open a new window to display the link associated with the story.&lt;/p&gt;&lt;p&gt;That’s all the code changes we require. Now we can turn our attention to our as yet empty CSS file.&lt;/p&gt;&lt;h5&gt;Detail View 2.0: Cascading Style Sheet&lt;/h5&gt;&lt;p&gt;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:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;font face="Courier New"&gt;DiggTitle&lt;/font&gt; which refers to the title of a story &lt;/li&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;Diggs&lt;/font&gt; which refers to the number of Diggs a story has had &lt;/li&gt;
&lt;li&gt;and &lt;font face="Courier New"&gt;DiggLink&lt;/font&gt; which refers to the hyperlink to the full story &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAXJWsPtI/AAAAAAAAANo/SQG_G_L8jpY/s1600-h/CSS_12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CSS style for story title" border="0" alt="CSS style for story title" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAXdQHYkI/AAAAAAAAANs/q_iuFDVjcDo/CSS_1_thumb.png?imgmax=800" width="472" height="191" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;This block of CSS starts with the class name to which it applies, preceded by a period. Within the block we specify that the &lt;font color="#800000" face="Courier New"&gt;font-weight&lt;/font&gt; should be bold, the text should be centred and that the &lt;font color="#800000" face="Courier New"&gt;font-size&lt;/font&gt; should be &lt;font color="#0000ff" face="Courier New"&gt;1.25em&lt;/font&gt;. 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.&lt;/p&gt;&lt;p&gt;Next, we style the number of diggs the current story has had, using the following CSS:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAXoTuRaI/AAAAAAAAANw/5G1qSo8B1Rg/s1600-h/CSS_22.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CSS style for number of diggs" border="0" alt="CSS style for number of diggs" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAX4bRHyI/AAAAAAAAAN0/tV4qv00LtVc/CSS_2_thumb.png?imgmax=800" width="311" height="184" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Here’s the CSS for the unselected state:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAYLLI_VI/AAAAAAAAAN4/Co9tJ_p7wL0/s1600-h/CSS_32.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CSS style for unselected link" border="0" alt="CSS style for unselected link" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAYjmejKI/AAAAAAAAAN8/VOkAzV-Zc-8/CSS_3_thumb.png?imgmax=800" width="465" height="135" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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 &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;a&lt;/font&gt;&amp;gt;&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;We apply a typical style for hyperlinks, underlining the link, using blue text and rendering it in bold font to make it stand out.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAY2fQieI/AAAAAAAAAOA/pMjTAj8PLFU/s1600-h/CSS_42.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CSS style for selected link" border="0" alt="CSS style for selected link" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAZN77hgI/AAAAAAAAAOE/DFqD1S4rijA/CSS_4_thumb.png?imgmax=800" width="273" height="116" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;As with the CSS for the unselected state, the CSS above defines a style that is applied to &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;a&lt;/font&gt;&amp;gt;&lt;/font&gt; tags within elements identified by the class “DiggLink”. However, we only want this style to be applied if the &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;a&lt;/font&gt;&amp;gt;&lt;/font&gt; element has focus. The CSS pseudo-class “:focus” is used to specify this constraint on the application of the above style.&lt;/p&gt;&lt;p&gt;The style itself simply inverts the text of the link, using white text on a blue background. &lt;/p&gt;&lt;h5&gt;Goodbye “Hello”&lt;/h5&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAZWxC-KI/AAAAAAAAAOI/2U6CjzZudpQ/s1600-h/NewIcon2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="New improved icon" border="0" alt="New improved icon" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAZjAo1qI/AAAAAAAAAOM/fWqJI1MOq9U/NewIcon_thumb.png?imgmax=800" width="91" height="90" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;h3&gt;Coming next…&lt;/h3&gt;&lt;p&gt;This concludes the fourth part of our tutorial on creating a Digg client with Nokia WRT &amp;amp; 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.&lt;/p&gt;&lt;h2 align="right"&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-5.html"&gt;Part 5&amp;gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-1294884786913368241?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/1294884786913368241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-4.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1294884786913368241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1294884786913368241'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-4.html' title='Web Runtime Widget Tutorial – Part 4: Refining the UI'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvARNlZ_KI/AAAAAAAAAMs/BJo7d19nk8I/s72-c/Code_1_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-7441573872038173422</id><published>2009-12-18T17:47:00.002Z</published><updated>2009-12-18T18:11:42.369Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WRTKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WRT'/><category scheme='http://www.blogger.com/atom/ns#' term='Aptana'/><category scheme='http://www.blogger.com/atom/ns#' term='Digg'/><title type='text'>Web Runtime Widget Tutorial – Part 3: Requesting data from Digg and displaying the results</title><content type='html'>&lt;h2&gt;&lt;font color="#800080"&gt;&lt;a href="http://cid-41c47f6e8baac5b4.skydrive.live.com/self.aspx/.Public/DiggClient%20-%20Part%203.zip" target="_blank"&gt;Grab the code!&lt;/a&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_vf9nBbI/AAAAAAAAAJI/d8FL9y_GZhU/s1600-h/Before2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Before" border="0" alt="Before" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_w8mXa9I/AAAAAAAAAJM/HM_0xw-_IK8/Before_thumb.png?imgmax=800" width="385" height="536" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We had a &lt;font face="Courier New"&gt;TextField&lt;/font&gt; and a &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; that didn’t really do anything useful, plus three hardcoded &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s masquerading as content.&lt;/p&gt;&lt;p&gt;Well, with a bit more code, we end up with this:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_xVM2psI/AAAAAAAAAJQ/igIgn4Cp-UE/s1600-h/After2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="After" border="0" alt="After" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_yAHxsGI/AAAAAAAAAJU/KAJNgZga_Ts/After_thumb.png?imgmax=800" width="343" height="530" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;There’s no hardcoded trickery going on in the screenshot above. That’s genuine content retrieved from Digg.&lt;/p&gt;&lt;h4&gt;Digg List Stories API&lt;/h4&gt;&lt;p&gt;Digg publish a number of APIs that allow users &amp;amp; partners to interact programmatically with Digg services. I encourage you to read more about the &lt;a href="http://apidoc.digg.com/" target="_blank"&gt;APIs&lt;/a&gt; on offer and in particular I’d like to draw your attention to the &lt;a href="http://apidoc.digg.com/LicenseAgreement" target="_blank"&gt;API License Agreement&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;We will be making use of just one of Digg’s APIs, the &lt;a href="http://apidoc.digg.com/ListStories" target="_blank"&gt;List Stories API&lt;/a&gt;. 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. &lt;/p&gt;&lt;p&gt;The&amp;#160; request we will send to Digg will be a variant of this form:&lt;/p&gt;&lt;p&gt;&lt;a href="http://services.digg.com/stories/topic/sometopic?count=20&amp;amp;appkey=http%3A%2F%2Fgavinmeiklejohn.com&amp;amp;type=xml"&gt;http://services.digg.com/stories/topic/&lt;em&gt;sometopic&lt;/em&gt;?count=20&amp;amp;appkey=http%3A%2F%2Fgavinmeiklejohn.com&amp;amp;type=xml&lt;/a&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;where “&lt;em&gt;sometopic&lt;/em&gt;” will be replaced with the topic entered in our widget’s &lt;font face="Courier New"&gt;TextField&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;I should also draw your attention to the &lt;em&gt;appkey&lt;/em&gt; 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 &lt;a href="http://apidoc.digg.com/ApplicationKeys" target="_blank"&gt;Digg’s application keys rules&lt;/a&gt;.&lt;/p&gt;&lt;h4&gt;Digg XML Response Example&lt;/h4&gt;&lt;p&gt;The XML responses issued by Digg are presented in Digg’s own custom XML format. &lt;/p&gt;&lt;p&gt;You can see an example of the type of XML data our widget should receive by looking at the &lt;a href="http://apidoc.digg.com/ListStories#XML" target="_blank"&gt;example XML response&lt;/a&gt; on the &lt;a href="http://apidoc.digg.com/ListStories" target="_blank"&gt;List Stories API page&lt;/a&gt; referenced earlier.&lt;/p&gt;&lt;p&gt;Briefly, the response consists of a &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;stories&lt;/font&gt;&amp;gt;&lt;/font&gt; container, within which will be &lt;em&gt;0..n&lt;/em&gt; &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;story&lt;/font&gt;&amp;gt;&lt;/font&gt; elements. (In our case, &lt;em&gt;n&lt;/em&gt; will be limited to the value of &lt;em&gt;count&lt;/em&gt; in the request we send to Digg.) Each &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;story&lt;/font&gt;&amp;gt;&lt;/font&gt; 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.&lt;/p&gt;&lt;h3&gt;New file&lt;/h3&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_yaBNd1I/AAAAAAAAAJY/GU7P4zO1xxI/s1600-h/NewFile12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Create a new file" border="0" alt="Create a new file" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_y_9HwlI/AAAAAAAAAJc/_3ICrQe63RY/NewFile1_thumb.png?imgmax=800" width="559" height="415" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&amp;#160; &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_zXT0nbI/AAAAAAAAAJg/RoTYmjrlNN0/s1600-h/NewFile22.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="New file dialog" border="0" alt="New file dialog" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_z12Y_II/AAAAAAAAAJk/8rNBPOR0c2Q/NewFile2_thumb.png?imgmax=800" width="525" height="501" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Change the file name to “diggweb.js” and click the Finish button. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_0ShrgAI/AAAAAAAAAJo/acEEKh_xCtI/s1600-h/NewFile32.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Name the new file" border="0" alt="Name the new file" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_06c6-WI/AAAAAAAAAJs/s6uYqye97dI/NewFile3_thumb.png?imgmax=800" width="526" height="500" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_1M9VCCI/AAAAAAAAAJw/fVb-6wjF_gE/s1600-h/NewFile42.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="New file open in editor" border="0" alt="New file open in editor" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_1jrvC9I/AAAAAAAAAJ0/JIstxoQQUcU/NewFile4_thumb.png?imgmax=800" width="472" height="421" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;There are two ways to resolve this. You can either write a small function to dynamically add a &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;&lt;/font&gt; tag to your widget’s DOM document, defining the &lt;font color="#ff0000" face="Courier New"&gt;src&lt;/font&gt; attribute of the &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;&lt;/font&gt; 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. &lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;&amp;lt;!DOCTYPE &lt;font color="#ff0000"&gt;html&lt;/font&gt; &lt;font color="#000080"&gt;PUBLIC&lt;/font&gt; &lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;/font&gt;&lt;font color="#000000" face="Courier New"&gt;&amp;quot;        &lt;br /&gt;
&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;"&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;&amp;gt;        &lt;br /&gt;
&amp;lt;&lt;font color="#800000"&gt;html&lt;/font&gt; &lt;font color="#ff0000"&gt;xmlns&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;a href="http://www.w3.org/1999/xhtml&amp;quot;"&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;http://www.w3.org/1999/xhtml&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;&amp;gt;        &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;head&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;title&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;title&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;meta&lt;/font&gt; &lt;font color="#ff0000"&gt;http-equiv&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;Content-Type&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;content&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/html; charset=UTF-8&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; /&amp;gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/javascript&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;src&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;diggclient.js&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&lt;/font&gt;&lt;font face="Courier New"&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/javascript&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;src&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;diggweb.js&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;&amp;#160; &lt;br /&gt;
&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/javascript&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;src&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;WRTKit/WRTKit.js&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;link&lt;/font&gt; &lt;font color="#ff0000"&gt;rel&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;stylesheet&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;href&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;diggclient.css&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/css&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;META&lt;/font&gt; &lt;font color="#ff0000"&gt;NAME&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;Generator&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;CONTENT&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;Nokia WRT plug-in for Aptana Studio 2.3.0&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; /&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;/&lt;font color="#800000"&gt;head&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;body&lt;/font&gt; &lt;font color="#ff0000"&gt;onload&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;init()&amp;quot;&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;/&lt;font color="#800000"&gt;body&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;lt;/&lt;font color="#800000"&gt;html&lt;/font&gt;&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;h3&gt;Requesting data from Digg&lt;/h3&gt;&lt;p&gt;Let’s get on and write the code to request data from Digg.&lt;/p&gt;&lt;p&gt;In common with virtually all modern browser environments, Nokia WRT supports the &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; 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. &lt;/p&gt;&lt;p&gt;&lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;The good news is that WRTKit builds on the &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; API to offer an Ajax object, which deals with the differences in underlying API implementation &amp;amp; security policies between browser environments. The Ajax object is a very thin wrapper over the basic &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; but makes the task of issuing a request to an HTTP server about as simple as it can get.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;h4&gt;DiggWeb object constructor&lt;/h4&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_18GlyTI/AAAAAAAAAJ4/fH7_ImwpkPQ/s1600-h/DWCode12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DiggWeb constuctor" border="0" alt="DiggWeb constuctor" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_2t8hPeI/AAAAAAAAAJ8/d33F6wgrrvY/DWCode1_thumb.png?imgmax=800" width="598" height="222" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h4&gt;DiggWeb properties&lt;/h4&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_3BKvIJI/AAAAAAAAAKA/yKCaGNyVoz4/s1600-h/DWCode22.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DiggWeb properties" border="0" alt="DiggWeb properties" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_35eaUnI/AAAAAAAAAKE/E2IUsWElL2I/DWCode2_thumb.png?imgmax=800" width="401" height="120" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;h5&gt;What does DiggWeb.prototype mean?&lt;/h5&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;No classes? Any function can be a constructor? Surely this is chaos! No, there is order and control in the way JavaScript works.&lt;/p&gt;&lt;p&gt;Every JavaScript object has a &lt;font face="Courier New"&gt;prototype&lt;/font&gt; 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 &lt;font face="Courier New"&gt;Object&lt;/font&gt; data type, from which every JavaScript object inherits. &lt;/p&gt;&lt;p&gt;Any object can extend it’s set of properties by adding new properties to it’s &lt;font face="Courier New"&gt;prototype&lt;/font&gt; property. These new properties can be data properties or new functions, which provides a powerful mechanism to construct complex objects and object inheritance trees.&lt;/p&gt;&lt;p&gt;So, a line of JavaScript such as:&lt;/p&gt;&lt;p&gt;&lt;font face="Courier New"&gt;DiggWeb.prototype.ajaxRequest = &lt;font color="#800000"&gt;null&lt;/font&gt;;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;is saying, add a new property called &lt;font face="Courier New"&gt;ajaxRequest&lt;/font&gt; to the set of properties contained by &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt;’s &lt;font face="Courier New"&gt;prototype&lt;/font&gt; property.&lt;/p&gt;&lt;p&gt;If you’d like to read more about the object-oriented aspects of JavaScript I suggest you start with the following links:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Guide/Class-Based_vs._Prototype-Based_Languages#Adding_and_Removing_Properties" target="_blank"&gt;Mozilla Developer Center&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://mckoss.com/jscript/object.htm" target="_blank"&gt;Mike Koss’s paper on Object Oriented Programming in JavaScript&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;If you want to go further or if you prefer books, I recommend &lt;a href="http://www.amazon.co.uk/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1259482561&amp;amp;sr=8-1" target="_blank"&gt;Douglas Crockford’s “JavaScript: The Good Parts”&lt;/a&gt;&lt;/p&gt;&lt;h4&gt;Issuing a HTTP request&lt;/h4&gt;&lt;p&gt;In addition to two properties, our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_4VetvjI/AAAAAAAAAKI/iBuiRDe4J_U/s1600-h/DWCode32.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Requesting data from Digg - 1" border="0" alt="Requesting data from Digg - 1" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_4j4lrVI/AAAAAAAAAKM/FyZLbP8Bqow/DWCode3_thumb.png?imgmax=800" width="774" height="236" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We start by defining a function called &lt;font face="Courier New"&gt;requestFromDigg&lt;/font&gt; that takes two parameters.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;font face="Courier New"&gt;topic&lt;/font&gt; – 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 &lt;/li&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;callback&lt;/font&gt; – this will be a reference to a function in diggclient.js that is to be called when the HTTP request completes. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Next, we create a WRTKit &lt;font face="Courier New"&gt;Ajax&lt;/font&gt; object and assign it to our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object’s &lt;font face="Courier New"&gt;ajaxRequest&lt;/font&gt; property. The reference to the callers callback function is stored in our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object’s property of the same name.&lt;/p&gt;&lt;p&gt;The &lt;font face="Courier New"&gt;Ajax&lt;/font&gt; 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 &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt;’s &lt;font face="Courier New"&gt;onreadystatechange()&lt;/font&gt; function, like this:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_5BOrXEI/AAAAAAAAAKQ/g2eHEmjFlSI/s1600-h/DWCode42.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Requesting data from Digg - 2" border="0" alt="Requesting data from Digg - 2" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_5U4m6dI/AAAAAAAAAKU/LFce3vFm2xI/DWCode4_thumb.png?imgmax=800" width="655" height="116" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;What we’ve done here is provide a simple implementation for &lt;font face="Courier New"&gt;XMLHttpRequest.onreadystatechange()&lt;/font&gt; that will call the function &lt;font face="Courier New"&gt;readyStateChange()&lt;/font&gt; on our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object. &lt;font face="Courier New"&gt;readyStateChange()&lt;/font&gt; is the second of the two functions we will add to our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object.&lt;/p&gt;&lt;p&gt;Why have we written &lt;font face="Courier New"&gt;self.readyStateChange()&lt;/font&gt; rather than &lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;this&lt;/font&gt;.readyStateChange()&lt;/font&gt;? Because when the function &lt;font face="Courier New"&gt;XMLHttpRequest.onreadystatechange()&lt;/font&gt; runs, &lt;font color="#0000ff" face="Courier New"&gt;this&lt;/font&gt; would refer to the &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; object, not our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object. We want the function &lt;font face="Courier New"&gt;readyStateChange()&lt;/font&gt; in our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object to be called, so we need to take care to be explicit about which object we’re referring to. &lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_5qZGUGI/AAAAAAAAAKY/8U9KN9X5U3c/s1600-h/DWCode52.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Requesting data from Digg - 3" border="0" alt="Requesting data from Digg - 3" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_58vLDcI/AAAAAAAAAKc/k9yWaJHxtOI/DWCode5_thumb.png?imgmax=800" width="585" height="105" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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, &lt;font face="Courier New"&gt;topic&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;Finally we can actually transmit our request out on to the web:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_6POpe-I/AAAAAAAAAKg/dfPugzXhEDE/s1600-h/DWCode62.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Requesting data from Digg - 4" border="0" alt="Requesting data from Digg - 4" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_6gyEmuI/AAAAAAAAAKk/F0tnjN0npK0/DWCode6_thumb.png?imgmax=800" width="396" height="99" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;As with typical browsing requests, we’re issuing an HTTP “GET” command, hence the first parameter to the &lt;font face="Courier New"&gt;open()&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The call to &lt;font face="Courier New"&gt;open()&lt;/font&gt; prepares the &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; object to send the request. Nothing actually gets sent until we call &lt;font face="Courier New"&gt;send()&lt;/font&gt;. We pass &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt; to &lt;font face="Courier New"&gt;send()&lt;/font&gt; because we’ve already defined all the data that needs to be sent in the &lt;font face="Courier New"&gt;open()&lt;/font&gt; function.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;h4&gt;Dealing with request state changes&lt;/h4&gt;&lt;p&gt;&lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; has an internal &lt;font face="Courier New"&gt;readyState&lt;/font&gt; property. Every time the &lt;font face="Courier New"&gt;readyState&lt;/font&gt; property changes in value, the &lt;font face="Courier New"&gt;readystatechange&lt;/font&gt; event is fired. &lt;/p&gt;&lt;p&gt;The &lt;font face="Courier New"&gt;readyState&lt;/font&gt; property can have one of the following values:&lt;/p&gt;&lt;table border="2" cellspacing="0" cellpadding="2" width="607"&gt;&lt;tbody&gt;
&lt;tr&gt;       &lt;td valign="top" width="135"&gt;&lt;strong&gt;&lt;font color="#800000"&gt;readyState value&lt;/font&gt;&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="468"&gt;&lt;strong&gt;&lt;font color="#800000"&gt;Meaning&lt;/font&gt;&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;       &lt;td valign="top" width="135"&gt;0&lt;/td&gt;        &lt;td valign="top" width="468"&gt;The &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; object has not yet been used to send any request.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;       &lt;td valign="top" width="135"&gt;1&lt;/td&gt;        &lt;td valign="top" width="468"&gt;The &lt;font face="Courier New"&gt;open()&lt;/font&gt; function has been called, but no data has yet been sent.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;       &lt;td valign="top" width="135"&gt;2&lt;/td&gt;        &lt;td valign="top" width="468"&gt;The &lt;font face="Courier New"&gt;send()&lt;/font&gt; function has been called and a request has been sent, but no response has been received yet.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;       &lt;td valign="top" width="135"&gt;3&lt;/td&gt;        &lt;td valign="top" width="468"&gt;Data is now being received by the &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; object.&lt;/td&gt;     &lt;/tr&gt;
&lt;tr&gt;       &lt;td valign="top" width="135"&gt;4&lt;/td&gt;        &lt;td valign="top" width="468"&gt;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 &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; object.&lt;/td&gt;     &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;The &lt;font face="Courier New"&gt;readystatechange&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;It is the &lt;font face="Courier New"&gt;readystatechange&lt;/font&gt; event that &lt;font face="Courier New"&gt;XMLHttpRequest’&lt;/font&gt;s &lt;font face="Courier New"&gt;onreadystatechange()&lt;/font&gt; function is being called to process. We’ve already seen that we delegate that event handling to a method of our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object called &lt;font face="Courier New"&gt;readyStateChange()&lt;/font&gt;. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_68di_JI/AAAAAAAAAKo/jmK-wbA1-Ig/s1600-h/DWCode72.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Ajax callback state check" border="0" alt="Ajax callback state check" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_7M5uEZI/AAAAAAAAAKs/nc-3rRcFWUw/DWCode7_thumb.png?imgmax=800" width="555" height="167" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;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 &lt;font face="Courier New"&gt;readyState&lt;/font&gt; property; if it’s anything other than 4, we return from the function and don’t do any further processing.&lt;/p&gt;&lt;p&gt;If the value of the &lt;font face="Courier New"&gt;readyState&lt;/font&gt; property is 4, our request is complete and we should call our client’s callback function:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_7YLTqGI/AAAAAAAAAKw/gEWpIfIM0yA/s1600-h/DWCode82.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Ajax callback forwarded to client" border="0" alt="Ajax callback forwarded to client" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_79dvtnI/AAAAAAAAAK0/VbzN5BpQhEM/DWCode8_thumb.png?imgmax=800" width="648" height="169" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Recall that we stored a reference to the client’s callback function in our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object’s &lt;font face="Courier New"&gt;callback&lt;/font&gt; property.&lt;/p&gt;&lt;p&gt;We use the &lt;font face="Courier New"&gt;callback&lt;/font&gt; 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. &lt;/p&gt;&lt;p&gt;The second parameter we pass to the callback function varies depending on whether the request completed correctly, or with an error.&lt;/p&gt;&lt;p&gt;If all went well and we have a HTTP status of 200, we pass &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt;’s &lt;font face="Courier New"&gt;responseXML&lt;/font&gt; property as the second parameter to the client’s callback function. &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt; detects if valid XML is returned as a result of a request; if so, it stores a XML tree in the &lt;font face="Courier New"&gt;responseXML&lt;/font&gt; property, ready for parsing.&lt;/p&gt;&lt;p&gt;If something unexpected happened and we did not get a HTTP status of 200, we pass &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt;’s &lt;font face="Courier New"&gt;statusText&lt;/font&gt; property as the second parameter to the client’s callback function. The &lt;font face="Courier New"&gt;statusText&lt;/font&gt; property contains a human readable textual version of the HTTP status code, such as “Not found” for a status code of 404. &lt;/p&gt;&lt;h3&gt;Displaying the data in our widget’s UI&lt;/h3&gt;&lt;p&gt;Instead of going through every line of code in diggclient.js as we have done in parts 1 &amp;amp; 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.&lt;/p&gt;&lt;h4&gt;More objects, more variables&lt;/h4&gt;&lt;p&gt;Let’s start by looking at the new variables we require this time.&lt;/p&gt;&lt;p&gt;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 &lt;font face="Courier New"&gt;Label&lt;/font&gt; control that will be shown in the main view, as necessary.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_8Or-8AI/AAAAAAAAAK4/au926c7USbY/s1600-h/Code_12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="A new label control" border="0" alt="A new label control" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_8VF2wFI/AAAAAAAAAK8/2PnyTAVS_TU/Code_1_thumb.png?imgmax=800" width="393" height="99" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The variable &lt;font face="Courier New"&gt;noStoriesLabel&lt;/font&gt; will hold a reference to this new &lt;font face="Courier New"&gt;Label&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;We also need one variable to reference our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; 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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_8rbYDuI/AAAAAAAAALA/fzxyoeJO0wQ/s1600-h/Code_23.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Web request &amp;amp; story array variables" border="0" alt="Web request &amp;amp; story array variables" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_9KgNKcI/AAAAAAAAALE/WceW1F1puWE/Code_2_thumb1.png?imgmax=800" width="382" height="120" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The other variables we require are as defined in part 2 of the tutorial.&lt;/p&gt;&lt;h4&gt;Initialisation&lt;/h4&gt;&lt;p&gt;Our &lt;font face="Courier New"&gt;init()&lt;/font&gt; 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 &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s to the main view and replace it with code that adds a &lt;font face="Courier New"&gt;Label&lt;/font&gt; to show that there are no stories available yet.&lt;/p&gt;&lt;p&gt;Remove the following code from your &lt;font face="Courier New"&gt;init()&lt;/font&gt; function…&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_9aaFcCI/AAAAAAAAALI/XnLK-Nq6MBs/s1600-h/Code_3A2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Out with the old..." border="0" alt="Out with the old..." src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_9-Gjq0I/AAAAAAAAALM/LJIP8H_p2cQ/Code_3A_thumb.png?imgmax=800" width="634" height="137" /&gt;&lt;/a&gt;&amp;#160; and replace it with the following code:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_-N6DFrI/AAAAAAAAALQ/l8nyNd0-eE0/s1600-h/Code_3B2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="...in with the new" border="0" alt="...in with the new" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_-dVz2rI/AAAAAAAAALU/7I-imxCNqKA/Code_3B_thumb.png?imgmax=800" width="634" height="84" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Here we’ve created a new &lt;font face="Courier New"&gt;Label&lt;/font&gt; control and assigned it to our new &lt;font face="Courier New"&gt;noStoriesLabel&lt;/font&gt; variable. The &lt;font face="Courier New"&gt;Label&lt;/font&gt; is constructed in the familiar way, but here we pass &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt; as the second parameter to the &lt;font face="Courier New"&gt;Label&lt;/font&gt; constructor, signalling that we do not require a caption associated with this &lt;font face="Courier New"&gt;Label&lt;/font&gt;. Once constructed, the &lt;font face="Courier New"&gt;Label&lt;/font&gt; is added to our widget’s main view. &lt;/p&gt;&lt;p&gt;We will still use &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; controls to represent each story returned from Digg, but we’ll create the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; controls as and when they are needed and we’ll also dynamically swap between displaying &lt;font face="Courier New"&gt;NavigationButtons&lt;/font&gt; when there is data to show and the “No stories available” &lt;font face="Courier New"&gt;Label&lt;/font&gt; when there is not.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h4&gt;Button Event Handlers&lt;/h4&gt;&lt;p&gt;In part 2 of our tutorial we had two button event handler functions:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;font face="Courier New"&gt;diggButtonClicked()&lt;/font&gt; that handled the event fired by the user clicking on the main view’s “Digg it” button. &lt;/li&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt; that handled the event fired by the user clicking on one of the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s representing stories in the main view &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Of these event handlers, only the implementation of &lt;font face="Courier New"&gt;diggButtonClicked()&lt;/font&gt; changes in this part of the tutorial. The new implementation looks like this:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_-0WH0HI/AAAAAAAAALY/0new4bDiqzQ/s1600-h/Code_43.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Digg button event handler" border="0" alt="Digg button event handler" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu__Rc1b1I/AAAAAAAAALc/HvzbsClGq7s/Code_4_thumb1.png?imgmax=800" width="674" height="223" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Compared to the implementation in part 2 of the tutorial, it’s only the code within the &lt;font color="#0000ff" face="Courier New"&gt;else&lt;/font&gt; clause that is different. Now, instead of just displaying a notification showing the user the text they had entered into the &lt;font face="Courier New"&gt;TextField&lt;/font&gt; control, we want to do something useful and issue a request to Digg for some stories on the topic entered by the user.&lt;/p&gt;&lt;p&gt;We do this by creating a new &lt;font face="Courier New"&gt;Array&lt;/font&gt; and assigning the resulting array to our &lt;font face="Courier New"&gt;storyArray&lt;/font&gt; variable. &lt;font face="Courier New"&gt;Array&lt;/font&gt; is an inbuilt JavaScript object that allows easy creation, manipulation and removal of data in an array. Next we create one of our own &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; objects and assign that to the &lt;font face="Courier New"&gt;webRequest&lt;/font&gt; variable. &lt;/p&gt;&lt;p&gt;Finally, we use our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object to issue a request to Digg for some stories. As we know, because we wrote the &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object, we issue a request by calling the &lt;font face="Courier New"&gt;requestFromDigg()&lt;/font&gt; function of our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object. We also know that we need to pass two parameters to &lt;font face="Courier New"&gt;requestFromDigg()&lt;/font&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;the topic on which we want some stories &lt;/li&gt;
&lt;li&gt;a reference to the function we want to be called when the request completes &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Therefore, we pass in the &lt;font face="Courier New"&gt;topic&lt;/font&gt; variable which holds the text the user entered in the &lt;font face="Courier New"&gt;TextField&lt;/font&gt; control and a reference to a function called &lt;font face="Courier New"&gt;handleDiggResponse()&lt;/font&gt;, the implementation of which we’ll look at next.&lt;/p&gt;&lt;h4&gt;Handling data returned from Digg&lt;/h4&gt;&lt;p&gt;You might like to have a look at the &lt;a href="http://apidoc.digg.com/ListStories#XML" target="_blank"&gt;example XML data&lt;/a&gt; provided by Digg as you follow the implementation of this function.&lt;/p&gt;&lt;p&gt;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 &lt;a href="https://developer.mozilla.org/en/DOM" target="_blank"&gt;Mozilla Developer Center&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu__uCWipI/AAAAAAAAALg/Yjl48Mj7cgQ/s1600-h/Code_52.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Digg response handler - 1" border="0" alt="Digg response handler - 1" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAAOd0aWI/AAAAAAAAALk/WObMM8fAR0Q/Code_5_thumb.png?imgmax=800" width="641" height="272" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;If we’ve got an HTTP status of 200, what we want next are all the &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;story&lt;/font&gt;&amp;gt;&lt;/font&gt; elements in the XML returned from Digg. &lt;/p&gt;&lt;p&gt;We get all of the &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;story&lt;/font&gt;&amp;gt;&lt;/font&gt; elements by calling the DOM API function &lt;font face="Courier New"&gt;getElementsByTagName()&lt;/font&gt; 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. &lt;/p&gt;&lt;p&gt;Now we need to dissect each “story” element in turn and pull out the data we’re interested in. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAAZtzlOI/AAAAAAAAALo/ywm1lnWziYs/s1600-h/Code_63.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Digg response handler - 2" border="0" alt="Digg response handler - 2" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAAxZ9EjI/AAAAAAAAALs/oG_vmb7_0xk/Code_6_thumb1.png?imgmax=800" width="514" height="289" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We use a &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; loop to examine each story element in turn. The length property of the array of story elements returned by &lt;font face="Courier New"&gt;getElementsByTagName()&lt;/font&gt; gives us the number of stories we have received from Digg.&lt;/p&gt;&lt;p&gt;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 (&lt;a href="http://www.json.org/" target="_blank"&gt;JSON&lt;/a&gt;) to combine the parts into a single object and add it to our array of stories. &lt;/p&gt;&lt;p&gt;&lt;em&gt;Note: A good introduction to JSON can be found on the &lt;a href="http://msdn.microsoft.com/en-us/library/bb299886.aspx" target="_blank"&gt;msdn&lt;/a&gt; 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 &lt;a href="http://www.amazon.co.uk/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1259482561&amp;amp;sr=8-1" target="_blank"&gt;“JavaScript: The Good Parts”&lt;/a&gt;, JSON is another reason to do so.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Having obtained the attributes for the current story, we store the values of the “link” and “diggs” attributes in their namesake variables.&lt;/p&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvABB7fVJI/AAAAAAAAALw/qMcVC6rMUfE/s1600-h/Code_7A2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Digg response handler - 3" border="0" alt="Digg response handler - 3" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvABjTRyLI/AAAAAAAAAL0/1_eRWwiHKgw/Code_7A_thumb.png?imgmax=800" width="897" height="255" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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 &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; loop to allow us to examine each child node in turn, looking for the data that is of interest to us.&lt;/p&gt;&lt;p&gt;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 &amp;amp; description of our story together with the thumbnail image associated with the story, if there is one.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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 &lt;font color="#ff0000" face="Courier New"&gt;src&lt;/font&gt; 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 &lt;font color="#ff0000" face="Courier New"&gt;src&lt;/font&gt; attribute. We store the value of the thumbnail’s &lt;font color="#ff0000" face="Courier New"&gt;src&lt;/font&gt; attribute in the &lt;font face="Courier New"&gt;thumbnail&lt;/font&gt; variable defined earlier in this function.&lt;/p&gt;&lt;p&gt;We use JSON to combine the variables declared earlier into a single object which we store in our array of stories by calling the &lt;font face="Courier New"&gt;push()&lt;/font&gt; function on our &lt;font face="Courier New"&gt;storyArray&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAB-mn9WI/AAAAAAAAAL4/mrd3zgqi-Ng/s1600-h/Code_7B2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Code_7B" border="0" alt="Code_7B" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvACFIhV5I/AAAAAAAAAL8/8wREGatHqTM/Code_7B_thumb.png?imgmax=800" width="400" height="120" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;JSON provides us with a useful mechanism to create simple data objects on the fly which we can then add to our &lt;font face="Courier New"&gt;storyArray&lt;/font&gt;. &lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;So our JSON statement creates an object with properties named &lt;font face="Courier New"&gt;title&lt;/font&gt;, &lt;font face="Courier New"&gt;description&lt;/font&gt;, &lt;font face="Courier New"&gt;diggs&lt;/font&gt;, &lt;font face="Courier New"&gt;thumbnail&lt;/font&gt; and &lt;font face="Courier New"&gt;link&lt;/font&gt;, giving each of these properties the value of the appropriate data extracted from the XML received from Digg.&lt;/p&gt;&lt;p&gt;The call to &lt;font face="Courier New"&gt;push()&lt;/font&gt; on our &lt;font face="Courier New"&gt;storyArray&lt;/font&gt; 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 &lt;font face="Courier New"&gt;storyArray&lt;/font&gt;, we can directly reference the properties &lt;font face="Courier New"&gt;title&lt;/font&gt;, &lt;font face="Courier New"&gt;description&lt;/font&gt;, &lt;font face="Courier New"&gt;diggs&lt;/font&gt;, &lt;font face="Courier New"&gt;thumbnail&lt;/font&gt; and &lt;font face="Courier New"&gt;link&lt;/font&gt;, even though there is no object defined anywhere in our code that has such properties.&lt;/p&gt;&lt;p&gt;I encourage you to read more about JSON and find out what it can do to make your JavaScript development both easier &amp;amp; more powerful.&lt;/p&gt;&lt;p&gt;Note that the closing brace shown on line 257 above is the closing brace of the outer &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; loop of our story processing code.&lt;/p&gt;&lt;p&gt;All we need to do now is deal with the case when the request has failed in some way:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvACW3WaoI/AAAAAAAAAMA/94FtBzp3Upo/s1600-h/Code_83.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Digg response handler - 4" border="0" alt="Digg response handler - 4" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvACqhVslI/AAAAAAAAAME/brD24yyakBo/Code_8_thumb1.png?imgmax=800" width="543" height="120" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Recall from the implementation of our &lt;font face="Courier New"&gt;DiggWeb&lt;/font&gt; object that we return the &lt;font face="Courier New"&gt;XMLHttpRequest&lt;/font&gt;’s &lt;font face="Courier New"&gt;xmlResponse&lt;/font&gt; property if the request completes correctly, but we return the &lt;font face="Courier New"&gt;statusText&lt;/font&gt; property if there was a problem which we can use to conveniently present a notification to the user informing them why the request failed.&lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The last thing we do in our &lt;font face="Courier New"&gt;handleDiggResponse()&lt;/font&gt; function is call another new function, &lt;font face="Courier New"&gt;refreshMainView()&lt;/font&gt;, passing it the &lt;font face="Courier New"&gt;storyArray&lt;/font&gt;. 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.&lt;/p&gt;&lt;h4&gt;Updating the main view&lt;/h4&gt;&lt;p&gt;To display the stories received from Digg in our widget’s main view, we need to perform two tasks:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Remove any current content from the view that is no longer relevant. &lt;/li&gt;
&lt;li&gt;Add the updated content. &lt;/li&gt;
&lt;/ol&gt;&lt;h5&gt;Removing old content&lt;/h5&gt;&lt;p&gt;Only two controls in the main view are always relevant – the &lt;font face="Courier New"&gt;TextField&lt;/font&gt; and the &lt;font face="Courier New"&gt;FormButton&lt;/font&gt;, so we’ll write code to remove everything apart from these controls from the main view:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvADBkicpI/AAAAAAAAAMI/g0cU7dTAdjE/s1600-h/Code_98.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Removing old content" border="0" alt="Removing old content" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvADQsl9CI/AAAAAAAAAMM/_ujERVGOhsc/Code_9_thumb2.png?imgmax=800" width="662" height="273" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;We start this function by retrieving an array of the controls in the main view, which we get by calling the function &lt;font face="Courier New"&gt;getControls()&lt;/font&gt; on the &lt;font face="Courier New"&gt;mainView&lt;/font&gt; object.&lt;/p&gt;&lt;p&gt;A &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; loop is then used, which starts with the last control and finishes with the third control which was added to the main view.&lt;/p&gt;&lt;p&gt;Within the &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; loop we delete each control by calling &lt;font face="Courier New"&gt;removeControl()&lt;/font&gt; on the &lt;font face="Courier New"&gt;mainView&lt;/font&gt; 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 &lt;font face="Courier New"&gt;TextField&lt;/font&gt; and the &lt;font face="Courier New"&gt;FormButton&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;Note that this code is dependent on the fact that the &lt;font face="Courier New"&gt;ListView&lt;/font&gt; maintains an array of controls, listed by addition / insertion order. We know therefore that &lt;font face="Courier New"&gt;curControls[0]&lt;/font&gt; is the &lt;font face="Courier New"&gt;TextField&lt;/font&gt; control and that &lt;font face="Courier New"&gt;curControls[1]&lt;/font&gt; is the &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; control.&lt;/p&gt;&lt;h5&gt;Check your references&lt;/h5&gt;&lt;p&gt;Beware! If you reversed the direction of the &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; loop in the code above you would not get the desired result. The call to &lt;font face="Courier New"&gt;ListView.getControls()&lt;/font&gt; returns a reference to the array of controls contained by the &lt;font face="Courier New"&gt;ListView&lt;/font&gt; control. When a control is removed from the internal array by calling &lt;font face="Courier New"&gt;ListView.removeControl()&lt;/font&gt;, the result is visible via the reference we got before we started removing content. Therefore, by advancing the index in the &lt;font color="#0000ff" face="Courier New"&gt;for&lt;/font&gt; 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.&lt;/p&gt;&lt;h5&gt;Adding new content&lt;/h5&gt;&lt;p&gt;The array of stories we received from Digg was passed as the parameter, &lt;font face="Courier New"&gt;newStories&lt;/font&gt;, to this function. So all we need to do to add fresh content to the main view is construct a &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; for each story, using relevant data from each item in our array of stories. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAD-qLl2I/AAAAAAAAAMQ/aHT_LnA2gnY/s1600-h/Code_102.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Adding new content" border="0" alt="Adding new content" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/SyvAEIqGweI/AAAAAAAAAMU/7mQFdFyyOig/Code_10_thumb.png?imgmax=800" width="860" height="170" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;We start by checking the length of the &lt;font face="Courier New"&gt;newStories&lt;/font&gt; array because we only want to add &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s if we’ve got at least one story. For each story, we create a &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; and associate the &lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt; 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 &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s to the main view in the &lt;font face="Courier New"&gt;init()&lt;/font&gt; function in part 2 of the tutorial.&lt;/p&gt;&lt;p&gt;The data used to construct each &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; is extracted from the appropriate item in the &lt;font face="Courier New"&gt;newStories&lt;/font&gt; array.&amp;#160; Notice that we again use a numerical index as the id of the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; 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 &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; constructor becomes the &lt;font color="#ff0000" face="Courier New"&gt;src&lt;/font&gt; attribute of an HTML &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;img&lt;/font&gt;&amp;gt;&lt;/font&gt; element.&lt;/p&gt;&lt;p&gt;All that’s left to do now is handle the case where there are no stories available. We’ve already created a new &lt;font face="Courier New"&gt;Label&lt;/font&gt; control and stored a reference to the control in a variable called &lt;font face="Courier New"&gt;noStoriesLabel&lt;/font&gt;. So we can quite simply deal with this case by adding our &lt;font face="Courier New"&gt;noStoriesLabel&lt;/font&gt; control to the main view, in lieu of more interesting content:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAEU13acI/AAAAAAAAAMY/teQv3qGuqCo/s1600-h/Code_112.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="What to do if there&amp;#39;s no content" border="0" alt="What to do if there&amp;#39;s no content" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/SyvAE3gU5AI/AAAAAAAAAMc/jot7WmJKpCY/Code_11_thumb.png?imgmax=800" width="400" height="104" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h4&gt;Updating the detail view&lt;/h4&gt;&lt;p&gt;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 &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;Now we can do a little better by using some of the data we’ve got stored in our story array.&lt;/p&gt;&lt;p&gt;Here’s the new implementation of &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/SyvAFJHQ7gI/AAAAAAAAAMg/DfNRGUxc4B4/s1600-h/Code_123.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Replacing hardcoded data with dynamic data" border="0" alt="Replacing hardcoded data with dynamic data" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/SyvAFdCoPMI/AAAAAAAAAMk/M8dkmTqsuZs/Code_12_thumb.png?imgmax=800" width="506" height="140" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The parameter passed to &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; is still the object which fired the &lt;font color="#008000" face="Courier New"&gt;ActionPerformed&lt;/font&gt; 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 &lt;font face="Courier New"&gt;storyArray&lt;/font&gt; of the relevant story object.&lt;/p&gt;&lt;p&gt;Given this, we can now populate the three labels in the detail view with relevant content received from Digg.&lt;/p&gt;&lt;h3&gt;Additional Notes&lt;/h3&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Again I suggest that by using &amp;amp; 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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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!&lt;/p&gt;&lt;h3&gt;Coming next…&lt;/h3&gt;&lt;p&gt;This concludes the third part of our tutorial on creating a Digg client with Nokia WRT &amp;amp; Aptana Studio. We now have a functional widget which uses HTTP requests to retrieve content from Digg and present it to the user. &lt;/p&gt;&lt;p&gt;Except, there are a few problems:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;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! &lt;/li&gt;
&lt;li&gt;The detail view only shows a short description of the story, there’s no way to access the full story! &lt;/li&gt;
&lt;li&gt;And what’s with the “Hello” icon? Can’t we have something better? &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;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!&lt;/p&gt;&lt;h2 align="right"&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-4.html"&gt;Part 4&amp;gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-7441573872038173422?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/7441573872038173422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-3.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/7441573872038173422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/7441573872038173422'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-3.html' title='Web Runtime Widget Tutorial – Part 3: Requesting data from Digg and displaying the results'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_w8mXa9I/AAAAAAAAAJM/HM_0xw-_IK8/s72-c/Before_thumb.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-8990841704140872942</id><published>2009-12-18T17:44:00.002Z</published><updated>2009-12-18T18:10:23.193Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WRTKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WRT'/><category scheme='http://www.blogger.com/atom/ns#' term='Aptana'/><category scheme='http://www.blogger.com/atom/ns#' term='Digg'/><title type='text'>Web Runtime Widget Tutorial – Part 2: Structuring the Digg Client UI</title><content type='html'>&lt;h2&gt;&lt;font color="#800080"&gt;&lt;a href="http://cid-41c47f6e8baac5b4.skydrive.live.com/self.aspx/.Public/DiggClient%20-%20Part%202.zip" target="_blank"&gt;Grab the code!&lt;/a&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;In the case of our Digg Client widget, I’ve designed a UI that takes the essence of Scott Guthrie’s &lt;a href="http://weblogs.asp.net/scottgu/pages/silverlight-2-end-to-end-tutorial-building-a-digg-search-client.aspx" target="_blank"&gt;Silverlight Digg Client UI&lt;/a&gt; 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.&lt;/p&gt;&lt;p&gt;Let’s start by looking at the target UI. I’ve designed a widget consisting of three views. &lt;/p&gt;&lt;h4&gt;Main View&lt;/h4&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_QAQNbqI/AAAAAAAAAGw/MfTeUsTIVQk/s1600-h/TargetMainView4.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Main view" border="0" alt="Main view" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_QmKre_I/AAAAAAAAAG0/4X73TduoBp4/TargetMainView_thumb2.jpg?imgmax=800" width="385" height="536" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;The view consists of a &lt;font face="Courier New"&gt;ListView&lt;/font&gt;, a &lt;font face="Courier New"&gt;TextField&lt;/font&gt;, a &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; and a set of &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s representing the stories received from Digg. &lt;/font&gt;&lt;/p&gt;&lt;p&gt;The content of the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s&lt;/font&gt; – the icon &amp;amp; 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 &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s&lt;/font&gt; 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.&lt;/p&gt;&lt;h4&gt;About View&lt;/h4&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_Q-ALjuI/AAAAAAAAAG4/qMR52bZlNCY/s1600-h/TargetAboutView4.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="About view" border="0" alt="About view" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_RLf0MZI/AAAAAAAAAG8/cv3eqMtERoE/TargetAboutView_thumb2.jpg?imgmax=800" width="364" height="535" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h4&gt;Detail View&lt;/h4&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_Rm6FCUI/AAAAAAAAAHA/rdPxuYicn-8/s1600-h/TargetDetailView4.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Detail view" border="0" alt="Detail view" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_RxXuixI/AAAAAAAAAHE/6O7Lsf8Y6I8/TargetDetailView_thumb2.jpg?imgmax=800" width="356" height="539" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;This view is quite simple and consists of just three &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; controls. Each &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; 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.&lt;/p&gt;&lt;h3&gt;Three times the UI… three times the code?&lt;/h3&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;All of the work we need to do is confined to the&lt;font color="#000000" face="geor"&gt; diggclient.js &lt;/font&gt;file. Every other file in the project remains as it was in part 1 of the tutorial.&lt;/p&gt;&lt;h4&gt;More objects, more variables&lt;/h4&gt;&lt;p&gt;Let’s start with all these new UI objects and the variables we’ll use to represent them:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_SQwnmtI/AAAAAAAAAHI/_kxtB7OvYeQ/s1600-h/Code_13.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Global variables" border="0" alt="Global variables" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_SxUSCrI/AAAAAAAAAHM/4SGX6Ld6s3A/Code_1_thumb.jpg?imgmax=800" width="649" height="474" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;As in part 1 of the tutorial, we declare a variable for our WRTKit &lt;font color="#000000" face="Courier New"&gt;uiManager&lt;/font&gt; and then one variable for each of our three views – &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;mainView&lt;/font&gt;, &lt;font face="Courier New"&gt;detailView&lt;/font&gt; &amp;amp; &lt;font face="Courier New"&gt;aboutView&lt;/font&gt;.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Next there are three sets of variable declarations, each set declaring the variables needed to represent the UI objects specific to a given view. &lt;/p&gt;&lt;p&gt;For the main view we need a &lt;font color="#000000" face="Courier New"&gt;TextField&lt;/font&gt; and a &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt;, so we declare two variables to represent them. Notice that there are no variables declared to represent the stories.&lt;/p&gt;&lt;p&gt;For the detail view, we need three &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; controls, so we declare three variables to represent them. &lt;/p&gt;&lt;p&gt;As in part 1 of the tutorial, the about view only requires a single variable to represent a &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; control.&lt;/p&gt;&lt;p&gt;The next variable declaration – &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; – helps to support the logic needed to navigate between the three views of our widget. It&amp;#160; is used to reference one of the functions that we call to show a specific view.&lt;/p&gt;&lt;p&gt;In part 1 of the tutorial we only had two views – the main view &amp;amp; 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 &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; to refer to the appropriate &lt;font color="#000000" face="Courier New"&gt;show&lt;em&gt;XXX&lt;/em&gt;()&lt;/font&gt; function to ensure the correct view is displayed when the user closes the about view. &lt;/p&gt;&lt;p&gt;Finally, as before, we declare &lt;font color="#000000" face="Courier New"&gt;MENU_ITEM_ABOUT&lt;/font&gt;, which defines the position of the “About” option in the widget’s option menu.&lt;/p&gt;&lt;h4&gt;Initialisation&lt;/h4&gt;&lt;p&gt;Because every other file in the project except&lt;font color="#000000"&gt; diggclient.js &lt;/font&gt;remains the same between parts 1 &amp;amp; 2 of this tutorial, you know from part 1 that the JavaScript method called when our widget starts up is&lt;font color="#000000"&gt; &lt;font face="Courier New"&gt;init()&lt;/font&gt;.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;The first block of code in &lt;font color="#000000" face="Courier New"&gt;init()&lt;/font&gt; should look familiar:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_TFonb2I/AAAAAAAAAHQ/9LE0x605XV0/s1600-h/Code_23.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation" border="0" alt="Initialisation" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_Tml5TwI/AAAAAAAAAHU/JfwgpfxtjLI/Code_2_thumb.jpg?imgmax=800" width="564" height="273" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;If you can’t remember what this code does, refer back to the explanation given in part 1 of this tutorial. &lt;/p&gt;&lt;p&gt;The next block of code creates the WRTKit &lt;font color="#000000" face="Courier New"&gt;UIManager&lt;/font&gt; object and the three &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; objects we need:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_TwOaKaI/AAAAAAAAAHY/y47liffdUho/s1600-h/Code_33.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation - core UI variables" border="0" alt="Initialisation - core UI variables" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_UWcQLyI/AAAAAAAAAHc/LbUmnB1pGr4/Code_3_thumb.jpg?imgmax=800" width="456" height="221" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Now it’s time to add come controls to the three views. This code is a mixture of old and new:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_Un7QcGI/AAAAAAAAAHg/NExVVxztLhQ/s1600-h/Code_4a3.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation - main view controls" border="0" alt="Initialisation - main view controls" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_UzLenPI/AAAAAAAAAHk/CtIbavdSBhc/Code_4a_thumb1.jpg?imgmax=800" width="605" height="171" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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 &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;TextField&lt;/font&gt;, a &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; and a set of &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s that will&lt;/font&gt; represent a list of stories. &lt;/p&gt;&lt;p&gt;The code to create &lt;font color="#000000"&gt;the &lt;font face="Courier New"&gt;TextField&lt;/font&gt; and &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; controls will again look familiar to you from part 1 of the tutorial. The &lt;font face="Courier New"&gt;TextField&lt;/font&gt;’s prompt and the &lt;font face="Courier New"&gt;FormButton&lt;/font&gt;’s text have changed to suit the needs of our UI, and the function that will be called when the &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; is clicked&lt;/font&gt; has been given a new name, to keep it consistent with the name of the object who’s event it is handling.&lt;/p&gt;&lt;p&gt;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 &lt;font color="#800080" face="Courier New"&gt;for&lt;/font&gt; loop to create three objects that will represent stories in our main view.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_VcLwXsI/AAAAAAAAAHo/_vEe9MdwEGI/s1600-h/Code_4b3.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation - temporary content" border="0" alt="Initialisation - temporary content" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_Vjk7RwI/AAAAAAAAAHs/PGqnPfDbnAE/Code_4b_thumb1.jpg?imgmax=800" width="686" height="154" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The &lt;font color="#000080" face="Courier New"&gt;for&lt;/font&gt; loop creates &lt;font color="#000000"&gt;three &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; controls and adds each one to the main view. A &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; is another WRTKit control which is intended to be used to allow users to navigate between views in a widget. The icon &amp;amp; text on the face of the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;&lt;/font&gt; 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!&lt;/p&gt;&lt;p&gt;We create &lt;font color="#000000"&gt;each &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; by passing three parameters to the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; 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 &lt;font color="#000080" face="Courier New"&gt;for&lt;/font&gt; loop, so each &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; object gets&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;The second parameter passed to &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;’s&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s and &lt;font face="Courier New"&gt;FormButton&lt;/font&gt;s both derive from the abstract base class &lt;font face="Courier New"&gt;ActionControl&lt;/font&gt;, which fires the &lt;font color="#008000" face="Courier New"&gt;ActionPerformed&lt;/font&gt; event whenever the user clicks a button derived from &lt;font face="Courier New"&gt;ActionControl&lt;/font&gt;. So just as we did with the &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; control on the main view, we add an event listener to each &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; we create. The same function, &lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt;, is passed &lt;/font&gt;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.&lt;/p&gt;&lt;p&gt;Moving on to our new detail view, we need to create three &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; 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. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_V4mMnWI/AAAAAAAAAHw/mDW3Ir-yLSE/s1600-h/Code_53.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation - detail view controls" border="0" alt="Initialisation - detail view controls" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_WcmQUgI/AAAAAAAAAH0/tUsgbqDK-gQ/Code_5_thumb1.jpg?imgmax=800" width="425" height="151" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The code above shows that we simply create three &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; controls, giving each one a self-explanatory caption, and then add the three &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;Label&lt;/font&gt;’s&lt;/font&gt; to our new detail view.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The code to create the &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; control for the about view is once again the same as we used in part 1 of the tutorial:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_W35A82I/AAAAAAAAAH4/YSk_mlFWQJM/s1600-h/Code_63.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation - about view control" border="0" alt="Initialisation - about view control" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_XDG3RlI/AAAAAAAAAH8/4uYd_YB_3gM/Code_6_thumb1.jpg?imgmax=800" width="399" height="82" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We close &lt;font color="#000000"&gt;the &lt;font face="Courier New"&gt;init()&lt;/font&gt; function by telling the WRTKit &lt;font face="Courier New"&gt;UIManager&lt;/font&gt;&lt;/font&gt; object which view to use initially:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_Xf9nPjI/AAAAAAAAAIA/Sx7x2wUlu2s/s1600-h/Code_73.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Initialisation complete" border="0" alt="Initialisation complete" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_XvLBpNI/AAAAAAAAAIE/n4sjamfcPl0/Code_7_thumb1.jpg?imgmax=800" width="300" height="83" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h4&gt;Button Event Handlers&lt;/h4&gt;&lt;p&gt;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 &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s&lt;/font&gt; that represent stories returned from Digg.com.&lt;/p&gt;&lt;p&gt;Let’s start with some more familiar code – &lt;font color="#000000" face="Courier New"&gt;diggButtonClicked()&lt;/font&gt; – which is called, not surprisingly, when the user clicks on the “Digg it” button:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_YEiVJ2I/AAAAAAAAAII/Kgazfn5Ks14/s1600-h/Code_83.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Digg button event handler" border="0" alt="Digg button event handler" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_YVDVr9I/AAAAAAAAAIM/iLlgGHUpfo0/Code_8_thumb1.jpg?imgmax=800" width="690" height="186" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;We get the topic the user would like to search Digg.com for by retrieving the text held in the &lt;font color="#000000" face="Courier New"&gt;topicField&lt;/font&gt;. If the topic to be searched for is empty, we pop up a notification suggesting the user enters a topic.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Now let’s look at how we deal with a click on any one of the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s&lt;/font&gt; that represent stories:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_Y8RNtiI/AAAAAAAAAIQ/pSr5AZXXRhM/s1600-h/Code_9a2.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Story button event handler" border="0" alt="Story button event handler" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_ZG8go_I/AAAAAAAAAIU/e6HMfa7tC2U/Code_9a_thumb.jpg?imgmax=800" width="347" height="118" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;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 &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;Label&lt;/font&gt; controls in &lt;font face="Courier New"&gt;showDetailView()&lt;/font&gt;?&lt;/font&gt;&lt;/p&gt;&lt;p&gt;We can’t wait until we’re &lt;font color="#000000"&gt;inside &lt;font face="Courier New"&gt;showDetailView()&lt;/font&gt; to add the relevant content to the view’s Label controls because &lt;font face="Courier New"&gt;showDetailView()&lt;/font&gt; can&lt;/font&gt; be called from two places:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;as a result of clicking on a story from the main view. &lt;/li&gt;
&lt;li&gt;on return from the about view, if the about view was called from the detail view. &lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;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. &lt;/p&gt;&lt;p&gt;What about the parameter we pass to &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt;?&lt;/font&gt;&lt;/p&gt;&lt;h5&gt;Event Message&lt;/h5&gt;&lt;p&gt;The parameter passed to event handlers is a JavaScript object which contains three properties you can access in your event handler code:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;font color="#000000"&gt;&lt;strong&gt;&lt;font face="Courier New"&gt;type&lt;/font&gt;&lt;/strong&gt; – this is a string that tells you the type of the event your code has been called to handle, for example, &lt;font color="#008000"&gt;“&lt;font face="Courier New"&gt;ActionPerformed&lt;/font&gt;”&lt;/font&gt;. &lt;/font&gt;&lt;/li&gt;
&lt;li&gt;&lt;font color="#000000"&gt;&lt;strong&gt;&lt;font face="Courier New"&gt;source&lt;/font&gt;&lt;/strong&gt; – 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 &lt;font face="Courier New"&gt;FormButton&lt;/font&gt; object, or one of our &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; objects. &lt;/font&gt;&lt;/li&gt;
&lt;li&gt;&lt;font color="#000000"&gt;&lt;strong&gt;&lt;font face="Courier New"&gt;value&lt;/font&gt;&lt;/strong&gt; – this contains &lt;/font&gt;additional data specific to the type of event. We don’t currently use this in our code. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;So, when &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; is called from &lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt; with a parameter of &lt;font face="Courier New"&gt;event.source&lt;/font&gt;, we’re calling &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; with the object that fired the event – the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; representing the story the user now wants to read.&lt;/p&gt;&lt;h5&gt;Populating the Detail view&lt;/h5&gt;&lt;p&gt;Here’s the code of &lt;font color="#000000" face="Courier New"&gt;populateDetailView()&lt;/font&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu_ZpIdE4I/AAAAAAAAAIY/SfREzEa8ozg/s1600-h/Code_9b2.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Populating the detail view" border="0" alt="Populating the detail view" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_Z4XRaRI/AAAAAAAAAIc/9WLh6uq6cuo/Code_9b_thumb.jpg?imgmax=800" width="411" height="137" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;We now know that the &lt;font face="Courier New"&gt;story&lt;/font&gt; parameter passed to &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; is the source property of the event message that was passed to &lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt;. We also now know that this means &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; is being passed a reference to the &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; that fired the event which resulted in &lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt; being called. &lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;When we created the controls for the main view, we said that the caption of each &lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt; 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 &lt;font face="Courier New"&gt;story.getText()&lt;/font&gt; and use that text as the content of detail view’s &lt;font face="Courier New"&gt;titleLabel&lt;/font&gt;.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;The other &lt;font face="Courier New"&gt;Label&lt;/font&gt; control&lt;/font&gt;s are assigned hardcoded text which we will dynamically populate in the next part of this tutorial.&lt;/p&gt;&lt;h4&gt;Look at the views!&lt;/h4&gt;&lt;p&gt;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:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_aH2sToI/AAAAAAAAAIg/SReAbSDMcMQ/s1600-h/Code_103.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing the detail view" border="0" alt="Showing the detail view" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_aaArQ2I/AAAAAAAAAIk/mb8WIFUy3co/Code_10_thumb1.jpg?imgmax=800" width="349" height="118" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Having implemented the function &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; to prepare the content of the detail view and ensured that the &lt;font face="Courier New"&gt;storyClicked()&lt;/font&gt; event handler calls &lt;font face="Courier New"&gt;populateDetailView()&lt;/font&gt; before calling &lt;font face="Courier New"&gt;showDetailView()&lt;/font&gt;, it should be no surprise to see that &lt;font face="Courier New"&gt;showDetailView()&lt;/font&gt; is&lt;/font&gt; very simple.&lt;/p&gt;&lt;p&gt;Both the detail and about views need the same softkeys – Options &amp;amp; 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,&amp;#160; &lt;font color="#800080" face="Courier New"&gt;&lt;font color="#000000"&gt;setSubViewSoftkeys()&lt;/font&gt;.&lt;/font&gt; &lt;/p&gt;&lt;p&gt;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 &lt;font color="#000000" face="Courier New"&gt;setSubViewSoftkeys()&lt;/font&gt; the function which should be called when the “Back” softkey is pressed.&lt;/p&gt;&lt;p&gt;Having set the softkeys, we ask the &lt;font color="#000000" face="Courier New"&gt;UIManager&lt;/font&gt; to show the detail view.&lt;/p&gt;&lt;h5&gt;Setting common softkeys &amp;amp; remembering where we were&lt;/h5&gt;&lt;p&gt;Before going on to look at the methods used to show the main and about views, let’s take a closer look at &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;setSubViewSoftkeys()&lt;/font&gt;:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_a7MSDSI/AAAAAAAAAIo/6lWRAWzV3iI/s1600-h/Code_114.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Setting softkeys for detail &amp;amp; about views" border="0" alt="Setting softkeys for detail &amp;amp; about views" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_bVpM2-I/AAAAAAAAAIs/QwJA7u0w_ng/Code_11_thumb1.jpg?imgmax=800" width="578" height="236" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;As you can see, the right softkey is always set to “Back” by this function. However, depending on the value of the parameter, &lt;font color="#000000" face="Courier New"&gt;func&lt;/font&gt;, the function that will be called when the user selects the “Back” softkey is different.&lt;/p&gt;&lt;p&gt;The parameter &lt;font color="#000000" face="Courier New"&gt;func&lt;/font&gt; is assumed to be a reference to a function, rather than a reference to a control or view or any other object.&lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;If &lt;font face="Courier New"&gt;func&lt;/font&gt; contains a value (&lt;font face="Courier New"&gt;func&lt;/font&gt; is not &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt;), &lt;font face="Courier New"&gt;func&lt;/font&gt; is used as the second parameter to &lt;font face="Courier New"&gt;menu.setRightSoftkeyLabel()&lt;/font&gt;, meaning that when the “Back” softkey is selected by the user, the function referred to by &lt;font face="Courier New"&gt;func&lt;/font&gt; will be called.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;If &lt;font face="Courier New"&gt;func&lt;/font&gt; is &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt; we pass another the variable &lt;font face="Courier New"&gt;viewFunc&lt;/font&gt; to &lt;font face="Courier New"&gt;menu.setRightSoftkeyLabel()&lt;/font&gt;. So in this case when the “Back” softkey is selected by the user, the function referred to by &lt;font face="Courier New"&gt;viewFunc&lt;/font&gt; will be called.&lt;/font&gt;&lt;/p&gt;&lt;h5&gt;Showing the About view&lt;/h5&gt;&lt;p&gt;So what is &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt;? To answer that, we need to look at how we display the about view, which we do with this code:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_bjmHxUI/AAAAAAAAAIw/iTgnEJFsugw/s1600-h/Code_123.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing the about view" border="0" alt="Showing the about view" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_cOsQUsI/AAAAAAAAAI0/Q3WTrUSb9kE/Code_12_thumb1.jpg?imgmax=800" width="669" height="376" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Earlier in this part of the tutorial while discussing the variables we said&amp;#160; that prior to showing the about view, we will set &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; 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.&lt;/p&gt;&lt;p&gt;First we get a reference to the current view from the &lt;font color="#000000" face="Courier New"&gt;UIManager&lt;/font&gt; object. We then compare that reference to our view variables to determine which view is currently being displayed.&lt;/p&gt;&lt;p&gt;If the current view is either the main view or the detail view, we set &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; to refer to the function used to show that view. However, if the current view is actually the about view, we don’t set &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt;, or, more accurately, we don’t &lt;em&gt;change&lt;/em&gt; the value of &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;In this way we ensure that &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; 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 –&amp;gt; About while already in the about view.&lt;/p&gt;&lt;p&gt;Once &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; is correctly set, it’s a simple matter of putting the appropriate text in the &lt;font color="#000000" face="Courier New"&gt;aboutLabel&lt;/font&gt; control, calling &lt;font color="#000000" face="Courier New"&gt;setSubViewSoftkeys()&lt;/font&gt; to ensure we get “Back” as our right softkey and then asking the &lt;font color="#000000" face="Courier New"&gt;UIManager&lt;/font&gt; object to show the about view. Notice that we don’t pass any parameter to &lt;font color="#000000" face="Courier New"&gt;setSubViewSoftkeys()&lt;/font&gt;. This means that the value of the &lt;font color="#000000" face="Courier New"&gt;func&lt;/font&gt; parameter that &lt;font color="#000000" face="Courier New"&gt;setSubViewSoftkeys()&lt;/font&gt; expects will be &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt;, and the value of &lt;font color="#000000" face="Courier New"&gt;viewFunc&lt;/font&gt; will be used as the function to be called when the right softkey is selected by the user.&lt;/p&gt;&lt;h5&gt;Showing the Main view&lt;/h5&gt;&lt;p&gt;The function, &lt;font color="#000000" face="Courier New"&gt;showMainView()&lt;/font&gt;, should be familiar to you as it is exactly as it was in part 1 of the tutorial:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu_cWQ_CBI/AAAAAAAAAI4/c-o1GeCz_dA/s1600-h/Code_134.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing the main view" border="0" alt="Showing the main view" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_cuKPnrI/AAAAAAAAAI8/9jBxFKKj9wU/Code_13_thumb1.jpg?imgmax=800" width="393" height="202" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h4&gt;Menu Event Handling&lt;/h4&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_c7zaK6I/AAAAAAAAAJA/9tvgAnvvPFA/s1600-h/Code_142.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Menu event handler" border="0" alt="Menu event handler" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu_deH51HI/AAAAAAAAAJE/od7kj1yMrnE/Code_14_thumb1.jpg?imgmax=800" width="414" height="171" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h3&gt;Additional Notes&lt;/h3&gt;&lt;p&gt;WRTKit offers an alternative control that could have removed the need for the new detail view. We could have used a &lt;font color="#000000" face="Courier New"&gt;ContentPanel&lt;/font&gt; object to represent each story. The &lt;font color="#000000" face="Courier New"&gt;ContentPanel&lt;/font&gt; 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 &lt;font color="#000000" face="Courier New"&gt;ContentPanel&lt;/font&gt; controls instead of &lt;font color="#000000" face="Courier New"&gt;NavigationButton&lt;/font&gt; controls we could remove the detail view. &lt;/p&gt;&lt;p&gt;I chose to use &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;NavigationButton&lt;/font&gt;s&lt;/font&gt; 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 &lt;font color="#000000" face="Courier New"&gt;ContentPanel&lt;/font&gt; controls rather than &lt;font color="#000000" face="Courier New"&gt;NavigationButton&lt;/font&gt; controls &amp;amp; remove the detail view.&lt;/p&gt;&lt;p&gt;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 –&amp;gt; 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 &lt;font face="Courier New"&gt;menu&lt;/font&gt; object’s &lt;font face="Courier New"&gt;remove()&lt;/font&gt; function to help you. &lt;/p&gt;&lt;h3&gt;Coming next…&lt;/h3&gt;&lt;p&gt;This concludes the second part of our tutorial on creating a Digg client with Nokia WRT &amp;amp; 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. &lt;/p&gt;&lt;p&gt;In the next part of this tutorial we will get real data into our widget from the internet.&lt;/p&gt;&lt;h2 align="right"&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-3.html"&gt;Part 3&amp;gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-8990841704140872942?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/8990841704140872942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/8990841704140872942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/8990841704140872942'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-2.html' title='Web Runtime Widget Tutorial – Part 2: Structuring the Digg Client UI'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu_QmKre_I/AAAAAAAAAG0/4X73TduoBp4/s72-c/TargetMainView_thumb2.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-1136594237646596810</id><published>2009-12-18T17:42:00.005Z</published><updated>2009-12-18T18:08:49.078Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WRTKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WRT'/><category scheme='http://www.blogger.com/atom/ns#' term='Aptana'/><category scheme='http://www.blogger.com/atom/ns#' term='Digg'/><title type='text'>Web Runtime Widget Tutorial – Part 1: Creating a “Hello World” widget with Nokia WRT &amp; Aptana Studio</title><content type='html'>&lt;h2&gt;&lt;font color="#800080"&gt;&lt;a href="http://cid-41c47f6e8baac5b4.skydrive.live.com/self.aspx/.Public/DiggClient%20-%20Part%201.zip" target="_blank"&gt;Grab the code!&lt;/a&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p&gt;This is part one of five of a tutorial that will take you, step by step, through the process of building a simple Digg client using Nokia WRT and Aptana Studio.&lt;/p&gt;&lt;h3&gt;Getting the tools we need&lt;/h3&gt;&lt;p&gt;One of the good things about developing Nokia WRT widgets is that the necessary tools are free! It is perfectly possible to create WRT widgets using nothing more than your favourite text editor &amp;amp; a free WRT download from Forum Nokia.&lt;/p&gt;&lt;p&gt;However, there are more advanced tools available that will make your development life easier and more productive. Best of all, you can also download them for free!&lt;/p&gt;&lt;p&gt;This tutorial uses Aptana Studio and the Nokia WRT plugin for Aptana Studio. You can download a free copy of Aptana Studio from &lt;a href="http://www.aptana.org"&gt;www.aptana.org&lt;/a&gt;. Once you have Aptana Studio installed and running, you should install the Nokia WRT plugin for Aptana Studio, following the instructions given here: &lt;a title="http://tools.ext.nokia.com/wrt/prod/aptana/plugin/" href="http://tools.ext.nokia.com/wrt/prod/aptana/plugin/"&gt;http://tools.ext.nokia.com/wrt/prod/aptana/plugin/&lt;/a&gt;&amp;#160;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;&lt;em&gt;Note: This tutorial has been put together using Aptana Studio version 1.5.1 &amp;amp; version 2.3.0 of the Nokia WRT plugin for Aptana Studio.&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;&lt;h3&gt;Creating a new WRT project using Aptana Studio&lt;/h3&gt;&lt;p&gt;Now you’ve got the tools you need, we can get started. &lt;/p&gt;&lt;p&gt;From Aptana, select File-&amp;gt;New Project.    &lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-vBab0gI/AAAAAAAAAEI/uvYFA3uR4ZA/s1600-h/1_12.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Create a new project in Aptana Studio" border="0" alt="Create a new project in Aptana Studio" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-vXDKItI/AAAAAAAAAEM/e3us1e6y-yw/1_1_thumb2.jpg?imgmax=800" width="488" height="135" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;In the New Project dialog, select “Nokia Web Runtime (WRT)” –&amp;gt; “New Nokia Web Runtime Widget” wizard and click on the “Next” button.    &lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-v1twLFI/AAAAAAAAAEQ/P-0lVa9CCJI/s1600-h/1_23.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Select a project wizard in Aptana Studio" border="0" alt="Select a project wizard in Aptana Studio" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-wQ0VXyI/AAAAAAAAAEU/AXiQuPJeQ4U/1_2_thumb2.jpg?imgmax=800" width="521" height="499" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;In the New Nokia Widget Project dialog, select the “Basic Widget with WRTKit” template and click on the “Next” button. We’re using the Basic Widget with WRTKit template rather than the version without WRTKit support because we want to take advantage of the ready made UI controls Nokia provides for us in WRTKit, rather than having to create everything from scratch ourselves.    &lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-w-z4IiI/AAAAAAAAAEY/2DnhNqaI-2k/s1600-h/1_33.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Select a template for your project" border="0" alt="Select a template for your project" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-xb0l7NI/AAAAAAAAAEc/a_s-vSOBpZk/1_3_thumb2.jpg?imgmax=800" width="525" height="499" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Give the project a name, for example, “DiggClient”. Either tick the “Use default location” box or select your preferred location for the project files then click on the “Next” button.    &lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-xhMWMhI/AAAAAAAAAEg/kYMz3SHcqvM/s1600-h/1_43.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Define your project name &amp;amp; location" border="0" alt="Define your project name &amp;amp; location" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu-yL6h4GI/AAAAAAAAAEk/JU70_U5dSGw/1_4_thumb2.jpg?imgmax=800" width="547" height="501" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We don’t need to change the Widget name or identifier. Leave the “Enable HomeScreen” box unchecked as we won’t be discussing HomeScreen widgets in this tutorial. &lt;/p&gt;&lt;p&gt;At this point, the template has enough information to create a skeleton project, however, rather than clicking the “Finish” button at this stage we will click the “Next” button instead.    &lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-ynmAd_I/AAAAAAAAAEo/bLd5Qe6VVvI/s1600-h/1_53.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Define your widget&amp;#39;s name &amp;amp; identifier" border="0" alt="Define your widget&amp;#39;s name &amp;amp; identifier" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-zHqvzLI/AAAAAAAAAEs/UZdqel6JM9Y/1_5_thumb2.jpg?imgmax=800" width="549" height="500" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Replace the default names for the main HTML, CSS &amp;amp; JavaScript files with “diggclient” and click the “Finish” button.    &lt;br /&gt;
&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-zuCIpLI/AAAAAAAAAEw/gbtK2YARVKc/s1600-h/1_63.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Define initial file names for your project" border="0" alt="Define initial file names for your project" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-0NVGC2I/AAAAAAAAAE0/Kus43dU9rms/1_6_thumb2.jpg?imgmax=800" width="547" height="501" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;That’s it! Aptana has created a fully functional “Hello World” Web Runtime Widget implementation for you. Before we see our new widget in action, let’s take a look at what Aptana &amp;amp; the Nokia WRT plugin created for you. &lt;/p&gt;&lt;h3&gt;What makes up a WRT Widget project?&lt;/h3&gt;&lt;p&gt;Aptana created a set of files for you when you clicked the Finish button. If you expand the DiggClient project within Aptana you’ll see something similar to the following:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-0UmfIlI/AAAAAAAAAE4/OEX9RdFOYgY/s1600-h/1_74.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Your project file list" border="0" alt="Your project file list" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-01rv_2I/AAAAAAAAAE8/5zeqQQwxPTI/1_7_thumb3.jpg?imgmax=800" width="337" height="349" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;h4&gt;Info.plist &lt;/h4&gt;&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;The first file we’ll look at is Info.plist.&lt;/p&gt;&lt;p&gt;Info.plist is a mandatory part of each and every widget you will develop and resides in the root directory of your widget project. The file itself is an XML dictionary that provides the Web runtime with key information about your widget.&lt;/p&gt;&lt;p&gt;If you examine the contents of the Info.plist file created for you by Aptana, you will see something like the following:&lt;/p&gt;&lt;p&gt;&lt;font color="#800080"&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;&amp;lt;?&lt;/font&gt;&lt;font color="#800000"&gt;xml&lt;/font&gt; &lt;font color="#000080"&gt;version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;?&amp;gt;&lt;/font&gt;         &lt;br /&gt;
&lt;font color="#0000ff"&gt;&amp;lt;!DOCTYPE&lt;/font&gt; &lt;font color="#ff0000"&gt;plist&lt;/font&gt; &lt;font color="#000080"&gt;PUBLIC&lt;/font&gt; &lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;-//Nokia//DTD PLIST 1.0//EN&lt;/font&gt;&lt;font color="#000000"&gt;&amp;quot; &amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;a href="http://www.nokia.com/DTDs/plist-1.0.dtd&amp;quot;"&gt;&lt;font color="#800080"&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;http://www.nokia.com/DTDs/plist-1.0.dtd&lt;/font&gt;&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#800080"&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;&amp;gt;          &lt;br /&gt;
&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;plist&lt;/font&gt; &lt;font color="#ff0000"&gt;version&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;1.0&lt;/font&gt;&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;         &lt;br /&gt;
&lt;/font&gt;&lt;font color="#0000ff" face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;dict&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;DisplayName&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;DiggClient&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;Identifier&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;com.DiggClient.basic.widget&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;Version&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;1.0&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;MainHTML&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;diggclient.html&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;string&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;AllowNetworkAccess&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;true&lt;/font&gt;/&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;&lt;font color="#000000"&gt;MiniViewEnabled&lt;/font&gt;&amp;lt;/&lt;font color="#800000"&gt;key&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;false&lt;/font&gt;/&amp;gt;         &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;/&lt;font color="#800000"&gt;dict&lt;/font&gt;&amp;gt;         &lt;br /&gt;
&amp;lt;/&lt;font color="#800000"&gt;plist&lt;/font&gt;&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Notice that the project name you supplied to the template appears in the Info.plist file as the widget’s &lt;font color="#000000" face="Courier New"&gt;DisplayName&lt;/font&gt;, as does the widget identifier.&lt;/p&gt;&lt;p&gt;Notice also that diggclient.html is defined as the value of the &lt;font color="#000000" face="Courier New"&gt;MainHTML&lt;/font&gt; key. The file referred to by the &lt;font color="#000000" face="Courier New"&gt;MainHTML&lt;/font&gt; key is loaded by the Web runtime when your widget is launched.&lt;/p&gt;&lt;p&gt;Also included in the Info.plist file is the key &lt;font color="#000000" face="Courier New"&gt;Version&lt;/font&gt;, which corresponds to the version number of your widget implementation. Finally, notice that your widget is permitted to access network resources because the &lt;font color="#000000" face="Courier New"&gt;AllowNetworkAccess&lt;/font&gt; key is defined as true, whilst &lt;font color="#000000" face="Courier New"&gt;MiniViewEnabled&lt;/font&gt; is defined as false, which means this widget does not support the HomeScreen.&lt;/p&gt;&lt;h4&gt;diggclient.html &lt;/h4&gt;&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;A widget must contain one and only one HTML file, the name of which is defined by the &lt;font color="#000000" face="Courier New"&gt;MainHTML&lt;/font&gt; key in the Info.plist file. The file can be called &amp;lt;anything&amp;gt;.html; I like to use the name of my widget – diggclient.html in this case. Other people like to use index.html, the choice is yours. As with the Info.plist file, your HTML file is mandatory and must reside in the root directory of your widget project.&lt;/p&gt;&lt;p&gt;Your diggclient.html file should look something like this:&lt;/p&gt;&lt;p&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;&amp;lt;!DOCTYPE &lt;font color="#ff0000"&gt;html&lt;/font&gt; &lt;font color="#000080"&gt;PUBLIC&lt;/font&gt; &lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;/font&gt;&lt;font color="#000000" face="Courier New"&gt;&amp;quot;        &lt;br /&gt;
&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;"&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;&amp;gt;        &lt;br /&gt;
&amp;lt;&lt;font color="#800000"&gt;html&lt;/font&gt; &lt;font color="#ff0000"&gt;xmlns&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;a href="http://www.w3.org/1999/xhtml&amp;quot;"&gt;&lt;font color="#0000ff"&gt;&lt;font face="Courier New"&gt;http://www.w3.org/1999/xhtml&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/a&gt;&lt;font color="#0000ff" face="Courier New"&gt;&amp;gt;      &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;head&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;title&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;title&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;meta&lt;/font&gt; &lt;font color="#ff0000"&gt;http-equiv&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;Content-Type&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;content&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/html; charset=UTF-8&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; /&amp;gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/javascript&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;src&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;diggclient.js&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;script&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/javascript&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;src&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;WRTKit/WRTKit.js&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;&amp;lt;/&lt;font color="#800000"&gt;script&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;link&lt;/font&gt; &lt;font color="#ff0000"&gt;rel&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;stylesheet&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;href&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;diggclient.css&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;type&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;text/css&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;META&lt;/font&gt; &lt;font color="#ff0000"&gt;NAME&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;Generator&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; &lt;font color="#ff0000"&gt;CONTENT&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;&lt;/font&gt;Nokia WRT plug-in for Aptana Studio 2.3.0&lt;font color="#000000"&gt;&amp;quot;&lt;/font&gt; /&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;/&lt;font color="#800000"&gt;head&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;&lt;font color="#800000"&gt;body&lt;/font&gt; &lt;font color="#ff0000"&gt;onload&lt;/font&gt;&lt;font color="#000000"&gt;=&amp;quot;init()&amp;quot;&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;/&lt;font color="#800000"&gt;body&lt;/font&gt;&amp;gt;       &lt;br /&gt;
&amp;lt;/&lt;font color="#800000"&gt;html&lt;/font&gt;&amp;gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Because our widget is using the WRTKit for it’s UI elements we don’t require much HTML. The example file shown above is very typical of WRTKit based WRT widgets. Almost all of the real work is done by JavaScript in a WRTKit based widget. &lt;/p&gt;&lt;p&gt;What we do need to do in HTML is define a basic document structure for your widget, referring to one or more JavaScript files within the &lt;font color="#0000ff" face="Courier New"&gt;&amp;lt;&lt;font color="#800000"&gt;head&lt;/font&gt;&amp;gt;&lt;/font&gt; section of your HTML document. Usually it will be these referenced JavaScript files that contain the logic that implements your widget. In the case of our tutorial widget, we refer to diggclient.js, which is our widget’s own JavaScript file and WRTKit.js which is the entry point for the Nokia WRTKit UI library.&lt;/p&gt;&lt;p&gt;To define the layout &amp;amp; appearance of your widget’s UI elements, you are encouraged to make use of cascading-style sheets, so our HTML file links to diggclient.css, our widget’s own cascading-style sheet. &lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;font color="#000000"&gt;Note: If you open diggclient.css, you will see the file is currently empty; the layout &amp;amp; appearance of our widget is being handled by WRTKit controls.&lt;/font&gt; &lt;/em&gt;&lt;/p&gt;&lt;p&gt;Technically there is nothing to stop you adding all of your CSS definitions and JavaScript code to your widget’s HTML file, but it is easier to manage your projects if you separate the HTML, CSS &amp;amp; JavaScript from each other. &lt;/p&gt;&lt;p&gt;It should also be noted that it is perfectly possible to create a WRT widget entirely in HTML without using CSS or JavaScript. Such widgets tend not to be very visually appealing as they can’t make use of the WRTKit or any other JavaScript libraries, however it is possible to create such widgets and therefore the usage of JavaScript and CSS files is optional rather than mandatory.&lt;/p&gt;&lt;p&gt;Both your JavaScript &amp;amp; CSS files, if present, can reside in any directory within your widget project, including the root directory.&lt;/p&gt;&lt;p&gt;Our widget does use JavaScript and the function called when the widget is loaded is given by the value of the &lt;font color="#ff0000" face="Courier New"&gt;onload&lt;/font&gt; attribute of the &lt;font color="#800000" face="Courier New"&gt;body&lt;/font&gt; element. So our widget calls the JavaScript function, &lt;font color="#000000" face="Courier New"&gt;init()&lt;/font&gt; on loading.&lt;/p&gt;&lt;h4&gt;Icon.png &lt;/h4&gt;&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;/u&gt;&lt;/strong&gt;Notice that Aptana has included an Icon.png file in the created project files. An icon is optional.&lt;/p&gt;&lt;p&gt;If you do include an icon for your widget, it must reside in the root directory of your widget project and must be in PNG format. The recommended resolution for an icon is 88 by 88 pixels. The icon will be scaled by the runtime depending on the device on which the widget is running.&lt;/p&gt;&lt;p&gt;If you do not include an icon for your widget, the runtime will provide the default S60 application icon to represent your widget in the device shell.&lt;/p&gt;&lt;h4&gt;diggclient.js&amp;#160; &lt;/h4&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;diggclient.js is where the bulk of our widget’s implementation is to be found. But rather than examine the file in detail now, let’s come back to it after you see your widget come to life. &lt;/p&gt;&lt;h3&gt;Seeing is believing&lt;/h3&gt;&lt;p&gt;To see your widget in action, simply double click on diggclient.html in the list of files in your Aptana project. Aptana will open the file and display the contents in the main editor pane.&lt;/p&gt;&lt;p&gt;At the bottom of the main pane in Aptana Studio, you should see two tabs – one labelled “Source”, which is the tab opened by default, and another tab labelled “Nokia Web Runtime (WRT)”. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-1P5gZDI/AAAAAAAAAFA/hlULi3a8Yrc/s1600-h/Tabs2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Source &amp;amp; Nokia Web Runtime tabs" border="0" alt="Source &amp;amp; Nokia Web Runtime tabs" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-1qPSPvI/AAAAAAAAAFE/JR7WTAGxEhI/Tabs_thumb.png?imgmax=800" width="319" height="163" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;em&gt;Note: The “Nokia Web Runtime (WRT)” tab is only visible when your project’s HTML file is open and focussed in Aptana.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Select the “Nokia Web Runtime (WRT)” tab and you will see a fully interactive preview of your widget running in Aptana Studio. If all is well, you should see something similar to this:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu-18bKYXI/AAAAAAAAAFI/WFWMTkOD0lA/s1600-h/1_82.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Running widget" border="0" alt="Running widget" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-2XKX72I/AAAAAAAAAFM/J2K16kSX9w4/1_8_thumb1.jpg?imgmax=800" width="422" height="534" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Play around with your widget. Enter your name in the text box and click the “Say Hello!” button to receive a predictable greeting:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-2mDOesI/AAAAAAAAAFQ/kDh0GPCEVM0/s1600-h/1_92.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Hello Widget" border="0" alt="Hello Widget" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-29moDOI/AAAAAAAAAFU/4FuTTYhrsCk/1_9_thumb1.jpg?imgmax=800" width="363" height="526" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Notice that the Options menu is functional, giving an example of a simple About notice and an option to exit the widget.&lt;/p&gt;&lt;p&gt;Not bad for less than 15 lines of HTML! But of course, by now you realise the real work is being done by the as yet unseen JavaScript code.&lt;/p&gt;&lt;h3&gt;Show me the script!&lt;/h3&gt;&lt;p&gt;At the start of the script, we declare some JavaScript variables which will be used to represent parts of our widget’s UI:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-3YAquAI/AAAAAAAAAFY/RxQGP8plzaw/s1600-h/Code_161.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Variables" border="0" alt="Variables" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-3slUuiI/AAAAAAAAAFc/UL0ijsjDk8Y/Code_1_thumb6.jpg?imgmax=800" width="678" height="307" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;This small block of code shows that we initially declare variables to represent various UI objects: &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;uiManager&lt;/font&gt;, &lt;font face="Courier New"&gt;mainView&lt;/font&gt;, &lt;font face="Courier New"&gt;helloButton&lt;/font&gt;, &lt;/font&gt;&lt;font color="#800080" face="Courier New"&gt;&lt;font color="#000000"&gt;nameField&lt;/font&gt; &lt;/font&gt;and &lt;font color="#000000" face="Courier New"&gt;aboutLabel&lt;/font&gt;.&amp;#160; Finally, we declare &lt;font color="#000000" face="Courier New"&gt;MENU_ITEM_ABOUT&lt;/font&gt;, which defines the position of the “About” option in the widget’s option menu. &lt;/p&gt;&lt;p&gt;&lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;uiManager&lt;/font&gt;, &lt;font face="Courier New"&gt;mainView&lt;/font&gt;, &lt;font face="Courier New"&gt;helloButton&lt;/font&gt;, &lt;font face="Courier New"&gt;nameField&lt;/font&gt;&lt;/font&gt; and &lt;font color="#000000" face="Courier New"&gt;aboutLabel&lt;/font&gt; will all become WRTKit UI objects. The &lt;font color="#000000" face="Courier New"&gt;uiManager&lt;/font&gt; will become the root element in a hierarchy of WRTKit objects in our widget; one or other of the &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt; or &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt; will be set as the current view on the &lt;font color="#000000" face="Courier New"&gt;uiManager&lt;/font&gt; object at all times. The &lt;font color="#000000" face="Courier New"&gt;helloButton&lt;/font&gt; &amp;amp; &lt;font color="#000000" face="Courier New"&gt;nameField&lt;/font&gt; will be controls in the &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt; and &lt;font color="#000000" face="Courier New"&gt;aboutLabel&lt;/font&gt; will be a control in the &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt;.&lt;/p&gt;&lt;strong&gt;   &lt;h4&gt;Implicit variable declaration &lt;/h4&gt;&lt;/strong&gt;  &lt;p&gt;“What &lt;font face="Courier New"&gt;aboutView&lt;/font&gt;?” you might be asking. Welcome to JavaScript! Whilst it’s certainly very good practice to declare your variables before use – and as a seasoned C++ &amp;amp; C# coder, I can’t think of doing anything else - JavaScript will declare variables at the point of first use, which is illustrated nicely by (a bug in) the wizard that generated the code. There is no variable called &lt;font face="Courier New"&gt;aboutView&lt;/font&gt; defined here! Yet code later in the script happily creates a WRTKit &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; object and assigns it to &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt; without complaint. &lt;/p&gt;&lt;p&gt;Although it’s not essential at this stage, I recommend you add the following line:&lt;/p&gt;&lt;p align="center"&gt;&lt;font color="#000000" face="Courier New"&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt; aboutView;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;to the generated JavaScript, immediately after the declaration of    &lt;br /&gt;
&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;var&lt;/font&gt; mainView; &lt;/font&gt;&lt;/p&gt;&lt;font face="Courier New"&gt;&lt;font face="Georgia"&gt;     &lt;p&gt;Declaring your variables up front, before you use them, gives you the advantage of controlling your variable’s scope, although to be fair, all of the variables declared so far are global anyway. The wizard that generated the code for us gets away with not declaring &lt;font face="Courier New"&gt;aboutView&lt;/font&gt; explicitly simply because this widget is trivial and there are no issues with scope caused by creating the &lt;font face="Courier New"&gt;aboutView&lt;/font&gt; variable at the point of first use.&lt;/p&gt;&lt;/font&gt;    &lt;p&gt;&lt;font face="Georgia"&gt;Right, let’s do something with these variables…&lt;/font&gt;&lt;/p&gt;&lt;/font&gt;  &lt;h4&gt;Our “entry point” &lt;/h4&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;Recall from the discussion of diggclient.html, that we set the &lt;font color="#ff0000" face="Courier New"&gt;onload&lt;/font&gt; attribute of our HTML document’s &lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#800000"&gt;body&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt; tag to &lt;font color="#000000" face="Courier New"&gt;“init()”&lt;/font&gt;, meaning that this is the JavaScript function that will be called when our HTML document is loaded. We’ll take the &lt;font color="#000000" face="Courier New"&gt;init()&lt;/font&gt; function piece by piece. To kick the function off, we have the following:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-30IbIqI/AAAAAAAAAFg/O9q6DP04t1I/s1600-h/Code_22.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="First part of init() funtion" border="0" alt="First part of init() funtion" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-4X_jKwI/AAAAAAAAAFk/uMDwZ0c3Wng/Code_2_thumb2.jpg?imgmax=800" width="565" height="138" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The first thing we do in our &lt;font color="#000000" face="Courier New"&gt;init()&lt;/font&gt; function is set up our options menu. We do this by creating a &lt;font color="#000000" face="Courier New"&gt;MenuItem&lt;/font&gt; object, passing the string to represent this item in the menu, together with the position in the menu this item is to occupy, to the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;MenuItem&lt;/font&gt;’s&lt;/font&gt; constructor. Next, we set the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;MenuItem&lt;/font&gt;’s&lt;/font&gt; &lt;font color="#000000" face="Courier New"&gt;onSelect&lt;/font&gt; property to point to a function that will be called when this menu item is selected. In this case, we want the function &lt;font color="#000000" face="Courier New"&gt;menuItemSelected()&lt;/font&gt; to be called when our menu item is selected. The last thing we do to prepare the menu is append our &lt;font color="#000000" face="Courier New"&gt;MenuItem&lt;/font&gt; object to the widget’s menu. &lt;/p&gt;&lt;p&gt;Notice that this last step shows another benefit of explicitly declaring your variables; we haven’t declared anything called “&lt;font color="#000000" face="Courier New"&gt;menu&lt;/font&gt;” anywhere, so JavaScript is just going to create it for us, yes? No! In this case, &lt;font color="#000000" face="Courier New"&gt;menu&lt;/font&gt; is actually an object provided by WRT to each widget. In fact, WRT provides a set of objects to each widget, the most fundamental of which are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;font face="Courier New"&gt;widget&lt;/font&gt; – provides a set of methods &amp;amp; properties that apply globally to your widget as a whole. Can be accessed through the keyword &lt;font face="Courier New"&gt;widget&lt;/font&gt;. &lt;/li&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;menu&lt;/font&gt; – provides APIs to manipulate the options menu &amp;amp; softkeys of your widget. Can be accessed through the keyword &lt;font face="Courier New"&gt;menu&lt;/font&gt;. Note that the options menu is always associated with the left softkey and your code cannot change this – one implication of this is that the left softkey text is always “Options” in English, or the equivalent in the current UI language of the device. An option to Exit the widget is always added by WRT to the set of menu items your widget defines. &lt;/li&gt;
&lt;li&gt;&lt;font face="Courier New"&gt;MenuItem&lt;/font&gt; – provides APIs to represent and manipulate the items in a widget’s menu. &lt;font face="Courier New"&gt;MenuItem&lt;/font&gt; is a reference type and objects of type &lt;font face="Courier New"&gt;MenuItem&lt;/font&gt; are always created by using the &lt;font color="#000080" face="Courier New"&gt;new&lt;/font&gt; operator. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Next we enable tab navigation and show the softkeys – but only if the widget is running within the WRT:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-4tImWKI/AAAAAAAAAFo/xvT_q-mdaw0/s1600-h/Code_33.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Selecting navigation mode and showing softkeys" border="0" alt="Selecting navigation mode and showing softkeys" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-5NpIjzI/AAAAAAAAAFs/SBxfx2nxiyg/Code_3_thumb2.jpg?imgmax=800" width="432" height="137" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;By default, cursor mode navigation is enabled, but we don’t want this for our widget so we call &lt;font color="#800080"&gt;&lt;font face="Courier New"&gt;&lt;font color="#000000"&gt;setNavigationEnabled(&lt;/font&gt;false&lt;font color="#000000"&gt;)&lt;/font&gt;&lt;/font&gt;&lt;/font&gt; to enable tab navigation instead. Some advanced widgets would use cursor navigation, which relies on the use of an onscreen pointer, similar to the S60 browser. Tab navigation is typically used by simpler widgets that only have a few UI elements, usually arranged in a vertical stack. Note that your widget can change between tab and cursor navigation at any time as required.&lt;/p&gt;&lt;p&gt;Why do we need a WRT environment check? We’re creating a WRT widget aren’t we? Well, yes we are, but the brains of your widget are just JavaScript functions. This JavaScript can be run in a variety of environments, such as your PC’s browser or on your phone. Also, in principle, some or all of the code that makes up your widget may come from elsewhere – a website, a widget from another platform, a JavaScript library. Alternatively, you may want to reuse the code you write to power your widget in another project. To support these scenarios – and to aid debugging - it’s good to ensure you’re in the WRT environment before you try and use WRT specific features.&lt;/p&gt;&lt;p&gt;Now it’s time to create some UI objects:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-5Re3MII/AAAAAAAAAFw/m5BlFG5Gj0c/s1600-h/Code_43.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Creating WRTKit objects" border="0" alt="Creating WRTKit objects" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-5uTZWsI/AAAAAAAAAF0/SDAtPV-pNzo/Code_4_thumb2.jpg?imgmax=800" width="445" height="173" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;When we set our widget project up, we selected the Basic Widget with WRTKit support template. We did this so that we could take advantage of the richer UI controls provided by Nokia in the WRTKit. In order to use the WRTKit, we need to create a &lt;font color="#000000" face="Courier New"&gt;UIManager&lt;/font&gt; object which will manage the presentation of our widget’s views and manage resources for us.&lt;/p&gt;&lt;p&gt;Having created the WRTKit &lt;font color="#000000" face="Courier New"&gt;UIManager&lt;/font&gt; object, we create two views – &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt; and &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt;. Notice that both views are created as &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; objects. &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; is one of the UI controls provided by the WRTKit which arranges controls added to the list control as a vertical stack. Two parameters are passed to the &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; constructor, both of which are strings: an id that uniquely identifies the resulting list view and a caption that occupies the area at the top of the list. One reason to specify an id for an object is to be able to identify a specific object as the source of an event in an event handler. However, if you do not need to identify a given object in an event handler, you can set the id to null. The caption can be an empty string if you want to have a caption area without any content, or null if you want a list view without a caption area.&lt;/p&gt;&lt;p&gt;At this point, we’ve created a UI manager and two empty views. To add some content to our views we do the following:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-6I2KmxI/AAAAAAAAAF4/dEKZsyE6yt0/s1600-h/Code_54.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Creating &amp;amp; initialising WRTKit UI controls" border="0" alt="Creating &amp;amp; initialising WRTKit UI controls" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-6cIyeeI/AAAAAAAAAF8/KDNrkJ_IIF4/Code_5_thumb3.jpg?imgmax=800" width="617" height="239" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Here we create a &lt;font color="#000000" face="Courier New"&gt;TextField&lt;/font&gt; object which allows the user to enter some text, with a prompt of “Enter your name”. We then add the &lt;font color="#000000" face="Courier New"&gt;TextField&lt;/font&gt; to our &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt;. Recalling that &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt; is a &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; control and that &lt;font color="#000000" face="Courier New"&gt;ListView&lt;/font&gt; controls present their content as a vertical stack, you can see that the text “Enter your name” will appear at the top of our view, beneath the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;mainView&lt;/font&gt;’s&lt;/font&gt; caption.&lt;/p&gt;&lt;p&gt;Next we add a &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; control to the &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt;. A &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; is a basic button control that allows us to attach an event handler (or &lt;font color="#000000" face="Courier New"&gt;EventListener&lt;/font&gt; in WRTKit language) which will be called when the button is pressed. When we call the &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; constructor we again pass in an id (&lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt;) and also a string which is used as the label on the face of the button. &lt;/p&gt;&lt;p&gt;We bind an event handler to the &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; control by calling &lt;font color="#000000" face="Courier New"&gt;addEventListener()&lt;/font&gt; on the &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; object, passing the name of the event that we want to handle (&lt;font color="#008000"&gt;“&lt;font face="Courier New"&gt;ActionPerformed&lt;/font&gt;”&lt;/font&gt;) and the name of the function we want called when the event occurs (&lt;font color="#000000" face="Courier New"&gt;helloButtonClicked()&lt;/font&gt;). If you are wondering where the event name &lt;font color="#008000"&gt;“&lt;font face="Courier New"&gt;ActionPerformed&lt;/font&gt;”&lt;/font&gt; comes from, it is defined as an event by the abstract class &lt;font color="#000000" face="Courier New"&gt;ActionControl&lt;/font&gt;, from which &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; is derived.&lt;/p&gt;&lt;p&gt;The about view is trivial and consists simply of a label control that will show some information about the widget to the user. So we create an instance of the WRTKit’s &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; class and add this to our &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;All that remains to complete the construction and initialisation of our widget is simply to tell the &lt;font color="#000000" face="Courier New"&gt;uiManager&lt;/font&gt; object which view to use initially:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-601PKJI/AAAAAAAAAGA/HOxxmgchQKE/s1600-h/Code_74.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing the initial view" border="0" alt="Showing the initial view" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-7Ava7jI/AAAAAAAAAGE/UWDw0nGUv3o/Code_7_thumb2.jpg?imgmax=800" width="302" height="85" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;strong&gt;   &lt;h4&gt;Button Event Handler &amp;amp; Notifications&lt;/h4&gt;&lt;/strong&gt;  &lt;p&gt;Let’s look now at what happens when the user clicks our widget’s “Say Hello!” button. We already know that we’ve configured the &lt;font color="#000000" face="Courier New"&gt;FormButton&lt;/font&gt; control to call a function called &lt;font color="#000000" face="Courier New"&gt;helloButtonClicked()&lt;/font&gt; when the button is pushed. Here is the code of that function:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-7Ud-QcI/AAAAAAAAAGI/z3ssEExmEuk/s1600-h/Code_84.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Button event handler" border="0" alt="Button event handler" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-79S8q_I/AAAAAAAAAGM/v0hMvGmXDFU/Code_8_thumb2.jpg?imgmax=800" width="686" height="188" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;In order to present a popup notification to the user, the first thing we need to do is get the current text that the user has entered in the text field control, which we do by assigning the result of calling the &lt;font color="#000000" face="Courier New"&gt;getText()&lt;/font&gt; method on &lt;font color="#000000" face="Courier New"&gt;nameField&lt;/font&gt; to a variable.&lt;/p&gt;&lt;p&gt;We then call the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;uiManager&lt;/font&gt;’s&lt;/font&gt; &lt;font color="#000000" face="Courier New"&gt;showNotification(…)&lt;/font&gt; method to present a notification dialog to the user. If the &lt;font color="#000000" face="Courier New"&gt;nameField&lt;/font&gt; is empty, we present a warning note, asking the user to enter their name. If the &lt;font color="#000000" face="Courier New"&gt;nameField&lt;/font&gt; contains at least one character, we present an info note, greeting the user to the world of WRT widgets. In each case, three parameters are passed to &lt;font color="#000000" face="Courier New"&gt;showNotification(…)&lt;/font&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;duration (in milliseconds) to show the note &lt;/li&gt;
&lt;li&gt;type of note (which influences the icon shown in the note dialog) &lt;/li&gt;
&lt;li&gt;message to be shown to the user &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;When the duration for which the note is to be shown expires, the note is removed from the screen and destroyed by the &lt;font color="#000000" face="Courier New"&gt;uiManager&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;Notice that we make no use of the event parameter passed to our event handler. There is no need in this simple case, but we will look again at event handlers and the information passed to them later in this tutorial.&lt;/p&gt;&lt;strong&gt;   &lt;h4&gt;Menu Event Handling&lt;/h4&gt;&lt;/strong&gt;  &lt;p&gt;In our &lt;font color="#000000" face="Courier New"&gt;init()&lt;/font&gt; method, we set &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;aboutMenuItem&lt;/font&gt;’s&lt;/font&gt; &lt;font color="#000000" face="Courier New"&gt;onSelect&lt;/font&gt; property to refer to the function &lt;font color="#000000" face="Courier New"&gt;menuItemSelected()&lt;/font&gt;. Whenever “About” is selected from our Options menu, the function &lt;font color="#000000" face="Courier New"&gt;menuItemSelected()&lt;/font&gt; will be called. &lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_9NKlMCdyKxQ/Syu-8XCXWfI/AAAAAAAAAGQ/jbuKjwpU9Sw/s1600-h/Code_94.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Menu event handler" border="0" alt="Menu event handler" src="http://lh6.ggpht.com/_9NKlMCdyKxQ/Syu-8tSI7jI/AAAAAAAAAGU/Yq-eqjv4tM8/Code_9_thumb2.jpg?imgmax=800" width="399" height="149" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;You can use the same function to handle the selection of several or all of your menu options, which is why WRT passes an integer id to your function. This id is the position of the selected item in the menu. Recalling that the position of our “About” option is defined by the variable &lt;font color="#000000" face="Courier New"&gt;MENU_ITEM_ABOUT&lt;/font&gt;, you can see that whenever the user selects “About” from the Options menu, the function &lt;font color="#000000" face="Courier New"&gt;showAboutView()&lt;/font&gt; is ultimately called.&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu-809q0hI/AAAAAAAAAGY/g-RlWlG_l18/s1600-h/Code_104.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Handling About option" border="0" alt="Handling About option" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-9VsCOWI/AAAAAAAAAGc/rtGQ8elhFuw/Code_10_thumb2.jpg?imgmax=800" width="737" height="135" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Courier New"&gt;showAboutView()&lt;/font&gt; sets the textual content of the &lt;font color="#000000" face="Courier New"&gt;aboutLabel&lt;/font&gt; to a message about the software that is included in your widget by passing the message as a string to the &lt;font color="#000000" face="Courier New"&gt;setText()&lt;/font&gt; function of the &lt;font color="#000000" face="Courier New"&gt;Label&lt;/font&gt; object.&lt;/p&gt;&lt;p&gt;Before we can display the &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt;, we need to modify the softkeys in use. We’re only really concerned about the right softkey because if we leave it as “Exit”, there will be no way for the user to return to our widget’s main view. We change the softkeys for the about view by calling another function, &lt;font color="#000000" face="Courier New"&gt;setAboutViewSoftkeys()&lt;/font&gt;.&lt;/p&gt;&lt;p&gt;Now we can display our about view to the user by calling the &lt;font color="#000000"&gt;&lt;font face="Courier New"&gt;uiManager&lt;/font&gt;’s&lt;/font&gt; &lt;font color="#000000" face="Courier New"&gt;setView()&lt;/font&gt; function, passing the &lt;font color="#000000" face="Courier New"&gt;aboutView&lt;/font&gt; object as the parameter. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;strong&gt;   &lt;h4&gt;Changing the Softkeys and Returning to the Main view&lt;/h4&gt;&lt;/strong&gt;  &lt;p&gt;As noted above, we need to change the right softkey used in the About view to provide a mechanism for the user to return to the main view. We could have achieved this aim by modifying the options menu – perhaps by removing the About option and replacing it with a Main option – but this wouldn’t be a very intuitive solution.&lt;/p&gt;&lt;p&gt;The way we will achieve this is to change the right softkey from “Exit” to “Ok”. At the same time, we will assign a handler function to implement the logic of switching back to the main view when the “Ok” softkey is selected by the user.&amp;#160; The code to do this is as follows:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu-9tuLJOI/AAAAAAAAAGg/gx2E7QtxGN8/s1600-h/Code_114.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Setting softkeys for About view" border="0" alt="Setting softkeys for About view" src="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-97fMehI/AAAAAAAAAGk/YDeT1_1C_O8/Code_11_thumb2.jpg?imgmax=800" width="516" height="135" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;As you can see from the code, the function we call when the user selects our “Ok” softkey is &lt;font color="#000000" face="Courier New"&gt;showMainView()&lt;/font&gt;:&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu--RF2vfI/AAAAAAAAAGo/x2hOnBMtvk0/s1600-h/Code_124.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing the main view again" border="0" alt="Showing the main view again" src="http://lh5.ggpht.com/_9NKlMCdyKxQ/Syu--kEfbmI/AAAAAAAAAGs/wpxclNMXXuc/Code_12_thumb2.jpg?imgmax=800" width="398" height="187" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Courier New"&gt;showMainView()&lt;/font&gt; resets the right softkey to “Exit” by clearing the text currently assigned to the right softkey and setting the handler function to &lt;font color="#800080" face="Courier New"&gt;null&lt;/font&gt;. WRT notices this and supplies the “Exit” text and an appropriate handler function automatically.&lt;/p&gt;&lt;p&gt;Then all we need to do to return to our widget’s main view is tell the &lt;font color="#000000" face="Courier New"&gt;uiManager&lt;/font&gt; to show our &lt;font color="#000000" face="Courier New"&gt;mainView&lt;/font&gt; again.&lt;/p&gt;&lt;strong&gt;   &lt;h3&gt;Coming next…&lt;/h3&gt;&lt;/strong&gt;  &lt;p&gt;This concludes the first part of our tutorial on creating a Digg client with Nokia WRT &amp;amp; Aptana Studio. Clearly we’ve not done very much yet, indeed, if we’re honest, we’ve done close to nothing – Aptana &amp;amp; the Nokia WRT project wizard has done all the work so far.&amp;#160; &lt;/p&gt;&lt;p&gt;In the next part of this tutorial we will start taking some steps towards turning our Hello World widget into a Digg client.&lt;/p&gt;&lt;h2 align="right"&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-2.html"&gt;&lt;br /&gt;
Part 2&amp;gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-1136594237646596810?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/1136594237646596810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1136594237646596810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1136594237646596810'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-1.html' title='Web Runtime Widget Tutorial – Part 1: Creating a “Hello World” widget with Nokia WRT &amp;amp; Aptana Studio'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_9NKlMCdyKxQ/Syu-vXDKItI/AAAAAAAAAEM/e3us1e6y-yw/s72-c/1_1_thumb2.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-1516833289813832851</id><published>2009-12-18T17:40:00.003Z</published><updated>2009-12-18T18:02:19.764Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WRTKit'/><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='WRT'/><category scheme='http://www.blogger.com/atom/ns#' term='Aptana'/><category scheme='http://www.blogger.com/atom/ns#' term='Digg'/><title type='text'>Web Runtime Widget Tutorial: Building a Digg Search Client</title><content type='html'>&lt;h2&gt;&lt;font color="#800080"&gt;&lt;a href="http://cid-41c47f6e8baac5b4.skydrive.live.com/self.aspx/.Public/DiggClient%20-%20Part%205.zip" target="_blank"&gt;Grab the code!&lt;/a&gt;&lt;/font&gt;&lt;/h2&gt;&lt;p&gt;When I started looking at Nokia’s Web Runtime (WRT) I was pleasantly surprised by how easy it was to get a functional UI up and running, particularly when compared to native S60 development. However, there didn’t seem to be many end-to-end tutorials that took you through the steps needed to create a widget. &lt;/p&gt;&lt;p&gt;Sometime ago, when I was first getting into Silverlight development, I came across &lt;a href="http://weblogs.asp.net/scottgu/pages/silverlight-2-end-to-end-tutorial-building-a-digg-search-client.aspx" target="_blank"&gt;Scott Guthrie’s 8-part tutorial&lt;/a&gt; which walks the reader through all of the tasks needed to create a Digg Search Client using Silverlight 2 and Visual Studio 2008. I thought it might be an interesting exercise to create an equivalent tutorial using the Nokia WRT &amp;amp; Aptana Studio.&lt;/p&gt;&lt;p&gt;The next five posts in this blog will attempt to give you a taste of how easily and quickly you can create something useful with WRT. &lt;/p&gt;&lt;p&gt;The five parts of the tutorial are listed below.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-1.html"&gt;Part 1: Creating a “Hello World” widget with Nokia WRT &amp;amp; Aptana Studio&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-2.html"&gt;Part 2: Structuring the Digg Client UI&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-3.html"&gt;Part 3: Requesting data from Digg and displaying the results&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-4.html"&gt;Part 4: Refining the UI&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-5.html"&gt;Part 5: Installing the widget on your phone&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The code for each part of the tutorial can be found by following the “Grab the code!” link at the top of each post. Note that the code link in this post and in part 5 is for the completed widget, included the packaged widget, ready for deployment to your phone. The link in part 4 has the complete code, but does not include the packaged widget.&lt;/p&gt;&lt;h2 align="right"&gt;&lt;a href="http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-part-1.html"&gt;Part 1&amp;gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-1516833289813832851?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/1516833289813832851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-building.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1516833289813832851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1516833289813832851'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/12/web-runtime-widget-tutorial-building.html' title='Web Runtime Widget Tutorial: Building a Digg Search Client'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-5977952691859628623</id><published>2009-11-24T22:07:00.001Z</published><updated>2009-11-24T22:07:42.476Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='XP mode'/><title type='text'>Windows 7 – Windows XP Mode: Part II</title><content type='html'>&lt;p&gt;In the first part of my post on Windows XP Mode I noted that whilst my laptop’s processor supports hardware assisted virtualisation, the BIOS on my Acer laptop offers no option to enable this. This is a problem because Microsoft Virtual PC only runs on hardware that supports hardware assisted virtualisation.&lt;/p&gt;  &lt;p&gt;I was hopeful that I would be able to set up a virtual XP machine using the Windows XP Mode download from Microsoft and VirtualBox.&lt;/p&gt;  &lt;p&gt;Indeed I was. It worked well. Until I tried to activate the virtual copy of Windows XP. XP Mode includes a license key as part of the installation, however, this key cannot be used to activate Windows XP using the conventional activation mechanism. Attempting online activation using the supplied key fails.&lt;/p&gt;  &lt;p&gt;When activation fails, there is an option to activate by telephone using an auto-generated 60-digit installation identifier. Unfortunately, the telephone option declares that there is an error in this identifier and declines to supply a key to activate Windows XP. Worse still, at least in the UK, the telephone option is fully automated with no option to speak to a person to find a resolution.&lt;/p&gt;  &lt;p&gt;Thinking about this, I’m not surprised by the problems in activating the XP image included in Windows XP Mode. I’m quite sure Microsoft have checks in place to ensure that XP Mode hasn’t provided a source of freely downloadable, licensed XP images.&lt;/p&gt;  &lt;p&gt;I assume there is some interaction between Windows Virtual PC and XP Mode which handles the activation process and ensures that the copy of XP supplied as part of XP Mode is correctly activated and licensed. &lt;/p&gt;  &lt;p&gt;At the very least, I assume Virtual PC ensures it is running on an appropriate edition of Windows 7 and uses this information to assist in the activation of XP Mode’s XP image.&lt;/p&gt;  &lt;p&gt;I’ve read the EULA for XP Mode and as far as I can see it is perfectly legal and valid to use XP Mode with alternative virtualisation solutions. Sadly this seems not to be supported in practice.&lt;/p&gt;  &lt;p&gt;In summary, it seems from my experiments that the only way to use XP Mode on Windows 7 is to use the officially supported combination of XP Mode &amp;amp; Virtual PC on a machine that supports hardware assisted virtualisation. If anyone knows differently, I would like to hear from you.&lt;/p&gt;  &lt;h3&gt;Next steps…&lt;/h3&gt;  &lt;p&gt;Time to take a break from getting XP Mode to run on my Acer laptop and reflect on just over a month of life with Windows 7…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-5977952691859628623?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/5977952691859628623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/11/windows-7-windows-xp-mode-part-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/5977952691859628623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/5977952691859628623'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/11/windows-7-windows-xp-mode-part-ii.html' title='Windows 7 – Windows XP Mode: Part II'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-4000839563603124371</id><published>2009-11-19T19:08:00.007Z</published><updated>2009-12-18T18:14:49.700Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><category scheme='http://www.blogger.com/atom/ns#' term='Acer'/><category scheme='http://www.blogger.com/atom/ns#' term='symbian'/><category scheme='http://www.blogger.com/atom/ns#' term='XP mode'/><title type='text'>Windows 7 – Windows XP Mode: Part I</title><content type='html'>One reason I was looking forward to upgrading from Windows Vista to Windows 7 was the prospect of Windows XP mode. I hadn’t actually tested this while running the Windows 7 release candidate so I didn’t know what to expect.&lt;br /&gt;
&lt;br /&gt;
Pointing my browser at &lt;a href="http://www.windows.com/business/downloads"&gt;www.windows.com/business/downloads&lt;/a&gt; told me that I needed to download Windows Virtual PC and Windows XP Mode separately. Downloading and installing these two packages would allow me to use Windows XP as a virtual machine on my Windows 7 computer. I’ve used the open source virtualisation solution &lt;a href="http://www.virtualbox.org/" target="_blank"&gt;VirtualBox&lt;/a&gt; for a few years to enable me to run Ubuntu as a guest OS on my Windows XP &amp;amp; Vista environments. So the idea of using a virtual machine to provide an XP environment on my Windows 7 machine made sense to me.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, my attempts at installing XP mode came to an abrupt halt at the hands of a little tool called the Microsoft Hardware-Assisted Virtualization Detection Tool. It turns out that &lt;a href="http://go.microsoft.com/fwlink/?LinkId=163321" target="_blank"&gt;“Windows Virtual PC requires processors capable of hardware-assisted virtualization with AMD-V, Intel VT or VIA VT turned on in the BIOS”&lt;/a&gt;. In my case, the tool says my processor is not capable.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Want to run XP Mode? Be wary of Acer* laptops!&lt;/h3&gt;&lt;br /&gt;
This can’t be right! My processor supports virtualisation. I’ve checked. Twice. I might have paid for a machine with a processor that supports virtualisation, but Acer have decreed thou shalt not use the virtualisation support provided by the processor you paid for. Sure enough, there is no setting in the BIOS to enable virtualisation. In fact, there’s very little you can do with a typical Acer BIOS. You can change the boot device order, and the clock. That’s about it.&lt;br /&gt;
&lt;br /&gt;
Acer have been playing cat and mouse with their customers on this one for a while. There are a number of discussions, rants, “support” articles and so on online which show that Acer are unlikely to release a BIOS version that allows their customers to enable virtualisation.&lt;br /&gt;
&lt;br /&gt;
Some clever people managed to hack the BIOS and provided a &lt;a href="http://marcansoft.com/blog/2009/06/enabling-intel-vt-on-the-aspire-8930g/" target="_blank"&gt;mechanism to modify hidden settings to enable virtualisation&lt;/a&gt;… only for Acer to release a new BIOS version that plugged the holes that were exploited by these clever people and the workarounds no longer work. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, my first move was to go to the Acer website and upgrade my BIOS, expecting to see a setting to enable virtualisation. Only after being disappointed by that approach did I find the articles on the web about hacking the BIOS… only to be further disappointed to find they only worked on the version of the BIOS I’d just replaced.&lt;br /&gt;
&lt;br /&gt;
My own attempts at requesting support from Acer on this have failed to produce a satisfactory response. Acer referred me to their premium support line, I’m guessing because I was (a) out of warranty and (b) had installed an operating system different to the one the machine was shipped with. Though I admit I’m reading a lot into a single line response that wasn’t even proper English.&lt;br /&gt;
&lt;br /&gt;
The “Acer” premium support line in the UK is just a third party helpdesk that services the needs of various PC manufacturers customers. They were no help to me though, saying I would need to speak directly to Acer about my issue. I’m still waiting for Acer to respond to my second query, though I’m not expecting a helpful response.&lt;br /&gt;
&lt;br /&gt;
Next time you buy a PC, don’t just look at the technical specs, get the people in the store to let you poke around in the BIOS and make sure you’re getting access to &lt;em&gt;everything&lt;/em&gt; you’re paying for.&lt;br /&gt;
&lt;br /&gt;
While it’s possibly unfair to blame Microsoft for my problem, I would like to know why Microsoft have designed Windows Virtual PC to only work with processors that support virtualisation, when solutions such as VirtualBox manage with or without such support.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;If Windows 7 is so great, why bother with XP Mode?&lt;/h3&gt;&lt;br /&gt;
If you go to download XP Mode from the website mentioned earlier, you will find yourself asked a couple of questions – the first of which is:&lt;br /&gt;
&lt;a href="http://lh3.ggpht.com/_9NKlMCdyKxQ/SwWZFeuMAvI/AAAAAAAAACk/pL-v0c03NfA/s1600-h/DoINeedXPMode4.jpg"&gt;&lt;img alt="DoINeedXPMode" border="0" height="119" src="http://lh4.ggpht.com/_9NKlMCdyKxQ/SwWZFhlkE5I/AAAAAAAAACo/Y0BjZjVT7xE/DoINeedXPMode_thumb2.jpg?imgmax=800" style="border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline;" title="DoINeedXPMode" width="526" /&gt;&lt;/a&gt; &lt;br /&gt;
Windows XP Mode runs some older productivity applications that may not run otherwise on Windows 7 (or Vista). Well I want to be able to run Nokia S60 SDKs and associated Symbian OS toolchains. Unfortunately, the S60 SDKs and Symbian toolchain don't get on too well with either Vista or Windows 7.&lt;br /&gt;
&lt;br /&gt;
It is possible to persuade the S60 SDKs and associated tools to work on Windows 7, but for me there are just too many workarounds and hacks required in order to do so, particularly when I develop for a number of platforms but only have issues using the S60 SDKs on post-XP Windows releases. For example, Nokia's Qt SDK &amp;amp; Google's Android environment run on Vista and Windows 7 without complaint. &lt;br /&gt;
&lt;br /&gt;
An XP virtual machine running on Windows 7 sounds like a good solution to allow me to develop for S60, without needing to maintain a dedicated physical XP machine. &lt;br /&gt;
&lt;br /&gt;
Unfortunately, Acer disagree.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Next steps…&lt;/h3&gt;&lt;br /&gt;
I’m not beaten yet. I know VirtualBox can read Microsoft Virtual PC virtual hard disks...&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;(*Acer are certainly not alone in their approach on this issue. Ask your favourite search engine…) &lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-4000839563603124371?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/4000839563603124371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/11/windows-7-windows-xp-mode-part-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/4000839563603124371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/4000839563603124371'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/11/windows-7-windows-xp-mode-part-i.html' title='Windows 7 – Windows XP Mode: Part I'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_9NKlMCdyKxQ/SwWZFhlkE5I/AAAAAAAAACo/Y0BjZjVT7xE/s72-c/DoINeedXPMode_thumb2.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-1194551668958003161</id><published>2009-11-10T19:21:00.002Z</published><updated>2009-11-10T19:22:44.781Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows 7'/><title type='text'>Windows 7 – The installation</title><content type='html'>&lt;p&gt;When Microsoft announced cut price copies of Windows 7 for those prepared to pre-order back in the summer, I jumped at the chance. It wasn’t a gamble for me as I’d been testing Windows 7 for some time and at the time I placed my order, was using the Windows 7 Release Candidate on a regular basis, so I knew what I was going to get.&lt;/p&gt;&lt;p&gt;Yet when the courier arrived on 22nd October with my new retail copy of Windows 7 I must admit to suddenly feeling a bit apprehensive about installing it for real.&lt;/p&gt;&lt;p&gt;My apprehension wasn’t caused by the idea of running Windows 7 “full time”, it was the task of upgrading my Vista machine that was fuelling the need for something stronger than coffee. &lt;/p&gt;&lt;p&gt;I’d already backed up all my data, downloaded installation files for numerous applications from the internet and had a bunch of CDs and DVDs to hand for the boxed software I use. What could possibly go wrong?&lt;/p&gt;&lt;p&gt;Well, thankfully, not very much as it turns out. But it wasn’t perfect.&lt;/p&gt;&lt;h3&gt;To Upgrade, or  Cleanly Install?&lt;/h3&gt;&lt;p&gt;I popped the DVD in my drive and let setup go about its job. It asked for the usual information – which country was I in, what language did I want to use, keyboard layout, that sort of thing. Then it asked if I wanted to perform an upgrade or a clean installation. Excellent – I’ve got everything backed up, I’ll have a clean installation please!&lt;/p&gt;&lt;p&gt;What I didn’t notice (I’m sure it wasn’t there… it is, I just must have missed it!) was the option to do a spot of disk administration before performing the installation. Having selected a clean installation without doing any disk administration, setup detected my existing Vista installation and proudly informed me that it would copy my Vista installation to a directory called “Windows.old” and that I would be able to access my files, but wouldn’t be able to boot into Vista.&lt;/p&gt;&lt;p&gt;Hmm… what definition of “clean” is being used here?&lt;/p&gt;&lt;h3&gt;Simple Installation&lt;/h3&gt;&lt;p&gt;The installation itself was surprisingly simple. Gone are the days of specifying endless options and waiting while individual cabinets are copied and uncompressed… and then configured… With Windows 7 what gets installed is a standard disk image – much like the IT department at your local large company might do. It still took 50 minutes though!&lt;/p&gt;&lt;p&gt;If I recall correctly, two restarts were needed during the installation process. However, setup neglects to tell you that it’s finished with the DVD and that you can remove it from your drive, so if you’re not paying attention and your computer is set to boot from DVD, it’s quite possible to go round an endless loop re-doing the same part of the installation process!&lt;/p&gt;&lt;p&gt;Eventually my PC re-booted and started Windows 7 for real. It looked good, everything was where I expected it to be, it found my network and I could get online and reach the internet and other computers on my home network without any fuss. All seemed well, so I started installing my applications in priority order.&lt;/p&gt;&lt;h3&gt;Hang on… something’s not right here&lt;/h3&gt;&lt;p&gt;About half way through loading my computer with software I suddenly realised that the visual niceties of Windows 7 were missing. I’d selected the Aero interface, but I wasn’t getting it. A quick poke around in device manager revealed that Windows 7 had failed to detect my video card properly (even though the release candidate managed) and had installed some vanilla drivers.&lt;/p&gt;&lt;p&gt;My card reader didn’t work.&lt;/p&gt;&lt;p&gt;My webcam didn’t work.&lt;/p&gt;&lt;p&gt;What I’d not done, lulled into a false sense of security by the success of the release candidate, was examine Vista’s Device Manager and make a note of all the devices on my system and their respective vendors &amp;amp; driver information before installing Windows 7. D’oh!&lt;/p&gt;&lt;h3&gt;nVidia 1 – Windows Update 0&lt;/h3&gt;&lt;p&gt;Luckily nVidia provide a nice tool that can be run on your computer and quickly identifies what graphics hardware you have – and then goes and fetches the appropriate driver for your combination of hardware and OS. Full marks to nVidia for that. No further graphics problems – Aero interface fully operational. Nice!&lt;/p&gt;&lt;p&gt;Not so many marks for Windows Update which subsequently &amp;amp; repeatedly tried to get me to install an older version of the nVidia drivers. &lt;/p&gt;&lt;p&gt;I patched up the other non-functional devices using Vista drivers (the driver model – except the video driver model – is the same between Vista and Windows 7) from my computer manufacturer’s website and had a fully functional computer once more.&lt;/p&gt;&lt;p&gt;I completed the installation of my application software and so far I can report that all applications are running correctly on Windows 7.&lt;/p&gt;&lt;h3&gt;Remembering the bronze age&lt;/h3&gt;&lt;p&gt;I’ve noticed that Microsoft seem to be a bit mean with the supplied mouse pointers and sample images / videos in Windows 7. The sample images and videos aren’t an issue for me – but I’ve used the 3D bronze mouse pointer for many years, so I was a bit disappointed to see that it wasn’t included in Windows 7.&lt;/p&gt;&lt;p&gt;Maybe this is one trivial reason the Windows 7 setup retains your Vista files in a Windows.old directory? A quick dive into the Windows.old\Cursors directory and I copied the 3D bronze mouse pointers over to my Windows 7 installation. It’s not a perfect solution, but it does mean I’ve got my 3D bronze mouse pointer back in most cases! &lt;/p&gt;&lt;h3&gt;Next steps…&lt;/h3&gt;&lt;p&gt;I think I’ll try Windows XP Mode next. I’ll report back shortly…&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-1194551668958003161?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/1194551668958003161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/11/windows-7-installation.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1194551668958003161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/1194551668958003161'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/11/windows-7-installation.html' title='Windows 7 – The installation'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7181454077103467897.post-3377692898986803742</id><published>2009-04-23T18:45:00.006+01:00</published><updated>2009-12-18T19:10:50.105Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='foundation'/><category scheme='http://www.blogger.com/atom/ns#' term='symbian'/><title type='text'>Will Symbian OS flourish in the open source community?</title><content type='html'>Over at &lt;a href="http://stackoverflow.com/questions/623924/will-open-sourcing-bring-good-to-symbian/"&gt;Stack Overflow&lt;/a&gt; there's an interesting discussion on whether releasing Symbian OS to the open source community will be a good thing for Symbian. This post is a re-working of my contribution to that discussion.&lt;br/&gt;&lt;br /&gt;
Personally I think it's too early to say whether Symbian going open source will be a good or bad thing for the OS. The debate over the &lt;a href="http://blog.symbian.org/2009/04/02/symbian-beats-with-a-heart/"&gt;branding&lt;/a&gt; selected for the Symbian Foundation website shows a degree of uncertainty of the role Symbian software will play in the future and who the target customers and contributors really are, other than the familiar mobile telecoms players.&lt;br/&gt;&lt;br /&gt;
Open source projects live or die not by how popular the products are to consumers, but first and foremost, by how popular the software is with the open source development community and how actively the community contributes to the project.&lt;br/&gt;&lt;br /&gt;
That doesn't sound like a big problem, there is, after all, a significant and active pool of developers writing software for Symbian OS already - often referred to as an ecosystem when considered in terms of the combined contribution of these developers and the companies they work for. However, while it's true to say that there is an entire ecosystem that knows about the specifics of developing for Symbian OS, that's pretty meaningless in its own right. The vast majority of the Symbian ecosystem are professional developers paid by their employers to produce proprietary code based on Symbian OS. In some cases, notably Nokia, a large amount of that proprietary software will now be opened up and contributed to the Symbian Foundation. But when you remove professional developers from the equation, the size of the ecosystem is much smaller.&lt;br/&gt;&lt;br /&gt;
When looking at the size of the Symbian developer ecosystem, you need to consider that Symbian OS has been around for over a decade and the software powers in excess of 100 million devices today. For a software platform that powers so many devices and is as mature as the Symbian platform is, the developer ecosystem is surprisingly small.&lt;br/&gt;&lt;br /&gt;
Consider then the rate of growth of the ecosystems surrounding the offerings from Google and Apple. Symbian never generated that level of excitement and never saw that sort of growth in developer interest. Of course, we're a decade down the line and you could argue Symbian did the hard work and created the landscape in which Google and Apple are now competing. But just because Symbian was first, doesn't make it best and doesn't give it any right to survive.&lt;br/&gt;&lt;br /&gt;
Symbian development seems to divide the developer community; some acknowledge the usefulness of the platform idioms, climb the steep learning curve and get on with it. Others consider the platform to be so far removed from other developer platforms and refuse to climb the learning curve.&lt;br/&gt;&lt;br /&gt;
It is true to state that the Symbian C++ idioms can be a barrier and can be a pain to learn. However, it is incorrect to suggest that there is &lt;a href="http://stackoverflow.com/questions/623924/will-open-sourcing-bring-good-to-symbian/630019#630019"&gt;no justification&lt;/a&gt; for getting rid of them. One justification is simply the persistent perception, 10 years on, that developing native code for Symbian OS is too hard. Most if not all these painful idioms were design decisions taken over a decade ago and, whilst still beneficial on the latest mobile devices, are no longer essential. Mobile hardware has moved on substantially in the last decade. As a native developer platform, Symbian OS has not fundamentally changed over the past decade.&lt;br/&gt;&lt;br /&gt;
Looking at alternative mobile platforms, consider Android and Maemo. Both are linux based systems. Both use more developer focussed, standard development approaches which are immediately appealing and recognisable to developers while simultaneously leaving Symbian OS looking like it's come from another age.&lt;br/&gt;&lt;br /&gt;
That in itself is not necessarily a problem for developers using rather than contributing to the platform because Symbian OS supports several runtime environments that make development for devices running Symbian OS much more approachable for the average developer.&lt;br/&gt;&lt;br /&gt;
Yet taking the runtime support to its natural conclusion, the underlying OS becomes irrelevant. The OS selection is just another choice made by the device manufacturer based on cost, time to market, quality etc. But the end user doesn't care and in many cases doesn't know what the OS is. Developers then develop for their preferred runtime, rather than write native code and can therefore access a much wider pool of devices than they could by writing native code for a specific OS.&lt;br/&gt;&lt;br /&gt;
Symbian OS has worked very well over the past decade as a proprietary platform, but it is by no means certain that the platform will flourish as an open source project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7181454077103467897-3377692898986803742?l=refactoredthoughts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://refactoredthoughts.blogspot.com/feeds/3377692898986803742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/04/will-symbian-os-flourish-in-open-source.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/3377692898986803742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7181454077103467897/posts/default/3377692898986803742'/><link rel='alternate' type='text/html' href='http://refactoredthoughts.blogspot.com/2009/04/will-symbian-os-flourish-in-open-source.html' title='Will Symbian OS flourish in the open source community?'/><author><name>Gavin Meiklejohn</name><uri>http://www.blogger.com/profile/10273378282026252358</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
