Adding Symbian.org Widget 1.0rc3 source
authorivanl
Fri, 05 Jun 2009 16:18:05 +0100
changeset 0 54498df70f5d
child 1 609a552a42fa
Adding Symbian.org Widget 1.0rc3 source
Symbian.org/.project
Symbian.org/Bugzilla.js
Symbian.org/FeedPresentation.js
Symbian.org/FeedUpdateBroker.js
Symbian.org/ForumPostForm.js
Symbian.org/Forums.js
Symbian.org/Icon.png
Symbian.org/Info.plist
Symbian.org/Login.js
Symbian.org/Main.js
Symbian.org/RssReader.js
Symbian.org/WRTKit/Resources/CheckBox.png
Symbian.org/WRTKit/Resources/ContentPanelFoldIcons.png
Symbian.org/WRTKit/Resources/ControlAssemblyBackground.png
Symbian.org/WRTKit/Resources/DocumentBackground.png
Symbian.org/WRTKit/Resources/FormButtonCenter.png
Symbian.org/WRTKit/Resources/FormButtonLeft.png
Symbian.org/WRTKit/Resources/FormButtonRight.png
Symbian.org/WRTKit/Resources/ListViewCaptionBackground.png
Symbian.org/WRTKit/Resources/NotificationPopupBackground.png
Symbian.org/WRTKit/Resources/NotificationPopupTypeIndicator.png
Symbian.org/WRTKit/Resources/ProgressBarUnknown.gif
Symbian.org/WRTKit/Resources/RadioButton.png
Symbian.org/WRTKit/Resources/ScrollbarThumbBottom.png
Symbian.org/WRTKit/Resources/ScrollbarThumbMiddle.png
Symbian.org/WRTKit/Resources/ScrollbarThumbTop.png
Symbian.org/WRTKit/Resources/ScrollbarTrackBottom.png
Symbian.org/WRTKit/Resources/ScrollbarTrackMiddle.png
Symbian.org/WRTKit/Resources/ScrollbarTrackTop.png
Symbian.org/WRTKit/Resources/SeparatorCenter.png
Symbian.org/WRTKit/Resources/SeparatorLeft.png
Symbian.org/WRTKit/Resources/SeparatorRight.png
Symbian.org/WRTKit/Resources/UI.css
Symbian.org/WRTKit/UI/ActionControl.js
Symbian.org/WRTKit/UI/Ajax.js
Symbian.org/WRTKit/UI/ContentPanel.js
Symbian.org/WRTKit/UI/Control.js
Symbian.org/WRTKit/UI/FormButton.js
Symbian.org/WRTKit/UI/ImageLabel.js
Symbian.org/WRTKit/UI/Label.js
Symbian.org/WRTKit/UI/ListView.js
Symbian.org/WRTKit/UI/NavigationButton.js
Symbian.org/WRTKit/UI/NotificationPopup.js
Symbian.org/WRTKit/UI/Scrollbar.js
Symbian.org/WRTKit/UI/SelectionControl.js
Symbian.org/WRTKit/UI/SelectionList.js
Symbian.org/WRTKit/UI/SelectionMenu.js
Symbian.org/WRTKit/UI/Separator.js
Symbian.org/WRTKit/UI/TabView.js
Symbian.org/WRTKit/UI/TextArea.js
Symbian.org/WRTKit/UI/TextEntryControl.js
Symbian.org/WRTKit/UI/TextField.js
Symbian.org/WRTKit/UI/UIElement.js
Symbian.org/WRTKit/UI/UIInit.js
Symbian.org/WRTKit/UI/UIManager.js
Symbian.org/WRTKit/UI/View.js
Symbian.org/WRTKit/Utils/Logger.js
Symbian.org/WRTKit/WRTKit.js
Symbian.org/blueright.gif
Symbian.org/index.html
Symbian.org/logo.png
Symbian.org/preview/css/menu.css
Symbian.org/preview/css/style.css
Symbian.org/preview/images/arrow.png
Symbian.org/preview/images/device-bottom.png
Symbian.org/preview/images/device-left-softkey.png
Symbian.org/preview/images/device-left.png
Symbian.org/preview/images/device-right-softkey.png
Symbian.org/preview/images/device-right.png
Symbian.org/preview/images/device/5320_main.jpg
Symbian.org/preview/images/device/5800_main.jpg
Symbian.org/preview/images/device/6210_main.jpg
Symbian.org/preview/images/device/6220_main.jpg
Symbian.org/preview/images/device/6650-2_main.jpg
Symbian.org/preview/images/device/N95_main.jpg
Symbian.org/preview/images/device/e51_main.jpg
Symbian.org/preview/images/device/e66_main.jpg
Symbian.org/preview/images/device/e71_main.jpg
Symbian.org/preview/images/device/e90_main.jpg
Symbian.org/preview/images/device/n78_main.jpg
Symbian.org/preview/images/device/n79_main.jpg
Symbian.org/preview/images/device/n82_main.jpg
Symbian.org/preview/images/device/n85_main.jpg
Symbian.org/preview/images/device/n95_8gb_main.jpg
Symbian.org/preview/images/device/n96_main.jpg
Symbian.org/preview/images/menuItemHover.png
Symbian.org/preview/images/new-pull-down-btn.png
Symbian.org/preview/images/s60-tiny-icon.png
Symbian.org/preview/images/select-device-text.png
Symbian.org/preview/images/toolbar-bg-shadow.png
Symbian.org/preview/images/top-navigation-bg.png
Symbian.org/preview/nopreview.html
Symbian.org/preview/preview_exit.html
Symbian.org/preview/script/build.js
Symbian.org/preview/script/device.js
Symbian.org/preview/script/lib/loader.js
Symbian.org/preview/script/lib/menu.js
Symbian.org/preview/script/lib/menuItem.js
Symbian.org/preview/script/lib/systeminfo.js
Symbian.org/preview/script/lib/widget.js
Symbian.org/right.gif
Symbian.org/style.css
Symbian.org/titlebar.png
Symbian.org/wrt_preview_frame.html
Symbian.org/wrt_preview_main.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/.project	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>Symbian.org</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>com.nokia.wrt.widgetPreviewBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>com.nokia.wrt.WidgetProjectNature</nature>
+		<nature>com.aptana.ide.project.nature.web</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/Bugzilla.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,273 @@
+
+
+var bugzillaTableStyle = "bugzilla";
+
+// Bugzilla access 
+
+function BugzillaSearchPanel(parent) {
+	this.previousView = parent;
+	ListView.prototype.init.call(this, null, null);	
+
+	// add the banner and 'title bar' - avoids the caption bug
+	var titleBar = new NavigationButton(null, "titlebar.png", "Bugzilla");
+	titleBar.setEnabled(false);
+	this.addControl(titleBar);
+	
+	// search term control
+    this.searchTerm = new TextField('bugzillaSearchTerm', "Bugzilla search term:", "test");
+    this.addControl(this.searchTerm);
+
+	// add the search box
+	this.searchButton = new FormButton(null, "Search");
+	var self = this;
+    this.searchButton.addEventListener("ActionPerformed", function(){
+		self.bugzillaSearchClicked();
+	});
+	this.addControl(this.searchButton);
+}
+
+
+BugzillaSearchPanel.prototype = new ListView(null,null);
+
+
+BugzillaSearchPanel.prototype.bugzillaSearchClicked = function() {
+	// create the RssReader for bugzilla
+	var searchString = this.searchTerm.getText();
+	var title = "Bugzilla: " + searchString;
+	var url = symbianOrgBaseUrl + "/bugs/buglist.cgi?"
+		+ "bug_status=NEW&bug_status=ASSIGNED&bug_status=UNCONFIRMED"
+		+ "&field-1-0-0=bug_status&field0-0-0=product&field0-0-1=component&field0-0-2=short_desc"
+		+ "&field0-0-3=status_whiteboard&field0-0-4=longdesc"
+		+ "&query_format=advanced&remaction=&type-1-0-0=anyexact"
+		+ "&type0-0-0=substring&type0-0-1=substring&type0-0-2=substring&type0-0-3=substring"
+		+ "&type0-0-4=substring&value-1-0-0=NEW%2CASSIGNED%2CUNCONFIRMED"
+		+ "&value0-0-0=" + searchString
+		+ "&value0-0-1=" + searchString
+		+ "&value0-0-2=" + searchString
+		+ "&value0-0-3=" + searchString
+		+ "&value0-0-4=" + searchString
+		+ "&title=Bug List&ctype=atom";
+	var reader = new RssReader(title, url, new BugzillaFeedPresenter(null), this, parseBugzillaFeed);
+	reader.show();
+}
+
+
+function parseBugzillaFeed(broker, responseStatus, xmlDoc) {
+    if (responseStatus == 200 && xmlDoc != null) {
+        // node ref for iterating
+        var node;
+
+		// for compatibility with rss
+		var lastModified = new Date();
+		
+        // init result items array
+        var items = [];
+
+		var itemElements = xmlDoc.getElementsByTagName("entry");
+		
+		for (var i = 0; i < itemElements.length; i++) {
+            // iterate through child nodes of this item and gather
+            // all the data we need for a feed item
+            var title = null;
+            var date = null;
+            var description = null;
+            var url = null;
+            var author = null;
+			var bugid;
+            node = itemElements[i].firstChild;
+            while (node != null) {
+                if (node.nodeType == Node.ELEMENT_NODE) {
+                    if (node.nodeName == "title") {
+                        // item title
+                        title = getTextOfNode(node);
+						if ( title.length > 48) {
+							title = title.substring(0,45) + "...";
+						}
+                    } else if (node.nodeName == "updated" ) {
+                        // item publishing date
+                        date = getTextOfNode(node);
+                    } else if (node.nodeName == "summary" && !this.ignoreContent ) {
+                        // item description
+                        description = getTextOfNode(node);
+                    } else if (node.nodeName == "link") {
+                        // link URL
+                        url = node.getAttribute("href");
+						// extract bug id
+						var ind = url.indexOf("?id=");
+						if ( ind != -1 ) {
+							bugid = url.substring(ind + 4);
+							url = symbianOrgBaseUrl + "/bugtracker/show_bug.cgi?ctype=xml&id="+bugid;
+						}
+                    } else if (node.nodeName == "author" ) {
+						author = getTextOfNode(node);
+					}
+                }
+                node = node.nextSibling;
+            }
+            items.push({ title: title, date: date, description: description, url: url, author: author });
+		}
+
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
+
+// Implementation of FeedPresenter that shows feed as a clickable
+// button and shows feed entry title as label
+function BugzillaFeedPresenter(rssreader) {
+	ButtonFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+// BugzillaFeedPresenter is a subclass of ButtonFeedPresenter
+BugzillaFeedPresenter.prototype = new ButtonFeedPresenter(null);
+
+// Handle the button-press
+BugzillaFeedPresenter.prototype.feedClicked = function(event){
+	var clickedButton = event.source;
+	var id = clickedButton.id;
+	var url = this.items[id].url;
+	var presenter = new HtmlFeedPresenter(null);
+	presenter.expanded = true;
+	var reader = new RssReader(this.items[id].title, url, 
+		presenter, uiManager.currentView, parseBugzillaBugFeed);
+	reader.show();
+}
+
+
+function parseBugzillaBugFeed(broker, responseStatus, xmlDoc) {
+    if (responseStatus == 200 && xmlDoc != null) {
+        // node ref for iterating
+        var node;
+
+		// for compatibility with rss
+		var lastModified = new Date();
+		
+        // init result items array
+        var items = [];
+
+		var itemElements = xmlDoc.getElementsByTagName("bug");
+		
+		for (var i = 0; i < itemElements.length; i++) {
+            // iterate through child nodes of this item and gather
+            // all the data we need for a feed item
+            var title = null;
+            var date = null;
+            var url = null;
+            var author = null;
+			var bugid = null;
+			var creationTime = "Not specified";
+			var product = "Not specified";
+			var component = "Not specified";
+			var classification = "Not specified";
+			var op_sys = "Not specified";
+			var bug_status = "Not specified";
+			var bug_file_loc = "Not specified";
+			var priority = "Not specified";
+			var severity = "Not specified";
+			var target_milestone = "Not specified";
+			var version = "Not specified";
+			var platform = "Not specified";
+			var assignedToName = "Not specified";
+			var solutionDetails = "Not specified";
+			var longdesc = "";
+			var shortDesc = "";
+			var bugid = "";
+			
+            node = itemElements[i].firstChild;
+            while (node != null) {
+                if (node.nodeType == Node.ELEMENT_NODE) {
+                    if (node.nodeName == "bug_id") {
+                        // item title
+                        bugid = "Bug " + getTextOfNode(node);
+                    } else if (node.nodeName == "updated" ) {
+                        // item publishing date
+                        date = getTextOfNode(node);
+                    } else if (node.nodeName == "creation_ts" ) {
+                        // item publishing date
+                        creationTime = getTextOfNode(node);
+                    } else if (node.nodeName == "short_desc" && !this.ignoreContent ) {
+                        // item description
+                        title = getTextOfNode(node);
+                    } else if (node.nodeName == "reporter" ) {
+						author = getTextOfNode(node);
+					} else if (node.nodeName == "product" ) {
+                        product = getTextOfNode(node);
+					} else if (node.nodeName == "component" ) {
+                        component = getTextOfNode(node);
+					} else if (node.nodeName == "classification" ) {
+                        classification = getTextOfNode(node);
+					} else if (node.nodeName == "version" ) {
+                        version = getTextOfNode(node);
+					} else if (node.nodeName == "op_sys" ) {
+                        op_sys = getTextOfNode(node);
+					} else if (node.nodeName == "bug_status" ) {
+                        bug_status = getTextOfNode(node);
+					} else if (node.nodeName == "bug_file_loc" ) {
+                        bug_file_loc = getTextOfNode(node);
+					} else if (node.nodeName == "priority" ) {
+                        priority = getTextOfNode(node);
+					} else if (node.nodeName == "severity" ) {
+                        severity = getTextOfNode(node);
+					} else if (node.nodeName == "target_milestone" ) {
+                        target_milestone = getTextOfNode(node);
+					} else if (node.nodeName == "platform" ) {
+                        platform = getTextOfNode(node);
+					} else if (node.nodeName == "cf_solutiondetails" ) {
+                        solutionDetails = getTextOfNode(node);
+					} else if (node.nodeName == "long_desc" ) {
+                        longdesc += "<br><table style="+bugzillaTableStyle+">";
+						var ld_nodes = node.childNodes;
+						for ( var tmp = 0 ; tmp < ld_nodes.length ; tmp++ ) {
+	                        longdesc += "<tr><td>" 
+								+ getTextOfNode(ld_nodes[tmp]) + "</td></tr>";
+						}
+                        longdesc += "</table>";
+					} else if (node.nodeName == "assigned_to" ) {
+                        assignedToName = getTextOfNode(node);
+					} 
+                }
+                node = node.nextSibling;
+            }
+			// format the description
+			var description = "<table style="+bugzillaTableStyle+">";
+			description += "<tr><td>Reported:" + "</td><td>" + creationTime + "</td></tr>";
+			description += "<tr><td>Product:" + "</td><td>" + product + "</td></tr>";
+			description += "<tr><td>Component:" + "</td><td>" + component + "</td></tr>";
+			description += "<tr><td>Classification:" + "</td><td>" + classification + "</td></tr>";
+			description += "<tr><td>Operating system:" + "</td><td>" + op_sys + "</td></tr>";
+			description += "<tr><td>Status:" + "</td><td>" + bug_status + "</td></tr>";
+			description += "<tr><td>Priority:" + "</td><td>" + priority + "</td></tr>";
+			description += "<tr><td>Severity:" + "</td><td>" + severity + "</td></tr>";
+			description += "<tr><td>Version:" + "</td><td>" + version + "</td></tr>";
+			description += "<tr><td>Platform:" + "</td><td>" + platform + "</td></tr>";
+			description += "<tr><td>Reported by:" + "</td><td>" + author + "</td></tr>";
+			description += "<tr><td>Assigned to:" + "</td><td>" + assignedToName + "</td></tr>";
+			description += "<tr><td>Target milestone:" + "</td><td>" + target_milestone + "</td></tr>";
+			description += "<tr><td>File location:" + "</td><td>" + bug_file_loc + "</td></tr>";
+			description += "</table>";
+			
+			description += "<table style="+bugzillaTableStyle+">";
+			description += "<tr><td>Description:" + "</td></tr>";
+			description += "<tr><td>" + longdesc + "</td></tr>";
+			description += "</table>";
+			
+			description += "<table style="+bugzillaTableStyle+">";
+			description += "<tr><td>Solution details:" + "</td></tr>";
+			description += "<tr><td>" + solutionDetails + "</td></tr>";
+			description += "</table>";			
+			
+            items.push({ title: title, date: date, description: description, url: url, author: author });
+		}
+
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/FeedPresentation.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,155 @@
+// ////////////////////////////////////////////////////////////////////////////
+// (c)2009 Symbian Foundation
+// ////////////////////////////////////////////////////////////////////////////
+
+// Feed presentation classes
+
+// Abstract class used to create controls to represent feed entries.
+function FeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+// FeedPresenter "Constructor"
+FeedPresenter.prototype.init = function(rssreader){
+	this.rssreader = rssreader;
+}
+
+// Create a control that represents this item and add it to
+// parent rss reader
+FeedPresenter.prototype.show = function(item){
+}
+
+// Create and add controls to be shown before items list.
+FeedPresenter.prototype.addPreambleItems = function(){
+}
+
+// No items returned, show "No messages"
+FeedPresenter.prototype.showNoItems = function(){
+	var label = new Label(null, null, "No messages");
+	this.rssreader.addControl(label);
+}
+
+// Implementation of FeedPresenter that shows feed in a 
+// ContentPanel
+function HtmlFeedPresenter(rssreader) {
+	if (rssreader) {
+		this.init(rssreader);
+	}
+	this.expanded = false;
+}
+
+// HtmlFeedPresenter is a subclass of FeedPresenter
+HtmlFeedPresenter.prototype = new FeedPresenter(null);
+
+// HtmlFeedPresenter "constructor"
+HtmlFeedPresenter.prototype.init = function(rssreader) {
+	FeedPresenter.prototype.init.call(this, rssreader);
+}
+
+// Create a control that represents this item and add it to
+// parent rss reader
+HtmlFeedPresenter.prototype.show = function(item) {
+			// get a feed item control from the pool or create one and
+		// place it in the pool if there aren't enough feed item controls
+		var feedItemControl = new ContentPanel(null, null, null, true);
+
+		// initialize feed item control
+		feedItemControl.setCaption(item.title);
+		feedItemControl.setContent(this.getContentHTMLForFeedItem(item));
+		feedItemControl.setExpanded(this.expanded);
+		
+		// add the feed item control to the main view
+		this.rssreader.feedItemControls.push(feedItemControl);
+		this.rssreader.addControl(feedItemControl);
+}
+
+// Returns the content HTML for a feed item.
+HtmlFeedPresenter.prototype.getContentHTMLForFeedItem = function (item){
+	var buf = "";
+	
+	// item date
+	if (item.date != null) {
+		buf += "<div class=\"FeedItemDate\">" ;
+		if ( item.author != null ) {
+			buf += item.author + ", ";
+		}
+		buf += item.date + "</div>";
+	}
+	
+	// item description
+	if (item.description != null) {
+		buf += "<div class=\"FeedItemDescription\">" + item.description + "</div>";
+	}
+
+	if (item.url != null) {
+		// blogs
+        buf += "<div class=\"FeedItemLink\">";
+//            buf += "<a href=\"JavaScript:void(0)\" onclick=\"openURL('" + item.title + "', '" + item.url + "'); return false;\">";
+            buf += "<a href=\"JavaScript:void(0)\" onclick=\"openURL('" + item.url + "'); return false;\">";
+            buf += "Read more...";
+            buf += "</a>";
+        buf += "</div>";
+	}
+	
+	return buf;
+}
+
+
+// Implementation of FeedPresenter that shows feed as a clickable
+// button that shows feed entry title as label
+function ButtonFeedPresenter(rssreader) {
+	if (rssreader) {
+		this.init(rssreader);
+	}
+	this.indexCounter = 0;
+	this.items = [];
+}
+
+// ButtonFeedPresenter is a subclass of FeedPresenter
+ButtonFeedPresenter.prototype = new FeedPresenter(null);
+
+// ButtonFeedPresenter "constructor"
+ButtonFeedPresenter.prototype.init = function(rssreader) {
+	FeedPresenter.prototype.init.call(this, rssreader);
+}
+
+// Create a control that represents this item and add it to
+// parent rss reader
+ButtonFeedPresenter.prototype.show = function(item) {
+	this.items[this.indexCounter] = item;
+	// get a feed item control from the pool or create one and
+	// place it in the pool if there aren't enough feed item controls
+	var feedItemControl = new NavigationButton(this.indexCounter, "right.gif", item.title);
+
+	// add button press handler
+    var self = this;
+	feedItemControl.addEventListener("ActionPerformed", 
+		function(event) { self.feedClicked(event); } );
+
+	this.indexCounter++;
+		
+	// add the feed item control to the main view
+	this.rssreader.feedItemControls.push(feedItemControl);
+	this.rssreader.addControl(feedItemControl);
+}
+
+// Handle the button-press
+ButtonFeedPresenter.prototype.feedClicked = function(event){
+	var clickedButton = event.source;
+	var id = clickedButton.id;
+	var url = this.items[id].url;
+	
+	if (url.indexOf("/wiki/index.php")) {
+		// hack for printable wiki pages
+		var articleName = url.replace(wikiBaseUrl + "/", "");
+		url = wikiBaseUrl + "?title=" + articleName + "&action=render";
+		openURL(url);
+	}
+	else {
+		openURL(url);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/FeedUpdateBroker.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,220 @@
+///////////////////////////////////////////////////////////////////////////////
+// The FeedUpdateBroker class implements a simple RSS fetcher and parser.
+// Adapted from WRTKit RssReader example
+
+// Constructor.
+function FeedUpdateBroker() {
+    this.httpReq = null;
+    this.feedAddress = null;
+    this.callback = null;
+	this.ignoreContent = false;
+	this.cancelled = false;
+	this.responseParser = this.handleRssResponse;
+	this.startFromItem = 0;
+	this.maxItems = 0;
+}
+
+// Fetches a feed from the specified URL and calls the callback when the feed
+// has been fetched and parsed, or if the process results in an error.
+FeedUpdateBroker.prototype.doFetchFeed = function(){    
+    // create new XML HTTP request
+    this.httpReq = new Ajax();
+    
+    // set callback
+    var self = this;
+    this.httpReq.onreadystatechange = function() { self.readyStateChanged(); };
+
+	var fullURL = this.feedAddress;
+    if (fullURL.indexOf("?") == -1) {
+        fullURL += "?";
+    } else {
+        fullURL += "&";
+    }
+    fullURL += "nocache=" + (new Date().getTime());
+
+    // initiate the request
+    this.httpReq.open("GET", fullURL, true);
+    this.httpReq.send(null);
+}
+
+// has been fetched and parsed, or if the process results in an error.
+FeedUpdateBroker.prototype.fetchFeed = function(feedURL, callback) {
+    // remember callback
+    this.callback = callback;
+    this.feedAddress = feedURL;
+	this.doFetchFeed();
+}
+
+// Callback for ready-state change events in the XML HTTP request.
+FeedUpdateBroker.prototype.readyStateChanged = function() {
+    // complete request?
+    if (this.httpReq.readyState == 4) {
+        // attempt to get response status
+        var responseStatus = null;
+        try {
+            responseStatus = this.httpReq.status;
+        } catch (noStatusException) {}
+        
+		// are we being prompted for login?
+		var text = this.httpReq.responseText;
+		if ( isLoginPrompt (text) ) {
+			var self = this;
+			login(function(){self.doFetchFeed();});
+			return;
+		}
+		
+        // handle the response and call the registered callback object
+		var response = this.httpReq.responseXML;
+		if (response == null) {
+			// if the content type is not set correctly, we get the response as text
+			var xmlparser = new DOMParser();
+		    response = xmlparser.parseFromString(this.httpReq.responseText, "text/xml");
+		}
+        this.callback.feedUpdateCompleted(this.handleResponse(responseStatus, response));
+    }
+}
+
+// Handles a completed response.
+FeedUpdateBroker.prototype.handleResponse = function(responseStatus, xmlDoc){
+	if (this.responseParser == null) {
+		return this.handleRssResponse(responseStatus, xmlDoc);
+	}
+	else {
+		return this.responseParser.call(this, this, responseStatus, xmlDoc);
+	}	
+}
+
+
+FeedUpdateBroker.prototype.handleRssResponse = function(broker, responseStatus, xmlDoc){
+	if ( this.cancelled ) {
+        return { status: "cancelled" };
+	}
+    if (responseStatus == 200 && xmlDoc != null) {
+        // node ref for iterating
+        var node;
+        
+        // get last modified time - default to current time
+        var lastModified = new Date().getTime();
+        var channelElements = xmlDoc.getElementsByTagName("channel");
+        if (channelElements.length > 0) {
+            node = channelElements[0].firstChild;
+            while (node != null) {
+                if (node.nodeType == Node.ELEMENT_NODE) {
+                    if (node.nodeName == "pubDate" ||
+                            node.nodeName == "lastBuildDate" ||
+                            node.nodeName == "dc:date") {
+                        lastModified = getTextOfNode(node);
+                        break;
+                    }
+                }
+                node = node.nextSibling;
+            }
+        }
+        
+        // init feed items array
+        var items = [];
+        
+        // we got the feed XML so now we'll parse it
+        var itemElements = xmlDoc.getElementsByTagName("item");
+		
+        for (var i = this.startFromItem; i < itemElements.length; i++) {
+			if ( this.maxItems > 0 && this.maxItems < i ) {
+				break;
+			}
+            // iterate through child nodes of this item and gather
+            // all the data we need for a feed item
+            var title = null;
+            var date = null;
+            var description = null;
+            var url = null;
+            var author = null;
+            node = itemElements[i].firstChild;
+            while (node != null) {
+                if (node.nodeType == Node.ELEMENT_NODE) {
+                    if (node.nodeName == "title") {
+                        // item title
+                        title = getTextOfNode(node);
+                    } else if (node.nodeName == "pubDate" || node.nodeName == "dc:date") {
+                        // item publishing date
+                        date = getTextOfNode(node);
+                    } else if (node.nodeName == "description" && !this.ignoreContent ) {
+                        // item description
+                        description = getTextOfNode(node);
+                    } else if (node.nodeName == "link") {
+                        // link URL
+                        url = getTextOfNode(node);
+                    } else if (node.nodeName == "dc:creator" ) {
+						author = getTextOfNode(node);
+					}
+                }
+                node = node.nextSibling;
+            }
+            
+            // create the item and add to the items array
+            items.push({ title: title, date: date, description: description, url: url, author: author });
+        }
+        
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
+// Returns the text of a node.
+function getTextOfNode(node) {
+    var buf = "";
+    
+    // iterate through all child elements and collect all text to the buffer
+    var child = node.firstChild;
+    while (child != null) {
+        if (child.nodeType == Node.TEXT_NODE || child.nodeType == Node.CDATA_SECTION_NODE) {
+            // append text to buffer
+            if (buf != "") {
+                buf += " ";
+            }
+            buf += child.nodeValue;
+        }
+        child = child.nextSibling;
+    }
+    
+    // strip all tags from the buffer
+    var strippedBuf = "";
+    var textStartPos = -1;
+    var tagBalance = 0;
+    
+    // iterate through the text and append all text to the stripped buffer
+    // that is at a tag balance of 0
+    for (pos = 0; pos < buf.length; pos++) {
+        var c = buf.charAt(pos);
+        if (c == '<') {
+            // entering a tag
+            if (tagBalance == 0 && textStartPos != -1) {
+                // everything up to here was valid text
+                strippedBuf += buf.substring(textStartPos, pos);
+                textStartPos = -1;
+            }
+            tagBalance++;
+        } else if (c == '>') {
+            // leaving a tag
+            tagBalance--;
+            textStartPos = -1;
+        } else if (tagBalance == 0 && textStartPos == -1) {
+            // first char of text
+            textStartPos = pos;
+        }
+    }
+    
+    // add remaining text - if any
+    if (tagBalance == 0 && textStartPos != -1) {
+        strippedBuf += buf.substring(textStartPos, pos);
+    }
+    
+    return strippedBuf;
+}
+
+FeedUpdateBroker.prototype.cancel = function() {
+	this.cancelled = true;
+	this.httpReq.abort();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/ForumPostForm.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,328 @@
+// ////////////////////////////////////////////////////////////////////////////
+// (c)2009 Symbian Foundation
+// ////////////////////////////////////////////////////////////////////////////
+
+
+function ForumPostForm(aParentView, forumid) {
+	ListView.prototype.init.call(this, null, null);
+	this.previousView = aParentView;
+	this.forumid = forumid;
+	
+	// add the banner / 'title bar' - avoids the caption bug
+	var titleBar = new NavigationButton(null, "titlebar.png", "New thread in " + aParentView.feedName);
+	titleBar.setEnabled(false);
+	this.addControl(titleBar);
+	
+	// add topic name textfield
+	this.topicNameTf = new TextField('threadPostTopic', "Topic title", "");
+	this.addControl(this.topicNameTf);
+	
+	// add content textarea
+	this.contentTa = new TextArea('threadPostContent', "Message", "", 6);
+	this.addControl(this.contentTa);
+	
+	var self = this;
+
+    // post button
+    this.postButton = new FormButton(null, "Submit");
+    this.postButton.addEventListener("ActionPerformed", function(){
+		login( function(){
+			submitNewTopic(
+				self.topicNameTf.getText(), // title
+				self.contentTa.getText(), // message
+				self.forumid, // forumid
+				function() { self.goBack();uiManager.currentView.update(true);}
+				);
+			});
+		});
+    this.addControl(this.postButton);
+    
+    // cancel settings button
+    this.cancelButton = new FormButton(null, "Cancel");
+    this.cancelButton.addEventListener("ActionPerformed", function(){self.goBack();});
+    this.addControl(this.cancelButton);
+	
+}
+
+ForumPostForm.prototype = new ListView(null, null);
+
+
+function ForumReplyForm(aParentView, threadid, postid, parentTitle) {
+	ListView.prototype.init.call(this, null, null);
+	this.previousView = aParentView;
+	this.threadid = threadid;
+	this.postid = postid;
+	this.parentTitle = parentTitle;
+	
+	// add the banner / 'title bar' - avoids the caption bug
+	var titleBar = new NavigationButton(null, "titlebar.png", "Reply to " + parentTitle);
+	titleBar.setEnabled(false);
+	this.addControl(titleBar);
+	
+	// add topic name textfield
+	this.topicNameTf = new TextField('threadPostTopic', "Title", "");
+	this.addControl(this.topicNameTf);
+	
+	// add content textarea
+	this.contentTa = new TextArea('threadPostContent', "Message", "", 6);
+	this.addControl(this.contentTa);
+	
+	var self = this;
+
+    // post button
+    this.postButton = new FormButton(null, "Submit");
+    this.postButton.addEventListener("ActionPerformed", function(){
+		login(
+		function(){
+			submitNewReply(self.topicNameTf.getText(), // title
+			 self.contentTa.getText(), // message
+			 self.threadid, // threadid
+			 self.postid, // threadid
+			 function(){
+				self.goBack();
+				uiManager.currentView.update(true);
+			});
+		});
+	});
+    this.addControl(this.postButton);
+    
+    // cancel settings button
+    this.cancelButton = new FormButton(null, "Cancel");
+    this.cancelButton.addEventListener("ActionPerformed", function(){self.goBack();});
+    this.addControl(this.cancelButton);
+	
+}
+
+ForumReplyForm.prototype = new ListView(null, null);
+
+
+// Submitting a new to vBulletin is somewhat complex. There appears to be
+// no XML based interface so we have to go through the usual web posting
+// procedure. So, first we must be logged in. Then, we must request forums
+// home page to get bbsessionhash cookie. Next, we request the form,
+// to collect required security information (securitytoken etc) from the form.
+// If all goes well, we can now post a message.
+
+var submitUrlContent = null;
+var submitUrlHttpReq = null;
+var submitCallback = null;
+var submitTitle = null;
+var submitContent = null;
+var submitForumId = null;
+var submitThreadId = null;
+var submitPostId = null;
+var submitCallback = null;
+var reply = false;
+
+// Initiates the submission process by requesting the form
+function submitNewTopic(title, content, forumid, callback){
+	uiManager.showNotification(-1, "wait", "Submitting...", -1);
+
+	// Dealing with vBulletin nastiness...
+	
+	// ensure we have all the cookies we need
+	var vbCookieGet = new Ajax();
+	var vburl = symbianOrgBaseUrl + "/forum/";
+	vbCookieGet.open('GET', vburl, false);
+	vbCookieGet.send(null);
+
+	// Now we have to harvest some info from the post form. 	
+	submitUrlHttpReq = new Ajax();
+	var self = this;
+	submitTitle = title;
+	submitContent = content;
+	submitForumId = forumid;
+	submitThreadId = null;
+	submitPostId = null;
+	submitCallback = callback;
+    submitUrlHttpReq.onreadystatechange = submitFormReady;
+	reply = false;
+	
+	var url = symbianOrgBaseUrl + "/forum/newthread.php?do=newthread&f=" + forumid;
+	submitUrlHttpReq.open('GET', url, true);
+	submitUrlHttpReq.send(null);
+}
+
+// Initiates the submission process by requesting the form
+function submitNewReply(title, content, threadid, postid, callback){
+	uiManager.showNotification(-1, "wait", "Submitting...", -1);
+	
+	// Dealing with vBulletin nastiness...
+	
+	// ensure we have all the cookies we need
+	var vbCookieGet = new Ajax();
+	var vburl = symbianOrgBaseUrl + "/forum/";
+	vbCookieGet.open('GET', vburl, false);
+	vbCookieGet.send(null);
+
+	// Now we have to harvest some info from the post form. 	
+	submitUrlHttpReq = new Ajax();
+	var self = this;
+	submitTitle = title;
+	submitContent = content;
+	submitForumId = null;
+	submitThreadId = threadid;
+	submitPostId = postid;
+	submitCallback = callback;
+    submitUrlHttpReq.onreadystatechange = submitFormReady;
+	reply = true;
+	
+	var url = symbianOrgBaseUrl + "/forum/newreply.php?do=newreply&noquote=1&p=" + postid;
+	submitUrlHttpReq.open('GET', url, true);
+	submitUrlHttpReq.send(null);
+}
+
+
+var forumPostHarvestString_loggedinuser = "name=\"loggedinuser\" value=\"";
+var forumPostHarvestString_poststarttime = "name=\"poststarttime\" value=\"";		
+var forumPostHarvestString_posthash = "name=\"posthash\" value=\"";		
+var forumPostHarvestString_securitytoken = "name=\"securitytoken\" value=\"";		
+		
+// Form has been received, extract important info
+function submitFormReady(){
+	uiManager.showNotification(-1, "wait", "Submitting...", -1);
+    if (submitUrlHttpReq.readyState == 4) {
+        // attempt to get response status
+        var responseStatus = null;
+        try {
+            responseStatus = submitUrlHttpReq.status;
+        } catch (noStatusException) {}
+        
+		
+		var content = submitUrlHttpReq.responseText;
+		checkForSecurityToken("submitFormReady", content);
+
+		// this is what we need to hardvest
+		var forumPostSecurityToken, forumPostHash, forumPostStartTime, forumPostLoggedInUser;
+		
+		if ( content.indexOf(forumPostHarvestString_loggedinuser) == -1 ) {
+			uiManager.showNotification(5000, "warning", "Submit failed.");	
+		} else {
+			forumPostLoggedInUser = extractFormField(content, forumPostHarvestString_loggedinuser);
+			forumPostStartTime = extractFormField(content, forumPostHarvestString_poststarttime);
+			forumPostHash = extractFormField(content, forumPostHarvestString_posthash);
+			forumPostSecurityToken = extractFormField(content, forumPostHarvestString_securitytoken);
+			
+			if (forumPostSecurityToken == null || forumPostSecurityToken.length < 5) {
+			    // workaround for a vBulletin bug, restart the process...
+				login( function(){
+					if (reply) {
+						submitNewReply(submitTitle, // title
+						 submitContent, // message
+						 submitThreadId, // threadid
+						 submitPostId, // threadid
+						 submitCallback);
+					}
+					else {
+						submitNewTopic(submitTitle, // title
+							 submitContent, // message
+							 submitForumId, // forumid
+							 submitCallback);
+					}
+				});
+			} else {
+				doSubmitPost(submitTitle, submitContent, submitForumId, submitCallback, forumPostSecurityToken, forumPostHash, forumPostStartTime, forumPostLoggedInUser);
+			}
+		}
+    }
+}
+
+// Send a POST request with our post information
+function doSubmitPost(title, message, forumid, callback, 
+			forumPostSecurityToken, forumPostHash, forumPostStartTime, forumPostLoggedInUser){
+	uiManager.showNotification(-1, "wait", "Submitting...", -1);
+	var url = null;
+	var parameters = null;
+	
+	if (reply) {
+		// posting a reply to an article
+		url = symbianOrgNewReplyUrl + "do=postreply&t=" + submitThreadId;
+		parameters = "title=" + title + "&message=" + message +
+		"&wysiwyg=0&iconid=0&s=&securitytoken=" + forumPostSecurityToken +
+		"&do=postreply" +
+		"&t=" + submitThreadId + "&p=" + submitPostId + 
+		"&specifiedpost=0" +
+		"&posthash" + forumPostHash +
+		"&poststarttime=" + forumPostStartTime +
+		"&loggedinuser=" + forumPostLoggedInUser +
+		"&multiquoteempty=&sbutton=Submit+Reply&parseurl=1&emailupdate=9999&rating=0";
+	} else {
+		// posting a new thread
+		url = symbianOrgNewThreadUrl + "do=postthread&f=" + forumid;
+		parameters = "do=postthread&f=" + forumid + "&subject=" + title + "&message=" + message +
+		"&wysiwyg=0&taglist=&iconid=0&s=&securitytoken=" + forumPostSecurityToken +
+		"&posthash" + forumPostHash +
+		"&poststarttime=" + forumPostStartTime +
+		"&loggedinuser=" + forumPostLoggedInUser +
+		"&sbutton=Submit+New+Thread&parseurl=1&emailupdate=9999&polloptions=4";
+	}
+	
+	submitUrlHttpReq = new Ajax();
+    submitUrlHttpReq.onreadystatechange = submitComplete;
+    // initiate the request
+	submitUrlHttpReq.open('POST', url, true);
+	submitUrlHttpReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+	submitUrlHttpReq.setRequestHeader("Content-length", parameters.length);
+	submitUrlHttpReq.setRequestHeader("Connection", "close");
+	submitUrlHttpReq.send(parameters);
+}
+
+// Response to our POST has been received, analyse the result
+function submitComplete(){
+    if (submitUrlHttpReq.readyState == 4) {
+		// attempt to get response status
+		var responseStatus = null;
+		try {
+			responseStatus = submitUrlHttpReq.status;
+		} 
+		catch (noStatusException) {
+		}
+		var content = submitUrlHttpReq.responseText;
+		if ( content.indexOf(submitTitle) == -1 ) {
+			uiManager.showNotification(3000, "warning", "Posting failed.");	
+		} else {
+			uiManager.showNotification(3000, "warning", "Please wait...");	
+			if ( submitCallback != null ) {
+				submitCallback.call();
+			}
+		}
+	}	
+}
+
+// Test weather page HTML contains a login form. This is useful in
+// being able to tell weather a login has been successfull, or if
+// we received login prompt instead of XML at any point.
+function isLoginPrompt (text) {
+	return text.indexOf("form name=\"frmLogin\"") != -1;
+}
+
+// Stores the current view, then shows the settings dialog
+// so that once settings dialog is closed, we go back to current screen
+function promptForPassword() {
+		if (uiManager.currentView == settings) {
+			settings.previousView = home;
+		}
+		else {
+			settings.previousView = uiManager.currentView;
+		}
+		uiManager.hideNotification();
+		settings.show();
+}
+
+function extractFormField(content, harvestString){
+	var startind = content.indexOf(harvestString);
+	if ( startind == -1 ) {
+		return null;
+	}
+	startind += harvestString.length;
+	var endind = content.indexOf("\"", startind);
+	return content.substring(startind, endind);
+}
+
+function checkForSecurityToken(where, content) {
+//	var stpos = content.indexOf("securitytoken");
+//	if ( stpos == -1 ) {
+//		var test = content.substring(stpos , stpos + 100);
+//		alert("securityToken not found in " + where + " : "+ test);
+//	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/Forums.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,443 @@
+// ////////////////////////////////////////////////////////////////////////////
+// (c)2009 Symbian Foundation
+// ////////////////////////////////////////////////////////////////////////////
+
+// Forums
+
+// Forums have the following structure:
+//
+// Forum group list
+//   Forum list
+//     Thread list
+//       Message list
+
+// All four views are based on customised RssReader. We customise two aspects:
+// - Parsing XML - data is not RSS
+// - Handling item selection (e.g. creating a new view for a newly selected forum)
+
+// /////////////////////////////////////////////////////////////////////////////
+// Forum groups
+
+// response parser for forum groups
+function forumGroupsResponseParser(broker, responseStatus, xmlDoc) {
+    if (responseStatus == 200 && xmlDoc != null) {
+        // node ref for iterating
+        var node;
+
+		// for compatibility with rss
+		var lastModified = new Date();
+		
+        // init result items array
+        var items = [];
+
+		var elements = xmlDoc.getElementsByTagName("group");
+		for (var i = 0; i < elements.length; i++) {
+			var groupid = elements[i].getAttribute("id");
+			var grouptitle = elements[i].getAttribute("title");
+            items.push({ id: groupid, title: grouptitle});
+		}
+
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
+// FeedPresenter implementation for forum groups
+function ForumGroupsFeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+// ForumGroupsFeedPresenter is a subclass of ButtonFeedPresenter
+ForumGroupsFeedPresenter.prototype = new ButtonFeedPresenter(null);
+
+// ForumGroupsFeedPresenter "Constructor"
+ForumGroupsFeedPresenter.prototype.init = function(rssreader) {
+	ButtonFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+// Handle the click on a specific item
+ForumGroupsFeedPresenter.prototype.feedClicked = function(event){
+	var buttonid = event.source.id;
+	
+	if (buttonid == "latestPosts") {
+		// show latest posts
+		var url = forumFeedURL;
+		var latestPostsView = new RssReader("Latest posts", url, new LatestPostsFeedPresenter(null), this.rssreader, null);
+		latestPostsView.show();
+	}
+	else {
+		// show forum group
+		var groupid = this.items[buttonid].id;
+		var grouptitle = this.items[buttonid].title;
+		
+		var url = forumsListUrl + groupid;
+		var forumListView = new RssReader(grouptitle, url, new ForumsListFeedPresenter(null), this.rssreader, forumListResponseParser);
+		forumListView.show();
+	}
+}
+
+// Create and add controls to be shown before items list.
+ForumGroupsFeedPresenter.prototype.addPreambleItems = function(){
+	var feedItemControl = new NavigationButton("latestPosts", "blueright.gif", "Latest posts");
+    var self = this;
+	feedItemControl.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
+	this.rssreader.addControl(feedItemControl);
+}
+
+
+// ///////////////////////////////////////////////////////////////////////////
+// List of forums in a group
+
+// response parser for forum list - in a group
+function forumListResponseParser(broker, responseStatus, xmlDoc) {
+    if (responseStatus == 200 && xmlDoc != null) {
+        // node ref for iterating
+        var node;
+
+		// for compatibility with rss
+		var lastModified = new Date();
+		
+        // init result items array
+        var items = [];
+
+		// extract items for all group elements
+		var elements = xmlDoc.getElementsByTagName("group");
+		for (var i = 0; i < elements.length; i++) {
+			var forumid = elements[i].getAttribute("id");
+			var forumtitle = elements[i].getAttribute("title");
+            items.push({ id: forumid, title: forumtitle});
+		}
+
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
+// FeedPresenter implementation for forum groups
+function ForumsListFeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+// ForumsListFeedPresenter is a subclass of ButtonFeedPresenter
+ForumsListFeedPresenter.prototype = new ButtonFeedPresenter(null);
+
+// ForumsListFeedPresenter constructor
+ForumsListFeedPresenter.prototype.init = function(rssreader) {
+	ButtonFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+
+// forum has been selected, create a reader showing threads in the forum
+ForumsListFeedPresenter.prototype.feedClicked = function(event){
+	var buttonid = event.source.id;
+	if (buttonid == "latestPosts") {
+		// show latest posts
+		var url = forumFeedURL + "&forumids=";
+		// append requested forum ids
+		for( var i = 0; i < this.items.length; i++) {
+			url += this.items[i].id + ",";
+		}
+		
+		var latestPostsView = new RssReader(
+			"Latest posts in " + this.rssreader.feedName, 
+			url, 
+			new LatestPostsFeedPresenter(null), 
+			this.rssreader, 
+			null);
+		latestPostsView.show();
+	}
+	else {
+		var forumid = this.items[buttonid].id;
+		var forumtitle = this.items[buttonid].title;
+		
+		var url = forumFeedURL + forumsForumSpecQuery + forumid;
+		var forumListView = new RssReader(forumtitle, url, new ThreadListFeedPresenter(null), this.rssreader, null);
+		forumListView.show();
+	}
+}
+
+// Create and add controls to be shown before items list.
+ForumsListFeedPresenter.prototype.addPreambleItems = function(){
+	var feedItemControl = new NavigationButton("latestPosts", "blueright.gif", "Latest posts in " + this.rssreader.feedName);
+    var self = this;
+	feedItemControl.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
+	this.rssreader.addControl(feedItemControl);
+}
+
+
+
+// ///////////////////////////////////////////////////////////////////////////
+// List of threads in a forum
+
+// response parser for thread list is the usual rss parser
+
+// FeedPresenter implementation for forum groups
+function ThreadListFeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+// ThreadListFeedPresenter is a subclass of ButtonFeedPresenter
+ThreadListFeedPresenter.prototype = new ButtonFeedPresenter(null);
+
+// ThreadListFeedPresenter constructor
+ThreadListFeedPresenter.prototype.init = function(rssreader) {
+	ButtonFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+
+// Handle the click on a specific item
+ThreadListFeedPresenter.prototype.feedClicked = function(event){
+	var buttonid = event.source.id;
+	
+	if (buttonid == "newThread") {
+		// extract forum id from rssreader.feedURL
+		var ind = this.rssreader.feedURL.indexOf(forumsForumSpecQuery);
+		var forumid = this.rssreader.feedURL.substring( ind + forumsForumSpecQuery.length);
+		var postForm = new ForumPostForm(this.rssreader, forumid);
+		postForm.show();
+	}
+	else {
+		var weburl = this.items[buttonid].url;
+		
+		// extract thread id from url. looking for t=xxx
+		var ind1 = weburl.indexOf("?t=");
+		if (ind1 == -1) {
+			ind1 = weburl.indexOf("&t=");
+		}
+		if (ind1 != -1) {
+			var threadid = "";
+			var ind2 = weburl.indexOf("&", ind1);
+			if (ind2 == -1) {
+				threadid = weburl.substring(ind1 + 3); // ?t=
+			}
+			else {
+				threadid = weburl.substring(ind1 + 3, ind2); // ?t=
+			}
+			var url = forumThreadUrl + threadid;
+			var title = this.items[buttonid].title;
+			if (title.length > 30) {
+				title = title.substring(0, 30) + "...";
+			}
+			var threadView = new RssReader(title, url, new ThreadFeedPresenter(null), this.rssreader, threadResponseParser);
+			threadView.show();
+		}
+	}
+}
+
+// Create and add controls to be shown before items list.
+ThreadListFeedPresenter.prototype.addPreambleItems = function(){
+	var feedItemControl = new NavigationButton("newThread", "blueright.gif", "Post a new thread");
+    var self = this;
+	feedItemControl.addEventListener("ActionPerformed", function(event) { self.feedClicked(event); });
+	this.rssreader.addControl(feedItemControl);
+}
+
+// ///////////////////////////////////////////////////////////////////////////
+// List of messages in a thread
+
+// response parser for thread list
+function threadResponseParser(broker, responseStatus, xmlDoc) {
+    if (responseStatus == 200 && xmlDoc != null) {
+        // node ref for iterating
+        var node;
+
+		// for compatibility with rss
+		var lastModified = new Date();
+		
+        // init result items array
+        var items = [];
+
+		// iterate over message elements
+		var elements = xmlDoc.getElementsByTagName("message");
+		for (var i = 0; i < elements.length; i++) {
+			var postid;
+			var threadid;
+			var username;
+			var title;
+			var dateline;
+			var pagetext;
+			var isdeleted;
+			
+			// extract info about the post
+			node = elements[i].firstChild;
+			while (node != null) {
+				if ( node.nodeName == "postid" ) postid=getTextOfNode(node);
+				else if ( node.nodeName == "threadid" ) threadid=getTextOfNode(node);
+				else if ( node.nodeName == "username" ) username=getTextOfNode(node);
+				else if ( node.nodeName == "title" ) title=getTextOfNode(node);
+				else if ( node.nodeName == "dateline" ) dateline=getTextOfNode(node);
+				else if ( node.nodeName == "pagetext" ) pagetext=getTextOfNode(node);
+				else if ( node.nodeName == "isdeleted" ) isdeleted=getTextOfNode(node);
+				node = node.nextSibling;
+			}
+			if ( isdeleted == 1 ) continue;
+			
+			items.push({
+				postid: postid,
+				threadid: threadid,
+				username: username,
+				title: title,
+				dateline: dateline,
+				pagetext: pagetext
+			});
+		}
+
+        // update was completed successfully
+        return { status: "ok", lastModified: lastModified, items: items };
+    } else {
+        // update failed
+        return { status: "error" };
+    }
+}
+
+// FeedPresenter implementation for forum groups
+function ThreadFeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+// ThreadFeedPresenter is a subclass of HtmlFeedPresenter
+ThreadFeedPresenter.prototype = new HtmlFeedPresenter(null);
+
+// ThreadFeedPresenter constructor
+ThreadFeedPresenter.prototype.init = function(rssreader) {
+	HtmlFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+
+// Handle the click on a specific item
+ThreadFeedPresenter.prototype.feedClicked = function(event){
+	// do nothing
+}
+
+// Create a control that represents this item and add it to
+// parent rss reader
+ThreadFeedPresenter.prototype.show = function(item) {
+	// get a feed item control from the pool or create one and
+	// place it in the pool if there aren't enough feed item controls
+	var feedItemControl = new ContentPanel(null, null, null, true);
+
+	// initialize feed item control
+	var title = item.title;
+	if ( title.length == 0 ) { 
+		title = "Re:";
+		item.title = title;
+	}
+	feedItemControl.setCaption(bbcode2html(title));
+	feedItemControl.setContent(this.getContentHTMLForFeedItem(item));
+	feedItemControl.setExpanded(true);
+	
+	// add the feed item control to the main view
+	this.rssreader.feedItemControls.push(feedItemControl);
+	this.rssreader.addControl(feedItemControl);
+}
+
+// Generate HTML content from the feed item
+ThreadFeedPresenter.prototype.getContentHTMLForFeedItem = function (item){
+	var buf = "";
+	
+	// item date
+	if (item.dateline != null) {
+		var date = new Date();
+		date.setTime(item.dateline*1000);
+		buf += "<div class=\"FeedItemDate\">" ;
+		if ( item.username != null ) {
+			buf += item.username + ", ";
+		}
+		buf += date + "</div>";
+	}
+	
+	// item description
+	if (item.pagetext != null) {
+		var text = bbcode2html(item.pagetext);
+		text = text.replace(/\r\n/g, "<br>");
+		buf += "<div class=\"FeedItemDescription\">" + text + "</div>";
+        buf += "<div class=\"FeedItemLink\">";
+		buf += "<a href=\"JavaScript:void(0)\" onclick=\"showReplyForm(" 
+				+ item.threadid+ "," + item.postid + ", '" + item.title
+				+ "'); return false;\">";
+		buf += "<strong>Reply to this post<strong></a>"
+		buf += "</div>";
+	}
+	
+	return buf;
+}
+
+// Show the reply-to-post form
+function showReplyForm(threadid, postid, title) {
+	var replyForm = new ForumReplyForm(uiManager.currentView, threadid, postid, title);
+	replyForm.show();
+}
+
+
+// ///////////////////////////////////////////////////////////////////////////
+// Latest posts - same as ThreadListFeedPresenter, only has no preamble items
+// because it doesn't show one thread (so we can't post to latest items)...
+
+// FeedPresenter implementation for latest posts
+function LatestPostsFeedPresenter(rssreader){
+	if (rssreader) {
+		this.init(rssreader);
+	}
+}
+
+LatestPostsFeedPresenter.prototype = new ThreadListFeedPresenter(null);
+
+// ForumGroupsFeedPresenter "Constructor"
+LatestPostsFeedPresenter.prototype.init = function(rssreader) {
+	ButtonFeedPresenter.prototype.init.call(this, rssreader);
+}
+
+// LatestPostsFeedPresenter has no preamble items
+LatestPostsFeedPresenter.prototype.addPreambleItems = function(){
+}
+
+
+// ///////////////////////////////////////////////////////////////////////////
+// Utilities
+
+
+// feeds contain bbcodes - this function should turn the bbcode markup
+// to HTML
+function bbcode2html(s) {
+	return sanitize(s);
+}
+
+// Forum posts can be be quite messy and include bbcodes, smilies etc.
+// This function does the minimum by stripping bbcodes and such
+function sanitize(text) {
+	var prevind = 0;
+	var ind = text.indexOf("[");
+	if ( ind == -1 ) return text;
+	var buf = "";
+	while ( ind != -1 ) {
+		buf += text.substring(prevind, ind);
+		var ind2 = text.indexOf("]", ind);
+		if ( ind2 != -1 ) {
+			prevind = ind2+1;
+		} else {
+			break;
+		}
+		ind = text.indexOf("[", prevind);
+	}
+	if ( prevind > 0 && prevind < text.length) {
+		buf += text.substring(prevind);
+	}
+	return buf;
+}
+
+
+
Binary file Symbian.org/Icon.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/Info.plist	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Nokia//DTD PLIST 1.0//EN" "http://www.nokia.com/NOKIA_COM_1/DTDs/plist-1.0.dtd">
+<plist version="1.0">
+    <dict>
+        <key>DisplayName</key>
+        <string>Symbian.org</string>
+        <key>Identifier</key>
+        <string>org.symbian.developer.widget</string>
+        <key>Version</key>
+        <string>1.0</string>
+        <key>MainHTML</key>
+        <string>index.html</string>
+        <key>AllowNetworkAccess</key>
+        <true/>
+    </dict>
+</plist>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/Login.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,76 @@
+// ////////////////////////////////////////////////////////////////////////////
+// (c)2009 Symbian Foundation
+// ////////////////////////////////////////////////////////////////////////////
+
+
+// Login to the developer site
+
+var loginUrlContent = null;
+var loginUrlHttpReq = null;
+var loginCallback = null;
+
+function login(callback){
+	if ( forumUsername == null || forumPassword == null ) {
+		loginInitiated = true;
+		loginInitiatedCallback = callback;
+		promptForPassword();
+		return;
+	}
+	loginCallback = callback;
+	loginInitiated = false;
+	loginInitiatedCallback = null;
+	uiManager.showNotification(-1, "wait", "Please wait...", -1);	
+	
+	var parameters =  symbianOrgLoginUsernameField + "=" + forumUsername
+	          + "&" + symbianOrgLoginPasswordField + "=" + forumPassword
+			  + "&submit=Login&image_submit.x=0&image_submit.y=0&image_submit=submit"
+			  + "&referrer="+symbianOrgBaseUrl;
+	loginUrlHttpReq = new Ajax();
+    loginUrlHttpReq.onreadystatechange = loginComplete;
+	
+    // initiate the request
+	loginUrlHttpReq.open('POST', symbianOrgLoginUrl +"?referer="+symbianOrgBaseUrl, true);
+	loginUrlHttpReq.setRequestHeader("Referer", symbianOrgBaseUrl);
+	loginUrlHttpReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+	loginUrlHttpReq.setRequestHeader("Content-length", parameters.length);
+	loginUrlHttpReq.setRequestHeader("Connection", "close");
+	loginUrlHttpReq.send(parameters);
+}
+
+function loginComplete(){
+	if ( loginUrlHttpReq == null ) {
+		return;
+	}
+    // complete request?
+	var readyState = loginUrlHttpReq.readyState;
+    // attempt to get response status
+    var responseStatus = null;
+    try {
+        responseStatus = loginUrlHttpReq.status;
+    } catch (noStatusException) {}
+    if (readyState == 4) {
+
+		if (responseStatus < 300) {
+			
+			var content = loginUrlHttpReq.responseText;
+			if (content.indexOf("LoginWelcome") == -1) {
+				uiManager.showNotification(3000, "warning", "Login failed.");
+				promptForPassword();
+			}
+			else {
+				uiManager.hideNotification();
+				if (loginCallback != null) {
+					loginCallback.call();
+				}
+				checkForSecurityToken("loginComplete", content);
+			}
+		} else if (responseStatus < 400) {
+			// do nothing, this must be a redirect
+		} else {
+			uiManager.hideNotification();
+			uiManager.showNotification(3000, "warning", "Login failed.");
+			promptForPassword();
+		}
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/Main.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,348 @@
+// ////////////////////////////////////////////////////////////////////////////
+// (c)2009 Symbian Foundation
+// ////////////////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////////////////
+// A widget for accessing developer.symbian.org forums
+
+
+// Reference to the WRTKit user interface manager and main view.
+var uiManager;
+
+// Global settings / URLs and such
+
+// Symbian.org web site base URL
+//var symbianOrgBaseUrl = "http://staging.foundationhost.org";
+//var symbianOrgBaseUrlSsl = "https://staging.foundationhost.org";
+var symbianOrgBaseUrl = "http://developer.symbian.org";
+var symbianOrgBaseUrlSsl = "https://developer.symbian.org";
+var registrationURL = symbianOrgBaseUrl + "/main/user_profile/register.php";
+var blogFeedName = "Symbian Blog";
+var blogFeedUrl = "http://blog.symbian.org/feed/";
+
+// FORUM vars and settings 
+var symbianOrgNewThreadUrl = symbianOrgBaseUrl+"/forum/newthread.php?";
+var symbianOrgNewReplyUrl = symbianOrgBaseUrl+"/forum/newreply.php?";
+var symbianOrgLoginUrl = symbianOrgBaseUrlSsl+"/main/user_profile/login.php";
+var symbianOrgLoginUsernameField = "username";
+var symbianOrgLoginPasswordField = "password";
+var forumUsername = null	;
+var forumPassword = null;
+
+// Feed name, URL etc for forums
+var forumFeedName = "Symbian.org Forums";
+var forumFeedURL = symbianOrgBaseUrl+ "/forum/external.php?type=rss2"; //&fulldesc=1&lastpost=1
+var forumsForumSpecQuery = "&forumid=";
+var forumFeedUpdateFrequency = -1;
+
+var forumGroupsUrl = symbianOrgBaseUrl+ "/rss/forum.php?type=groups";
+var forumsListUrl = symbianOrgBaseUrl+ "/rss/forum.php?type=forums&group=";
+var forumThreadUrl = symbianOrgBaseUrl+ "/rss/forum.php?type=threadmsgs&threadid=";
+
+// Wiki url etc
+var wikiFeedName = "New on Symbian.org Wiki";
+var wikiFeedUrl = symbianOrgBaseUrl+"/wiki/index.php?title=Special:NewPages&feed=rss";
+var wikiBaseUrl = symbianOrgBaseUrl+"/wiki/index.php";
+
+// Update variables
+var myversion = "1.0rc3";
+var versionWikiPageUrl = wikiBaseUrl + "/Symbian.org_WRT_Widget";
+var versionWikiPageString = "Current widget version is [";
+var downloadUrl = symbianOrgBaseUrl + "/wiki/images/c/c5/Symbian.org.wgz";
+
+// UI elements
+
+// blog / forum instances
+// all are SOScreen subclasses
+var home;   // home screen
+var blog;   // RSSReader showing blog
+var wiki;   // RSSReader showing wiki
+var bugzila; // RSSReader showing bugzilla feeds
+var forumGroups; // RSSReader showing list of forum groups
+var settings;
+var about;
+
+// currently showing SOScreen
+var currentScreen = null;
+
+// Controls for the settings view
+var forumUsernameControl;
+var forumPasswordControl;
+
+// Constants for menu item identifiers.
+var MENU_ITEM_SETTINGS = 0;
+var MENU_ITEM_REFRESH = 1;
+var MENU_ITEM_ABOUT = 2;
+var MENU_ITEM_CHECK_UPDATE = 3;
+
+// Flag indicating weather the web site login has been initiated
+var loginInitiated = false;
+var loginInitiatedCallback = null;
+
+
+var widgetHomepage = symbianOrgBaseUrl + "/wiki/index.php?title=Symbian.org_WRT_Widget&action=render";
+var aboutText = "<strong>Symbian.org "+myversion+"</strong><br>"
+				+ "Symbian.org WRT Widget is a Web Runtime application which allows mobile "
+				+ "access to Symbian Foundation Forums, Blog, Wiki and Bugzilla. <br>"
+				+ "For more information and updates check <div class=FeedItemLink>"
+				+ "<a href=\"JavaScript:void(0)\" onclick=\"openURL('" 
+				+ widgetHomepage 
+				+ "'); return false;\">"
+				+" Symbian.org Widget Homepage </a> </div><p>"
+				+ "Credits: Ivan Litovski, Ryan Grentz, James Mentz";
+
+
+// Called from the onload event handler to initialize the widget.
+function init() {
+	
+    // set tab-navigation mode and show softkeys
+    // (only if we are in the WRT environment)
+    if (window.widget) {
+        widget.setNavigationEnabled(false);
+        window.menu.showSoftkeys();
+        // create menu
+        var settingsMenuItem = new MenuItem("Settings", MENU_ITEM_SETTINGS);
+        settingsMenuItem.onSelect = menuItemSelected;
+        menu.append(settingsMenuItem);
+        var refreshMenuItem = new MenuItem("Refresh", MENU_ITEM_REFRESH);
+        refreshMenuItem.onSelect = menuItemSelected;
+        menu.append(refreshMenuItem);
+		var aboutMenuItem = new MenuItem("About", MENU_ITEM_ABOUT);
+		aboutMenuItem.onSelect = menuItemSelected;
+		menu.append(aboutMenuItem);
+		var updateMenuItem = new MenuItem("Check for updates", MENU_ITEM_CHECK_UPDATE);
+		updateMenuItem.onSelect = menuItemSelected;
+		menu.append(updateMenuItem);
+    }
+
+    // load prefs 
+	if (!forumUsername || !forumPassword) {
+		loadPreferences();
+	}
+
+    // create UI manager
+    uiManager = new UIManager();
+    
+	// Create the home view
+	home = new ListView(null, "<img src=logo.png>");
+	
+	// add forums button
+	var forumsButton = new NavigationButton(1, "right.gif", "Forums")
+	forumsButton.addEventListener("ActionPerformed", function(){forumGroups.show();});
+	home.addControl(forumsButton);
+
+	// add blogs button
+	var blogsButton = new NavigationButton(2, "right.gif", "Blogs")
+	blogsButton.addEventListener("ActionPerformed", function(){blog.show();});
+	home.addControl(blogsButton);
+	
+	// add wiki button
+	var wikiButton = new NavigationButton(3, "right.gif", "Wiki")
+	wikiButton.addEventListener("ActionPerformed", function(){wiki.show();});
+	home.addControl(wikiButton);
+	
+	// add bugzilla button
+	var bugzillaButton = new NavigationButton(3, "right.gif", "Bugzilla")
+	bugzillaButton.addEventListener("ActionPerformed", function(){login(function(){bugzilla.show();});});
+	home.addControl(bugzillaButton);
+	
+	// soft keys
+	home.setupSoftKeys = function()  {
+	    if (window.widget) {
+			menu.setRightSoftkeyLabel("Exit", function(){window.close();});
+	    }
+	}
+	
+	// create blog screen
+	blog = new RssReader(blogFeedName, blogFeedUrl, null, home, null);
+		
+	// create wiki screen
+	wiki = new RssReader(wikiFeedName, wikiFeedUrl, new ButtonFeedPresenter(null), home, null);
+	
+	// wiki feed contains full article text for many articles 
+	// this takes up a _lot_ of memory. Also we don't 
+	// really want the full text at the stage when we want a list
+	// of recent articles.
+	wiki.ignoreContent = true;
+	
+	wiki.maxItems = 20;
+	
+	bugzilla = new BugzillaSearchPanel(home);
+	
+	// create the top level forums screen - list of forum groups
+	// forumsGroup, forum and thread screens are dynamically generated by forumGroups
+	forumGroups = new RssReader("Forums", forumGroupsUrl, new ForumGroupsFeedPresenter(null), home, forumGroupsResponseParser);
+
+    // create settings view
+    settings = new ListView(null, createCaption("Settings"));
+	settings.previousView = home;
+	
+	var settingsIntroLabel = new Label(null, null, 
+		"In order to access all site features, you must login. "
+		+ "If you have not registered yet, please click the 'Register' button below.");
+		
+	settings.addControl(settingsIntroLabel);
+    // forum username control
+    forumUsernameControl = new TextField('forumUsername', "Symbian.org username", forumUsername?forumUsername:"");
+    settings.addControl(forumUsernameControl);
+	
+    // forum password control
+    forumPasswordControl = new TextField('forumPassword', "Symbian.org password", forumPassword?forumPassword:"", true);
+    settings.addControl(forumPasswordControl);
+
+    // save settings button
+    settingsSaveButton = new FormButton(null, "Save");
+    settingsSaveButton.addEventListener("ActionPerformed", saveSettingsClicked);
+    settings.addControl(settingsSaveButton);
+    
+
+    // cancel settings button
+    var settingsRegisterButton = new FormButton(null, "Register");
+    settingsRegisterButton.addEventListener("ActionPerformed", function(){openURL(registrationURL);});
+    settings.addControl(settingsRegisterButton);
+
+    // cancel settings button
+    settingsCancelButton = new FormButton(null, "Cancel");
+    settingsCancelButton.addEventListener("ActionPerformed", function(){settings.goBack();});
+    settings.addControl(settingsCancelButton);
+	
+	//Create about view
+	about = new ListView(null, createCaption("Symbian.org"));
+    about.previousView = home;
+	// About label control
+	aboutLabel = new ContentPanel(null, null, null, true);
+	aboutLabel.setCaption("About this Widget");
+	aboutLabel.setContent(aboutText);
+	aboutLabel.setExpanded(true);
+	about.addControl(aboutLabel);
+
+	home.show();
+	login(null);	
+}
+
+// Callback for when menu items are selected.
+function menuItemSelected(id) {
+	var currentView = uiManager.getView();
+    switch (id) {
+        case MENU_ITEM_SETTINGS:
+			if ( currentView == settings || currentView == about) {
+				settings.previousView = home;
+			} else {
+				settings.previousView = currentView;
+			}
+			uiManager.hideNotification();
+            settings.show();
+            break;
+        case MENU_ITEM_REFRESH:
+            currentView.update(true);
+            break;
+        case MENU_ITEM_CHECK_UPDATE:
+            checkForUpdates();
+            break;
+		case MENU_ITEM_ABOUT:
+			if ( currentView == settings || currentView == about) {
+				about.previousView = home;
+			} else {
+				about.previousView = currentView;
+			}
+			about.show();
+			break;
+    }
+}
+
+// Loads widget preferences.
+function loadPreferences() {
+    if (window.widget) {
+        // load settings from widget preferences store
+        forumUsername = widget.preferenceForKey("forumUsername");
+        forumPassword = widget.preferenceForKey("forumPassword");
+    }
+}
+
+// Loads widget preferences.
+function savePreferences() {
+    if (window.widget) {
+        // save settings in widget preferences store
+        widget.setPreferenceForKey(forumUsername, "forumUsername");
+        widget.setPreferenceForKey(forumPassword, "forumPassword");
+    }
+}
+
+// Callback for settings view save button.
+function saveSettingsClicked() {
+	forumUsername = forumUsernameControl.getText();
+	forumPassword = forumPasswordControl.getText();
+
+    // save preferences
+    savePreferences();
+    
+	settings.goBack();
+	
+	if ( loginInitiated ) {
+		login(loginInitiatedCallback);
+	}
+}
+
+// Opens a URL in a separate browser window
+function openURL(url) {
+    if (window.widget) {
+        // in WRT
+        widget.openURL(url);
+    } else {
+        // outside WRT
+        window.open(url, "NewWindow");
+    }
+}
+
+var updatePageAjax = null;
+
+function checkForUpdates() {
+	uiManager.showNotification(-1, "wait", "Checking for updates...", -1);
+	updatePageAjax = new Ajax();
+	updatePageAjax.onreadystatechange = checkForUpdatesStage2;
+	updatePageAjax.open('GET', versionWikiPageUrl, true);
+	updatePageAjax.send(null);	
+}
+
+function checkForUpdatesStage2() {
+    if (updatePageAjax.readyState == 4) {
+		// extract version number
+		var content = updatePageAjax.responseText;
+		var ind = content.indexOf(versionWikiPageString);
+		if ( ind == -1 ) {
+			uiManager.showNotification(3000, "warning", "Update failed, check manually.");
+			return;
+		}
+		ind += versionWikiPageString.length;
+		var ind2 = content.indexOf("]",ind);
+		if ( ind2 == -1 || (ind2-ind) > 10 ) {
+			uiManager.showNotification(3000, "warning", "Update failed, check manually.");
+			return;
+		}
+		var version = content.substring(ind,ind2);
+		// compare to this version
+		if ( version != myversion ) {
+			var answer = confirm("Install new version " + version + "?");
+			if (answer) {
+				// ok, we have the update
+				uiManager.hideNotification();
+				openURL(downloadUrl);
+			} else {
+			uiManager.showNotification(3000, "info", "Update cancelled.");
+			}
+		} else {
+			uiManager.showNotification(3000, "info", "Up to date!");
+		}
+	}
+}
+
+function createCaption(caption) {
+	if (caption.length > 30) {
+		caption = caption.substring(0, 30) + "...";
+	}
+	return  "<table border=0>"
+		+ "<tr><td><img src=titlebar.png style=\"{vertical-align:middle}\" > </td></td><td>" 
+		+ "<p class=ListViewCaptionText>"+ caption +"</p>"
+		+ "</td></tr></table>";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/RssReader.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,137 @@
+///////////////////////////////////////////////////////////////////////////////
+// RSS Reader from WRTKit examples, modified for Symbian.org
+
+// RSS reader class
+
+function RssReader(aFeedName, aFeedUrl, aFeedPresenter, aParent, aResponseParser){
+	this.responseParser = aResponseParser;
+	this.feedUpdateBroker = null;
+	this.feedUpdateBrokerActive = false;
+	this.feedName = aFeedName;
+	this.feedURL = aFeedUrl;
+	this.feedUpdateForced = false;
+	this.feedItemControls = [];
+	this.feedLastModified = 0;
+	this.ignoreContent = false;
+	this.hasData = false;
+	this.startFromItem = 0;
+	this.maxItems = 0;
+	
+	var caption = createCaption(aFeedName);
+	
+	ListView.prototype.init.call(this, null, caption);
+	this.previousView = aParent;
+	if (aFeedPresenter != null) {
+		this.feedPresenter = aFeedPresenter;
+		this.feedPresenter.init(this);
+	} else {
+		this.feedPresenter = new HtmlFeedPresenter(this);
+	}
+	
+	// add pre-amble items (latest posts, new thread, reply etc)
+	this.feedPresenter.addPreambleItems();
+}	
+
+RssReader.prototype = new ListView(null, null);
+	
+// Callback function that gets called when a feed update has completed.
+RssReader.prototype.feedUpdateCompleted = function(event){
+	// remove cancel button
+	this.setupSoftKeys();
+	if (event.status == "ok") {
+		// if there aren't any feed items yet, we'll hide the progress dialog
+		
+		// check if the feed has updated
+		if (event.lastModified != this.feedLastModified) {
+			// remember the last modified timestamp
+			this.feedLastModified = event.lastModified;
+			
+			// feed fetched and parsed successfully
+			this.setFeedItems(event.items);
+			
+			// focus the first feed item control
+			// (but only if we are in the main view)
+			if (this.feedItemControls.length > 0 ) {
+				this.feedItemControls[0].setFocused(true);
+			}
+		}
+		uiManager.hideNotification();
+	}
+	else if (event.status != "cancelled") {
+		// show error message
+		uiManager.showNotification(3000, "warning", "Error while updating feed!<br/>(check network settings)");
+	}
+	
+	// reset the broker 
+	this.feedUpdateBroker = null;
+	this.feedUpdateBrokerActive = false;
+	
+	// reset commanded feed update flag
+	this.feedUpdateForced = false;
+}
+	
+// Removes feed items.
+RssReader.prototype.removeFeedItems = function (){
+	// remove all current feed items from the main view
+	for (var i = 0; i < this.feedItemControls.length; i++) {
+		this.removeControl(this.feedItemControls[i]);
+	}
+	
+	// reset feed item control array
+	this.feedItemControls = [];
+}
+	
+
+// Sets feed items.
+RssReader.prototype.setFeedItems = function (items){
+	// start by removing all current feed items
+	this.removeFeedItems();
+	
+	if (items.length == 0) {
+		this.feedPresenter.showNoItems();
+	}
+	else {
+		// create new feed items and add them to the main view
+		// use feed item pool to recycle controls
+		for (var i = 0; i < items.length; i++) {
+			var item = items[i];
+			this.feedPresenter.show(item);
+		}
+		
+	}
+	this.hasData = true;
+}
+	
+	
+// Update feed
+RssReader.prototype.update = function(forceFeedUpdate){
+	if ( this.hasData && !forceFeedUpdate ) {
+		return;
+	}		
+	this.feedUpdateForced = forceFeedUpdate;
+	
+	// check if a feed update has been scheduled, if it's time to update now,
+	// and if there's no update currently in progress and if we're in the main view
+	if ((this.feedURL != null) && (!this.feedUpdateBrokerActive) ) { //&& (uiManager.getView() == this) ) {
+		// fetch the feed from the specified URL
+		this.feedUpdateBrokerActive = true;
+		this.feedUpdateBroker = new FeedUpdateBroker();
+		this.feedUpdateBroker.startFromItem = this.startFromItem;
+		this.feedUpdateBroker.maxItems = this.maxItems;
+		
+		if ( this.responseParser != null ) {
+			this.feedUpdateBroker.responseParser = this.responseParser;
+		}
+		this.feedUpdateBroker.ignoreContent = this.ignoreContent;
+		this.feedUpdateBroker.fetchFeed(this.feedURL, this);
+		// allow cancelling
+	    if (window.widget) {
+			var self = this;
+			menu.setRightSoftkeyLabel("Cancel", function(){
+				self.feedUpdateBroker.cancel(); self.setupSoftKeys();
+				uiManager.hideNotification();
+				});
+	    }
+		uiManager.showNotification(-1, "wait", "Loading feed...", -1);
+	}
+}
Binary file Symbian.org/WRTKit/Resources/CheckBox.png has changed
Binary file Symbian.org/WRTKit/Resources/ContentPanelFoldIcons.png has changed
Binary file Symbian.org/WRTKit/Resources/ControlAssemblyBackground.png has changed
Binary file Symbian.org/WRTKit/Resources/DocumentBackground.png has changed
Binary file Symbian.org/WRTKit/Resources/FormButtonCenter.png has changed
Binary file Symbian.org/WRTKit/Resources/FormButtonLeft.png has changed
Binary file Symbian.org/WRTKit/Resources/FormButtonRight.png has changed
Binary file Symbian.org/WRTKit/Resources/ListViewCaptionBackground.png has changed
Binary file Symbian.org/WRTKit/Resources/NotificationPopupBackground.png has changed
Binary file Symbian.org/WRTKit/Resources/NotificationPopupTypeIndicator.png has changed
Binary file Symbian.org/WRTKit/Resources/ProgressBarUnknown.gif has changed
Binary file Symbian.org/WRTKit/Resources/RadioButton.png has changed
Binary file Symbian.org/WRTKit/Resources/ScrollbarThumbBottom.png has changed
Binary file Symbian.org/WRTKit/Resources/ScrollbarThumbMiddle.png has changed
Binary file Symbian.org/WRTKit/Resources/ScrollbarThumbTop.png has changed
Binary file Symbian.org/WRTKit/Resources/ScrollbarTrackBottom.png has changed
Binary file Symbian.org/WRTKit/Resources/ScrollbarTrackMiddle.png has changed
Binary file Symbian.org/WRTKit/Resources/ScrollbarTrackTop.png has changed
Binary file Symbian.org/WRTKit/Resources/SeparatorCenter.png has changed
Binary file Symbian.org/WRTKit/Resources/SeparatorLeft.png has changed
Binary file Symbian.org/WRTKit/Resources/SeparatorRight.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/Resources/UI.css	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,912 @@
+	/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+/******************************************************************************/
+/*        Definition of visuals for the WRTKit user interface toolkit         */
+/******************************************************************************/
+
+/******************************************************************************/
+/* Document body rules */
+
+body {
+    margin: 0px;
+    background: url("DocumentBackground.png") repeat;  /* repeat-x fixed; */
+    font: normal 12px Arial, sans-serif;
+    color: rgb(0,0,0);
+}
+
+
+/******************************************************************************/
+/* Override default WRT styling for HTML form controls */
+
+/* Textarea when focused */
+textarea:focus {
+    outline: none;
+}
+
+/* Textarea when hovering */
+textarea:hover {
+    outline: none;
+}
+
+/* Select elements when focused */
+select:focus {
+    outline: none;
+}
+
+/* Select elements when hovering */
+select:hover {
+    outline: none;
+}
+
+/* Input elements when focused */
+input:focus {
+    outline: none;
+}
+
+/* Input elements when hovering */
+input:hover {
+    outline: none;
+}
+
+/* Link elements */
+a {
+    text-decoration: none;
+    color: rgb(0,0,0);
+}
+
+/* Links when focused */
+a:focus {
+    background: none;
+    outline: none;
+}
+
+/* Links when hovering */
+a:hover {
+    background: none;
+    outline: none;
+}
+
+
+/******************************************************************************/
+/* Rules for default view and document scrollbar containers */
+
+/* Default view container rules */
+.ViewContainer {
+    margin: 0px 0px 0px 0px;
+}
+
+/* Default document scrollbar container rules */
+.DocumentScrollbarContainer {
+    position: fixed;
+    right: 0px;
+    top: 0px;
+    height: 100%;
+    width: 7px;
+}
+
+
+/******************************************************************************/
+/* View style rules */
+
+/* Rules for the list view */
+.ListView {
+    margin: 0px 0px 0px 0px;
+}
+
+/* Rules for the list view caption */
+.ListViewCaption {
+    background: url("ListViewCaptionBackground.png");
+    height: 35px;
+}
+
+/* Rules for the list view caption text */
+.ListViewCaptionText {
+    font-size: 18px;
+    font-weight: bold;
+    padding: 7px 0px 0px 11px;
+}
+
+/* Rules for the list view control list element */
+.ListViewControlList {
+    margin: 1px 10px 1px 3px;
+}
+
+
+/******************************************************************************/
+/* Control style rules */
+
+/* Rules for control root element (rootElement) */
+.Control {
+    
+}
+
+/* Control assembly rules (assemblyElement) */
+.ControlAssembly {
+    background: url("ControlAssemblyBackground.png") repeat-x;
+    padding: 1px 5px;
+}
+
+/* Control assembly in normal state */
+.ControlAssemblyNormal {
+    background-position: 0px 0px;
+}
+
+/* Control assembly in focused state */
+.ControlAssemblyFocus {
+    background-position: 0px -250px;
+}
+
+/* Control assembly in hovering state */
+.ControlAssemblyHover {
+    background-position: 0px -500px;
+}
+
+/* Control assembly in disabled state */
+.ControlAssemblyDisabled {
+    background-position: 0px 0px;
+}
+
+/* Caption for controls (captionElement) */
+.ControlCaption {
+    font-weight: bold;
+    padding: 3px 0px 0px 3px;
+}
+
+/* Caption for controls in normal state */
+.ControlCaptionNormal {
+    
+}
+
+/* Caption for controls when focused */
+.ControlCaptionFocus {
+    color: rgb(0,0,0);
+}
+
+/* Caption for controls when hovering */
+.ControlCaptionHover {
+    
+}
+
+/* Caption for controls when disabled */
+.ControlCaptionDisabled {
+    color: rgb(125,125,125);
+}
+
+/* Control element rules (controlElement) */
+.ControlElement {
+    padding: 3px 3px 3px 3px;
+}
+
+/******************************************************************************/
+/* Label */
+
+/* Rules for the text value of a Label control */
+.LabelText {
+    
+}
+
+
+/******************************************************************************/
+/* ContentPanel */
+
+/* Caption area rules for non-foldable content panels */
+.ContentPanelCaptionNonFoldable {
+    padding: 3px 0px 0px 3px;
+}
+
+/* Caption area rules for foldable content panels */
+.ContentPanelCaptionFoldable {
+    padding: 4px 0px 3px 3px;
+}
+
+/* Rules for fold toggling element in content panel */
+.ContentPanelFoldToggle {
+    background: url("ContentPanelFoldIcons.png") no-repeat;
+    padding-left: 16px;
+}
+
+/* Collapsed fold */
+.ContentPanelFoldToggleCollapsed {
+    background-position: 0px 0px;
+}
+
+/* Expanded fold */
+.ContentPanelFoldToggleExpanded {
+    background-position: 0px -100px;
+}
+
+/* Rules for the content panel caption text */
+.ContentPanelCaptionText {
+    font-weight: bold;
+}
+
+/* Caption text for content panel in normal state */
+.ContentPanelCaptionTextNormal {
+    
+}
+
+/* Caption text for content panel when focused */
+.ContentPanelCaptionTextFocus {
+    color: rgb(0,0,0);
+}
+
+/* Caption text for content panel when hovering */
+.ContentPanelCaptionTextHover {
+    
+}
+
+/* Caption text for content panel when disabled */
+.ContentPanelCaptionTextDisabled {
+    color: rgb(125,125,125);
+}
+
+/* Rules for content in the content panel */
+.ContentPanelContent {
+    padding: 2px 2px 2px 8px;
+}
+
+
+/******************************************************************************/
+/* FormButton */
+
+/* Rules for form button */
+.FormButton {
+    
+}
+
+/* Rules for form button control element */
+.FormButtonControlElement {
+    
+}
+
+/* Rules for form button table (table) */
+.FormButtonTable {
+    width: 100%;
+    border-spacing: 0px;
+    padding: 0px;
+    table-layout: fixed;
+}
+
+/* Form button row (tr) */
+.FormButtonRow {
+    padding: 0px;
+}
+
+/* Rules for form button left cell (td) */
+.FormButtonLeftCell {
+    width: 8px;
+    height: 26px;
+    background: url("FormButtonLeft.png") no-repeat;
+    padding: 0px;
+}
+
+/* Rules for form button center cell (td) */
+.FormButtonCenterCell {
+    height: 26px;
+    background: url("FormButtonCenter.png") repeat-x;
+    padding: 0px;
+    vertical-align: middle;
+    text-align: center;
+}
+
+/* Rules for form button right cell (td) */
+.FormButtonRightCell {
+    width: 8px;
+    height: 26px;
+    background: url("FormButtonRight.png") no-repeat;
+    padding: 0px;
+}
+
+/* Rules for form button left cell in normal state (td) */
+.FormButtonLeftCellNormal {
+    background-position: 0px 0px;
+}
+
+/* Rules for form button left cell in focused state (td) */
+.FormButtonLeftCellFocus {
+    background-position: 0px -50px;
+}
+
+/* Rules for form button left cell in hover state (td) */
+.FormButtonLeftCellHover {
+    background-position: 0px -100px;
+}
+
+/* Rules for form button left cell in disabled state (td) */
+.FormButtonLeftCellDisabled {
+    background-position: 0px -150px;
+}
+
+/* Rules for form button center cell in normal state (td) */
+.FormButtonCenterCellNormal {
+    background-position: 0px 0px;
+}
+
+/* Rules for form button center cell in focused state (td) */
+.FormButtonCenterCellFocus {
+    background-position: 0px -50px;
+}
+
+/* Rules for form button center cell in hover state (td) */
+.FormButtonCenterCellHover {
+    background-position: 0px -100px;
+}
+
+/* Rules for form button center cell in disabled state (td) */
+.FormButtonCenterCellDisabled {
+    background-position: 0px -150px;
+}
+
+/* Rules for form button left cell in normal state (td) */
+.FormButtonRightCellNormal {
+    background-position: 0px 0px;
+}
+
+/* Rules for form button left cell in focused state (td) */
+.FormButtonRightCellFocus {
+    background-position: 0px -50px;
+}
+
+/* Rules for form button left cell in hover state (td) */
+.FormButtonRightCellHover {
+    background-position: 0px -100px;
+}
+
+/* Rules for form button left cell in disabled state (td) */
+.FormButtonRightCellDisabled {
+    background-position: 0px -150px;
+}
+
+/* Rules for form button text */
+.FormButtonText {
+    font-weight: bold;
+}
+
+/* Form button text in normal state */
+.FormButtonTextNormal {
+    color: rgb(255,255,255);
+}
+
+/* Form button text when focused */
+.FormButtonTextFocus {
+    color: rgb(255,255,255);
+}
+
+/* Form button text when hovering */
+.FormButtonTextHover {
+    color: rgb(255,255,255);
+}
+
+/* Form button text when disabled */
+.FormButtonTextDisabled {
+    color: rgb(200,200,200);
+}
+
+
+/******************************************************************************/
+/* NavigationButton */
+
+/* Rules for navigation button */
+.NavigationButton {
+    
+}
+
+/* Rules for navigation button control element */
+.NavigationButtonControlElement {
+    padding: 3px 3px 3px 3px;
+}
+
+/* Rules for navigation button table (table) */
+.NavigationButtonTable {
+    border-spacing: 0px;
+    padding: 0px;
+}
+
+/* Navigation button row (tr) */
+.NavigationButtonRow {
+    padding: 0px;
+}
+
+/* Rules for navigation button image cell (td) */
+.NavigationButtonImageCell {
+    line-height: 1px;
+    font-size: 1px;
+    vertical-align: middle;
+}
+
+/* Rules for navigation button text cell (td) */
+.NavigationButtonTextCell {
+    vertical-align: middle;
+    padding: 0px;
+}
+
+/* Rules for navigation button image */
+.NavigationButtonImage {
+    padding: 0px 5px 0px 0px;
+}
+
+/* Rules for navigation button text */
+.NavigationButtonText {
+    font-weight: bold;
+}
+
+/* Navigation button text in normal state */
+.NavigationButtonTextNormal {
+    
+}
+
+/* Navigation button text when focused */
+.NavigationButtonTextFocus {
+    color: rgb(0,0,0);
+}
+
+/* Navigation button text when hovering */
+.NavigationButtonTextHover {
+    
+}
+
+/* Navigation button text when disabled */
+.NavigationButtonTextDisabled {
+    color: rgb(125,125,125);
+}
+
+
+/******************************************************************************/
+/* TextField */
+
+/* Rules for textField */
+.TextField {
+    width: 100%;
+    border: 1px solid rgb(0,0,0);
+    background: rgb(255,255,255);
+    margin: 0px 0px 3px 0px;
+}
+
+/* TextField in normal state */
+.TextFieldNormal {
+    
+}
+
+/* TextField in focus state */
+.TextFieldFocus {
+    
+}
+
+/* TextField in hover state */
+.TextFieldHover {
+    
+}
+
+/* TextField in disabled state */
+.TextFieldDisabled {
+    color: rgb(50,50,50);
+    background: rgb(200,200,200);
+}
+
+
+/******************************************************************************/
+/* TextArea */
+
+/* Rules for TextArea */
+.TextArea {
+    width: 100%;
+    border: 1px solid rgb(0,0,0);
+    background: rgb(255,255,255);
+    margin: 0px 0px 3px 0px;
+}
+
+/* TextArea in normal state */
+.TextAreaNormal {
+    
+}
+
+/* TextArea in focus state */
+.TextAreaFocus {
+    
+}
+
+/* TextArea in hover state */
+.TextAreaHover {
+    
+}
+
+/* TextArea in disabled state */
+.TextAreaDisabled {
+    color: rgb(50,50,50);
+    background: rgb(200,200,200);
+}
+
+
+/******************************************************************************/
+/* Separator */
+
+/* Rules for Separator (table) */
+.Separator {
+    width: 100%;
+    padding: 0px;
+    border-spacing: 0px;
+    table-layout: fixed;
+    margin: 3px 0px;
+}
+
+/* Separator row (tr) */
+.SeparatorRow {
+    padding: 0px;
+}
+
+/* Separator left cell (td) */
+.SeparatorLeftCell {
+    width: 5px;
+    height: 2px;
+    background: url("SeparatorLeft.png") no-repeat;
+    padding: 0px;
+}
+
+/* Separator center cell (td) */
+.SeparatorCenterCell {
+    height: 2px;
+    background: url("SeparatorCenter.png") repeat-x;
+    padding: 0px;
+}
+
+/* Separator right cell (td) */
+.SeparatorRightCell {
+    width: 6px;
+    height: 2px;
+    background: url("SeparatorRight.png") no-repeat;
+    padding: 0px;
+}
+
+
+/******************************************************************************/
+/* SelectionMenu */
+
+/* Rules for SelectionMenu select element */
+.SelectionMenu {
+    width: 100%;
+    border: 1px solid rgb(0,0,0);
+    background: rgb(255,255,255);
+    margin: 0px 0px 3px 0px;
+}
+
+/* SelectionMenu in normal state */
+.SelectionMenuNormal {
+    
+}
+
+/* SelectionMenu in focus state */
+.SelectionMenuFocus {
+    
+}
+
+/* SelectionMenu in hover state */
+.SelectionMenuHover {
+    
+}
+
+/* SelectionMenu in disabled state */
+.SelectionMenuDisabled {
+    color: rgb(50,50,50);
+    background: rgb(200,200,200);
+}
+
+/* Rules for SelectionMenu option elements */
+.SelectionMenuOption {
+    background: rgb(255,255,255);
+}
+
+/* SelectionMenu option in normal state */
+.SelectionMenuOptionNormal {
+    
+}
+
+/* SelectionMenu option in focus state */
+.SelectionMenuOptionFocus {
+    
+}
+
+/* SelectionMenu option in hover state */
+.SelectionMenuOptionHover {
+    
+}
+
+/* SelectionMenu option in disabled state */
+.SelectionMenuOptionDisabled {
+    color: rgb(50,50,50);
+    background: rgb(200,200,200);
+}
+
+
+/******************************************************************************/
+/* SelectionList */
+
+/* SelectionList option list element */
+.SelectionList {
+    
+}
+
+/* SelectionList option list element in normal state */
+.SelectionListNormal {
+    
+}
+
+/* SelectionList option list element in focus state */
+.SelectionListFocus {
+    
+}
+
+/* SelectionList option list element in hover state */
+.SelectionListHover {
+    
+}
+
+/* SelectionList option list element in disabled state */
+.SelectionListDisabled {
+    
+}
+
+/* SelectionList option element in single selection mode */
+.SelectionListOptionSingle {
+    padding-left: 19px;
+    background: url("RadioButton.png") no-repeat;
+    height: 16px;
+}
+
+/* SelectionList option element in single selection mode, unchecked normal state */
+.SelectionListOptionSingleUncheckedNormal {
+    background-position: 0px 0px;
+}
+
+/* SelectionList option element in single selection mode, unchecked focus state */
+.SelectionListOptionSingleUncheckedFocus {
+    background-position: 0px -50px;
+}
+
+/* SelectionList option element in single selection mode, unchecked diabled state */
+.SelectionListOptionSingleUncheckedDisabled {
+    background-position: 0px -100px;
+}
+
+/* SelectionList option element in single selection mode, checked normal state */
+.SelectionListOptionSingleCheckedNormal {
+    background-position: 0px -150px;
+}
+
+/* SelectionList option element in single selection mode, checked focus state */
+.SelectionListOptionSingleCheckedFocus {
+    background-position: 0px -200px;
+}
+
+/* SelectionList option element in single selection mode, checked diabled state */
+.SelectionListOptionSingleCheckedDisabled {
+    background-position: 0px -250px;
+}
+
+/* SelectionList option element in multi selection mode */
+.SelectionListOptionMulti {
+    padding-left: 19px;
+    background: url("CheckBox.png") no-repeat;
+    height: 16px;
+}
+
+/* SelectionList option element in multi selection mode, unchecked normal state */
+.SelectionListOptionMultiUncheckedNormal {
+    background-position: 0px 0px;
+}
+
+/* SelectionList option element in multi selection mode, unchecked focus state */
+.SelectionListOptionMultiUncheckedFocus {
+    background-position: 0px -50px;
+}
+
+/* SelectionList option element in multi selection mode, unchecked diabled state */
+.SelectionListOptionMultiUncheckedDisabled {
+    background-position: 0px -100px;
+}
+
+/* SelectionList option element in multi selection mode, checked normal state */
+.SelectionListOptionMultiCheckedNormal {
+    background-position: 0px -150px;
+}
+
+/* SelectionList option element in multi selection mode, checked focus state */
+.SelectionListOptionMultiCheckedFocus {
+    background-position: 0px -200px;
+}
+
+/* SelectionList option element in multi selection mode, checked diabled state */
+.SelectionListOptionMultiCheckedDisabled {
+    background-position: 0px -250px;
+}
+
+/* SelectionList option text */
+.SelectionListOptionText {
+    
+}
+
+/* SelectionList option text in normal state */
+.SelectionListOptionTextNormal {
+    
+}
+
+/* SelectionList option text in focus state */
+.SelectionListOptionTextFocus {
+    color: rgb(0,0,0);
+}
+
+/* SelectionList option text in hover state */
+.SelectionListOptionTextHover {
+    
+}
+
+/* SelectionList option text in disabled state */
+.SelectionListOptionTextDisabled {
+    color: rgb(125,125,125);
+}
+
+
+/******************************************************************************/
+/* Scrollbar */
+
+/* Scrollbar root element */
+.Scrollbar {
+    position: absolute;
+    height: 100%;
+    width: 7px;
+}
+
+/* Top portion of scrollbar track */
+.ScrollbarTrackTop {
+    position: absolute;
+    background: url("ScrollbarTrackTop.png") no-repeat;
+    width: 7px;
+    height: 4px;
+}
+
+/* Middle portion of scrollbar track */
+.ScrollbarTrackMiddle {
+    position: absolute;
+    background: url("ScrollbarTrackMiddle.png") repeat-y;
+    width: 7px;
+}
+
+/* Bottom portion of scrollbar track */
+.ScrollbarTrackBottom {
+    position: absolute;
+    background: url("ScrollbarTrackBottom.png") no-repeat;
+    width: 7px;
+    height: 4px;
+}
+
+/* Top portion of scrollbar thumb */
+.ScrollbarThumbTop {
+    position: absolute;
+    background: url("ScrollbarThumbTop.png") no-repeat;
+    width: 7px;
+    height: 5px;
+}
+
+/* Middle portion of scrollbar thumb */
+.ScrollbarThumbMiddle {
+    position: absolute;
+    background: url("ScrollbarThumbMiddle.png") repeat-y;
+    width: 7px;
+}
+
+/* Bottom portion of scrollbar thumb */
+.ScrollbarThumbBottom {
+    position: absolute;
+    background: url("ScrollbarThumbBottom.png") no-repeat;
+    width: 7px;
+    height: 5px;
+}
+
+
+/******************************************************************************/
+/* NotificationPopup */
+
+/* Container that defines the area for the popup dialog */
+.NotificationPopupContainer {
+    position: fixed;
+    bottom: 0px;
+    left: 50%;
+    margin-left: -115px;
+    width: 230px;
+    height: 85px;
+}
+
+/* Notification popup dialog */
+.NotificationPopup {
+    position: absolute;
+    width: 230px;
+    height: 85px;
+    background: url("NotificationPopupBackground.png") repeat-x;
+    border: 1px solid rgb(0,0,0);
+}
+
+/* Notification type indicator */
+.NotificationPopupTypeIndicator {
+    position: absolute;
+    left: 195px;
+    top: 10px;
+    width: 24px;
+    height: 34px;
+    background: url("NotificationPopupTypeIndicator.png") no-repeat;
+}
+
+/* Notification type indicator for notifications of undefined type */
+.NotificationPopupTypeIndicatorNone {
+    background-position: 0px 0px;
+}
+
+/* Notification type indicator for info notifications */
+.NotificationPopupTypeIndicatorInfo {
+    background-position: 0px -50px;
+}
+
+/* Notification type indicator for warning notifications */
+.NotificationPopupTypeIndicatorWarning {
+    background-position: 0px -100px;
+}
+
+/* Notification type indicator for wait notifications */
+.NotificationPopupTypeIndicatorWait {
+    background-position: 0px -150px;
+}
+
+/* Notification text area */
+.NotificationPopupText {
+    position: absolute;
+    left: 10px;
+    top: 8px;
+    width: 180px;
+    height: 50px;
+}
+
+/* Progress bar */
+.NotificationPopupProgressBar {
+    position: absolute;
+    left: 6px;
+    top: 60px;
+    width: 218px;
+    height: 16px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/ActionControl.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,144 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (ÒNokiaÓ) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under NokiaÕs copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The ActionControl class is an abstract base class for action controls like
+// buttons. Don't use ActionControl directly.
+
+// Constructor.
+function ActionControl(id, caption) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption);
+    }
+}
+
+// ActionControl inherits from Control.
+ActionControl.prototype = new Control(UI_NO_INIT_ID);
+
+// Reference to the button element.
+ActionControl.prototype.buttonElement = null;
+
+// Reference to the link element.
+ActionControl.prototype.linkElement = null;
+
+// Enabled status.
+ActionControl.prototype.enabled = false;
+
+// Initializer - called from constructor.
+ActionControl.prototype.init = function(id, caption) {
+    uiLogger.debug("ActionControl.init(" + id + ", " + caption + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, caption);
+    
+    // the control defaults to enabled
+    this.enabled = true;
+}
+
+// Common event listeners hookup function called from subclasses.
+ActionControl.prototype.bindActionControlListeners = function() {
+    var self = this;
+    this.linkElement.addEventListener("focus", function() { self.focusStateChanged(true); }, false);
+    this.linkElement.addEventListener("blur", function() { self.focusStateChanged(false); }, false);
+    this.buttonElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
+    this.buttonElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
+    this.buttonElement.addEventListener("mousedown", function(event) {
+                                                       self.controlClicked(event);
+                                                       event.stopPropagation();
+                                                       event.preventDefault();
+                                                   }, true);
+    this.buttonElement.addEventListener("keydown", function(event) {
+                                                    // center and enter trigger the action
+                                                    if (event.keyCode == 0 || event.keyCode == 13) {
+                                                        self.controlClicked();
+                                                        event.stopPropagation();
+                                                        event.preventDefault();
+                                                    }
+                                                 }, true);
+}
+
+// Returns the enabled state.
+ActionControl.prototype.isEnabled = function() {
+    return this.enabled;
+}
+
+// Sets the enabled state.
+ActionControl.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("ActionControl.setEnabled(" + enabled + ")");
+    // switch the state
+    this.enabled = enabled;
+}
+
+// Sets the focused state for the control.
+// Note: This may not always succeed.
+ActionControl.prototype.setFocused = function(focused) {
+    uiLogger.debug("ActionControl.setFocused(" + focused + ")");
+    if (this.enabled) {
+        if (focused) {
+            this.linkElement.focus();
+        } else {
+            this.linkElement.blur();
+        }
+    }
+}
+
+// Callback for clicks.
+ActionControl.prototype.controlClicked = function(event) {
+    uiLogger.debug("ActionControl.controlClicked()");
+    
+    // if we're enabled then a click results in an action performed event
+    if (this.enabled) {
+        // focus when clicked
+        if (!this.focused) {
+            this.linkElement.focus();
+        }
+        
+        // notify event listeners
+        this.actionPerformed(event);
+    }
+}
+
+// Callback for action performed events.
+ActionControl.prototype.actionPerformed = function(event) {
+    uiLogger.debug("ActionControl.actionPerformed()");
+    // notify event listeners
+    this.fireEvent(this.createEvent("ActionPerformed", event));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/Ajax.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,103 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// Ajax utility calss to create XmlHttpRequest object
+function Ajax() 
+{
+	//	xmlHttpRequest object	
+	var request = null;
+
+    // branch for native XMLHttpRequest object
+    if(window.XMLHttpRequest && !(window.ActiveXObject)) {
+    	try 
+		{
+			request = new XMLHttpRequest();
+			try
+			{
+				//	attach the Bypass code, if the browser is firefox
+				if(netscape.security.PrivilegeManager.enablePrivilege)
+				{
+					//	duplicate the function
+					request._open = request.open;
+					
+					//	redefine the function definition
+					request.open = function(method, url, flag)
+					{
+						try
+						{
+							// Enable Universal Browser Read
+							netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
+
+							//	call the native XmlHttpRequest.open method
+							this._open(method, url, flag);
+						}catch(e)
+						{
+							//	call the native XmlHttpRequest.open method
+							this._open(method, url, flag);
+						}
+					}
+				}
+			}
+			catch(e)
+			{
+				//	eatup all exceptions
+			}
+		} 
+		catch(e) {
+			request = null;
+        }
+    // branch for IE/Windows ActiveX version
+    } else if(window.ActiveXObject) {
+       	try {
+        	request = new ActiveXObject("Msxml2.XMLHTTP");
+      	} catch(e) {
+        	try {
+          		request = new ActiveXObject("Microsoft.XMLHTTP");
+        	} catch(e) {
+          		alert('Failed to create XmlHttprequest');
+				return null;
+        	}
+		}
+    }
+	
+	return (request);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/ContentPanel.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,368 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The ContentPanel class is a control for displaying content. The panel
+// can be expanded and collapsed.
+
+// Constructor.
+function ContentPanel(id, caption, content, foldable, expanded) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, content, foldable, expanded);
+    }
+}
+
+// ContentPanel inherits from Control.
+ContentPanel.prototype = new Control(UI_NO_INIT_ID);
+
+// The element hierarchy in a content panel is as follows:
+//
+// rootElement
+//     assemblyElement
+//         captionElement
+//             foldToggleElement
+//                 captionLinkElement
+//                     captionTextElement
+//     contentElement
+//
+// captionTextElement is moved under foldToggleElement if disabled
+// or captionElement if not foldable
+
+// The fold toggle element used for folding content panels.
+ContentPanel.prototype.foldToggleElement = null;
+
+// The caption link element of this control.
+ContentPanel.prototype.captionLinkElement = null;
+
+// The caption text element of this control.
+ContentPanel.prototype.captionTextElement = null;
+
+// The content element of this control.
+ContentPanel.prototype.contentElement = null;
+
+// The foldable state of this control.
+ContentPanel.prototype.foldable = false;
+
+// The expanded state of this control.
+ContentPanel.prototype.expanded = false;
+
+// Enabled status.
+ContentPanel.prototype.enabled = false;
+
+// Initializer - called from constructor.
+ContentPanel.prototype.init = function(id, caption, content, foldable, expanded) {
+    uiLogger.debug("ContentPanel.init(" + id + ", " + caption + ", " + content + ", " + foldable + ", " + expanded + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, caption);
+    
+    // the control defaults to enabled
+    this.enabled = true;
+    
+    // create caption text element
+    this.captionTextElement = document.createElement("span");
+    
+    // disconnect the control element
+    this.assemblyElement.removeChild(this.controlElement);
+    
+    // set the foldable state
+    this.foldable = foldable;
+    
+    // is this a foldable content panel?
+    if (foldable) {
+        // create fold toggle element
+        this.foldToggleElement = document.createElement("div");
+        this.captionElement.appendChild(this.foldToggleElement);
+        
+        // create caption link and add to caption element
+        this.captionLinkElement = document.createElement("a");
+        this.captionLinkElement.href = "JavaScript:void(0)";
+        this.foldToggleElement.appendChild(this.captionLinkElement);
+        
+        // add the text element to the link element
+        this.captionLinkElement.appendChild(this.captionTextElement);
+        
+        // bind event listeners
+        var self = this;
+        this.captionLinkElement.addEventListener("focus", function() { self.focusStateChanged(true); }, false);
+        this.captionLinkElement.addEventListener("blur", function() { self.focusStateChanged(false); }, false);
+        this.foldToggleElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
+        this.foldToggleElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
+        this.foldToggleElement.addEventListener("mousedown", function(event) {
+                                                                 self.captionClicked();
+                                                                 event.stopPropagation();
+                                                                 event.preventDefault();
+                                                             }, true);
+        this.foldToggleElement.addEventListener("keydown", function(event) {
+                                                               // center and enter trigger the action
+                                                               if (event.keyCode == 0 || event.keyCode == 13) {
+                                                                   self.captionClicked();
+                                                                   event.stopPropagation();
+                                                                   event.preventDefault();
+                                                               }
+                                                           }, true);
+        
+        this.expanded = expanded;
+    } else {
+        // since this is not a foldable panel the content should be expanded
+        this.expanded = true;
+        
+        // add the text element directly to the caption element
+        this.captionElement.appendChild(this.captionTextElement);
+    }
+    
+    // create content element
+    this.contentElement = document.createElement("div");
+    this.contentElement.style.display = this.expanded ? "block" : "none";
+    this.rootElement.appendChild(this.contentElement);
+    
+    // set caption, content and expanded state
+    this.setCaption(caption);
+    this.setContent(content);
+    
+    // update style
+    this.updateStyleFromState();
+}
+
+// Returns the enabled state.
+ContentPanel.prototype.isEnabled = function() {
+    return this.enabled;
+}
+
+// Sets the enabled state.
+ContentPanel.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("ContentPanel.setEnabled(" + enabled + ")");
+    
+    // bail out early if there is no change in state
+    if (this.enabled == enabled) {
+        return;
+    }
+    
+    // set the enabled state
+    this.enabled = enabled;
+    
+    // is this a foldable content?
+    if (this.foldable) {
+         // the caption link must be disabled
+        if (this.enabled) {
+            // diabled -> enabled
+            this.foldToggleElement.removeChild(this.captionTextElement);
+            this.foldToggleElement.appendChild(this.captionLinkElement);
+            this.captionLinkElement.appendChild(this.captionTextElement);
+        } else {
+            // enabled -> diabled
+            this.captionLinkElement.removeChild(this.captionTextElement);
+            this.foldToggleElement.removeChild(this.captionLinkElement);
+            this.foldToggleElement.appendChild(this.captionTextElement);
+        }
+    }
+    
+    // update style
+    this.updateStyleFromState();    
+}
+
+// Returns the caption; null if none.
+ContentPanel.prototype.getCaption = function() {
+    return this.caption;
+}
+
+// Sets the caption; null if none.
+ContentPanel.prototype.setCaption = function(caption) {
+    // bail out if the caption text element has not been created
+    // this is to prevent the superclass init calling this before
+    // we've initialized our custom caption
+    if (this.captionTextElement == null)
+        return;
+    
+    uiLogger.debug("ContentPanel.setCaption(" + caption + ")");
+    
+    // set the display style
+    this.captionElement.style.display = (caption == null) ? "none" : "block";
+    
+    // set the caption
+    this.caption = caption;
+    this.captionTextElement.innerHTML = (caption == null) ? "" : caption;
+    
+    // update style
+    this.updateStyleFromState();
+}
+
+// Returns the content.
+ContentPanel.prototype.getContent = function() {
+    return this.contentElement.innerHTML;
+}
+
+// Sets the content.
+ContentPanel.prototype.setContent = function(content) {
+    uiLogger.debug("ContentPanel.setContent(" + content + ")");
+    this.contentElement.innerHTML = (content == null) ? "" : content;
+}
+
+// Returns the focusable state for the control.
+ContentPanel.prototype.isFocusable = function() {
+    // a content panel is focusable if it's foldable and enabled
+    return (this.foldable && this.enabled);
+}
+
+// Sets the focused state for the control.
+// Note: This may not always succeed.
+ContentPanel.prototype.setFocused = function(focused) {
+    uiLogger.debug("ContentPanel.setFocused(" + focused + ")");
+    if (this.enabled && this.foldable) {
+        if (focused) {
+            this.captionLinkElement.focus();
+        } else {
+            this.captionLinkElement.blur();
+        }
+    }
+    // note that this.focused gets set as a result of focusStateChanged() being called
+    // rather than setting it explicitly here
+}
+
+// Returns the expanded state.
+ContentPanel.prototype.isExpanded = function() {
+    return this.expanded;
+}
+
+// Sets the expanded state.
+ContentPanel.prototype.setExpanded = function(expanded) {
+    uiLogger.debug("ContentPanel.setExpanded(" + expanded + ")");
+    
+    // make sure only foldable content panels are folded
+    if (!this.foldable) {
+        uiLogger.warn("Cannot fold a non-foldable content panel!");
+        return;
+    }
+    
+    this.expanded = expanded;
+    if (this.expanded) {
+        // expand
+        this.contentElement.style.display = "block";
+        
+        // find out control top and bottom
+        var controlTop = this.getAbsoluteTop(this.rootElement);
+        var controlHeight = this.rootElement.clientHeight;
+        var controlBottom = controlTop + controlHeight;
+        
+        // find out the viewport top and bottom
+        var viewportTop = window.scrollY;
+        var viewportHeight = window.innerHeight;
+        var viewportBottom = viewportTop + viewportHeight;
+        
+        // make sure the control is positioned so that it can be seen
+        var overflow = controlBottom - viewportBottom;
+        if (overflow > 0) {
+            // there's overflow so we need to scroll to get the control
+            // into the viewport - however not so far that the control
+            // goes past the viewport top.
+            var distanceToTop = controlTop - viewportTop;
+            var scrollAmount = Math.min(overflow, distanceToTop);
+            window.scrollBy(0, scrollAmount);
+        }
+    } else {
+        // collapse
+        this.contentElement.style.display = "none";
+    }
+    
+    // notify event listeners
+    this.fireEvent(this.createEvent("ExpandedStateChanged", this.expanded));
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Returns the absolute position (y) of the given element.
+ContentPanel.prototype.getAbsoluteTop = function(element) {
+    // traverse from element to root and add top-offset
+    // for each element we find on the way
+    var absTop = 0;
+    while (element != null) {
+        absTop += element.offsetTop;
+        element = element.offsetParent;
+    }
+    return absTop;
+}
+
+// Callback for when the caption is clicked.
+ContentPanel.prototype.captionClicked = function() {
+    uiLogger.debug("ContentPanel.captionClicked()");
+    
+    // if we're enabled then a click results toggling the expanded state
+    if (this.enabled) {
+        // focus when clicked
+        if (!this.focused) {
+            this.captionLinkElement.focus();
+        }
+        
+        // toggle the expanded state
+        this.setExpanded(!this.expanded);
+    }
+}
+
+// Updates the style of the control to reflects the state of the control.
+ContentPanel.prototype.updateStyleFromState = function() {
+    uiLogger.debug("ContentPanel.updateStyleFromState()");
+
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set root element class name
+    this.setClassName(this.rootElement, "Control");
+
+    // set the control assembly class names
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
+    
+    if (this.foldable) {
+        // foldable content panel
+        this.setClassName(this.captionElement, "ContentPanelCaptionFoldable");
+        this.setClassName(this.foldToggleElement, "ContentPanelFoldToggle ContentPanelFoldToggle" + (this.expanded ? "Expanded" : "Collapsed"));
+    } else {
+        // non-folding
+        this.setClassName(this.captionElement, "ContentPanelCaptionNonFoldable");
+    }
+    
+    // set the content caption text class names
+    this.setClassName(this.captionTextElement, "ContentPanelCaptionText ContentPanelCaptionText" + stateName);
+    
+    // set the content element class names
+    this.setClassName(this.contentElement, "ContentPanelContent");
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/Control.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,231 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The Control class is an abstract base class for all user interface controls.
+
+// Constructor.
+function Control(id, caption) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption);
+    }
+}
+
+// Control inherits from UIElement.
+Control.prototype = new UIElement(UI_NO_INIT_ID);
+
+// The view that control belongs to.
+Control.prototype.view = null;
+
+// Is the control focused?
+Control.prototype.focused = false;
+
+// Is the pointer over this control?
+Control.prototype.hovering = false;
+
+// The element hierarchy in a control is as follows:
+//
+// rootElement
+//     assemblyElement
+//         captionElement
+//         controlElement
+//
+// The assembly element groups the portion of a control that typically handle
+// the visual effects for focus and hover states. Having a separate root and
+// assembly elements allows other elements to be added to a control without
+// them being affected by the CSS rules of the assembly element.
+
+// The assembly element of this control.
+Control.prototype.assemblyElement = null;
+
+// The caption of this control; null if none.
+Control.prototype.caption = null;
+
+// The caption element of this control.
+Control.prototype.captionElement = null;
+
+// The control element of this control.
+Control.prototype.controlElement = null;
+
+// Initializer - called from constructor.
+Control.prototype.init = function(id, caption) {
+    uiLogger.debug("Control.init(" + id + ", " + caption + ")");
+    
+    // call superclass initializer
+    UIElement.prototype.init.call(this, id);
+    
+    // create assembly, caption and control elements
+    this.assemblyElement = document.createElement("div");
+    this.captionElement = document.createElement("div");
+    this.assemblyElement.appendChild(this.captionElement);
+    this.controlElement = document.createElement("div");
+    this.assemblyElement.appendChild(this.controlElement);
+    this.rootElement.appendChild(this.assemblyElement);
+    
+    // set the caption
+    // style is not updated because the subclass will update the style later
+    // when it has completely initialized the component
+    this.setCaption(caption, true);
+}
+
+// Returns the caption; null if none.
+Control.prototype.getCaption = function() {
+    return this.caption;
+}
+
+// Sets the caption; null if none.
+Control.prototype.setCaption = function(caption, noStyleUpdate) {
+    uiLogger.debug("Control.setCaption(" + caption + ")");
+    
+    // set the display style
+    this.captionElement.style.display = (caption == null) ? "none" : "block";
+    
+    // set the caption
+    this.caption = caption;
+    this.captionElement.innerHTML = (caption == null) ? "" : caption;
+    
+    // update style
+    if (!noStyleUpdate) {
+        this.updateStyleFromState();
+    }
+}
+
+// Returns the enabled state.
+// Override this in subclasses as required to implement the state change.
+Control.prototype.isEnabled = function() {
+    return false;
+}
+
+// Sets the enabled state.
+// Override this in subclasses as required to implement the state change.
+Control.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("Control.setEnabled(" + enabled + ")");
+}
+
+// Returns the focusable state for the control.
+// Defaults focusable if enabled - override this in subclasses as required.
+Control.prototype.isFocusable = function() {
+    return this.isEnabled();
+}
+
+// Returns the focused state for the control.
+Control.prototype.isFocused = function() {
+    return this.focused;
+}
+
+// Sets the focused state for the control.
+// Note: This may not always succeed.
+// Override this in subclasses as required to implement the state change.
+Control.prototype.setFocused = function(focused) {
+    uiLogger.debug("Control.setFocused(" + focused + ")");
+    // note that this.focused gets set as a result of focusStateChanged() being called
+    // rather than setting it explicitly here
+}
+
+// Called when the focus state has changed for this control.
+Control.prototype.focusStateChanged = function(focused) {
+    uiLogger.debug("Control.focusStateChanged(" + focused + ")");
+    if (this.focused != focused) {
+        this.focused = focused;
+        
+        // let the view know about the focus change
+        if (this.view != null) {
+            this.view.focusedControlChanged(focused ? this : null);
+        }
+        
+        // update the style from the current state
+        this.updateStyleFromState();
+        
+        // notify event listeners
+        this.fireEvent(this.createEvent("FocusStateChanged", focused));
+    }
+}
+
+// Called when the hover state has changed for this control.
+Control.prototype.hoverStateChanged = function(hovering) {
+    uiLogger.debug("Control.hoverStateChanged(" + hovering + ")");
+    if (this.hovering != hovering) {
+        this.hovering = hovering;
+        
+        // update the style from the current state
+        this.updateStyleFromState();
+        
+        // notify event listeners
+        this.fireEvent(this.createEvent("HoverStateChanged", hovering));
+    }
+}
+
+// Helper method that returns the state name for the current state.
+Control.prototype.getStyleStateName = function() {
+    var focusable = this.isFocusable();
+    if (focusable && this.focused) {
+        return "Focus";
+    } else if (focusable && this.hovering) {
+        return "Hover";
+    } else if (!this.isEnabled()) {
+        return "Disabled";
+    } else {
+        return "Normal";
+    }
+}
+
+// Resets the state tracking for focus and hover.
+// Override this in subclasses as required to implement the state reset.
+Control.prototype.resetFocusState = function() {
+    uiLogger.debug("Control.resetFocusState()");
+    this.hovering = false;
+    this.focused = false;
+    this.updateStyleFromState();
+}
+
+// Helper function that sets a classname for an element.
+// Only sets the class name if it actually is different from the current value.
+Control.prototype.setClassName = function(element, className) {
+    if (element.className != className) {
+        element.className = className;
+    }
+}
+
+// Updates the style of the control to reflects the state of the control.
+// Override this in subclasses as required to implement the state change.
+Control.prototype.updateStyleFromState = function() {
+    uiLogger.debug("Control.updateStyleFromState()");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/FormButton.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,177 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The FormButton class implements a button control for use in form-style UIs.
+
+// Constructor.
+function FormButton(id, text) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, text);
+    }
+}
+
+// FormButton inherits from ActionControl.
+FormButton.prototype = new ActionControl(UI_NO_INIT_ID);
+
+// Button table element.
+FormButton.prototype.tableElement = null;
+
+// Button table row element.
+FormButton.prototype.tableRowElement = null;
+
+// Button table left cell element.
+FormButton.prototype.tableLeftCellElement = null;
+
+// Button table center cell element.
+FormButton.prototype.tableCenterCellElement = null;
+
+// Button text element.
+FormButton.prototype.textElement = null;
+
+// Button table right cell element.
+FormButton.prototype.tableRightCellElement = null;
+
+// Initializer - called from constructor.
+FormButton.prototype.init = function(id, text) {
+    uiLogger.debug("FormButton.init(" + id + ", " + text + ")");
+    
+    // call superclass initializer
+    ActionControl.prototype.init.call(this, id, null);
+    
+    // remove caption element
+    this.assemblyElement.removeChild(this.captionElement);
+    
+    // construct the button
+    this.buttonElement = document.createElement("div");
+    this.tableElement = document.createElement("table");
+    this.tableRowElement = document.createElement("tr");
+    this.tableLeftCellElement = document.createElement("td");
+    this.tableCenterCellElement = document.createElement("td");
+    this.linkElement = document.createElement("a");
+    this.linkElement.href = "JavaScript:void(0)";
+    this.textElement = document.createElement("span");
+    this.tableRightCellElement = document.createElement("td");
+    this.tableElement.appendChild(this.tableRowElement);
+    this.tableRowElement.appendChild(this.tableLeftCellElement);
+    this.tableRowElement.appendChild(this.tableCenterCellElement);
+    this.tableCenterCellElement.appendChild(this.linkElement);
+    this.linkElement.appendChild(this.textElement);
+    this.tableRowElement.appendChild(this.tableRightCellElement);
+    this.buttonElement.appendChild(this.tableElement);
+    this.controlElement.appendChild(this.buttonElement);
+    
+    // set the text
+    this.setText(text);
+    
+    // bind event listeners
+    this.bindActionControlListeners();
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Sets the enabled state.
+FormButton.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("FormButton.setEnabled(" + enabled + ")");
+    
+    // bail out early if there is no change in state
+    if (this.enabled == enabled) {
+        return;
+    }
+    
+    // set the enabled state
+    this.enabled = enabled;
+    
+    if (this.enabled) {
+        // diabled -> enabled
+        this.tableCenterCellElement.removeChild(this.textElement);
+        this.tableCenterCellElement.appendChild(this.linkElement);
+        this.linkElement.appendChild(this.textElement);
+    } else {
+        // enabled -> diabled
+        this.linkElement.removeChild(this.textElement);
+        this.tableCenterCellElement.removeChild(this.linkElement);
+        this.tableCenterCellElement.appendChild(this.textElement);
+    }
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Returns the button text.
+FormButton.prototype.getText = function() {
+    return this.textElement.innerHTML;
+}
+
+// Sets the button text.
+FormButton.prototype.setText = function(text) {
+    uiLogger.debug("FormButton.setText(" + text + ")");
+    this.textElement.innerHTML = (text == null) ? "" : text;;
+}
+
+// Updates the style of the control to reflects the state of the control.
+FormButton.prototype.updateStyleFromState = function() {
+    uiLogger.debug("FormButton.updateStyleFromState()");
+    
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set root element class name
+    this.setClassName(this.rootElement, "Control");
+    
+    // set the control assembly class names
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssemblyNormal");
+    
+    // control element
+    this.setClassName(this.controlElement, "ControlElement FormButtonControlElement");
+    
+    // set the button table class names
+    this.setClassName(this.buttonElement, "FormButton");
+    this.setClassName(this.tableElement, "FormButtonTable");
+    this.setClassName(this.tableRowElement, "FormButtonRow");
+    this.setClassName(this.tableLeftCellElement, "FormButtonLeftCell FormButtonLeftCell" + stateName);
+    this.setClassName(this.tableCenterCellElement, "FormButtonCenterCell FormButtonLeftCell" + stateName);
+    this.setClassName(this.tableRightCellElement, "FormButtonRightCell FormButtonLeftCell" + stateName);
+    
+    // set the button text class name
+    this.setClassName(this.textElement, "FormButtonText FormButtonText" + stateName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/ImageLabel.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+// The ImageLabel class implements a control that displays an image
+
+// Constructor.
+function ImageLabel(id, caption, image) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, image);
+    }
+}
+
+// Label inherits from Control.
+ImageLabel.prototype = new Control(UI_NO_INIT_ID);
+
+// Content element for label text.
+ImageLabel.prototype.contentElement = null;
+
+// Content element for label text.
+ImageLabel.prototype.image = null;
+
+// Initializer - called from constructor.
+ImageLabel.prototype.init = function(id, caption, image) {
+    uiLogger.debug("ImageLabel.init(" + id + ", " + caption + ", " + image + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, caption);
+    
+	this.image = image;
+	
+    // create content element
+    this.contentElement = document.createElement("div");
+    this.controlElement.appendChild(this.contentElement);
+    
+    // set the image
+    this.setImage(image);
+}
+
+// Returns the enabled state for the control.
+ImageLabel.prototype.isEnabled = function() {
+    return true;
+}
+
+// Returns the focusable state for the control.
+ImageLabel.prototype.isFocusable = function() {
+    return false;
+}
+
+// Returns the control text.
+ImageLabel.prototype.getImage = function() {
+    return this.contentElement.innerHTML;
+}
+
+// Sets the text for the control.
+ImageLabel.prototype.setText = function(text) {
+    uiLogger.debug("Label.setText(" + text + ")");
+    this.contentElement.innerHTML = (text == null) ? "" : text;
+    this.updateStyleFromState();
+}
+
+// Updates the style of the control to reflects the state of the control.
+ImageLabel.prototype.updateStyleFromState = function() {
+    uiLogger.debug("Label.updateStyleFromState()");
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssemblyNormal");
+    this.setClassName(this.captionElement, "ControlCaption ControlCaptionNormal");
+    this.setClassName(this.controlElement, "ControlElement");
+    this.setClassName(this.contentElement, "LabelText");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/Label.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,105 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The Label class implements a control that displays textual content.
+
+// Constructor.
+function Label(id, caption, text) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, text);
+    }
+}
+
+// Label inherits from Control.
+Label.prototype = new Control(UI_NO_INIT_ID);
+
+// Content element for label text.
+Label.prototype.contentElement = null;
+
+// Initializer - called from constructor.
+Label.prototype.init = function(id, caption, text) {
+    uiLogger.debug("Label.init(" + id + ", " + caption + ", " + text + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, caption);
+    
+    // create content element
+    this.contentElement = document.createElement("div");
+    this.controlElement.appendChild(this.contentElement);
+    
+    // set the text
+    this.setText(text);
+}
+
+// Returns the enabled state for the control.
+Label.prototype.isEnabled = function() {
+    return true;
+}
+
+// Returns the focusable state for the control.
+Label.prototype.isFocusable = function() {
+    return false;
+}
+
+// Returns the control text.
+Label.prototype.getText = function() {
+    return this.contentElement.innerHTML;
+}
+
+// Sets the text for the control.
+Label.prototype.setText = function(text) {
+    uiLogger.debug("Label.setText(" + text + ")");
+    this.contentElement.innerHTML = (text == null) ? "" : text;
+    this.updateStyleFromState();
+}
+
+// Updates the style of the control to reflects the state of the control.
+Label.prototype.updateStyleFromState = function() {
+    uiLogger.debug("Label.updateStyleFromState()");
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssemblyNormal");
+    this.setClassName(this.captionElement, "ControlCaption ControlCaptionNormal");
+    this.setClassName(this.controlElement, "ControlElement");
+    this.setClassName(this.contentElement, "LabelText");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/ListView.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,186 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The ListView class implements a vertical list view that hosts controls
+// as child components.
+
+// Constructor.
+function ListView(id, caption) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption);
+    }
+}
+
+// ListView inherits from View.
+ListView.prototype = new View(UI_NO_INIT_ID);
+
+// The caption of this view; null if none.
+ListView.prototype.caption = null;
+
+// The caption element of this view.
+ListView.prototype.captionElement = null;
+
+// The caption text element of this view.
+ListView.prototype.captionTextElement = null;
+
+// Root HTML element for controls.
+ListView.prototype.listElement = null;
+
+// List of controls in the view.
+ListView.prototype.controls = null;
+
+// Initializer for ListView.
+ListView.prototype.init = function(id, caption) {
+    uiLogger.debug("ListView.init(" + id + ", " + caption + ")");
+    
+    // call superclass initializer
+    View.prototype.init.call(this, id);
+    
+    // init control array
+    this.controls = [];
+    
+    // set style class name for root element
+    this.rootElement.className = "ListView";
+    
+    // create caption and caption text elements
+    this.captionElement = document.createElement("div");
+    this.captionElement.className = "ListViewCaptionText";
+    this.rootElement.appendChild(this.captionElement);
+    
+    // create root element for controls and add to the view root element
+    this.listElement = document.createElement("div");
+    this.listElement.className = "ListViewControlList";
+    this.rootElement.appendChild(this.listElement);
+    
+    // set the caption
+    this.setCaption(caption);
+}
+
+// Returns the caption; null if none.
+ListView.prototype.getCaption = function() {
+    return this.caption;
+}
+
+// Sets the caption; null if none.
+ListView.prototype.setCaption = function(caption) {
+    uiLogger.debug("ListView.setCaption(" + caption + ")");
+    
+    // set the display style
+    this.captionElement.style.display = (caption == null) ? "none" : "block";
+    
+    // set the caption
+    this.caption = caption;
+    this.captionElement.innerHTML = (caption == null) ? "" : caption;
+}
+
+// Returns an array of controls in the view.
+ListView.prototype.getControls = function() {
+    return this.controls;
+}
+
+// Adds a control to the view.
+ListView.prototype.addControl = function(control) {
+    uiLogger.debug("ListView.addControl(" + control + ")");
+    
+    // add the control to the controls array and attach it to the list element
+    this.controls.push(control);
+    this.listElement.appendChild(control.rootElement);
+    control.view = this;
+}
+
+// Inserts a control to the view before the specified control.
+ListView.prototype.insertControl = function(control, beforeControl) {
+    uiLogger.debug("ListView.insertControl(" + control + ", " + beforeControl + ")");
+    
+    // iterate through current controls
+    for (var i = 0; i < this.controls.length; i++) {
+        // is this the control we should insert before?
+        if (this.controls[i] == beforeControl) {
+            // we found the control to insert before - insert here and connect to list element
+            this.controls.splice(i, 0, control);
+            this.listElement.insertBefore(control.rootElement, beforeControl.rootElement);
+            control.view = this;
+            return;
+        }
+    }
+    
+    // the control wasn't found so we'll add it last
+    this.addControl(control);
+}
+
+// Removes a control from the view.
+ListView.prototype.removeControl = function(control) {
+    uiLogger.debug("ListView.removeControl(" + control + ")");
+    
+    // iterate through current controls
+    for (var i = 0; i < this.controls.length; i++) {
+        // is this the control we should remove?
+        if (this.controls[i] == control) {
+            // we found the control to remove - remove it from the list element
+            this.controls.splice(i, 1);
+            this.listElement.removeChild(control.rootElement);
+            control.view = null;
+        }
+    }
+}
+
+// Attempts to focus the first focusable control.
+ListView.prototype.focusFirstControl = function() {
+    uiLogger.debug("ListView.focusFirstControl()");
+    for (var i = 0; i < this.controls.length; i++) {
+        // is this control focusable?
+        var control = this.controls[i];
+        if (control.isFocusable()) {
+            control.setFocused(true);
+            break;
+        }
+    }
+}
+
+// Attempts to reset all control focus states.
+// Override in subclasses as required.
+ListView.prototype.resetControlFocusStates = function() {
+    uiLogger.debug("ListView.resetControlFocusStates()");
+    for (var i = 0; i < this.controls.length; i++) {
+        this.controls[i].resetFocusState();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/NavigationButton.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,220 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The NavigationButton class implements a button control for use in
+// navigational contexts in menu-style UIs.
+
+// Constructor.
+function NavigationButton(id, image, text) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, image, text);
+    }
+}
+
+// NavigationButton inherits from ActionControl.
+NavigationButton.prototype = new ActionControl(UI_NO_INIT_ID);
+
+// Button table element.
+NavigationButton.prototype.tableElement = null;
+
+// Button table row element.
+NavigationButton.prototype.tableRowElement = null;
+
+// Button table left cell element.
+NavigationButton.prototype.tableLeftCellElement = null;
+
+// Button table right cell element.
+NavigationButton.prototype.tableRightCellElement = null;
+
+// Button image element.
+NavigationButton.prototype.imageElement = null;
+
+// Button link element.
+NavigationButton.prototype.linkElement = null;
+
+// Button text element.
+NavigationButton.prototype.textElement = null;
+
+// Initializer - called from constructor.
+NavigationButton.prototype.init = function(id, image, text) {
+    uiLogger.debug("NavigationButton.init(" + id + ", " + image + ", " + text + ")");
+    
+    // call superclass initializer
+    ActionControl.prototype.init.call(this, id, null);
+    
+    // remove caption element
+    this.assemblyElement.removeChild(this.captionElement);
+    
+    // construct the button
+    this.buttonElement = document.createElement("div");
+    this.tableElement = document.createElement("table");
+    this.tableRowElement = document.createElement("tr");
+    this.tableLeftCellElement = document.createElement("td");
+    this.tableRightCellElement = document.createElement("td");
+    this.imageElement = null;
+    this.linkElement = document.createElement("a");
+    this.linkElement.href = "JavaScript:void(0)";
+    this.textElement = document.createElement("span");
+    this.tableElement.appendChild(this.tableRowElement);
+    this.tableRowElement.appendChild(this.tableLeftCellElement);
+    this.tableRowElement.appendChild(this.tableRightCellElement);
+    this.tableRightCellElement.appendChild(this.linkElement);
+    this.linkElement.appendChild(this.textElement);
+    this.buttonElement.appendChild(this.tableElement);
+    this.controlElement.appendChild(this.buttonElement);
+    
+    // set the image and text
+    this.setImage(image);
+    this.setText(text);
+    
+    // bind event listeners
+    this.bindActionControlListeners();
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Sets the enabled state.
+NavigationButton.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("NavigationButton.setEnabled(" + enabled + ")");
+    
+    // bail out early if there is no change in state
+    if (this.enabled == enabled) {
+        return;
+    }
+    
+    // set the enabled state
+    this.enabled = enabled;
+    
+    if (this.enabled) {
+        // diabled -> enabled
+        this.tableRightCellElement.removeChild(this.textElement);
+        this.tableRightCellElement.appendChild(this.linkElement);
+        this.linkElement.appendChild(this.textElement);
+    } else {
+        // enabled -> diabled
+        this.linkElement.removeChild(this.textElement);
+        this.tableRightCellElement.removeChild(this.linkElement);
+        this.tableRightCellElement.appendChild(this.textElement);
+    }
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Returns the button image (URL); null if none.
+NavigationButton.prototype.getImage = function() {
+    return (this.imageElement != null) ? this.imageElement.src : null;
+}
+
+// Sets the button image (URL); null if none.
+NavigationButton.prototype.setImage = function(image) {
+    uiLogger.debug("NavigationButton.setImage(" + image + ")");
+    
+    if (image == null) {
+        // remove image - if any
+        if (this.imageElement != null) {
+            this.tableLeftCellElement.removeChild(this.imageElement);
+        }
+    } else {
+        // default to not append image element
+        var append = false;
+        
+        // create image element if one doesn't exist
+        if (this.imageElement == null) {
+            this.imageElement = document.createElement("img");
+            this.imageElement.setAttribute("alt", "");
+            append = true;
+        }
+        
+        // set image source URL
+        this.imageElement.src = image;
+        
+        // append the image element to the left cell?
+        if (append) {
+            this.tableLeftCellElement.appendChild(this.imageElement);
+        }
+    }
+}
+
+// Returns the button text.
+NavigationButton.prototype.getText = function() {
+    return this.textElement.innerHTML;
+}
+
+// Sets the button text.
+NavigationButton.prototype.setText = function(text) {
+    uiLogger.debug("NavigationButton.setText(" + text + ")");
+    this.textElement.innerHTML = (text == null) ? "" : text;;
+}
+
+// Updates the style of the control to reflects the state of the control.
+NavigationButton.prototype.updateStyleFromState = function() {
+    uiLogger.debug("NavigationButton.updateStyleFromState()");
+    
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set root element class name
+    this.setClassName(this.rootElement, "Control");
+    
+    // set the control assembly class names
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
+    
+    // control element
+    this.setClassName(this.controlElement, "ControlElement NavigationButtonControlElement");
+    
+    // set the button table class names
+    this.setClassName(this.buttonElement, "NavigationButton");
+    this.setClassName(this.tableElement, "NavigationButtonTable");
+    this.setClassName(this.tableRowElement, "NavigationButtonRow");
+    this.setClassName(this.tableLeftCellElement, "NavigationButtonImageCell");
+    this.setClassName(this.tableRightCellElement, "NavigationButtonTextCell");
+    
+    // set image class names
+    if (this.imageElement) {
+        this.setClassName(this.imageElement, "NavigationButtonImage");
+    }
+    
+    // set the button text class name
+    this.setClassName(this.textElement, "NavigationButtonText NavigationButtonText" + stateName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/NotificationPopup.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,321 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The NotificationPopup class handles the display of notifications such as
+// warnings, information messages and progress indication.
+
+// Constructor.
+function NotificationPopup() {
+    // create notification popup
+    this.containerElement = document.createElement("div");
+    this.containerElement.className = "NotificationPopupContainer";
+    this.popupElement = document.createElement("div");
+    this.popupElement.className = "NotificationPopup";
+    this.typeIndicatorElement = document.createElement("div");
+    this.typeIndicatorElement.className = "NotificationPopupTypeIndicator";
+    this.textElement = document.createElement("div");
+    this.textElement.className = "NotificationPopupText";
+    this.progressBarElement = document.createElement("div");
+    this.progressBarElement.className = "NotificationPopupProgressBar";
+    
+    // assemble popup
+    this.popupElement.appendChild(this.typeIndicatorElement);
+    this.popupElement.appendChild(this.textElement);
+    this.popupElement.appendChild(this.progressBarElement);
+    this.containerElement.appendChild(this.popupElement);
+    
+    // create progress bar image element and initialize it
+    this.progressBarImageElement = document.createElement("img");
+    var self = this;
+    this.progressBarImageElement.addEventListener("load", function() { self.progressBarImageLoadingCompleted(); }, false);
+    this.progressBarImageElement.setAttribute("alt", "");
+    this.progressBarImageURL = this.getProgressBarImage(this.PROGRESS_BAR_IMAGE_NONE);
+    this.progressBarImageElement.src = this.progressBarImageURL;
+    this.progressBarElement.appendChild(this.progressBarImageElement);
+    
+    // init the popup to be fully down
+    this.popupElement.style.top = "100%";
+    
+    // set default popup contents
+    this.setPopupContents(null, null, null);
+}
+
+// Notification container element.
+NotificationPopup.prototype.containerElement = null;
+
+// Notification popup element.
+NotificationPopup.prototype.popupElement = null;
+
+// Type indicator element.
+NotificationPopup.prototype.typeIndicatorElement = null;
+
+// Notification text element.
+NotificationPopup.prototype.textElement = null;
+
+// Progress bar element.
+NotificationPopup.prototype.progressBarElement = null;
+
+// Progress bar image element.
+NotificationPopup.prototype.progressBarImageElement = null;
+
+// Progress bar image URL.
+NotificationPopup.prototype.progressBarImageURL = null;
+
+// Has the progress bar image been loaded?
+NotificationPopup.prototype.progressBarImageLoaded = false;
+
+// Flag that tracks whether we're in the middle of starting to
+// show a notification popup.
+NotificationPopup.prototype.processingShowNotification = false;
+
+// Notification popup position (0 = hidden, 1 = showing).
+NotificationPopup.prototype.popupPosition = 0;
+
+// Interval for timer ticks (in milliseconds)
+NotificationPopup.prototype.ANIM_TIMER_INTERVAL = 25;
+
+// Animation timer identifier or null if no active timer.
+NotificationPopup.prototype.animTimerId = null;
+
+// Time in milliseconds for the popup animation to complete
+NotificationPopup.prototype.ANIM_TIME = 300;
+
+// Flag that determines the behavior of showNotification(). If set to true
+// the popup will snap open when showNotification() is called instead of
+// animation.
+NotificationPopup.prototype.SHOW_SNAPS_OPEN = true;
+
+// Animation direction (0 = no movement, -1 hiding, +1 = showing).
+NotificationPopup.prototype.animDir = 0;
+
+// Auto-hide timer identifier or null if no active timer.
+NotificationPopup.prototype.autoHideTimerId = null;
+
+// The commanded display time.
+NotificationPopup.prototype.displayTime = -1;
+
+NotificationPopup.prototype.PROGRESS_BAR_IMAGE_NONE = 0;
+
+// Displays a notification.
+NotificationPopup.prototype.showNotification = function(displayTime, type, text, progress) {
+    uiLogger.debug("NotificationPopup.showNotification(" + displayTime + ", " + type + ", " + text + ", " + progress + ")");
+    
+    // mark that showNotification() has been called and that we are in
+    // the middle of starting to show the notification popup
+    this.processingShowNotification = true;
+    
+    // remember the display time
+    this.displayTime = displayTime;
+    
+    // attach the popup to the document if not attached
+    if (this.containerElement.parentNode == null) {
+        document.body.appendChild(this.containerElement);
+        uiLogger.debug("Notification popup attached to document");
+    }
+    
+    // set popup contents and update style
+    this.setPopupContents(type, text, progress);
+    
+    // if the progress image is loaded then we can complete the showing
+    // of the notification popup immediately - otherwise the image loaded
+    // allback will complete the process.
+    if (this.progressBarImageLoaded) {
+        this.completeShowNotification();
+    }
+}
+
+// Completes displaying of a notification.
+// Note: Used internally - don't call this directly.
+NotificationPopup.prototype.completeShowNotification = function() {
+    uiLogger.debug("NotificationPopup.completeShowNotification()");
+    
+    // animation direction is +1 for showing the popup
+    if (this.popupPosition != 1) {
+        if (this.SHOW_SNAPS_OPEN) {
+            if (this.popupPosition == 0) {
+                this.popupPosition = 1;
+            }
+        }
+        this.animatePopup(1);
+    }
+    
+    // setup auto hiding if a display time is specified
+    if (this.displayTime > 0) {
+        // stop any existing timer
+        if (this.autoHideTimerId != null) {
+            clearTimeout(this.autoHideTimerId);
+            uiLogger.debug("Auto hide timer stopped");
+        }
+        // set timer to hide notification
+        var self = this;
+        this.autoHideTimerId = setTimeout(function() {
+                                              if (self.displayTime > 0) {
+                                                  self.hideNotification();
+                                              }
+                                          }, this.ANIM_TIME + this.displayTime);
+        uiLogger.debug("Auto hide timer started");
+    }
+    
+    // mark us as no longer processing a show notification call
+    this.processingShowNotification = false;
+}
+
+// Hides the currently displayed notification.
+NotificationPopup.prototype.hideNotification = function() {
+    uiLogger.debug("NotificationPopup.hideNotification()");
+    // mark us as no longer processing a show notification call
+    this.processingShowNotification = false;
+    
+    // animation direction is -1 for hiding the popup
+    if (this.popupPosition != 0) {
+        this.animatePopup(-1);
+    }
+    
+    // stop auto hide timer if one is set
+    if (this.autoHideTimerId != null) {
+        clearTimeout(this.autoHideTimerId);
+        this.autoHideTimerId = null;
+        uiLogger.debug("Auto hide timer stopped");
+    }
+}
+
+// Starts animation of the popup (1 to show, -1 to hide).
+NotificationPopup.prototype.animatePopup = function(direction) {
+    uiLogger.debug("NotificationPopup.animatePopup(" + direction + ")");
+    // set the direction and star the animation timer
+    this.animDir = direction;
+    if (this.animTimerId == null) {
+        var self = this;
+        this.animTimerId = setInterval(function() { self.animate(); }, this.ANIM_TIMER_INTERVAL);
+        uiLogger.debug("Notification popup animation started");
+    }
+}
+
+// Callback for animation timer.
+NotificationPopup.prototype.animate = function() {
+    // calculate new popup position and clamp
+    var animStep = (this.ANIM_TIMER_INTERVAL / this.ANIM_TIME) * this.animDir;
+    var newPos = this.popupPosition + animStep;
+    if (newPos < 0) {
+        newPos = 0;
+    } else if (newPos > 1) {
+        newPos = 1;
+    }
+    
+    // set the new position to the popup element
+    this.popupPosition = newPos;
+    this.popupElement.style.top = (100 - Math.round(this.popupPosition * 100)) + "%";
+    
+    // have we reached the end of the animation?
+    if (newPos == 0 || newPos == 1) {
+        // reset animation direction
+        this.animDir = 0;
+        
+        // remove the popup from the body if its hidden
+        if (newPos == 0) {
+            document.body.removeChild(this.containerElement);
+            uiLogger.debug("Notification popup detached from document");
+        }
+        
+        // stop timer
+        clearTimeout(this.animTimerId);
+        this.animTimerId = null;
+        uiLogger.debug("Notification popup animation stopped");
+    }
+}
+
+// Returns a URL for the progress bar image to use for the specified progress.
+NotificationPopup.prototype.getProgressBarImage = function(progress) {
+    // path for progress bar images
+    var progressBarImagePath = "WRTKit/Resources/";
+    
+    // unknown progress
+    return progressBarImagePath + "ProgressBarUnknown.gif";
+}
+
+// Sets the contents of the popup.
+NotificationPopup.prototype.setPopupContents = function(type, text, progress) {
+    uiLogger.debug("NotificationPopup.setPopupContents(" + type + ", " + text + ", " + progress + ")");
+    
+    // figure out notification type style name
+    var typeName = (type == null) ? "none" : type.toLowerCase();
+    typeName = typeName.charAt(0).toUpperCase() + typeName.substring(1);
+    
+    // set type element class names
+    this.typeIndicatorElement.className = "NotificationPopupTypeIndicator NotificationPopupTypeIndicator" + typeName;
+    
+    // set notification text
+    this.textElement.innerHTML = (text == null) ? "" : text;
+    
+    // set progress
+    this.progressBarElement.style.display = (progress == null) ? "none" : "block";
+    if (progress != null) {
+        var imgURL = this.getProgressBarImage(progress);
+        if (imgURL != this.progressBarImageURL) {
+            // load new image
+            this.progressBarImageLoaded = false;
+            this.progressBarImageURL = imgURL;
+            this.progressBarImageElement.src = imgURL;
+        } else {
+            // the correct image is already loaded
+            this.progressBarImageLoaded = true;
+        }
+    } else {
+        // there is no progress bar so there is no need
+        // to load any progress bar image
+        this.progressBarImageLoaded = true;
+    }
+}
+
+// Callback for notifying the object that its progress bar image completed loading.
+NotificationPopup.prototype.progressBarImageLoadingCompleted = function() {
+    uiLogger.debug("NotificationPopup.progressBarImageLoadingCompleted()");
+    
+    // mark the progress bar image as loaded
+    this.progressBarImageLoaded = true;
+    
+    // complete the process of displaying the notification popup
+    // if it has been commanded but not yet completed
+    if (this.processingShowNotification) {
+        this.completeShowNotification();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/Scrollbar.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,173 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The Scrollbar class is an implementation of a user interface element that
+// indicates the current viewport position in a document.
+
+// Constructor.
+function Scrollbar(parentElement) {
+    uiLogger.debug("Scrollbar(" + parentElement + ")");
+    
+    // get the parent element
+    this.parentElement = parentElement;
+    
+    // create the root element
+    this.rootElement = document.createElement("div");
+    this.rootElement.className = "Scrollbar";
+    this.rootElement.style.visibility = "hidden";
+    
+    // create the scrollbar
+    // the scrollbar consists of a root element with six children
+    // (three track elements and three thumb elements)
+    
+    // track
+    this.trackTopElement = document.createElement("div");
+    this.trackTopElement.className = "ScrollbarTrackTop";
+    this.trackMiddleElement = document.createElement("div");
+    this.trackMiddleElement.className = "ScrollbarTrackMiddle";
+    this.trackBottomElement = document.createElement("div");
+    this.trackBottomElement.className = "ScrollbarTrackBottom";
+    
+    // thumb
+    this.thumbTopElement = document.createElement("div");
+    this.thumbTopElement.className = "ScrollbarThumbTop";
+    this.thumbMiddleElement = document.createElement("div");
+    this.thumbMiddleElement.className = "ScrollbarThumbMiddle";
+    this.thumbBottomElement = document.createElement("div");
+    this.thumbBottomElement.className = "ScrollbarThumbBottom";
+    
+    // assemble and attach the scrollbar
+    this.rootElement.appendChild(this.trackTopElement);
+    this.rootElement.appendChild(this.trackMiddleElement);
+    this.rootElement.appendChild(this.trackBottomElement);
+    this.rootElement.appendChild(this.thumbTopElement);
+    this.rootElement.appendChild(this.thumbMiddleElement);
+    this.rootElement.appendChild(this.thumbBottomElement);
+    this.parentElement.appendChild(this.rootElement);
+    
+    // bring the scrollbar up to date
+    this.update(0, 100, 100);
+}
+
+// Parent element for the scrollbar.
+Scrollbar.prototype.parentElement = null;
+
+// Root HTML element in the scrollbar.
+Scrollbar.prototype.rootElement = null;
+
+// Scrollbar track top element.
+Scrollbar.prototype.trackTopElement = null;
+
+// Scrollbar track middle element.
+Scrollbar.prototype.trackMiddleElement = null;
+
+// Scrollbar track bottom element.
+Scrollbar.prototype.trackBottomElement = null;
+
+// Scrollbar thumb top element.
+Scrollbar.prototype.thumbTopElement = null;
+
+// Scrollbar thumb middle element.
+Scrollbar.prototype.thumbMiddleElement = null;
+
+// Scrollbar thumb bottom element.
+Scrollbar.prototype.thumbBottomElement = null;
+
+// Is the scrollbar needed?
+Scrollbar.prototype.scrollbarNeeded = false;
+
+// Updates the scrollbar.
+Scrollbar.prototype.update = function(scrollY, viewportHeight, documentHeight) {
+    // figure out current heights
+    var scrollbarHeight = this.rootElement.clientHeight;
+    var trackTopHeight = this.trackTopElement.clientHeight;
+    var trackBottomHeight = this.trackBottomElement.clientHeight;
+    var thumbTopHeight = this.thumbTopElement.clientHeight;
+    var thumbBottomHeight = this.thumbBottomElement.clientHeight;
+    
+    // scrollable height is the larger of document and viewport heights
+    var scrollableHeight = documentHeight;
+    var scrollbarNeeded = true;
+    if (viewportHeight >= documentHeight) {
+        scrollableHeight = viewportHeight;
+        scrollbarNeeded = false;
+    }
+    
+    // show or hide scrollbar?
+    if (scrollbarNeeded != this.scrollbarNeeded) {
+        this.scrollbarNeeded = scrollbarNeeded;
+        this.rootElement.style.visibility = scrollbarNeeded ? "visible" : "hidden";
+    }
+    
+    // calculate thumb top position...
+    var thumbTopPct = scrollY / scrollableHeight;
+    var thumbTop = scrollbarHeight * thumbTopPct;
+    // ...and bottom position...
+    var thumbBottomPct = (scrollY + viewportHeight) / scrollableHeight;
+    var thumbBottom = scrollbarHeight * thumbBottomPct;
+    
+    // ...and thumb height
+    var thumbHeight = thumbBottom - thumbTop;
+    
+    // ensure that the thumb is not too small
+    var thumbMinHeight = thumbTopHeight + thumbBottomHeight;
+    if (thumbHeight < thumbMinHeight) {
+        var underflow = thumbMinHeight - thumbHeight;
+        // adjust thumb top pos assuming a shorter scrollbar track
+        var thumbMid = (scrollbarHeight - underflow) * ((thumbTopPct + thumbBottomPct) / 2) + (underflow / 2);
+        thumbTop = thumbMid - (thumbMinHeight / 2);
+        thumbBottom = thumbTop + thumbMinHeight;
+        thumbHeight = thumbBottom - thumbTop;
+    }
+    
+    // position and size track element (add 1 to the middle section height for rounding errors)
+    this.trackTopElement.style.top = "0px";
+    this.trackMiddleElement.style.top = Math.round(trackTopHeight) + "px";
+    this.trackMiddleElement.style.height = Math.round(scrollbarHeight - trackTopHeight - trackBottomHeight + 1) + "px";
+    this.trackBottomElement.style.top = Math.round(scrollbarHeight - trackTopHeight) + "px";
+    
+    // position and size thumb element (add 1 to the middle section height for rounding errors)
+    this.thumbTopElement.style.top = Math.round(thumbTop) + "px";
+    this.thumbMiddleElement.style.top = Math.round(thumbTop + thumbTopHeight) + "px";
+    this.thumbMiddleElement.style.height = Math.round(thumbHeight - thumbTopHeight - thumbBottomHeight + 1) + "px";
+    this.thumbBottomElement.style.top = Math.round(thumbBottom - thumbBottomHeight) + "px";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/SelectionControl.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,189 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The SelectionControl class is an abstract base class for controls that lets
+// the user select one or more options from a list of options. Don't use
+// SelectionControl directly.
+
+// Constructor.
+function SelectionControl(id, caption, options, multipleSelection, selected) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, options, multipleSelection, selected);
+    }
+}
+
+// SelectionControl inherits from Control.
+SelectionControl.prototype = new Control(UI_NO_INIT_ID);
+
+// List of options.
+SelectionControl.prototype.options = null;
+
+// The single selected option in single selection controls
+// or list of options in multi selection controls.
+SelectionControl.prototype.selected = null;
+
+// Single or multiple selection.
+SelectionControl.prototype.multipleSelection = false;
+
+// Initializer - called from constructor.
+SelectionControl.prototype.init = function(id, caption, options, multipleSelection, selected) {
+    uiLogger.debug("SelectionControl.init(" + id + ", " + caption + ", " + options + ", " + multipleSelection + ", " + selected + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, caption);
+    
+    // set the multiple selection property
+    this.multipleSelection = multipleSelection;
+    
+    // init options and selected (makes copies of the original arrays)
+    this.options = (options != null) ? options.slice(0) : [];
+    if (multipleSelection) {
+        this.selected = (selected == null) ? [] : selected.slice(0);
+    } else {
+        this.selected = selected;
+    }
+    this.validateSelected();
+}
+
+// Returns true if the control is a multiple selection control; false if single.
+SelectionControl.prototype.isMultipleSelection = function() {
+    return this.multipleSelection;
+}
+
+// Returns true if the specified option is selected; false if not.
+SelectionControl.prototype.isSelected = function(option) {
+    if (this.multipleSelection) {
+        // multiple selection
+        // iterate through all selected options and look for the specified option
+        for (var i = 0; i < this.selected.length; i++) {
+            if (this.selected[i] == option) {
+                return true;
+            }
+        }
+        return false;
+    } else {
+        // single selection
+        return (this.selected == option);
+    }
+}
+
+// Returns the currently selected option in a single selection control or
+// an array of selected options in a multiple selection control. If there are
+// no selected options a single selection control returns null and a multiple
+// selection control returns an empty array.
+SelectionControl.prototype.getSelected = function() {
+    return this.multipleSelection ? this.selected.slice(0) : this.selected;
+}
+
+// Sets the currently selected options. Pass a single option in a single selection
+// control or an array of selected controls in a multiple selection control. To
+// deselect all options pass null in a single selection control and an empty array
+// in a multiple selection control.
+// Override in sublcasses to provide full implementation.
+SelectionControl.prototype.setSelected = function(selected) {
+    this.selected = this.multipleSelection ? selected.slice(0) : selected;
+    // make sure the selected option or options are legal
+    this.validateSelected();
+}
+
+// Ensures that the selected option or options exist among the options in this control.
+SelectionControl.prototype.validateSelected = function() {
+    if (this.multipleSelection) {
+        // multiple selection
+        // iterate through all selected options and ensure they exist among the options
+        for (var i = 0; i < this.selected.length; i++) {
+            // check that the selected option exists among the options
+            var found = false;
+            for (var j = 0; j < this.options.length; j++) {
+                if (this.options[j] == this.selected[i]) {
+                    // found - stop looking for this option
+                    found = true;
+                    break;
+                }
+            }
+            // not found - remove this selected element
+            if (!found) {
+                this.selected.splice(i, 1);
+                // since we removed an entry we must re-check this position
+                i--;
+            }
+        }
+    } else {
+        // single selection
+        if (this.selected != null) {
+            // check that the selected option exists among the options
+            for (var i = 0; i < this.options.length; i++) {
+                if (this.options[i] == this.selected) {
+                    // found - we're done
+                    return;
+                }
+            }
+            // not found - remove the selection
+            this.selected = null;
+        }
+    }
+}
+
+// Returns the options in the control as an array of option objects with
+// a value and text property.
+SelectionControl.prototype.getOptions = function() {
+    return this.options;
+}
+
+// Sets the options in the control.
+// Override in sublcasses to provide full implementation.
+SelectionControl.prototype.setOptions = function(options) {
+    this.options = options.slice(0);
+    // make sure the selected option or options are legal
+    this.validateSelected();
+}
+
+// Returns the option that has the specified value; null if none.
+SelectionControl.prototype.getOptionForValue = function(value) {
+    // iterate through all options and look for a match
+    for (var i = 0; i < this.options.length; i++) {
+        if (this.options[i].value == value) {
+            return this.options[i];
+        }
+    }
+    return null;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/SelectionList.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,355 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The SelectionList class implements a single or multi selection control
+// that lets users select one or more options from a list of options.
+
+// Constructor.
+function SelectionList(id, caption, options, multipleSelection, selected) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, options, multipleSelection, selected);
+    }
+}
+
+// SelectionList inherits from SelectionControl.
+SelectionList.prototype = new SelectionControl(UI_NO_INIT_ID);
+
+// Root element for options.
+SelectionList.prototype.optionListElement = null;
+
+// Array for tracking option elements.
+SelectionList.prototype.optionElements = null;
+
+// Tracking for currently focused option; null if none.
+SelectionList.prototype.focusedOption = null;
+
+// Enabled status.
+SelectionList.prototype.enabled = false;
+
+// Initializer - called from constructor.
+SelectionList.prototype.init = function(id, caption, options, multipleSelection, selected) {
+    uiLogger.debug("SelectionList.init(" + id + ", " + caption + ", " + options + ", " + multipleSelection + ", " + selected + ")");
+    
+    // call superclass initializer
+    SelectionControl.prototype.init.call(this, id, caption, options, multipleSelection, selected);
+    
+    // create option list element
+    this.optionListElement = document.createElement("div");
+    this.controlElement.appendChild(this.optionListElement);
+    
+    // the control defaults to enabled
+    this.enabled = true;
+    
+    // init option element arrays
+    this.optionElements = [];
+    
+    // update the option elements to match the options in this control
+    this.updateOptionElements();
+}
+
+// Returns the enabled state.
+SelectionList.prototype.isEnabled = function() {
+    return this.enabled;
+}
+
+// Sets the enabled state.
+SelectionList.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("SelectionList.setEnabled(" + enabled + ")");
+    // switch the state and update the the control
+    this.enabled = enabled;
+    this.updateOptionElements();
+}
+
+// Sets the focused state for the control.
+// Note: This may not always succeed.
+SelectionList.prototype.setFocused = function(focused) {
+    uiLogger.debug("SelectionList.setFocused(" + focused + ")");
+    if (this.enabled && this.optionElements.length > 0) {
+        if (focused) {
+            this.optionElements[0].link.focus();
+        } else {
+            this.optionElements[0].link.blur();
+        }
+    }
+}
+
+// Sets the currently selected options. Pass a single option in a single selection
+// control or an array of selected controls in a multiple selection control. To
+// deselect all options pass null in a single selection control and an empty array
+// in a multiple selection control.
+SelectionList.prototype.setSelected = function(selected) {
+    // call superclass setSelected()
+    SelectionControl.prototype.setSelected.call(this, selected);
+    this.updateStyleFromState();
+}
+
+// Sets the options in the control.
+SelectionList.prototype.setOptions = function(options) {
+    // call superclass setOptions()
+    SelectionControl.prototype.setOptions.call(this, options);
+    this.updateOptionElements();
+}
+
+// Updates the option elements for the control element.
+SelectionList.prototype.updateOptionElements = function() {
+    uiLogger.debug("SelectionControl.updateOptionElements()");
+    
+    // start by removing all current options from the option list element
+    while (this.optionListElement.firstChild != null) {
+        this.optionListElement.removeChild(this.optionListElement.firstChild);
+    }
+    
+    // iterate through the options and add (and possibly create) a
+    // properly configured option element for each option
+    for (var i = 0; i < this.options.length; i++) {
+        // get the option and option element we're working on
+        var option = this.options[i];
+        
+        // option, link and text elements for this option
+        var optionElement;
+        var optionLinkElement;
+        var optionTextElement;
+        
+        // get the elements
+        if (i == this.optionElements.length) {
+            // we need to create a new option element...
+            optionElement = document.createElement("div");
+            
+            // ...and a new option link element...
+            optionLinkElement = document.createElement("a");
+            optionLinkElement.href = "JavaScript:void(0)";
+            
+            // ...and a new option text element
+            optionTextElement = document.createElement("span");
+            
+            // hook up event listeners to the element
+            var self = this;
+            optionLinkElement.addEventListener("focus", function(event) { self.optionFocusStateChanged(event, true); }, false);
+            optionLinkElement.addEventListener("blur", function(event) { self.optionFocusStateChanged(event, false); }, false);
+            optionElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
+            optionElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
+            optionElement.addEventListener("mousedown", function(event) {
+                                                               self.optionClicked(event)
+                                                               event.stopPropagation();
+                                                               event.preventDefault();
+                                                        }, true);
+            optionElement.addEventListener("keydown", function(event) {
+                                                            // center and enter trigger the action
+                                                            if (event.keyCode == 0 || event.keyCode == 13) {
+                                                                self.optionClicked(event)
+                                                                event.stopPropagation();
+                                                                event.preventDefault();
+                                                            }
+                                                      }, true);
+            
+            // add the elements to the option element array
+            this.optionElements.push({ option: optionElement, link: optionLinkElement, text: optionTextElement });
+        } else {
+            // we already have ready elements so we'll reuse them
+            optionElement = this.optionElements[i].option;
+            optionLinkElement = this.optionElements[i].link;
+            optionTextElement = this.optionElements[i].text;
+            
+            // remove the option link element from its current parent - if any
+            if (optionLinkElement.parentNode != null) {
+                optionLinkElement.parentNode.removeChild(optionLinkElement);
+            }
+            
+            // remove the option text element from its current parent - if any
+            if (optionTextElement.parentNode != null) {
+                optionTextElement.parentNode.removeChild(optionTextElement);
+            }
+        }
+        
+        // set the option text
+        optionTextElement.innerHTML = option.text;
+        
+        // hook up the option to the control
+        if (this.enabled) {
+            // add the option link element to the option element
+            optionElement.appendChild(optionLinkElement);
+            // add the text element to the option element
+            optionLinkElement.appendChild(optionTextElement);
+        } else {
+            // add the text element directly to the control element
+            optionElement.appendChild(optionTextElement);
+        }
+        // add the option element to the option list element
+        this.optionListElement.appendChild(optionElement);
+    }
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Callback for focus state change events.
+SelectionList.prototype.optionFocusStateChanged = function(event, focused) {
+    uiLogger.debug("SelectionControl.optionFocusStateChanged()");
+    
+    // get the event source option
+    var option = null;
+    var optionElement = null;
+    for (var i = 0; i < this.optionElements.length; i++) {
+        optionElement = this.optionElements[i];
+        if (optionElement.link == event.currentTarget) {
+            option = this.options[i];
+            break;
+        }
+    }
+    
+    // remember the focused option; or null if none is focused
+    if (focused) {
+        this.focusedOption = option;
+    } else {
+        this.focusedOption = null;
+    }
+    
+    // call the superclass focus state change handler
+    this.focusStateChanged(focused);
+}
+
+// Callback for clicks.
+SelectionList.prototype.optionClicked = function(event) {
+    uiLogger.debug("SelectionControl.optionClicked()");
+    
+    // bail out if we're not enabled
+    if (!this.enabled) {
+        return false;
+    }
+    
+    // get the changed option
+    var option = null;
+    var optionElement = null;
+    for (var i = 0; i < this.optionElements.length; i++) {
+        optionElement = this.optionElements[i];
+        if (optionElement.option == event.currentTarget) {
+            option = this.options[i];
+            break;
+        }
+    }
+    
+    // make sure the option is focused
+    optionElement.link.focus();
+    
+    // toggle the selection
+    if (this.multipleSelection) {
+        // iterate through the selected options and see if this
+        // option is selected. if not then add it to the selection.
+        // if it already is selected then them remove it.
+        var found = false;
+        for (var i = 0; i < this.selected.length; i++) {
+            if (this.selected[i] == option) {
+                // remove from selected set
+                found = true;
+                this.selected.splice(i, 1);
+                break;
+            }
+        }
+        if (!found) {
+            // add to the selected set
+            this.selected.push(option);
+        }
+    } else {
+        // update the selected option
+        this.selected = option;
+    }
+    
+    // update the style
+    this.updateStyleFromState();
+    
+    // notify event listeners
+    this.fireEvent(this.createEvent("SelectionChanged", this.getSelected()));
+}
+
+// Resets the state tracking for focus and hover.
+// Override this in subclasses as required to implement the state reset.
+SelectionList.prototype.resetFocusState = function() {
+    uiLogger.debug("SelectionList.resetFocusState()");
+    this.hovering = false;
+    this.focused = false;
+    this.focusedOption = null;
+    this.updateStyleFromState();
+}
+
+// Updates the style of the control to reflects the state of the control.
+SelectionList.prototype.updateStyleFromState = function() {
+    uiLogger.debug("SelectionList.updateStyleFromState()");
+    
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.controlElement, "ControlElement");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
+    this.setClassName(this.captionElement, "ControlCaption ControlCaption" + stateName);
+    
+    // set option list and option class names
+    this.setClassName(this.optionListElement, "SelectionList SelectionList" + stateName);
+    for (var i = 0; i < this.options.length; i++) {
+        var option = this.options[i];
+        
+        // get the option and option text elements for this option
+        var optionElement = this.optionElements[i].option;
+        var optionTextElement = this.optionElements[i].text;
+        
+        // figure out the option state
+        var optionStateName = this.isSelected(option) ? "Checked" : "Unchecked";
+        if (!this.enabled) {
+            optionStateName += "Disabled";
+        } else if (this.focusedOption == option) {
+            optionStateName += "Focus";
+        } else {
+            optionStateName += "Normal";
+        }
+        
+        // set option element class names
+        if (this.multipleSelection) {
+            this.setClassName(optionElement, "SelectionListOptionMulti SelectionListOptionMulti" + optionStateName);
+        } else {
+            this.setClassName(optionElement, "SelectionListOptionSingle SelectionListOptionSingle" + optionStateName);
+        }
+        
+        // set option text class names
+        this.setClassName(optionTextElement, "SelectionListOptionText SelectionListOptionText" + stateName);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/SelectionMenu.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,204 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The SelectionMenu class implements a single or multi selection control
+// that lets users select one or more options from a menu.
+
+// Constructor.
+function SelectionMenu(id, caption, options, multipleSelection, selected) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, options, multipleSelection, selected);
+    }
+}
+
+// SelectionMenu inherits from SelectionControl.
+SelectionMenu.prototype = new SelectionControl(UI_NO_INIT_ID);
+
+// Reference to the peer HTML element.
+SelectionControl.prototype.peerElement = null;
+
+// Array for tracking option elements.
+SelectionMenu.prototype.optionElements = null;
+
+// Initializer - called from constructor.
+SelectionMenu.prototype.init = function(id, caption, options, multipleSelection, selected) {
+    uiLogger.debug("SelectionMenu.init(" + id + ", " + caption + ", " + options + ", " + multipleSelection + ", " + selected + ")");
+    
+    // call superclass initializer
+    SelectionControl.prototype.init.call(this, id, caption, options, multipleSelection, selected);
+    
+    // create the control
+    this.peerElement = document.createElement("select");
+    this.peerElement.multiple = multipleSelection;
+    this.controlElement.appendChild(this.peerElement);
+    
+    // init option elements array
+    this.optionElements = [];
+    
+    // update the option elements to match the options in this control
+    this.updateOptionElements();
+    
+    // bind event listeners
+    var self = this;
+    this.peerElement.addEventListener("focus", function() { self.focusStateChanged(true); }, false);
+    this.peerElement.addEventListener("blur", function() { self.focusStateChanged(false); }, false);
+    this.peerElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
+    this.peerElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
+    this.peerElement.addEventListener("change", function() { self.selectionChanged(); }, false);
+}
+
+// Returns the enabled state.
+SelectionMenu.prototype.isEnabled = function() {
+    return !this.peerElement.disabled;
+}
+
+// Sets the enabled state.
+SelectionMenu.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("SelectionMenu.setEnabled(" + enabled + ")");
+    this.peerElement.disabled = !enabled;
+}
+
+// Sets the focused state for the control.
+// Note: This may not always succeed.
+SelectionMenu.prototype.setFocused = function(focused) {
+    uiLogger.debug("SelectionMenu.setFocused(" + focused + ")");
+    if (focused) {
+        this.peerElement.focus();
+    } else {
+        this.peerElement.blur();
+    }
+}
+
+// Sets the currently selected options. Pass a single option in a single selection
+// control or an array of selected controls in a multiple selection control. To
+// deselect all options pass null in a single selection control and an empty array
+// in a multiple selection control.
+SelectionMenu.prototype.setSelected = function(selected) {
+    // call superclass setSelected()
+    SelectionControl.prototype.setSelected.call(this, selected);
+    
+    // iterate through the options and set the selected state
+    // on the corresponding option element
+    for (var i = 0; i < this.options.length; i++) {
+        this.optionElements[i].selected = this.isSelected(this.options[i]);
+    }
+}
+
+// Sets the options in the control.
+SelectionMenu.prototype.setOptions = function(options) {
+    // call superclass setOptions()
+    SelectionControl.prototype.setOptions.call(this, options);
+    this.updateOptionElements();
+}
+
+// Updates the option elements for the peer select element.
+SelectionMenu.prototype.updateOptionElements = function() {
+    // start by removing all current options from the select element
+    while (this.peerElement.firstChild != null) {
+        this.peerElement.removeChild(this.peerElement.firstChild);
+    }
+    
+    // iterate through the options and add (and possibly create) a
+    // properly configured option element for each option
+    for (var i = 0; i < this.options.length; i++) {
+        // do we need to create a new option element?
+        if (i == this.optionElements.length) {
+            this.optionElements.push(document.createElement("option"));
+        }
+        
+        // get the option and option element we're working on
+        var option = this.options[i];
+        var optionElement = this.optionElements[i];
+        
+        // set the state for this option element and add it to the
+        // peer select element
+        optionElement.text = option.text;
+        optionElement.selected = this.isSelected(option);
+        this.peerElement.appendChild(optionElement);
+    }
+    
+    // update the style
+    this.updateStyleFromState();    
+}
+
+// Callback for selection change events.
+SelectionMenu.prototype.selectionChanged = function() {
+    uiLogger.debug("SelectionControl.selectionChanged()");
+    
+    // update the selected options array or reference
+    this.selected = (this.multipleSelection) ? [] : null;
+    for (var i = 0; i < this.options.length; i++) {
+        if (this.optionElements[i].selected) {
+            if (this.multipleSelection) {
+                this.selected.push(this.options[i]);
+            } else {
+                this.selected = this.options[i];
+                break;
+            }
+        }
+    }
+    
+    // notify event listeners
+    this.fireEvent(this.createEvent("SelectionChanged", this.getSelected()));
+}
+
+// Updates the style of the control to reflects the state of the control.
+SelectionMenu.prototype.updateStyleFromState = function() {
+    uiLogger.debug("SelectionMenu.updateStyleFromState()");
+    
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.controlElement, "ControlElement");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
+    this.setClassName(this.captionElement, "ControlCaption ControlCaption" + stateName);
+    
+    // set select and option element class names
+    var peerStateName = this.isEnabled() ? stateName : "Disabled";
+    this.setClassName(this.peerElement, "SelectionMenu SelectionMenu" + peerStateName);
+    for (var i = 0; i < this.options.length; i++) {
+        var option = this.optionElements[i];
+        this.setClassName(option, "SelectionMenuOption SelectionMenuOption" + peerStateName);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/Separator.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,119 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The Separator class is used to provide a visual separator in a list.
+
+// Constructor.
+function Separator(id) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id);
+    }
+}
+
+// Separator inherits from Control.
+Separator.prototype = new Control(UI_NO_INIT_ID);
+
+// Reference to the separator element.
+Separator.prototype.separatorElement = null;
+
+// Separator row element.
+Separator.prototype.tableRowElement = null;
+
+// Left cell element.
+Separator.prototype.tableLeftCellElement = null;
+
+// Center cell element.
+Separator.prototype.tableCenterCellElement = null;
+
+// Right cell element.
+Separator.prototype.tableRightCellElement = null;
+
+// Initializer - called from constructor.
+Separator.prototype.init = function(id) {
+    uiLogger.debug("Separator.init(" + id + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, null);
+    
+    // remove caption and control elements
+    this.assemblyElement.removeChild(this.captionElement);
+    this.assemblyElement.removeChild(this.controlElement);
+    
+    // create separator
+    this.separatorElement = document.createElement("table");
+    this.tableRowElement = document.createElement("tr");
+    this.tableLeftCellElement = document.createElement("td");
+    this.tableCenterCellElement = document.createElement("td");
+    this.tableRightCellElement = document.createElement("td");
+    this.tableRowElement.appendChild(this.tableLeftCellElement);
+    this.tableRowElement.appendChild(this.tableCenterCellElement);
+    this.tableRowElement.appendChild(this.tableRightCellElement);
+    this.separatorElement.appendChild(this.tableRowElement);
+    this.assemblyElement.appendChild(this.separatorElement);
+    
+    // update style
+    this.updateStyleFromState();
+}
+
+// Returns the enabled state for the control.
+Separator.prototype.isEnabled = function() {
+    return true;
+}
+
+// Returns the focusable state for the control.
+Separator.prototype.isFocusable = function() {
+    return false;
+}
+
+// Updates the style of the control to reflects the state of the control.
+Separator.prototype.updateStyleFromState = function() {
+    uiLogger.debug("Separator.updateStyleFromState()");
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssemblyNormal");
+    this.setClassName(this.separatorElement, "Separator");
+    this.setClassName(this.tableRowElement, "SeparatorRow");
+    this.setClassName(this.tableLeftCellElement, "SeparatorLeftCell");
+    this.setClassName(this.tableCenterCellElement, "SeparatorCenterCell");
+    this.setClassName(this.tableRightCellElement, "SeparatorRightCell");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/TabView.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,155 @@
+
+function TabView(id, caption) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption);
+    }
+}
+
+// TabView inherits from View.
+TabView.prototype = new View(UI_NO_INIT_ID);
+
+// The caption of this view; null if none.
+TabView.prototype.caption = null;
+
+// The caption element of this view.
+TabView.prototype.captionElement = null;
+
+// The caption element of this view.
+TabView.prototype.captionTextElement = null;
+
+// Root HTML element for controls.
+TabView.prototype.tabViewRootElement = null;
+
+// HTML element for tabs heading .
+TabView.prototype.tabsElement = null;
+
+// HTML element for tab content.
+TabView.prototype.tabContent = null;
+
+// List of tabs in the view.
+TabView.prototype.tabs = [];
+
+// List of tab captions in the view.
+TabView.prototype.tabCaptions = [];
+
+// List of tab captions in the view.
+TabView.prototype.tabHeadElements = [];
+
+// Current tab in this view
+TabView.prototype.currentTab = null;
+
+// Initializer for TabView.
+TabView.prototype.init = function(id, caption) {
+    uiLogger.debug("ListView.init(" + id + ", " + caption + ")");
+    
+    // call superclass initializer
+    View.prototype.init.call(this, id);
+    
+    // init control array
+    this.controls = [];
+    
+    // set style class name for root element - reuse ListView style
+    this.rootElement.className = "ListView";
+    
+    // create caption and caption text elements
+    this.captionElement = document.createElement("div");
+    this.captionElement.className = "ListViewCaption";
+    this.captionTextElement = document.createElement("div");
+    this.captionTextElement.className = "ListViewCaptionText";
+    this.captionElement.appendChild(this.captionTextElement);
+    this.rootElement.appendChild(this.captionElement);
+    
+    // create root element for controls and add to the view root element
+    this.tabViewRootElement = document.createElement("div");
+    this.tabViewRootElement.className = "ListViewControlList";
+    this.tabsElement = document.createElement("div");
+    this.tabsElement.className = "ListViewCaption";
+    this.tabContent = document.createElement("div");
+    this.tabViewRootElement.appendChild(this.tabsElement);
+    this.tabViewRootElement.appendChild(this.tabContent);
+    this.rootElement.appendChild(this.tabViewRootElement);
+    
+    // set the caption
+    this.setCaption(caption);
+}
+
+// Returns the caption; null if none.
+TabView.prototype.getCaption = function() {
+    return this.caption;
+}
+
+// Sets the caption; null if none.
+TabView.prototype.setCaption = function(caption) {
+    uiLogger.debug("ListView.setCaption(" + caption + ")");
+    
+    // set the display style
+    this.captionElement.style.display = (caption == null) ? "none" : "block";
+    
+    // set the caption
+    this.caption = caption;
+    this.captionTextElement.innerHTML = (caption == null) ? "" : caption;
+}
+
+// Add a ListView as a tab
+TabView.prototype.addTab = function(tab) {
+	this.addTab(tab, tab.getCaption());
+}
+
+// Add a ListView as a tab specifying a label
+TabView.prototype.addTab = function(tab, label) {
+	this.tabs.push(tab);
+	this.tabCaptions.push(label);
+	// create a element for the tab heading
+    var tabHead = document.createElement("div");
+	tabHead.className = "TabViewTabCaption";
+	tabHead.innerHTML = label;
+	this.tabHeadElements.push(tabHead);
+    this.tabsElement.appendChild(this.tabHead);
+	if ( this.currentTab == null ) {
+		setCurrentTab(0);
+	}
+}
+
+TabView.prototype.setCurrentTab = function(newCurrentTab) {
+	// clear focus on current tab
+	
+	// store the current tab index
+	this.currentTab = newCurrentTab;
+	
+	// set focus on current tab
+	
+	// update the content element
+	this.tabContent.replaceNode(this.tabs[currentTab].rootElement);
+}
+
+
+TabView.prototype.bindTabActionListeners = function() {
+    var self = this;
+	// bind left-right actions to switching tabs
+    this.rootElement.addEventListener("keydown", function(event) { self.handleKeyPress(event); }, true); // capture phase
+//	for ( var t = 0; t < this.tabs.length; t++ ) {
+//		// bind tab listeners
+//	    this.tabHeadElements[t].addEventListener("focus", function() { self.focusStateChanged(true); }, false); // bubble phase
+//	    this.tabHeadElements[t].addEventListener("blur", function() { self.focusStateChanged(false); }, false);
+//	    this.tabHeadElements[t].addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
+//	    this.tabHeadElements[t].addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
+//	    this.tabHeadElements[t].addEventListener("mousedown", function(event){ self.setCurrentTab(t);}, true);
+//	}
+}
+
+TabView.prototype.handleKeyPress = function(event) {
+	if (event.keyCode == 37 ) { // left
+		if ( this.currentTab > 0 ) {
+			this.setCurrentTab(this.currentTab-1);
+		}
+		event.stopPropagation();
+		event.preventDefault();
+	}
+	if (event.keyCode == 39 ) { // right
+		if ( this.currentTab < this.tabs.length-1 ) {
+			this.setCurrentTab(this.currentTab+1);
+		}
+		event.stopPropagation();
+		event.preventDefault();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/TextArea.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,96 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The TextArea class implements a multi line text entry control.
+
+// Constructor.
+function TextArea(id, caption, value, rows) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, value, rows);
+    }
+}
+
+// TextArea inherits from TextEntryControl.
+TextArea.prototype = new TextEntryControl(UI_NO_INIT_ID);
+
+// Initializer - called from constructor.
+TextArea.prototype.init = function(id, caption, value, rows) {
+    uiLogger.debug("TextArea.init(" + id + ", " + caption + ", " + value + ", " + rows + ")");
+    
+    // call superclass initializer
+    TextEntryControl.prototype.init.call(this, id, caption);
+    
+    // create the peer element
+    this.peerElement = document.createElement("textarea");
+    // default rowcount is 3 if not defined
+    // width always comes from style but is a required attribute
+    this.peerElement.rows = (rows != null) ? rows : 3;
+    this.peerElement.cols = 20;
+    this.controlElement.appendChild(this.peerElement);
+    
+    // set the value
+    this.peerElement.value = (value == null) ? "" : value;
+    
+    // bind event listeners
+    this.bindTextEntryControlListeners();
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Updates the style of the control to reflects the state of the control.
+TextArea.prototype.updateStyleFromState = function() {
+    uiLogger.debug("TextArea.updateStyleFromState()");
+    
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.controlElement, "ControlElement");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
+    this.setClassName(this.captionElement, "ControlCaption ControlCaption" + stateName);
+    
+    // set peer element class names
+    var peerStateName = this.isEnabled() ? stateName : "Disabled";
+    this.setClassName(this.peerElement, "TextArea TextArea" + stateName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/TextEntryControl.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,125 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The TextEntryControl class is an abstract base class for the single and multi-
+// line text entry controls TextField and TextArea. Don't use TextEntryControl
+// directly.
+
+// Constructor.
+function TextEntryControl(id, caption) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption);
+    }
+}
+
+// TextEntryControl inherits from Control.
+TextEntryControl.prototype = new Control(UI_NO_INIT_ID);
+
+// Reference to the peer HTML element.
+TextEntryControl.prototype.peerElement = null;
+
+// Initializer - called from constructor.
+TextEntryControl.prototype.init = function(id, caption) {
+    uiLogger.debug("TextEntryControl.init(" + id + ", " + caption + ")");
+    
+    // call superclass initializer
+    Control.prototype.init.call(this, id, caption);
+}
+
+// Common event listeners hookup function called from subclasses.
+TextEntryControl.prototype.bindTextEntryControlListeners = function() {
+    var self = this;
+    this.peerElement.addEventListener("focus", function() { self.focusStateChanged(true); }, false);
+    this.peerElement.addEventListener("blur", function() { self.focusStateChanged(false); }, false);
+    this.peerElement.addEventListener("mouseover", function() { self.hoverStateChanged(true); }, false);
+    this.peerElement.addEventListener("mouseout", function() { self.hoverStateChanged(false); }, false);
+    this.peerElement.addEventListener("change", function() { self.valueChanged(); }, false);
+}
+
+// Returns the enabled state.
+// Override this in subclasses as required to implement the state change.
+TextEntryControl.prototype.isEnabled = function() {
+    return !this.peerElement.readOnly;
+}
+
+// Sets the enabled state.
+// Override this in subclasses as required to implement the state change.
+TextEntryControl.prototype.setEnabled = function(enabled) {
+    uiLogger.debug("TextEntryControl.setEnabled(" + enabled + ")");
+    this.peerElement.readOnly = !enabled;
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Returns the control text.
+TextEntryControl.prototype.getText = function() {
+    return this.peerElement.value;
+}
+
+// Sets the text for the control.
+TextEntryControl.prototype.setText = function(text) {
+    this.peerElement.value = text;
+}
+
+// Returns the focusable state for the control.
+TextEntryControl.prototype.isFocusable = function() {
+    // text entry controls are always focusable
+    return true;
+}
+
+// Sets the focused state for the control.
+// Note: This may not always succeed.
+TextEntryControl.prototype.setFocused = function(focused) {
+    uiLogger.debug("TextEntryControl.setFocused(" + focused + ")");
+    if (focused) {
+        this.peerElement.focus();
+    } else {
+        this.peerElement.blur();
+    }
+}
+
+// Callback for value change events.
+TextEntryControl.prototype.valueChanged = function() {
+    uiLogger.debug("TextEntryControl.valueChanged()");
+    // notify event listeners
+    this.fireEvent(this.createEvent("ValueChanged", this.peerElement.value));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/TextField.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,93 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The TextField class implements a single line text entry control.
+
+// Constructor.
+function TextField(id, caption, value, masked) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id, caption, value, masked);
+    }
+}
+
+// TextField inherits from TextEntryControl.
+TextField.prototype = new TextEntryControl(UI_NO_INIT_ID);
+
+// Initializer - called from constructor.
+TextField.prototype.init = function(id, caption, value, masked) {
+    uiLogger.debug("TextField.init(" + id + ", " + caption + ", " + value + ", " + masked + ")");
+    
+    // call superclass initializer
+    TextEntryControl.prototype.init.call(this, id, caption);
+    
+    // create the peer element
+    this.peerElement = document.createElement("input");
+    this.peerElement.type = masked ? "password" : "text";
+    this.controlElement.appendChild(this.peerElement);
+    
+    // set the value
+    this.peerElement.value = (value == null) ? "" : value;
+    
+    // bind event listeners
+    this.bindTextEntryControlListeners();
+    
+    // update the style
+    this.updateStyleFromState();
+}
+
+// Updates the style of the control to reflects the state of the control.
+TextField.prototype.updateStyleFromState = function() {
+    uiLogger.debug("TextField.updateStyleFromState()");
+    
+    // determine the state name
+    var stateName = this.getStyleStateName();
+    
+    // set element class names
+    this.setClassName(this.rootElement, "Control");
+    this.setClassName(this.controlElement, "ControlElement");
+    this.setClassName(this.assemblyElement, "ControlAssembly ControlAssembly" + stateName);
+    this.setClassName(this.captionElement, "ControlCaption ControlCaption" + stateName);
+    
+    // set peer element class names
+    var peerStateName = this.isEnabled() ? stateName : "Disabled";
+    this.setClassName(this.peerElement, "TextField TextField" + peerStateName);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/UIElement.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,114 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (“Nokia”) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia’s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The UIElement class is the base class for all user interface elements.
+
+// Constructor.
+function UIElement(id) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id);
+    }
+}
+
+// UI element identifier.
+UIElement.prototype.id = null;
+
+// Root HTML element in the UI element.
+UIElement.prototype.rootElement = null;
+
+// Initializer for UIElement.
+UIElement.prototype.init = function(id) {
+    uiLogger.debug("UIElement.init(" + id + ")");
+    
+    // copy identifier
+    this.id = id;
+    
+    // init event listener array
+    this.eventListeners = [];
+    
+    // create the root element
+    this.rootElement = document.createElement("div");
+    if (id != null) {
+        this.rootElement.id = id;
+    }
+}
+
+// Returns an array containing the current event listeners.
+UIElement.prototype.getEventListeners = function() {
+    return this.eventListeners;
+}
+
+// Adds an event listener.
+UIElement.prototype.addEventListener = function(eventType, listener) {
+    var listenerDef = { type: eventType, listener: listener };
+    this.eventListeners.push(listenerDef);
+}
+
+// Removes an event listener.
+UIElement.prototype.removeEventListener = function(eventType, listener) {
+    // iterate through current listeners and remove the specified
+    // listener when its found
+    for (var i = 0; i < this.eventListeners.length; i++) {
+        var listenerDef = this.eventListeners[i];
+        if ((listenerDef.type == eventType) &&
+                (listenerDef.listener == listener)) {
+            this.eventListeners.splice(i, 1);
+            return;
+        }
+    }
+}
+
+// Factory method for an event object where this object is the source object.
+UIElement.prototype.createEvent = function(type, value) {
+    return { source: this, type: type, value: value };
+}
+
+// Fires an event to all listeners.
+UIElement.prototype.fireEvent = function(event) {
+    // iterate through all event listeners and notify them of the event
+    for (var i = 0; i < this.eventListeners.length; i++) {
+        var listenerDef = this.eventListeners[i];
+        if (listenerDef.type == null || listenerDef.type == event.type) {
+            listenerDef.listener.call(this, event);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/UIInit.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,49 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The UIInit script is included before the rest of the UI scripts to setup
+// any resources needed by the UI toolkit.
+
+// Create UI logger.
+var uiLogger = new Logger();
+uiLogger.level = uiLogger.LOG_LEVEL_DEBUG;
+uiLogger.filter = ["QECR"];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/UIManager.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,277 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The UI manager manages a set of views and other user interface elements.
+
+// Constructor.
+function UIManager(viewParentElement, scrollbarParentElement, enableScrollBar, delayInit) {    
+    uiLogger.debug("UIManager(" + viewParentElement + ", " + scrollbarParentElement + ")");
+    if (delayInit == null) {
+        this.init(viewParentElement, enableScrollBar, scrollbarParentElement);
+    }
+}
+
+// Parent element for views.
+UIManager.prototype.viewParentElement = null;
+
+// Parent element for scrollbar.
+UIManager.prototype.scrollbarParentElement = null;
+
+// The currently displayed view.
+UIManager.prototype.currentView = null;
+
+// Reference to the scrollbar.
+UIManager.prototype.scrollbar = null;
+
+// Current scroll Y position.
+UIManager.prototype.scrollY = -1;
+
+// Current viewport height.
+UIManager.prototype.viewportHeight = -1;
+
+// Current document height.
+UIManager.prototype.documentHeight = -1;
+
+// Timer identifier or null if no active timer.
+UIManager.prototype.timerId = null;
+
+// Interval for timer ticks for the UI manager timer (in milliseconds)
+UIManager.prototype.TIMER_INTERVAL = 250;
+
+// Reference to the notification popup used to displays notifications.
+UIManager.prototype.notificationPopup = null;
+
+// is scrollbar enabled
+UIManager.prototype.enableScrollBar = null;
+
+// View switch animation
+UIManager.prototype.viewSwitchAnimation = false;
+UIManager.prototype.viewSwitchTimer = null;
+UIManager.prototype.viewSwitchDivPos = 0;
+UIManager.prototype.VIEW_SWITCH_TIMER_INTERVAL = 25;
+
+// init function
+UIManager.prototype.init = function(viewParentElement, enableScrollBar, scrollbarParentElement) {
+    this.enableScrollBar = enableScrollBar;
+    
+    // parent element for views
+    if (viewParentElement == null) {
+        // create a parent for views
+        this.viewParentElement = document.createElement("div");
+        this.viewParentElement.className = "ViewContainer";
+        document.body.appendChild(this.viewParentElement);
+    }
+    else {
+        this.viewParentElement = viewParentElement;
+    }
+    
+    // parent element for scrollbar
+    if (enableScrollBar) {
+        if (scrollbarParentElement == null) {
+            // create a parent for the scrollbar
+            this.scrollbarParentElement = document.createElement("div");
+            this.scrollbarParentElement.className = "DocumentScrollbarContainer";
+            document.body.appendChild(this.scrollbarParentElement);
+        }
+        else {
+            this.scrollbarParentElement = scrollbarParentElement;
+        }
+    }
+    
+    // currently selected view
+    this.currentView = null;
+    
+    // create the notification popup
+    // the notification popup adds itself as a child element to the document body
+    this.notificationPopup = new NotificationPopup();
+    
+    // create scrollbar
+    if (enableScrollBar) {
+        this.scrollbar = new Scrollbar(this.scrollbarParentElement);
+    }
+    
+    // setup scrollbar tracking
+    var self = this;
+    this.startTimer();
+    if (enableScrollBar) {
+        window.addEventListener("resize", function(){
+            self.updateScrollbar();
+        }, false);
+        window.addEventListener("scroll", function(){
+            self.updateScrollbar();
+        }, false);
+    }
+}
+
+// Returns the current view.
+UIManager.prototype.getView = function() {
+    return this.currentView;
+}
+
+// Switches to the specified view.
+UIManager.prototype.setView = function(view){
+	uiLogger.debug("View set to " + view.id);
+	if ( this.viewSwitchTimer != null ) {
+		return;
+	}
+	if (this.viewSwitchAnimation && this.currentView != null) {
+		var self = this;
+		this.viewSwitchDivPos = 0;
+		this.viewSwitchTimer = setInterval(function(){
+			self.animateViewSwitch(view);
+		}, this.VIEW_SWITCH_TIMER_INTERVAL);
+	}
+	else {
+		this.doSetView(view);
+	}
+}
+
+UIManager.prototype.animateViewSwitch = function(view) {
+	if (this.viewSwitchDivPos + window.innerWidth < 0 ) {
+		clearTimeout(this.viewSwitchTimer);
+		var tmp = this.currentView;
+		this.doSetView(view);
+		tmp.rootElement.style.left = null;
+		this.viewSwitchTimer = null;
+	}
+	else {
+		this.viewSwitchDivPos -= 25;
+		this.currentView.rootElement.style.left = this.viewSwitchDivPos;
+	}
+}
+
+
+UIManager.prototype.doSetView = function(view) {
+    // remove the current view from the parent element
+    if (this.currentView != null) {
+        this.viewParentElement.removeChild(this.currentView.rootElement);
+    }
+    
+    // reset scroll
+    window.scrollTo(0, 0);
+    
+    // add the new view to the parent element
+    if (view != null) {
+        this.currentView = view;
+        this.currentView.resetControlFocusStates();
+        this.viewParentElement.appendChild(this.currentView.rootElement);
+    }
+    
+    // update scrollbar
+    if (this.enableScrollBar) {
+        this.updateScrollbar();
+    }
+    
+    // focus the first focusable control
+    // a timer is used to prevent unwanted focus shift
+    setTimeout(function() { view.focusFirstControl(); }, 1);
+}
+
+// Updates the scrollbar.
+UIManager.prototype.updateScrollbar = function() {
+    if (this.enableScrollBar) {
+        // get current viewport and document position and dimensions
+        var scrollY = window.scrollY;
+        var viewportHeight = window.innerHeight;
+        var documentHeight = Math.max(document.documentElement.scrollHeight, document.height);
+        
+        // check if the scroll position or view has changed
+        if (this.scrollY != scrollY ||
+                this.viewportHeight != viewportHeight ||
+                this.documentHeight != documentHeight) {
+            // scroll position or view has changed
+            this.scrollY = scrollY;
+            this.viewportHeight = viewportHeight;
+            this.documentHeight = documentHeight;
+            
+            // update the scrollbar
+            this.scrollbar.update(scrollY, viewportHeight, documentHeight);
+            uiLogger.debug("Scrollbar updated");
+        }
+    }
+}
+
+// Starts the view manager timer.
+UIManager.prototype.startTimer = function() {
+    if (this.timerId == null) {
+        uiLogger.debug("UIManager timer started");
+        var self = this;
+        // setup the timer
+        this.timerId = setInterval(function() { self.onTimer(); }, this.TIMER_INTERVAL);
+    } else {
+        uiLogger.warn("UIManager timer already running");
+    }
+}
+
+// Stops the view manager timer.
+UIManager.prototype.stopTimer = function() {
+    if (this.timerId != null) {
+        // stop the timer
+        clearTimeout(this.timerId);
+        this.timerId = null;
+    } else {
+        uiLogger.warn("UIManager timer already stopped");
+    }
+}
+
+// Timer callback function.
+UIManager.prototype.onTimer = function() {
+    if (this.enableScrollBar) {
+        // make sure the scrollbar is up to date
+        this.updateScrollbar();
+    }
+}
+
+// Displays a notification.
+UIManager.prototype.showNotification = function(displayTime, type, text, progress) {
+    uiLogger.debug("UIManager.showNotification(" + displayTime + ", " + type + ", " + text + ", " + progress + ")");
+    // use the notification popup to show the notification
+    this.notificationPopup.showNotification(displayTime, type, text, progress);
+}
+
+// Hides the currently displayed notification.
+UIManager.prototype.hideNotification = function() {
+    uiLogger.debug("UIManager.hideNotification()");
+    // hide the notification popup
+    this.notificationPopup.hideNotification();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/UI/View.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,142 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// The View class is an abstract base class for views in the UI toolkit.
+// Don't use the View directly - instead use a concrete subclass like ListView.
+
+// Constructor.
+function View(id) {
+    if (id != UI_NO_INIT_ID) {
+        this.init(id);
+    }
+}
+
+// View inherits from UIElement.
+View.prototype = new UIElement(UI_NO_INIT_ID);
+
+// Currently focused control.
+View.prototype.focusedControl = null;
+
+// Allows going back from every view
+View.prototype.previousView = null;
+
+// Initializer - called from constructor.
+View.prototype.init = function(id) {
+    uiLogger.debug("View.init(" + id + ")");
+    
+    // call superclass initializer
+    UIElement.prototype.init.call(this, id);
+}
+
+// Returns the currently focused control; null if none.
+View.prototype.getFocusedControl = function() {
+    return this.focusedControl;
+}
+
+// Used to notify the view that the focused control has changed.
+View.prototype.focusedControlChanged = function(control) {
+    uiLogger.debug("View.focusedControlChanged(" + control + ")");
+    this.focusedControl = control;
+    // notify event listeners
+    this.fireEvent(this.createEvent("FocusedControlChanged", this.focusedControl));
+}
+
+// Attempts to focus the first focusable control.
+// Override in subclasses as required.
+View.prototype.focusFirstControl = function() {
+    uiLogger.debug("View.focusFirstControl()");
+}
+
+// Attempts to reset all control focus states.
+// Override in subclasses as required.
+View.prototype.resetControlFocusStates = function() {
+    uiLogger.debug("View.resetControlFocusStates()");
+}
+
+
+// ////////////////////////////////////////////////////////////////////
+// Added functions
+
+// abstract function for setting up menu
+View.prototype.setupMenu = function()  {
+}
+
+// set up soft keys. Default implementation sets right soft
+// key to Back if the previous view is set
+View.prototype.setupSoftKeys = function()  {
+    if (window.widget) {
+		if (this.previousView != null) {
+			var self = this;
+			menu.setRightSoftkeyLabel("Back", function(){self.goBack();});
+		} else {
+			menu.setRightSoftkeyLabel();
+		}
+    }
+}
+
+// show the view - sets up soft keys
+View.prototype.show = function () {
+	this.setupSoftKeys();
+	this.update(false);
+	uiManager.setView(this);
+}
+
+// abstract function for updating page content
+View.prototype.update = function(forceUpdate){
+}
+
+
+// Default back button handler takes us to previous view
+// if one is set
+View.prototype.goBack = function()  {
+	if ( this.previousView != null ) {
+		// transition looks funky
+		if (window.widget) {
+			widget.prepareForTransition("fade");
+		}
+		this.previousView.show();
+		if (window.widget) {
+			widget.performTransition();
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/Utils/Logger.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,117 @@
+/*
+© Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (ÒNokiaÓ) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under NokiaÕs copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// Logger utility class that uses the Firebug console class.
+
+// Constructor (everything is static so this is empty).
+function Logger() {
+    // Set default logger level.
+    this.level = this.LOG_LEVEL_OFF;
+}
+
+// Logger levels.
+Logger.prototype.LOG_LEVEL_DEBUG = 0;
+Logger.prototype.LOG_LEVEL_INFO = 1;
+Logger.prototype.LOG_LEVEL_WARN = 2;
+Logger.prototype.LOG_LEVEL_ERROR = 3;
+Logger.prototype.LOG_LEVEL_OFF = 4;
+
+Logger.prototype.level = null;
+Logger.prototype.filter = null;
+
+// Disable logging on other browsers except Firefox.
+Logger.prototype.enabled = (navigator.userAgent.indexOf("Firefox") != -1);
+
+// Dumps an objects properties and methods to the console.
+Logger.prototype.dump = function(obj) {
+    if (this.enabled) {
+        console.dir(obj);
+    }
+}
+
+// Dumps a stracktrace to the console.
+Logger.prototype.trace = function() {
+    if (this.enabled) {
+        console.trace();
+    }
+}
+
+// Prints a debug message to the console.
+Logger.prototype.debug = function(str) {
+    if (this.enabled && this.level <= this.LOG_LEVEL_DEBUG) {
+        if (this.filter == null) {
+            console.debug(str);
+        } else {
+            var show = false;
+            for (i in this.filter) {
+                if (str.indexOf(this.filter[i]) >= 0) {
+                    show = true;
+                    break;
+                }
+            }
+            if (show) {
+                console.debug(str);
+            }
+        }
+    }
+}
+
+// Prints an info message to the console.
+Logger.prototype.info = function(str) {
+    if (this.enabled && this.level <= this.LOG_LEVEL_INFO) {
+        console.info(str);
+    }
+}
+
+// Prints a warning message to the console.
+Logger.prototype.warn = function(str) {
+    if (this.enabled && this.level <= this.LOG_LEVEL_WARN) {
+        console.warn(str);
+    }
+}
+
+// Prints an error message to the console.
+Logger.prototype.error = function(str) {
+    if (this.enabled && this.level <= this.LOG_LEVEL_ERROR) {
+        console.error(str);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/WRTKit/WRTKit.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,91 @@
+/*
+� Copyright 2008 Nokia Corporation. All rights reserved.
+
+IMPORTANT:  The Nokia software ("WRTKit and Example Widget files") is supplied to you by Nokia
+Corporation (�Nokia�) in consideration of your agreement to the following terms. Your use, installation
+and/or redistribution of the WRTKit and Example Widget files constitutes acceptance of these terms. If
+you do not agree with these terms, please do not use, install, or redistribute the WRTKit and Example
+Widget files.
+
+In consideration of your agreement to abide by the following terms, and subject to these terms, Nokia
+grants you a personal, non-exclusive license, under Nokia�s copyrights in the WRTKit and Example
+Widget files, to use, reproduce, and redistribute the WRTKit and Example files, in text form (for HTML,
+CSS, or JavaScript files) or binary form (for associated images), for the sole purpose of creating S60
+Widgets.
+
+If you redistribute the WRTKit and Example files, you must retain this entire notice in all such
+redistributions of the WRTKit and Example files.
+
+You may not use the name, trademarks, service marks or logos of Nokia to endorse or promote products
+that include the WRTKit and Example files without the prior written explicit agreement with Nokia.
+Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by
+Nokia herein, including but not limited to any patent rights that may be infringed by your products that
+incorporate the WRTKit and Example files or by other works in which the WRTKit and Example files
+may be incorporated.
+
+The WRTKit and Example files are provided on an "AS IS" basis.  NOKIA MAKES NO
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE, REGARDING THE EXAMPLES OR ITS USE AND OPERATION
+ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, AND/OR
+DISTRIBUTION OF THE EXAMPLES, HOWEVER CAUSED AND WHETHER UNDER THEORY
+OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE,
+EVEN IF NOKIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// This script includes the WRTKit for use in a widget.
+
+// WRTKit version (major.minor.revision, e.g. 1.0.0).
+var WRTKIT_VERSION_MAJOR = 1;
+var WRTKIT_VERSION_MINOR = 0;
+var WRTKIT_VERSION_REVISION = 0;
+var WRTKIT_RESOURCE_DIRECTORY = "WRTKit/Resources/";
+
+// Include util script files.
+includeScript("WRTKit/Utils/Logger.js");
+
+// Include UI visual definition.
+includeStyleSheet("WRTKit/Resources/UI.css");
+
+// Include all UI toolkit script files.
+var UI_NO_INIT_ID = "UI_NO_INIT_ID";
+
+includeScript("WRTKit/UI/UIInit.js");
+includeScript("WRTKit/UI/UIElement.js");
+includeScript("WRTKit/UI/Scrollbar.js");
+includeScript("WRTKit/UI/NotificationPopup.js");
+includeScript("WRTKit/UI/UIManager.js");
+includeScript("WRTKit/UI/View.js");
+includeScript("WRTKit/UI/ListView.js");
+includeScript("WRTKit/UI/Control.js");
+includeScript("WRTKit/UI/Separator.js");
+includeScript("WRTKit/UI/Label.js");
+includeScript("WRTKit/UI/ContentPanel.js");
+includeScript("WRTKit/UI/TextEntryControl.js");
+includeScript("WRTKit/UI/TextField.js");
+includeScript("WRTKit/UI/TextArea.js");
+includeScript("WRTKit/UI/SelectionControl.js");
+includeScript("WRTKit/UI/SelectionMenu.js");
+includeScript("WRTKit/UI/SelectionList.js");
+includeScript("WRTKit/UI/ActionControl.js");
+includeScript("WRTKit/UI/FormButton.js");
+includeScript("WRTKit/UI/NavigationButton.js");
+includeScript("WRTKit/UI/TabView.js");
+includeScript("WRTKit/UI/Ajax.js");
+
+// Includes a script file by writing a script tag.
+function includeScript(src) {
+    document.write("<script type=\"text/javascript\" src=\"" + src + "\"></script>");
+}
+
+// Includes a style sheet by writing a style tag.
+function includeStyleSheet(src) {
+    document.write("<style type=\"text/css\"> @import url(\"" +  src + "\"); </style>");
+}
Binary file Symbian.org/blueright.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/index.html	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,21 @@
+<html>
+    <head>
+        <title>Symbian.org</title>
+		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />		
+        <script type="text/javascript" src="WRTKit/WRTKit.js"></script>
+        <script type="text/javascript" src="FeedUpdateBroker.js"></script>
+        <script type="text/javascript" src="FeedPresentation.js"></script>
+        <script type="text/javascript" src="Forums.js"></script>
+        <script type="text/javascript" src="Login.js"></script>
+        <script type="text/javascript" src="Bugzilla.js"></script>
+        <script type="text/javascript" src="ForumPostForm.js"></script>
+        <script type="text/javascript" src="RssReader.js"></script>
+        <script type="text/javascript" src="Main.js"></script>
+        <style type="text/css">
+            @import url("style.css");
+        </style>
+        <META NAME="Generator" CONTENT="Nokia WRT plug-in for Aptana Studio 1.0.0.36" />
+    </head>
+    <body onload="init()">
+    </body>
+</html>
\ No newline at end of file
Binary file Symbian.org/logo.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/css/menu.css	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,52 @@
+div#softKeysPane {
+	font-weight: bold;
+	background-color: #E1E1E1;
+	height: 20px;
+	background-image: url(../images/top-navigation-bg.png);
+	background-repeat: repeat-x;
+	color: #FFFFFF;
+}
+div#menuPane {
+
+}
+div#menuItemsPane {
+	background-color: #efefef;
+	z-index: 1000;
+	position: absolute;
+	top: 100px;
+	width: 240px;
+	border-top: 1px solid #CCCCCC;
+	display: none;
+}
+#menuItemsPane ul {
+	margin: 0px;
+	padding: 0px;
+	list-style-type: none;
+}
+#menuItemsPane li {
+	padding: 4px 2px 2px 4px;
+	height: 14px;
+	border-top: 1px solid #F4F4F4;
+	border-bottom: 1px solid #CCCCCC;
+	border-right: 1px solid #CCCCCC;
+	font-weight: bold;
+}
+
+#menuItemsPane li a{
+	text-decoration: none;
+	color: #000000;
+}
+
+#menuItemsPane li.subMenuItem{
+	background-image: url(../images/arrow.png);
+	background-repeat: no-repeat;
+	background-position: right top;
+}
+#menuItemsPane li.s60AppToggle{
+	background-image: url(../images/s60-tiny-icon.png);
+	background-repeat: no-repeat;
+	background-position: right center;
+}
+#menuItemsPane li.exitOrBackBtn{
+	background-color: #D4D4D4;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/css/style.css	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,188 @@
+iframe#widgetIframeWindow {
+	height: 300px;
+	z-index: 1;
+}
+body {
+	margin: 0px;
+	padding: 0px;
+	margin-top: 70px;
+	font-family: "Nokia Sans", Arial, Verdana;
+	font-size: 10px;
+	overflow-x: hidden;
+	overflow-y: auto;
+}
+#WrapperDiv {
+	width: 100%;
+	min-height: 700px;
+	overflow: hidden;
+}
+
+div#navigation {
+	background-image: url(../images/top-navigation-bg.png);
+	height: 52px;
+	overflow: hidden;
+	position: absolute;
+	width: 100%;
+	left: 0px;
+	top: 0px;
+}
+div#navigation strong{
+	color: #ffffff;	
+}
+#device {
+	margin-right: auto;
+	margin-left: auto;
+	width: 10px;
+}
+#DisplayOrientation {
+	height: 34px;
+	width: 250px;
+	margin-right: auto;
+	margin-left: auto;
+	margin-bottom: 10px;
+	background-image: url(../images/display-orientation.png);
+	background-repeat: no-repeat;
+	overflow:hidden;
+	background-color:#FFFFFF;
+}
+
+
+#DisplayOrientation.portrait {
+	background-position: 0px 0px;
+}
+
+#DisplayOrientation.landscape {
+	background-position: 0px -45px;
+}
+
+div#iframePreviewWindow {
+	background-color: #FFFFFF;
+	height: 320px;
+	width: 240px;
+}
+
+div#display {
+	background-image: url(../images/device-right.png);
+	background-repeat: no-repeat;
+	background-position: right top;
+}
+div#displayLeft {
+	background-image: url(../images/device-left.png);
+	background-repeat: no-repeat;
+	background-position: left top;
+	padding-top: 10px;
+	padding-right: 8px;
+	padding-bottom: 0px;
+	padding-left: 9px;
+}
+
+iframe{
+	overflow:hidden;
+}
+#DeviceSettings {
+	position: absolute;
+	top: 0px;
+	z-index: 1000;
+	font-size: 12px;
+	background-color: #ffffff;
+	padding-top: 0px;
+	padding-right: 0px;
+	padding-left: 10px;
+	display: block;
+	overflow: hidden;
+	color: #999999;
+	opacity: 0.9;
+	height: 100%;
+	background-image: url(../images/toolbar-bg-shadow.png);
+	background-repeat: repeat-y;
+	background-position: left top;
+}
+div#pullDown {
+	height: 50px;
+	width: 69px;
+	background-repeat: no-repeat;
+	margin-left: -61px;
+	position: absolute;
+	z-index: 1005;
+}
+div#pullDown.down {
+	background-image: url(../images/new-pull-down-btn.png);
+	background-position: 0px -50px;
+}
+div#pullDown.up {
+	background-image: url(../images/new-pull-down-btn.png);
+	background-position: 0px 0px;
+}
+
+#DeviceSettings strong {
+	color: #000000;
+}
+
+#Toolbar {
+	position: fixed;
+	right: 0px;
+	width: 320px;
+	top: 0;
+	height: 100%;
+}
+#pullDown {
+	margin-top: 10px;
+}
+
+
+#save {
+	background-image: url(../images/select-device-tab.png);
+	background-repeat: no-repeat;
+	background-position: center center;
+	font-weight: bold;
+	color: #FFFFFF;
+	padding-top: 5px;
+	padding-bottom: 5px;
+	border-top-width: 2px;
+	border-right-width: 2px;
+	border-bottom-width: 2px;
+	border-left-width: 2px;
+	border-top-style: solid;
+	border-right-style: solid;
+	border-bottom-style: solid;
+	border-left-style: solid;
+	border-top-color: #225311;
+	border-right-color: #3C931E;
+	border-bottom-color: #3C931E;
+	border-left-color: #225311;
+}
+
+#DeviceSettings p {
+	border-bottom: 1px solid #E0E0E0;
+	padding-bottom: 5px;
+	margin-right: 20px;
+	margin-left: 20px;
+	padding-top: 0px;
+	margin-top: 0px;
+	margin-bottom: 8px;
+}
+
+select#deviceResolution {
+	margin-left: 15px;
+	font-size: 13px;
+	width: 200px;
+	border: 1px solid #999999;
+	height: 90px;
+	margin-top: 10px;
+}
+#deviceResolution option {
+	padding: 3px;
+	font-family: "Nokia Sans", "Nokia Sans SemiBold";
+
+}
+#DeviceSettings img {
+	margin-top: 8px;
+}
+label {
+	padding-top: 8px;
+	font-weight: bold;
+	color: #000000;
+}
+#DeviceSettings input {
+	margin-top: 5px;
+}
Binary file Symbian.org/preview/images/arrow.png has changed
Binary file Symbian.org/preview/images/device-bottom.png has changed
Binary file Symbian.org/preview/images/device-left-softkey.png has changed
Binary file Symbian.org/preview/images/device-left.png has changed
Binary file Symbian.org/preview/images/device-right-softkey.png has changed
Binary file Symbian.org/preview/images/device-right.png has changed
Binary file Symbian.org/preview/images/device/5320_main.jpg has changed
Binary file Symbian.org/preview/images/device/5800_main.jpg has changed
Binary file Symbian.org/preview/images/device/6210_main.jpg has changed
Binary file Symbian.org/preview/images/device/6220_main.jpg has changed
Binary file Symbian.org/preview/images/device/6650-2_main.jpg has changed
Binary file Symbian.org/preview/images/device/N95_main.jpg has changed
Binary file Symbian.org/preview/images/device/e51_main.jpg has changed
Binary file Symbian.org/preview/images/device/e66_main.jpg has changed
Binary file Symbian.org/preview/images/device/e71_main.jpg has changed
Binary file Symbian.org/preview/images/device/e90_main.jpg has changed
Binary file Symbian.org/preview/images/device/n78_main.jpg has changed
Binary file Symbian.org/preview/images/device/n79_main.jpg has changed
Binary file Symbian.org/preview/images/device/n82_main.jpg has changed
Binary file Symbian.org/preview/images/device/n85_main.jpg has changed
Binary file Symbian.org/preview/images/device/n95_8gb_main.jpg has changed
Binary file Symbian.org/preview/images/device/n96_main.jpg has changed
Binary file Symbian.org/preview/images/menuItemHover.png has changed
Binary file Symbian.org/preview/images/new-pull-down-btn.png has changed
Binary file Symbian.org/preview/images/s60-tiny-icon.png has changed
Binary file Symbian.org/preview/images/select-device-text.png has changed
Binary file Symbian.org/preview/images/toolbar-bg-shadow.png has changed
Binary file Symbian.org/preview/images/top-navigation-bg.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/nopreview.html	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,8 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+</head>
+<body>
+Widget preview is not available for this file, it is not the main html file for the widget.
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/preview_exit.html	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+		<title>Preview Exit</title>
+		<style type="text/css">
+			body{
+				font-family: Arial, Helvetica, sans-serif;
+				font-size: 11px;
+			}
+			div{
+				margin-top: 50px;
+				background-color: #EFF5FB;
+				padding: 5px;
+				border: 1px solid #A9D0F5;
+			}
+		</style>
+	</head>
+	<body>
+		<div align="center">
+			You have selected the <strong>Exit</strong> option from the widget menu. To see the widget preview, <br/>Refresh <strong>Widget</strong> view.
+		</div>
+	</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/build.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,681 @@
+/*
+ * Call this function when window is ready
+ */
+	window.onload = function()
+	{
+		
+		//	Attach events to Resolution Options & Orientation select
+		$('deviceResolution').onchange = function(ele){
+			if(ele.target != undefined)
+				ele = ele.target;
+				
+			Emulator.cur_device = ele.options[ele.selectedIndex].value;
+			Emulator.setDeviceLabels(SUPPORTED_DEVICES[Emulator.cur_device]);
+			
+			//	save the selected device details
+			createCookie('DEVICE_NAME', Emulator.cur_device);
+		}
+
+		/*
+		 * Toggle b/w Portrait / Landscape mode
+		 */
+		$('DisplayOrientation_portrait').onclick = function(ele){
+			
+			if(ele.target != undefined)
+				ele = ele.target;
+			if(Emulator.orientation_mode != 'portrait')
+				Emulator.changeOrientation(ele);
+		}
+
+		$('DisplayOrientation_landscape').onclick = function(ele){
+			
+			if(ele.target != undefined)
+				ele = ele.target;
+			if(Emulator.orientation_mode != 'landscape')
+				Emulator.changeOrientation(ele);
+		}
+		$('Toolbar').style.right = "-320px";
+		
+		
+		//	Toggle ToolBar Show/Hide
+		$('pullDown').onclick = function()
+		{
+			if(is_toolbar_hidden)
+			{
+				showDeviceSettings();
+			}
+			else
+			{
+				hideDeviceSettings();	
+			}
+		} 
+		
+		//	Toggle ToolBar Show/Hide
+		$('WrapperDiv').onmouseover = function(){
+			if(!is_scrolling && !is_toolbar_hidden)
+				window.setTimeout('hideDeviceSettings()', 1);
+		} 
+		
+		//	Assign Soft-keys trigger to Textual links
+		$("leftSoftKey").onclick = function(){
+			Emulator.triggerChildLSK();
+		}
+		$("rightSoftKey").onclick = function(){
+			Emulator.triggerChildRSK();
+		}
+		
+		
+		//	Assign Soft-keys trigger to Image links
+		$("leftSoftKeyImg").onclick = function(){
+			Emulator.triggerChildLSK();
+		}
+		
+		$("rightSoftKeyImg").onclick = function(){
+			Emulator.triggerChildRSK();
+		}
+		
+		//	Preload Device Information
+		Emulator.loadDeviceSettings();
+		
+		//	set the Default size to device
+		Emulator.setDeviceSize();
+		
+		//	set the Menu Pane position
+		Emulator.setMenuPane();
+	}
+
+
+/*
+ * Helper function
+ */
+	function $(str)
+	{
+		return document.getElementById(str);
+	}
+
+
+/*
+ * Emulator, which manages the device interacations
+ */
+
+	var Emulator = {};
+	
+	//	Default, device screen resolution
+	Emulator.cur_device = 'n78';
+	Emulator.cur_resolution = '240x320';
+	Emulator.device_cover_width = 17;
+	Emulator.device_cover_height = 8;	
+	
+	Emulator.orientation_changed = false;
+	Emulator.orientation_mode = 'portrait'; // {  portrait | landscape 	}
+	
+	// Flag, inidcates Menu Object created/exists in the child window
+	Emulator.is_widgetMenuIntiated = false;
+	
+	// Used as a bridge between, Parent window & Child widget
+	Emulator.parentToChild_Reference = null;
+
+	//	Interval ID for X-Resize
+	Emulator.interval_X = null;
+
+	//	Interval ID for Y-Resize
+	Emulator.interval_Y = null;
+
+	Emulator.path = document.location.pathname;
+	
+/*
+ * 	Change the device resolution
+ */
+	
+	Emulator.changeResolution = function(cur_val, to_val)
+	{
+
+		if(!SUPPORTED_DEVICES[this.cur_device]['orientation']){
+	
+				//	check the Portrait mode
+				$("DisplayOrientation_portrait").checked = true;
+
+				$("DisplayOrientation_landscape").checked = false;
+				$("DisplayOrientation_landscape").disabled = true;
+				
+				//	update the orientation-mode
+				this.orientation_mode = 'portrait';
+				
+				
+				// Toggle the Orientation Flag
+				this.orientation_changed = false;
+			
+		}
+		else
+			$("DisplayOrientation_landscape").disabled = false;
+		
+		if(cur_val == to_val)
+			return false;
+	
+		cur_val = cur_val.split('x');
+		cur_val[0] = parseInt(cur_val[0]);
+		cur_val[1] = parseInt(cur_val[1]);
+
+		to_val = to_val.split('x');
+		to_val[0] = parseInt(to_val[0]);
+		to_val[1] = parseInt(to_val[1]);
+	
+		//	hide the keys, if the OPTION menu is OPEN
+		this.hideDeviceSoftKeys();
+		
+		$('widgetIframeWindow').style.height = '100%';
+		$('menuItemsPane').style.width = to_val[0]+'px';
+		
+
+		// for X
+		var adjust_x = 0;
+		if(cur_val[0]%10)
+		{
+			//	decrease these many pixels
+			adjust_x = ((cur_val[0]%10) * (-1));
+		}
+		else if(to_val[0]%10){
+			//	increase these many pixels
+			adjust_x = (to_val[0]%10);
+		}
+
+		cur_val[0] = cur_val[0] + adjust_x;
+		$('iframePreviewWindow').style.width = 	parseInt(cur_val[0] + adjust_x) + 'px';
+		$('device').style.width = parseInt(cur_val[0] + adjust_x) + this.device_cover_width+'px';
+
+
+		if (cur_val[0] < to_val[0]) 
+		{
+			this.resizeDivX(cur_val[0], to_val[0], true);
+		}
+		else
+		{
+			this.resizeDivX(cur_val[0], to_val[0], false);
+		} 
+			
+	
+		// for Y
+		var adjust_y = 0;
+		if(cur_val[1]%10)
+		{
+			//	decrease these many pixels
+			adjust_y = ((cur_val[1]%10) * (-1));
+		}
+		else if(to_val[1]%10){
+			//	increase these many pixels
+			adjust_y = (to_val[1]%10);
+		}
+		cur_val[1] = cur_val[1] + adjust_y;
+
+		$('iframePreviewWindow').style.height = 	parseInt(cur_val[1] + adjust_y) + 'px';
+		$('device').style.height = parseInt(cur_val[1] + adjust_y) + this.device_cover_height+'px';
+
+		if (cur_val[1] < to_val[1]) 
+		{
+			this.resizeDivY(cur_val[1], to_val[1], true);
+		}
+		else
+		{
+			this.resizeDivY(cur_val[1], to_val[1], false);
+		}
+
+	}
+
+/*
+ * Resize the device on Horizontally
+ */
+	
+	Emulator.resizeDivX = function(from, to, flag)
+	{
+		if(from != to)
+		{
+			var curWidth = $('iframePreviewWindow').style.width;
+			curWidth = parseInt(curWidth.substr(0, (curWidth.length-2)));
+			if(flag) 
+			{
+				curWidth = curWidth + 10;
+				to = parseInt(to) - 10;
+			}
+			else 
+			{
+				curWidth = curWidth - 10;
+				to = parseInt(to) + 10;
+			}
+			$('iframePreviewWindow').style.width = curWidth + 'px';
+			$('device').style.width = parseInt(curWidth + this.device_cover_width)+'px';
+			
+			if(this.interval_X)
+				clearInterval(this.interval_X);
+			this.interval_X = setInterval(function(){ Emulator.resizeDivX(from, to, flag); }, 10);
+		}
+		else{
+			clearInterval(this.interval_X);
+		}
+	}
+	
+/*
+ * Resize the device on Vertically
+ */
+	
+	Emulator.resizeDivY = function(from, to, flag)
+	{
+		if(from != to)
+		{
+			var curHeight = $('iframePreviewWindow').style.height;
+			curHeight = parseInt(curHeight.substr(0, (curHeight.length-2)));
+			if(flag) 
+			{
+				curHeight = curHeight + 10;
+				to = parseInt(to) - 10;
+			}
+			else 
+			{
+				curHeight = curHeight - 10;
+				to = parseInt(to) + 10;
+			}
+			$('iframePreviewWindow').style.height = curHeight + 'px';
+			$('device').style.height = parseInt(curHeight+this.device_cover_height)+'px';
+			
+			if(this.interval_Y)
+				clearInterval(this.interval_Y);
+			this.interval_Y = setInterval(function(){ Emulator.resizeDivY(from, to, flag); }, 10);
+		}
+		else
+		{
+			clearInterval(this.interval_Y);
+			
+			/*
+			 * Cross check, why i have written these lines @P-1
+			 */
+			if(!this.parentToChild_Reference.menu.is_sfk_disabled)
+			{
+				// show menu Pane
+				Emulator.setMenuPane();
+				$('menuPane').style.display = 'block';
+			}
+
+		}
+	}
+	
+/*
+ * 	Toggle device orienation b/w Landscape & Portrait
+ */
+	Emulator.changeOrientation = function(ele)
+	{
+		if(SUPPORTED_DEVICES[this.cur_device]['orientation'])
+		{
+			//	If the device supports Orientation, perform
+			if(this.parentToChild_Reference.widget.isrotationsupported)
+			{
+				// Swap the current resolution value
+				// Width  -> Height
+				// height -> Width
+				var cur_val = this.cur_resolution;
+				this.cur_resolution = this.cur_resolution.split('x');
+				this.cur_resolution = this.cur_resolution[1]+'x'+this.cur_resolution[0];
+	
+				// Toggle the Orientation Flag
+				this.orientation_changed = (this.orientation_changed) ? false : true;
+	
+				// Toggle the Orientation value
+				this.orientation_mode = (this.orientation_mode == 'portrait') ? 'landscape' : 'portrait';
+	
+				//	Apply the new resolution to the device
+				this.changeResolution(cur_val, this.cur_resolution);
+			}
+		}
+		else{
+				//	update the orientation-mode
+				this.orientation_mode = 'portrait';
+				
+				// Toggle the Orientation Flag
+				this.orientation_changed = false;
+		}
+	}
+	
+	
+/*
+ * 	Set the Device size
+ */	
+	Emulator.setDeviceSize = function()
+	{
+		var cur_val;
+		try
+		{
+			this.cur_device = readCookie('DEVICE_NAME');
+			if(this.cur_device == undefined)
+			{
+				this.cur_device = $('deviceResolution').options[0].value;
+			}
+		}
+		catch(e)
+		{
+				this.cur_device = $('deviceResolution').options[0].value;
+		}
+
+		//	get Device resolution
+		this.cur_resolution = SUPPORTED_DEVICES[this.cur_device]['display']
+
+		
+		//	update the Device label values
+		this.setDeviceLabels(SUPPORTED_DEVICES[this.cur_device]);
+		
+		//	select the corresponding option on the list
+		var select = $('deviceResolution');
+		for(var i=0; i<select.options.length; i++)
+		{
+			if(select.options[i].value == this.cur_device)
+			{
+				select.options[i].selected = true;
+			}
+		}
+		
+		//	Disable Landscape Mode if the device won't support
+		if(!SUPPORTED_DEVICES[this.cur_device]['orientation'])
+			$("DisplayOrientation_landscape").disabled = true;
+		else
+			$("DisplayOrientation_landscape").disabled = false;
+		
+		cur_val = this.cur_resolution.split('x')
+		$('iframePreviewWindow').style.width = parseInt(cur_val[0])+'px';
+		$('iframePreviewWindow').style.height = parseInt(cur_val[1])+'px';
+	
+		$('device').style.width = parseInt(cur_val[0]) + this.device_cover_width+'px';
+		$('device').style.height = parseInt(cur_val[1]) + this.device_cover_height+'px';
+	}
+
+
+/*
+ * 	Set Position of the MenuPane
+ */
+
+	Emulator.setMenuPane = function()
+	{
+		var height = $('iframePreviewWindow').style.height;
+		height = parseInt(height.substr(0, (height.length-2)));
+		
+		// decrement height of iframe
+		$('widgetIframeWindow').style.height = (height - 20) + 'px';
+		
+		//	Adjust the Soft-keys position
+		if ($('menuItemsPane').childNodes[0]) 
+		{
+			var length = parseInt($('menuItemsPane').childNodes[0].childNodes.length);
+			if (length) 
+				$('menuItemsPane').style.top = 55 + parseInt(height - (length * 20)) + 'px';
+	
+		}
+	}
+
+/*
+ * 	Show the Device-Softkeys
+ */	
+	Emulator.showDeviceSoftKeys = function()
+	{
+		this.setMenuPane();
+		
+		// show menu Pane
+		$('menuPane').style.display = 'block';
+		
+		// show menu items pane
+		$('menuItemsPane').style.display = 'block';
+		
+	}
+	
+	
+/*
+ * 	Hide the Device-Softkeys
+ */	
+	Emulator.hideDeviceSoftKeys = function()
+	{
+		var height = $('iframePreviewWindow').style.height;
+		height = parseInt(height.substr(0, (height.length-2)));
+		
+		// hide menuPane 
+		$('menuPane').style.display = 'none';
+		$('menuItemsPane').style.display = 'none';
+		
+		// Set iframe height to IframePreviewWindow
+		$('widgetIframeWindow').style.height = height + 'px';
+	}
+	
+/*
+ * 	Parent-To-Child bride functions
+ *  Function to trigger Left-Soft-Key-Event
+ */	
+	Emulator.triggerChildLSK = function()
+	{
+		if(this.parentToChild_Reference.menu)
+		{
+			this.parentToChild_Reference.triggeLSK();
+		}
+	}
+	
+/*
+ * 	Function to trigger Right-Soft-Key-Event
+ */	
+	Emulator.triggerChildRSK = function()
+	{
+		if(this.parentToChild_Reference.menu)
+		{
+			this.parentToChild_Reference.triggeRSK();
+		}
+	}
+	
+/*
+ * 	Function to trigger Exit
+ */	
+	Emulator.triggerExit = function()
+	{
+		// Hide softkeys
+		this.parentToChild_Reference.menu.hideSoftkeys();
+		
+		
+		//	Load the 'preview_exit' file
+		$("widgetIframeWindow").src = 'preview/preview_exit.html';
+		
+		//	assign the Dummy function to Right soft-key
+		$("rightSoftKey").innerHTML = 'Cancel';
+		$("rightSoftKey").onclick = 'javascript:;';
+		
+	}
+
+/*
+ * 	Function to trigger Menu Hide
+ */	
+	Emulator.triggerMenuAutoHide = function()
+	{
+		this.parentToChild_Reference.menu.cancel();
+	}
+	
+	
+/*
+ * 	Trigger Menu Show function
+ */
+	Emulator.triggerMenuShow = function(parentId)
+	{
+		this.parentToChild_Reference.menu.showMenu(parentId);
+	}
+
+
+/*
+ * 	Trigger Menu Show function
+ */
+	Emulator.triggerMenuExit = function(parentId)
+	{
+		this.parentToChild_Reference.menu.exit();
+	}
+
+/*
+ * 	Trigger Menu Event
+ */	
+	Emulator.triggerMenuEvent = function(MenuItemId)
+	{
+		this.parentToChild_Reference.menu.triggeEvent(MenuItemId);
+	}
+
+/*
+ * 	Load Device Details
+ */
+	Emulator.loadDeviceSettings = function()
+	{
+		if(SUPPORTED_DEVICES)
+		{
+			var select = $('deviceResolution');
+			select.innerHTML = '';
+			for(var key in SUPPORTED_DEVICES)
+			{
+				var option = document.createElement('option');
+				option.text = SUPPORTED_DEVICES[key]['name']; 
+				option.value = key;
+				option.className = '6320';
+				select.appendChild(option);
+			}
+		}
+	}
+
+/*
+ * 	Set Device Details
+ */
+	Emulator.setDeviceLabels = function(row)
+	{
+		$('ModelName').innerHTML = row['name'];
+		$('ModelResolution').innerHTML = row['display'] + ' pixels';
+		$('ModelImage').src = 'preview/images/device/' + row['image'];
+		$('ModelPlatform').innerHTML = row['platform'];
+		
+		
+		var cur_val = this.cur_resolution;
+		var to_val = row['display'];
+		
+		if(this.orientation_changed && SUPPORTED_DEVICES[this.cur_device]['orientation'])
+		{
+			to_val = to_val.split('x');
+			to_val = to_val[1]+'x'+to_val[0];
+		}
+		this.cur_resolution = to_val;
+		this.changeResolution(cur_val, to_val);
+
+	}
+	
+	function parentToChild_RSK_Event()
+	{
+		parentToChild_Reference.triggeRightSoftkeyEvent();
+	}
+
+	
+	function createCookie(name,value) 
+	{
+		var days = 240000;
+	//	var domain = "Nokia-WRT";
+	    if (days) {
+			var date = new Date();
+			date.setTime(date.getTime()+(days*24*60*60*1000));
+			var expires = "; expires="+date.toGMTString();
+		}
+		else var expires = "";
+		var value = "Nokia_WRT#"+Emulator.path+"#"+name+"="+value;
+		document.cookie = value+expires+"; Emulator.path=/"
+	//	+  ((domain) ? ';domain=' + domain : '') + ;
+	} 
+	
+	/**
+	 * This function retrieves back the values from the cookies
+	 * @param document
+	 * @param name
+	 * @return
+	 */
+	function readCookie(name) 
+	{
+		name = "Nokia_WRT#" + Emulator.path + "#" + name;		
+		var nameEQ = name + "=";
+	//	alert(name);
+		var ca = document.cookie.split(';');
+		for(var i=0;i < ca.length;i++) {
+			var c = ca[i];
+			while (c.charAt(0)==' ') c = c.substring(1,c.length);
+			if (c.indexOf(nameEQ) == 0) {
+	//			alert(c.substring(nameEQ.length,c.length));
+				return c.substring(nameEQ.length,c.length);
+			}
+		}
+		return undefined;
+	}
+
+	var scrollIntervalId = null;
+	var is_scrolling = false;
+	var is_toolbar_hidden = true;
+	function showDeviceSettings()
+	{	
+		if(is_scrolling)
+			return false;
+			
+		is_scrolling = true;
+		scrollDiv($('Toolbar'), 'down');
+	}
+
+	
+	function hideDeviceSettings()
+	{
+		if(is_scrolling)
+			return false;
+			
+		is_scrolling = true;
+		scrollDiv($('Toolbar'), 'up');
+	}
+	
+	var divHeight = 330;
+	var divWidth = 320;
+	function scrollDiv(ele, type)
+	{
+		var currentRight = ele.style.right;
+		currentRight = parseInt(currentRight.substr(0, (currentRight.length-2)));
+		
+		//	move up
+		if(type == 'up')
+		{
+			if( currentRight >  parseInt(divWidth * (-1)))
+			{
+				ele.style.right = parseInt(currentRight - 5) + 'px';
+				
+				if(scrollIntervalId)
+				{
+					clearInterval(scrollIntervalId);
+				}
+				scrollIntervalId = setInterval(function(){ scrollDiv($('Toolbar'), 'up'); }, -10);
+			}
+			else{
+				is_scrolling = false;
+				is_toolbar_hidden = true;
+				clearInterval(scrollIntervalId);
+				
+				$('pullDown').className = 'down';
+				
+				return false;
+			}
+		}
+		else if(type == 'down')
+		{
+			if( currentRight <  0)
+			{
+				ele.style.right = parseInt(currentRight + 5) + 'px';
+
+				if(scrollIntervalId)
+				{
+					clearInterval(scrollIntervalId);
+				}
+				scrollIntervalId = setInterval(function(){ scrollDiv($('Toolbar'), 'down'); }, -10);
+
+			}
+			else{
+				is_scrolling = false;
+				is_toolbar_hidden = false;
+				clearInterval(scrollIntervalId);
+
+				$('pullDown').className = 'up';
+
+				return false;
+			}
+			
+		}
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/device.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,174 @@
+/*
+ * Device details
+ */
+var SUPPORTED_DEVICES = new Object();
+
+//	N78
+SUPPORTED_DEVICES.N78 = {
+	"name"		:	"Nokia N78",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"n78_main.jpg",
+	"orientation"		:	true
+}
+
+//	N79
+SUPPORTED_DEVICES.N79 = {
+	"name"		:	"Nokia N79",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"n79_main.jpg",
+	"orientation"		:	true
+}
+
+//	N82
+SUPPORTED_DEVICES.N82 = {
+	"name"		:	"Nokia N82",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"n82_main.jpg",
+	"orientation"		:	true
+}
+
+//	N85
+SUPPORTED_DEVICES.N85 = {
+	"name"		:	"Nokia N85",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"n85_main.jpg",
+	"orientation"		:	true
+}
+
+//	N95
+SUPPORTED_DEVICES.N95 = {
+	"name"		:	"Nokia N95",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"n95_main.jpg",
+	"orientation"		:	true
+}
+
+//	N95_8GB
+SUPPORTED_DEVICES.N95_8GB = {
+	"name"		:	"Nokia N95 8GB",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"n95_8gb_main.jpg",
+	"orientation"		:	true
+}
+
+//	N96
+SUPPORTED_DEVICES.N96 = {
+	"name"		:	"Nokia N96",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"n96_main.jpg",
+	"orientation"		:	true
+}
+
+//	N96-3
+SUPPORTED_DEVICES.N96_3 = {
+	"name"		:	"Nokia N96-3",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"n96_main.jpg",
+	"orientation"		:	true
+}
+
+//	E51
+SUPPORTED_DEVICES.E51 = {
+	"name"		:	"Nokia E51",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"e51_main.jpg",
+	"orientation"		:	true
+}
+
+//	E66
+SUPPORTED_DEVICES.E66 = {
+	"name"		:	"Nokia E66",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"e66_main.jpg",
+	"orientation"		:	true
+}
+
+//	E71
+SUPPORTED_DEVICES.E71 = {
+	"name"		:	"Nokia E71",
+	"display"	:	"320x240",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"e71_main.jpg",
+	"orientation"		:	false
+}
+
+//	E90
+SUPPORTED_DEVICES.E90 = {
+	"name"		:	"Nokia E90 Communicator",
+	"display"	:	"800x352",
+	"s_display"	:	"240x320",
+	"platform"	:	"S60 3rd Edition, Feature Pack 1",
+	"image"		:	"e90_main.jpg",
+	"orientation"		:	false
+}
+
+//	5320 XpressMusic
+SUPPORTED_DEVICES.n5320 = {
+	"name"		:	"Nokia 5320 XpressMusic",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"5320_main.jpg",
+	"orientation"		:	true
+}
+
+//	6210 Navigator
+SUPPORTED_DEVICES.n6210 = {
+	"name"		:	"Nokia 6210 Navigator",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"6210_main.jpg",
+	"orientation"		:	true
+}
+
+//	6220 Classic
+SUPPORTED_DEVICES.n6220 = {
+	"name"		:	"Nokia 6220 Classic",
+	"display"	:	"240x320",
+	"s_display"	:	"",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"6220_main.jpg",
+	"orientation"		:	true
+}
+
+//	Nokia 6650
+SUPPORTED_DEVICES.n6650 = {
+	"name"		:	"Nokia 6650",
+	"display"	:	"240x320",
+	"s_display"	:	"128x160",
+	"platform"	:	"S60 3rd Edition, Feature Pack 2",
+	"image"		:	"6650-2_main.jpg",
+	"orientation"		:	true
+}
+
+//	5800 XpressMusic
+SUPPORTED_DEVICES.n5800 = {
+	"name"		:	"Nokia 5800 XpressMusic",
+	"display"	:	"360x640 ",
+	"s_display"	:	"",
+	"platform"	:	"S60 5th Edition",
+	"image"		:	"5800_main.jpg",
+	"orientation"		:	true
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/lib/loader.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,9 @@
+addScript("preview/script/lib/systeminfo.js");
+addScript("preview/script/lib/menu.js");
+addScript("preview/script/lib/menuItem.js");
+addScript("preview/script/lib/widget.js");
+
+// Includes a script file by writing a script tag.
+function addScript(src) {
+    document.write("<script type=\"text/javascript\" src=\"" + src + "\"></script>");
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/lib/menu.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,492 @@
+/*
+	Function 	:	menu()
+	Argument	:	Void
+	Returns		:	Void
+	Description	:	Constructor Function creates a Menu object to the WINDOW
+*/
+
+function Menu()
+{
+	this.items = Array();
+	this.index = null;
+	this.isDimmed = false;	
+		
+	//	Event triggers
+	this.onShow = null;
+	this.onRightSoftKeySelect = null;
+	
+	// Flag for Menu softkeys disabled to show
+	this.is_sfk_disabled = false;
+}
+
+
+/*
+	Function 	:	menu.append()
+	Argument	:	MenuItem Object
+	Returns		:	Void
+	Description	:	Function appends MenuItem to a Menu Object
+*/
+Menu.prototype.append = function(MenuItem)
+{
+	if(this.allowedTypeOf(MenuItem))
+	{
+		var i;
+		var flag = true;
+		try{
+		for(i=0; i<this.items.length; i++)
+		{
+			if(this.items[i].id == MenuItem.id)
+			{	
+				flag = false; 
+				break; 
+			}
+		}} catch(e){ }
+		if(flag)
+		{
+			//	MenuItem.parent = this;
+			this.items.push(MenuItem);
+		}
+	}
+}
+
+
+/*
+	Function 	:	menu.remove()
+	Argument	:	MenuItem Object
+	Returns		:	Void
+	Description	:	Function Remove the menuItem and its children from the container options menu.
+*/
+Menu.prototype.remove = function(MenuItem)
+{
+	if(!this.allowedTypeOf(MenuItem))
+		return false;
+
+	var i;
+	var flag = false;
+	if (this.items.length) {
+		for (i = 0; i < this.items.length; i++) {
+			if (this.items[i].id == MenuItem.id) {
+				flag = true;
+				break;
+			}
+		}
+	}
+	if(flag)
+	{
+		this.items.splice(i, 1);
+	}
+}
+
+/*
+	Function 	:	menu.clear()
+	Argument	:	Void
+	Returns		:	Void
+	Description	:	Clears (deletes) all the menu items in the menupane.
+*/
+Menu.prototype.clear = function()
+{
+	try
+	{
+		this.items.splice(0, this.items.length);
+	}catch(e){}
+}
+
+
+/*
+	Function 	:	Menu.getMenuItemById(id)
+	Argument	:	Integer
+	Returns		:	MenuItem Object
+	Description	:	Function get the MenuItem Object with the reference of id
+*/
+Menu.prototype.getMenuItemById = function(id)
+{
+	var menuItemRef = menuItemExhistsById(this, id, 0);
+	if(this.allowedTypeOf(menuItemRef))
+		return menuItemRef;
+	else
+		return undefined;
+}
+
+
+/*
+	Function 	:	Menu.getMenuItemByName(name)
+	Argument	:	String
+	Returns		:	MenuItem Object
+	Description	:	Function get the MenuItem Object with the reference of String name
+*/
+Menu.prototype.getMenuItemByName = function(name)
+{
+	var menuItemRef = menuItemExhistsById(this, name, 1);
+
+//	if(menuItemRef !=null)
+	if(this.allowedTypeOf(menuItemRef))
+		return menuItemRef;
+	else
+		return undefined;
+}
+
+/*
+	Function 	:	Menu.setRightSoftkeyLabel()
+	Argument	:	String, Function
+	Returns		:	Void
+	Description	:	Set the label of the right soft key to str. This enables the default text 
+					to be changed from �exit� and a new function assigned by setting a callbackfunction
+*/
+Menu.prototype.setRightSoftkeyLabel = function(label, callbackfunction)
+{
+	window.menu = this;
+	
+	try
+	{
+		var rightSoftKey = childToParent_Reference.$('rightSoftKey');
+		if(typeof(callbackfunction) == 'function')
+		{
+			rightSoftKey.innerHTML = label;
+	
+			this.onRightSoftKeySelect = callbackfunction;
+			rightSoftKey.setAttribute('onClick', 'javascript:Emulator.triggerChildRSK();');	
+		}
+		else
+		{
+			rightSoftKey.innerHTML = "Cancel";
+			this.onRightSoftKeySelect = null;
+			rightSoftKey.setAttribute('onClick', 'javascript:Emulator.triggerChildRSK();');	
+		}
+	}catch(e){  }
+}
+
+/*
+	Function 	:	Menu.showSoftkeys()
+	Argument	:	Void
+	Returns		:	Void
+	Description	:	Makes the softkeys visible. By default the softkeys are not visible
+
+*/
+Menu.prototype.showSoftkeys = function()
+{
+	/*
+	 *  Shows showSoftkeys
+	 */
+	this.is_sfk_disabled = false;
+	childToParent_Reference.Emulator.showDeviceSoftKeys();
+}
+
+/*
+	Function 	:	Menu.hideSoftkeys()
+	Argument	:	Void
+	Returns		:	Void
+	Description	:	Makes the softkeys invisible. By default the softkeys are not visible. 
+
+*/
+Menu.prototype.hideSoftkeys = function()
+{
+	/*
+	 *  Hide showSoftkeys
+	 */
+	this.is_sfk_disabled = true;
+	childToParent_Reference.Emulator.hideDeviceSoftKeys();
+}
+
+
+/*	
+ *  
+ * ----------------------------------------------------------------
+ * Exta Functionalities which helps to make main functions to work
+ * ----------------------------------------------------------------
+ *  
+*/
+
+Menu.prototype.cancel = function()
+{
+	/*
+	 *  Clear menu and Exit the widget
+	 */
+
+	childToParent_Reference.$('menuItemsPane').innerHTML = '';
+	childToParent_Reference.$('menuItemsPane').style.display = 'none';
+
+	if(this.is_sfk_disabled)
+		childToParent_Reference.Emulator.hideDeviceSoftKeys();
+}
+
+Menu.prototype.exit = function()
+{
+	/*
+	 *  Clear menu and Exit the widget
+	 */
+
+	childToParent_Reference.$('menuItemsPane').innerHTML = '';
+	childToParent_Reference.$('menuItemsPane').style.display = 'none';
+
+	if(childToParent_Reference.Emulator.showSoftKeys_disabled)
+		childToParent_Reference.$('menuPane').style.display = 'none';
+
+	//	call the Parent function
+	childToParent_Reference.Emulator.triggerExit();
+}
+
+
+Menu.prototype.showMenu = function(parentId)
+{
+	try{
+	var menuItemsPane = childToParent_Reference.$('menuItemsPane')
+	menuItemsPane.innerHTML = '';
+
+	var menuPane = childToParent_Reference.$('menuPane');
+	menuPane.style.display = 'block';
+
+	var ul = document.createElement('ul');
+	var ele = this;
+	if(parentId)
+	{
+		ele = menuItemExhistsById(ele, parentId, 0);
+	}
+	if(ele.items.length)
+	{
+		for(var i=0; i<ele.items.length; i++)
+		{
+			if(!ele.items[i].isDimmed){
+				
+				try{
+					ul.appendChild(createMenuElement(ele.items[i]));
+				}catch(e){  }
+			}
+		}
+		if(parentId)
+		{
+			if(ele.parent)
+				ul.appendChild(createNormalMenuElement('Back', ele.parent.id));	
+			else
+				ul.appendChild(createNormalMenuElement('Back', null));	
+		}
+		else
+		{
+			ul.appendChild(createExitMenuElement());	
+		}
+		if(ele.items.length > 1)
+			menuItemsPane.style.overflowY = 'scroll';
+		else
+			menuItemsPane.style.overflowY = 'hidden';
+	}
+	else
+	{
+		menuItemsPane.style.overflowY = 'hidden';
+		ul.appendChild(createExitMenuElement());	
+	}
+	menuItemsPane.innerHTML = '<ul>'+ul.innerHTML+'</ul>';
+	/*
+	 * Set the MenuKeys DIV style.top
+	 */
+	childToParent_Reference.Emulator.showDeviceSoftKeys();
+	}
+	catch(e)
+	{
+		alert('showMenu: '+e);
+	}
+}
+
+Menu.prototype.triggeLeftSoftKeyEvent = function()
+{
+	if(typeof(window.menu.onShow) == 'function')
+	{
+			window.menu.onShow();
+	}
+	childToParent_Reference.$('softKeysPane').style.display = 'block';
+	this.showMenu();
+}
+
+Menu.prototype.triggeEvent = function(MenuItemId)
+{
+	try{
+		var menuItemRef = menuItemExhistsById(this, MenuItemId, 0);
+		if(menuItemRef != null)
+		{
+			if(typeof menuItemRef.onSelect == 'function')
+				menuItemRef.onSelect(MenuItemId);
+	
+			if(menuItemRef.items.length)
+				this.showMenu(MenuItemId);
+			else
+				this.cancel();
+		}
+	}
+	catch(e)
+	{
+		alert('triggeEvent: '+MenuItemId+' >> '+e);
+	}
+}
+
+Menu.prototype.hasChild = function(parentId)
+{
+	for(var i=0; i<this.items.length; i++)
+	{
+		if(this.items[i].parentId == parentId)
+		{	
+			 return true;
+		}
+	}
+	return false;
+}
+
+
+Menu.prototype.allowedTypeOf = function(MenuItem)
+{
+	try
+	{
+		if( (typeof(MenuItem) == 'object') && (MenuItem.type == 'MenuItem'))
+			return true;			
+	}
+	catch(e)
+	{
+		return false;
+	}
+}
+
+function widgetMenuReferenceShowMenu_NOKIA(parentId)
+{
+	window.menu.showMenu(parentId);
+}
+
+function widgetTriggeMenuEvent_NOKIA(MenuItemId)
+{
+	alert(MenuItemId);
+	window.menu.triggeEvent(MenuItemId);
+}
+
+/*
+	MenuItemExhists??
+*/
+function menuItemExhistsById(menuReference, value, argumentType)
+{
+	var i;
+	var flag = null;
+	
+	for(i=0; i<menuReference.items.length; i++)
+	{
+		if(!argumentType)
+		{
+			if(menuReference.items[i].id == value)
+			{	
+				flag = true; 
+				break; 
+			}
+		}
+		else
+		{
+			if(menuReference.items[i].name == value)
+			{	
+				flag = true; 
+				break; 
+			}
+		}
+		
+		if(menuReference.items[i].items != undefined && menuReference.items[i].items.length)
+		{
+			var temp = menuItemExhistsById(menuReference.items[i], value, argumentType);
+			if(temp)
+				return temp;
+		}
+	}
+	if(flag)
+	{
+		// crate a package and send it
+		menuReference.items[i].index = i;
+		return menuReference.items[i];
+	}
+	else
+		return null;
+}
+
+function createMenuElement(MenuItem) 
+{
+	var listitem = document.createElement('li');
+	listitem.id = MenuItem.id;
+/*	if(MenuItem.onSelect)
+	{
+		listitem.setAttribute('onClick', 'javascript:widgetTriggeMenuEvent_NOKIA('+MenuItem.id+');');
+	}
+*/	listitem.setAttribute('onClick', 'javascript:Emulator.triggerMenuEvent('+MenuItem.id+');');
+
+    var anchor = document.createElement('a');
+	anchor.id = 'subMenuItem_'+MenuItem.id;
+	anchor.innerHTML = MenuItem.name;
+	if(MenuItem.items.length)
+ 	{  
+		listitem.className = 'subMenuItem';
+		anchor.setAttribute('href', 'javascript:Emulator.triggerMenuShow('+MenuItem.id+');');
+	}
+    listitem.appendChild(anchor);
+	return (listitem);
+}
+
+function createNormalMenuElement(MenuTitle, index) 
+{
+    var listitem = document.createElement('li');
+
+    var anchor = document.createElement('a');
+	anchor.id = 'subMenuItem_BACK';
+	anchor.innerHTML = MenuTitle;
+
+	if(MenuTitle == 'Application Switcher') 
+	{
+		listitem.className = 's60AppToggle';
+		anchor.setAttribute('href', 'javascript:window.menu.cancel();');
+	}
+	else if (MenuTitle == 'Back') {
+		listitem.className = 'exitOrBackBtn';
+		anchor.setAttribute('href', 'javascript:Emulator.triggerMenuShow(' + index + ');');
+	}
+	else 
+		anchor.setAttribute('href', 'javascript:Emulator.triggerMenuShow(' + index + ');');
+    
+	listitem.appendChild(anchor);
+	return (listitem);
+}
+
+function createExitMenuElement() 
+{
+    var listitem = document.createElement('li');
+	listitem.className = 'exitOrBackBtn';
+    var anchor = document.createElement('a');
+	anchor.id = 'subMenuItem_EXIT';
+	anchor.innerHTML = 'Exit';
+	anchor.setAttribute('href', 'javascript:Emulator.triggerMenuExit();');
+	
+    listitem.appendChild(anchor);
+	return (listitem);
+}
+
+function triggeRSK()
+{
+	try {
+		if (window.menu) {
+			if (childToParent_Reference.$('softKeysPane').style.display != 'none') {
+				if (window.menu.onRightSoftKeySelect != null) {
+					window.menu.onRightSoftKeySelect();
+					window.menu.cancel();
+				}
+				else {
+					window.menu.cancel();
+				}
+			}
+		}
+	}catch(e)
+	{
+		alert(e);
+	}
+}
+
+function triggeLSK()
+{
+	if(window.menu)
+	{
+		window.menu.showMenu();
+		if(typeof(window.menu.onShow) == 'function')
+		{
+			if(window.menu.onShow)
+			{
+				window.menu.onShow();
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/lib/menuItem.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,91 @@
+/*
+	Function 	:	MenuItem()
+	Argument	:	Void
+	Returns		:	Void
+	Description	:	Constructor Function creates a Menu object to the WINDOW
+*/
+
+function MenuItem(name, id)
+{
+	this.id = id;
+	this.name = name;
+	this.isDimmed = false;
+	
+	this.items = Array();
+	this.index = null;
+	this.parent = null;
+	this.type = 'MenuItem';
+	
+	
+	//	Event triggers
+	this.onSelect = null;
+}
+
+
+/*
+	Function 	:	MenuItem.append(MenuItem)
+	Argument	:	Menu Object
+	Returns		:	Void
+	Description	:	Function appends childMenuItem to a MenuItem
+*/
+MenuItem.prototype.append = function(childMenuItem)
+{
+	if( (childMenuItem != null) && (childMenuItem.type == 'MenuItem'))
+	{
+		childMenuItem.parent = this;
+		this.items.push(childMenuItem);
+	}
+}
+
+
+/*
+	Function 	:	MenuItem.remove()
+	Argument	:	Menu Object
+	Returns		:	Void
+	Description	:	Function Removes childMenuItem and its children from the parent menu item.
+*/
+MenuItem.prototype.remove = function(childMenuItem)
+{
+	if((childMenuItem != null) && (childMenuItem.type == 'MenuItem'))
+	{
+		var i = this.search(childMenuItem);
+		if(i > -1)
+			this.items.splice(i, 1);
+	}
+}
+
+/*
+	Function 	:	MenuItem.remove()
+	Argument	:	Menu Object
+	Returns		:	Void
+	Description	:	If flag is true the MenuItem is hidden and if flag is false the item is shown.
+*/
+MenuItem.prototype.setDimmed = function(flag)
+{
+	this.isDimmed = flag;
+}
+
+
+/*
+	Function 	:	MenuItem.search()
+	Argument	:	MenuItem Object
+	Returns		:	Integer
+	Description	:	Function Replace oldMenuItem with newMenuItem
+*/
+MenuItem.prototype.search = function(MenuItem)
+{
+		var i;
+		var flag = false;
+		for(i=0; i<this.items.length; i++)
+		{
+			if(this.items[i].id == MenuItem.id)
+			{	
+				flag = true; 
+				break; 
+			}
+		}
+		if(flag)
+			return i;
+		else
+			return -1;		
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/lib/systeminfo.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,103 @@
+/**
+	This API is used to provide system related data.
+	It takes the sysObject as an argument that is the embeded API in the main HTML file.
+	While using this API outside mobile environment, User or developer need not to take any extara action in oprder to support SYSAPI.
+*/
+
+function systemAPI(sysObject)
+{
+	/*
+	 * 	System Language information services
+	 */
+	sysObject.language = 'EN';
+
+
+
+
+	/*
+	 * 	Power information services
+	 */
+	
+	//	Properties
+	sysObject.chargelevel = 5;
+	sysObject.chargerconnected = 0;
+
+	//	Event triggers
+	sysObject.onchargelevel = null;
+	sysObject.onchargerconnected = null;
+
+
+
+	/*
+	 * 	Beep tone control services
+	 */	
+	sysObject.beep = function(frequency, duration){	}
+
+
+
+	/*
+	 * 	Network Information services
+	 */
+	
+	//	value range between: {0-7}
+	sysObject.signalbars = 7;
+
+	sysObject.networkname = 'No network';
+
+	//	value range between: {0-7}
+	sysObject.networkregistrationstatus = 0;
+	
+
+
+	/*
+	 * 	Display and keypad illumination information and control services
+	 */
+
+	//	Properties
+	sysObject.lightminintensity = 1;
+	sysObject.lightmaxintensity = 100;
+	sysObject.lightdefaultintensity = 0;
+	
+	sysObject.lightinfiniteduration = 0;
+	sysObject.lightmaxduration = 1;
+	sysObject.lightdefaultcycletime = 0;
+
+	sysObject.lighttargetprimarydisplayandkeyboard = 0x3;
+	sysObject.lighttargetsystem = 1;
+
+	//	functions
+	sysObject.lighton	= function(lighttarget, duration, intensity, fadein){ 	}
+	sysObject.lightblink	= function(lighttarget, duration, onduration, offduration, intensity){ 	}
+	sysObject.lightoff	= function(lighttarget, duration, fadeout){ 	}
+
+
+
+	/*
+	 * 	Vibration information and control services
+	 */
+	sysObject.vibraminintensity = 1;
+	sysObject.vibramaxintensity = 10;
+	sysObject.vibramaxduration = 100;
+	
+	//	Vibration setting in the user profile is off.
+	sysObject.vibrasettings = 2; 
+
+	sysObject.startvibra	= function(duration, intensity){	}
+
+	sysObject.stopvibra	= function(){	}
+
+
+
+
+	/*
+	 * 	Memory and file system information services
+	 */
+	sysObject.totalram = 32;	
+	sysObject.freeram = 10;	
+	sysObject.drivelist = 'C';	
+
+	sysObject.drivesize	= function(drive){	return 64;	}
+	
+	sysObject.drivefree	= function(drive){	return 32;	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/preview/script/lib/widget.js	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,388 @@
+/**
+ * Widget object constructor
+ * @param {void}
+ *     widget()
+ * @return {void}
+ */ 
+function Widget()
+{
+	//	widget identifier, dummy value
+	this.identifier = 14021981;
+	this.isrotationsupported = true;
+	
+	//	widget event triggers
+	this.onshow = null;
+	this.onhide = null;
+	
+	/*
+	 * Custom extra functionalities to support
+	 */
+	this.path = document.location.pathname;
+	this.sysAPI = null;
+	this.onload = null;
+	this.opacity = 50;
+	this.interval = 20;
+	this.isFront = false;
+	this.preferenceArray = new Array();
+	this.preferenceKey  = 0;
+}
+
+
+/**
+ * Launches the browser with the specified url 
+ * @param {String} url
+ *     openURL()
+ * @return {Void}
+ */ 
+Widget.prototype.openURL = function(url)
+{
+   if (url) {
+	   window.open(url ,"New Widget Window",'height=200 width=250');
+   }
+}
+
+
+/**
+ * Returns previously stored preference associated with the specified key
+ * @param {String} Key preference value to be fetch
+ *     preferenceForKey()
+ * @return {String} Value
+ */ 
+Widget.prototype.preferenceForKey = function(key){
+	var name = "Nokia_WRT#" + this.path + "#" + key;
+	var result = readCookie(document, name);
+	return result;
+}
+
+
+/**
+ * Stores the key associated with the specified preference
+ * @param {String} Preference value to be stored 
+ * @param {String} Key Preference value associated to
+ *     setPreferenceForKey()
+ * @return {Void}
+ */ 
+Widget.prototype.setPreferenceForKey = function(preference, key)
+{
+	var value;
+	//Specifying null for the preference parameter removes the specified key from the preferences
+	if(key == null){
+		if(this.preferenceKey>0){
+			this.preferenceKey--;
+		}
+		//delete from cookies
+	}
+	value = "Nokia_WRT#"+this.path+"#"+key;
+	this.preferenceArray[this.preferenceKey] = value;
+	
+	createCookie(document,value,preference,240000);
+	this.preferenceKey++;
+	
+	//save cookie for cookies
+	updateMainCookie(document);
+}
+
+
+
+/**
+ * Toggle between Tabbed navigation mode or Cursor mode
+ * @param {Boolean} Value
+ *     setNavigationEnabled()
+ * @return {Void}
+ */ 
+Widget.prototype.setNavigationEnabled = function(bool)
+{
+	//This function can not be used on preview browser
+}
+
+
+
+/**
+ * Open S0-Application identified by UID along with the specified params
+ * @param {Integer} Uid hexadecimal value to a specified application
+ * @param {String} Value
+ *     openApplication()
+ * @return {Void}
+ */ 
+Widget.prototype.openApplication = function(Uid, param)
+{
+	alert("openApplication function won't be simulated in this application");
+}
+
+
+
+/**
+ * Prepares the Widget.to do transition to specified transitionState
+ * @param {String} Value Transition state
+ *     prepareForTransition()
+ * @return {Void}
+ */ 
+Widget.prototype.prepareForTransition = function(transitionState)
+{
+    this.isFront = ("" + transitionState).toLowerCase() != "toback";
+    window.document.getElementsByTagName("body")[0].style.opacity = "0.3";
+}
+
+
+
+
+/**
+ * Does the animation to make the transition between the specified transitionState
+ * @param {Void}
+ *     performTransition()
+ * @return {Void}
+ */ 
+Widget.prototype.performTransition = function()
+{
+    var _self = this;
+    this.opacity = 0;
+    this.interval = window.setInterval(function() {
+      _self.opacity += 0.2;
+      if (_self.opacity > 1) {
+        _self.opacity = 1;
+      }
+      window.document.getElementsByTagName("body")[0].style.opacity = _self.opacity + "";
+      if (_self.opacity >= 1) {
+       window.clearInterval(_self.interval);
+       window.document.getElementsByTagName("body")[0].style.opacity = "1";
+      }
+      //do nothing
+    }, 50);  
+      //do nothing
+}
+
+
+
+
+
+/**
+ * Set the preferred screen orientation to landscape. 
+ * The display will flip if the phone display orientation 
+ * is portrait and the phone supports landscape mode.
+ * @param {Void}
+ *     setDisplayLandscape()
+ * @return {Void}
+ */ 
+Widget.prototype.setDisplayLandscape = function(){
+	try 
+	{
+		if (this.isrotationsupported && childToParent_Reference.Emulator.orientation_mode != 'landscape') 
+		{
+			childToParent_Reference.Emulator.changeOrientation(childToParent_Reference.$('DisplayOrientation'));
+		}
+	} 
+	catch (e) {}
+}
+
+
+
+
+/**
+ * Set the preferred screen orientation to portrait.  
+ * The display will flip if the phone display orientation 
+ * is landscape and the phone supports portrait mode.
+ * @param {Void}
+ *     setDisplayPortrait()
+ * @return {Void}
+ */ 
+Widget.prototype.setDisplayPortrait = function()
+{
+	try 
+	{
+		if (this.isrotationsupported && childToParent_Reference.Emulator.orientation_mode != 'portrait') 
+		{
+			childToParent_Reference.Emulator.changeOrientation(childToParent_Reference.$('DisplayOrientation'));
+		}
+	} 
+	catch (e) {}
+}
+
+/**
+ * Allows the definition of a function to be called 
+ * when a Widget.is displayed 
+ * @param {Void}
+ *     onshow()
+ * @return {Void}
+ */ 
+Widget.prototype.onshow = function()
+{
+	// to be implemented
+}
+
+
+
+
+/**
+ * Allows the definition of a function to be called 
+ * when a Widget.sent into the background (hidden) 
+ * @param {Void}
+ *     onhide()
+ * @return {Void}
+ */ 
+Widget.prototype.onhide  = function()
+{
+	// to be implemented
+}
+
+
+
+/**
+ * This function returns the System API if sysinfo is included in document embed
+ */
+Widget.prototype.enableSystemApi = function()
+{
+	
+	//	Identify, and Attach System-Info-Object properties
+	try 
+	{
+		var parentIframeRef = window.parent.frames[0];
+		if(parentIframeRef) 
+		{
+			if (parentIframeRef.document.embeds.length > 0) {
+				for (var i = 0; i < parentIframeRef.document.embeds.length; i++) 
+				{
+					//match the system Info API embed tag
+					if (parentIframeRef.document.embeds[i].type == 'application/x-systeminfo-widget') 
+					{
+						new systemAPI(parentIframeRef.document.embeds[i]);
+						widget.sysAPI = parentIframeRef.document.embeds[i];
+					}
+				}
+			}
+		}
+	} 
+	catch (e) {
+		alert('Error in attachSysInfo: ' + e);
+	}	
+
+	//	Attach menu object to window
+	window.menu = new Menu();
+
+	// Attach window reference to the Parent Window	
+	window.parent.Emulator.parentToChild_Reference = window;
+
+	//	add event listener to window.focus
+	window.onfocus = function(){ menu.cancel();	}
+
+	//	add event listener to window.focus
+	window.onunload = function()
+	{ 
+		try
+		{
+			//	Trigger Callback of Widget.onHide function
+			if(typeof(widget.onhide) == 'function')
+			{
+				widget.onhide();
+			}
+		}
+		catch(e){ errorLog('widget.onhide: '+e.description, 0); }
+	}
+
+
+	/*
+	 * Used as a bridge between, Child widget & Parent window
+	 */
+	window.childToParent_Reference = window.parent;
+
+}
+
+/*
+ * support functions for widget object
+ */
+
+/**
+ * This function stores cookie for all the cookies
+ * to help finding cookies of the same document while clearing preferences
+ * @param doucment -- Document object
+ */
+function updateMainCookie(doucment){
+	var temp="";
+	name = "Nokia_WRT#"+widget.path;
+	for (var k = 0; k<widget.preferenceArray.length; k++){
+		temp = temp+"|"+widget.preferenceArray[k];
+	}
+	createCookie(document,name,temp,24000);
+}
+
+/**
+ * This function creates cookie for the setPreferenceForKey function in order to save key-pref persistently
+ * 
+ * @param document -- Document object
+ * @param name -- Name of the cookie
+ * @param value -- value for the name cookie
+ * @param days -- expire
+ * 
+ */
+
+function createCookie(document,name,value,days) {
+    if (days) {
+		var date = new Date();
+		date.setTime(date.getTime()+(days*24*60*60*1000));
+		var expires = "; expires="+date.toGMTString();
+	}
+	else var expires = "";
+	document.cookie = name+"="+value+expires+"; path=/"
+} 
+
+/**
+ * This function retrieves back the values from the cookies
+ * @param document
+ * @param name
+ * @return
+ */
+function readCookie(document , name) {
+	var nameEQ = name + "=";
+	var ca = document.cookie.split(';');
+	for(var i=0;i < ca.length;i++) {
+		var c = ca[i];
+		while (c.charAt(0)==' ') c = c.substring(1,c.length);
+		if (c.indexOf(nameEQ) == 0) {
+			return c.substring(nameEQ.length,c.length);
+		}
+	}
+	return undefined;
+}
+
+
+/*
+ * /////////////////////////////////////////////////////////////////////////////////////
+ * //////////////////////////////	  Ends here		  //////////////////////////////////
+ * /////////////////////////////////////////////////////////////////////////////////////
+ */
+
+function errorLog(str, flag)
+{
+//	alert(str);
+}
+
+/*
+ * by John Resig
+ * @reference: http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
+ */
+function addEvent( obj, type, fn ){ 
+   if (obj.addEventListener){ 
+      obj.addEventListener( type, fn, false );
+   }
+   else if (obj.attachEvent){ 
+      obj["e"+type+fn] = fn; 
+      obj[type+fn] = function(){ obj["e"+type+fn]( window.event ); } 
+      obj.attachEvent( "on"+type, obj[type+fn] ); 
+   } 
+}
+
+/*
+ * 		Create a new Widget Object when DOM ready
+ * 
+*/
+try 
+{
+	//	attach widget object to window
+	var widget = new Widget();
+	
+	//	attach the System-Info api specific functionality
+	addEvent(window, 'load', widget.enableSystemApi);
+} 
+catch (e) 
+{
+	alert('Exception: Widget object creation');
+}
Binary file Symbian.org/right.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/style.css	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,53 @@
+/* Feed item date */
+.FeedItemDate {
+    font-style: italic;
+}
+
+/* Feed item text */
+.FeedItemDescription {
+    padding: 4px 0px;
+}
+
+/* Feed item links */
+.FeedItemLink {
+    font-weight: bold;
+}
+
+/* Anchor tags in the context of a feed item link */
+.FeedItemLink a {
+    text-decoration: underline;
+    font-weight: bold;
+    color: rgb(0,0,0);
+}
+
+/* Focused anchor tags */
+.FeedItemLink a:focus {
+    background: rgb(253,200,47);
+    color: rgb(0,0,0);
+}
+
+table.bugzilla {
+    font: normal 12px Arial, sans-serif;
+	border-width: thin thin thin thin;
+	border-spacing: 0px;
+	border-style: none none none none;
+	border-color: black black black black;
+	border-collapse: collapse;
+	background-color: white;
+}
+table.bugzilla th {
+    font: normal 12px Arial, sans-serif;
+	border-width: thin thin thin thin;
+	padding: 1px 1px 1px 1px;
+	border-style: inset inset inset inset;
+	border-color: gray gray gray gray;
+	background-color: white;
+}
+table.bugzilla td {
+    font: normal 12px Arial, sans-serif;
+	border-width: thin thin thin thin;
+	padding: 1px 1px 1px 1px;
+	border-style: inset inset inset inset;
+	border-color: gray gray gray gray;
+	background-color: white;
+}
Binary file Symbian.org/titlebar.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/wrt_preview_frame.html	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Nokia WRT Preview</title>
+<link href="preview/css/style.css" rel="stylesheet" type="text/css" />
+<script language="JavaScript" src="preview/script/device.js"></script>
+<script language="JavaScript" src="preview/script/build.js"></script>
+<link href="preview/css/menu.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<div id="Toolbar">
+  <div id="DeviceSettings">
+    <table cellpadding="0" cellspacing="0">
+      <tr valign="middle">
+        <td width="230" align="left" valign="top"><img src="preview/images/select-device-text.png" alt="Select Device" width="110" height="18" hspace="15" /><br />
+        <select name="deviceResolution" size="5" id="deviceResolution">
+                          </select></td>
+      <td width="87" align="center"><img src="preview/images/device/5320_main.jpg" alt="Device" name="ModelImage" width="57" height="150" id="ModelImage" /></td>
+      </tr><tr>
+	  <td colspan="2">    <p>Model: <br />
+        <strong id="ModelName">Nokia 5320 XpressMusic</strong></p>
+    <p>Resolution: <br />
+      <strong id="ModelResolution">240 x 320 pixels</strong></p>    </td>
+      </tr><tr>
+	  <td colspan="2"><p>Developer Platform: <br />
+            <strong id="ModelPlatform">S60 3rd Edition, Feature Pack 2</strong></p>
+        <p>Display Orientation:<br />
+            <label>
+            <input name="DisplayOrientation" type="radio" id="DisplayOrientation_portrait" value="portrait" checked="checked"/>
+              Portrait</label>
+            <label>
+            <input type="radio" name="DisplayOrientation" value="landscape" id="DisplayOrientation_landscape" />
+              Landscape<br />
+            </label>
+        </p></td>
+    </tr>
+  </table>
+</div>
+  <div class="down" id="pullDown"></div>
+  </div>
+<div id="WrapperDiv">
+<div id="device">
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+  <tr>
+    <td>
+     <div id="display">
+    	<div id="displayLeft">
+        	<div id="iframePreviewWindow">
+        		<iframe src="wrt_preview_main.html" frameborder="no" width="100%" id="widgetIframeWindow"></iframe>
+                <div id="menuPane">
+                	<div id="menuItemsPane">
+                    </div>
+                	<div id="softKeysPane">
+                    	<table width="100%" border="0" cellspacing="2" cellpadding="2">
+                          <tr>
+                            <td><span id="leftSoftKey">Options</span></td>
+                            <td align="right"><span id="rightSoftKey">Cancel</span></td>
+                          </tr>
+                      </table>
+                    </div>
+                </div>
+        	</div>
+        </div>
+  	</div>
+</td>
+  </tr>
+  <tr>
+    <td>
+    	<div id="softKeys">
+    	  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+            <tr>
+              <td width="46"><a id="leftSoftKeyImg"><img src="preview/images/device-left-softkey.png" width="103" height="46" border="0" /></a></td>
+              <td background="preview/images/device-bottom.png">&nbsp;</td>
+              <td width="46"><a id="rightSoftKeyImg"><img src="preview/images/device-right-softkey.png" width="103" height="46" border="0" /></a></td>
+            </tr>
+          </table>
+    	</div>
+    </td>
+  </tr>
+</table>
+</div>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian.org/wrt_preview_main.html	Fri Jun 05 16:18:05 2009 +0100
@@ -0,0 +1,23 @@
+<html>
+    <head>
+	<script language="JavaScript" type="text/javascript" src="preview/script/lib/loader.js"></script>
+
+        <title>Symbian.org</title>
+		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />		
+        <script type="text/javascript" src="WRTKit/WRTKit.js"></script>
+        <script type="text/javascript" src="FeedUpdateBroker.js"></script>
+        <script type="text/javascript" src="FeedPresentation.js"></script>
+        <script type="text/javascript" src="Forums.js"></script>
+        <script type="text/javascript" src="Login.js"></script>
+        <script type="text/javascript" src="Bugzilla.js"></script>
+        <script type="text/javascript" src="ForumPostForm.js"></script>
+        <script type="text/javascript" src="RssReader.js"></script>
+        <script type="text/javascript" src="Main.js"></script>
+        <style type="text/css">
+            @import url("style.css");
+        </style>
+        <META NAME="Generator" CONTENT="Nokia WRT plug-in for Aptana Studio 1.0.0.36" />
+    </head>
+    <body onload="init()">
+    </body>
+</html>
\ No newline at end of file