--- a/org.symbian.wrttools.doc.WRTKit/html/WRTKit_RSS_Reader_user_interface-GUID-1083a0c4-a953-4b6e-a4d0-45a031e51c35.html Fri Mar 05 19:11:15 2010 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,631 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html lang="en" xml:lang="en">
-<head>
-<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
-<meta name="copyright" content="(C) Copyright 2005" />
-<meta name="DC.rights.owner" content="(C) Copyright 2005" />
-<meta content="concept" name="DC.Type" />
-<meta name="DC.Title" content="RSS Reader user interface" />
-<meta scheme="URI" name="DC.Relation" content="WRTKit_RSS_Reader_Tutorial-GUID-678d197f-c7b0-4e5e-85e2-f8549c75bbe8.html" />
-<meta content="XHTML" name="DC.Format" />
-<meta content="GUID-1083A0C4-A953-4B6E-A4D0-45A031E51C35" name="DC.Identifier" />
-<meta content="en" name="DC.Language" />
-<link href="commonltr.css" type="text/css" rel="stylesheet" />
-<title>
-RSS Reader user interface</title>
-</head>
-<body id="GUID-1083A0C4-A953-4B6E-A4D0-45A031E51C35"><a name="GUID-1083A0C4-A953-4B6E-A4D0-45A031E51C35"><!-- --></a>
-
-
-
- <h1 class="topictitle1">
-RSS Reader user interface</h1>
-
- <div>
-
- <div class="section"><h2 class="sectiontitle">
-Preferences</h2>
-
-
- <p>
-
- Now it's time to write some code so let's open up RSSReader.js. The first thing
- we will do is implement the init() function that gets called when the widget has
- loaded. We will begin by setting up the timer-based updating mechanism for the
- feed updates by declaring four variables that we'll need for that:
- </p>
-
-<pre>
-
-// Feed update timer identifier.
-var updateTimerId = null;
-
-// Feed URL and update frequency (in milliseconds; -1 if no auto update).
-var feedURL = null;
-var feedUpdateFrequency = -1;
-
-// Next scheduled update time; -1 if never.
-var feedUpdateTime = -1;
-</pre>
-
- <p>
-
- We know that we'll need to get some working values for the feed URL and feed update
- frequency variables and we know that they will be configurable values so let's write
- the code for this:
- </p>
-
-<pre>
-
-// Called from the onload event handler to initialize the widget.
-function init() {
- // load preferences
- loadPreferences();
-
- // start feed update timer (called once every second)
- updateTimerId = setInterval(updateFeedTimerFunc, 1000);
-}
-
-// Loads widget preferences.
-function loadPreferences() {
- if (window.widget) {
- // read feed URL and update frequency from the widget settings
- feedURL = widget.preferenceForKey("FeedURL");
- var feedUpdateFrequencyStr = widget.preferenceForKey("FeedUpdateFrequency");
- feedUpdateFrequency = (feedUpdateFrequencyStr == null) ? -1 : parseInt(feedUpdateFrequencyStr);
- }
-}
-
-// Timer function for feed updates - called once every second.
-function updateFeedTimerFunc() {
-
-}
-</pre>
-
- <p>
-
- The init() function does two things at this point. First it calls our newly created
- loadPreferences() function that takes care of reading some values for the feedURL
- and feedUpdateFrequency variables. After this it starts up an interval timer that
- calls updateFeedTimerFunc() once every second. The function doesn't do anything
- yet but we'll get to that in a bit. The timer identifier is stored in the updateTimerId
- variable. If no configuration is found, feedURL will have a value of null and
- feedUpdateFrequency will have a value of -1. Note that all preferences are stored
- as strings so we need to parse the string value to an integer. Also note that we
- wrapped the preference loading code in an if-clause that checks if we are in the
- S60 Web Runtime environment. This allows us to run the code in a PC browser without
- getting an error message about the widget -related methods that don't exist outside
- of the S60 Web Runtime.
- </p>
-
- <p>
-
- While we're on the topic of preferences we'll write a save counterpart for the
- loadPreferences() function.
- </p>
-
-<pre>
-
-// Saves widget preferences.
-function savePreferences() {
- if (window.widget) {
- // save settings in widget preferences store
- widget.setPreferenceForKey(feedURL, "FeedURL");
- widget.setPreferenceForKey(feedUpdateFrequency.toString(), "FeedUpdateFrequency");
- }
-}
-</pre>
-
- <p>
-
- We're now almost done with the timer mechanism that will update the RSS feed but
- we are missing one thing: a way to manually schedule an immediate update of the
- feeds. Let's add a flag that we can use to track if an update was triggered
- automatically or manually:
- </p>
-
-<pre>
-
-// Flag that tracks if a feed update is commanded or automatic.
-var feedUpdateCommanded = false;
-</pre>
-
- <p>
-
- And now let's add a function that can be called to schedule an immediate update:
- </p>
-
-<pre>
-
-// Schedules an immediate feed update.
-function updateFeed() {
- feedUpdateTime = 0;
- feedUpdateCommanded = true;
-}
-</pre>
-
- <p>
-
- The function just sets the next update time to 0 so that the next time the
- timer function runs it will notice that it's time to schedule a feed update.
- The function also sets the feedUpdateCommanded flag to true so that the
- updating mechanism will know that this was a manual update.
- </p>
-
- </div>
-
- <div class="section"><h2 class="sectiontitle">
-Creating the user interface</h2>
-
-
- <p>
-
- Now let's create the user interface. We'll start by declaring three variables
- where we will hold references to the user interface manager, main view and settings
- view. Note that these should be outside the init() function.
- </p>
-
-<pre>
-
-// References to the WRTKit user interface manager and views.
-var uiManager;
-var mainView;
-var settingsView;
-</pre>
-
- <p>
-
- We want our user interface to be in tab navigation mode and we want the softkey
- bar to be visible. The code for this is the same as in the Hello World example.
- Next we create the user interface manager, main view and settings view by adding
- the following code to the init() function:
- </p>
-
-<pre>
-
-if (window.widget) {
- // set tab-navigation mode and show softkeys
- widget.setNavigationEnabled(false);
- menu.showSoftkeys();
-}
-
-// create UI manager
-uiManager = new UIManager();
-
-// create main view
-mainView = new ListView();
-
-// create settings view
-settingsView = new ListView(null, "Settings");
-</pre>
-
- <p>
-
- You might have noticed that we didn't supply any arguments to the ListView constructor
- when the main view was created. The reason for this is that we will set the view caption
- dynamically depending on the news feed we are following. And since we don't need the
- unique identifier for the main view we don't even have to pass null to it. Remember: in
- JavaScript if you don't pass an argument it will be undefined, which is equal to null.
- </p>
-
- <p>
-
- The main view will not get populated with controls until we have some news feed items
- to display, but we can go ahead and create the settings view. Again, we will first
- declare variables to hold references to the controls and again, they should be declared
- outside the init() method so that they are accessible elsewhere in the widget code:
- </p>
-
-<pre>
-
-// Reference to settings controls.
-var feedSelection;
-var feedUpdateFrequencySelection;
-var settingsSaveButton;
-var settingsCancelButton;
-</pre>
-
- <p>
-
- Now that we have variables to receive the control references we can go ahead and create
- them and add them to the settings view. We will create a SelectionMenu control to let
- the user select the RSS feed to show, a SelectionList control to allow selection of
- the feed update frequency and two form buttons: "Save" and "Cancel". The SelectionMenu
- and SelectionList controls are identical from a developer's point of view but look
- very different. The SelectionMenu takes up very little space in the view but when clicked
- it pops up a list of options that the user can select from. This is good if theres a lot
- of options and we don't want to use up a lot of space from the view. The SelectionList
- is the exact opposite and shows all the options right there in the view. This is good
- if the widget is in pointer navigation mode or if there are very few options.
- </p>
-
- <p>
-
- Options for the SelectionMenu and SelectionList controls are defined as an array of
- JavaScript objects that have two properties: value and text. The value property contains
- the actual data of the option and the text property contains the string to display to
- the user. Before we create the controls we need to create the option arrays for the
- RSS feed options and update frequency options. These will simply be hard coded arrays
- that are defined using JavaScript object notation (JSON) and we'll place them at the top
- of the widget code so that they can be easily customized later on:
- </p>
-
-<pre>
-
-// Feed source options.
-var feedOptions = [
- { value: "http://www.womworld.com/nseries/feed/", text: "Nseries WOM World" },
- { value: "http://feeds.feedburner.com/N958GB", text: "N95 8GB News" },
- { value: "http://feeds.feedburner.com/N95", text: "N95 News" },
- { value: "http://feeds.feedburner.com/N93", text: "N93 News" },
- { value: "http://feeds.feedburner.com/N91", text: "N91 News" },
- { value: "http://feeds.feedburner.com/N82", text: "N82 News" },
- { value: "http://feeds.feedburner.com/N81", text: "N81 News" },
- { value: "http://feeds.feedburner.com/N810", text: "N810 News" },
- { value: "http://feeds.feedburner.com/N800", text: "N800 News" },
- { value: "http://feeds.feedburner.com/N76", text: "N76 News" }
-];
-
-// Feed update frequency.
-var updateFrequencyOptions = [
- { value: -1, text: "never" },
- { value: (1000 * 60 * 5), text: "every 5 min" },
- { value: (1000 * 60 * 15), text: "every 15 min" },
- { value: (1000 * 60 * 60), text: "every 60 min" },
-];
-</pre>
-
- <p>
-
- The RSS feeds are all from the Nokia Nseries WOM World website but you could put any
- RSS feed URLs here that you like. However it is probably a good idea to stick with
- these for now since we know that they work. Later when the widget is completed you can try
- with other feeds. Note how the value is a URL but the text to display is a human readable
- name for the RSS feeds.
- </p>
-
- <p>
-
- The update frequency options are defined in milliseconds and there is one option with a
- magic value of -1 for "never". Here too you'll notice the difference between the value
- (an integer in this case) and the human readable text.
- </p>
-
- <p>
-
- Now that we have the option arrays we can create the controls for the settings view by
- adding the following code to the init() function:
- </p>
-
-<pre>
-
- // feed selection control
- feedSelection = new SelectionMenu(null, "Select feed", feedOptions);
- settingsView.addControl(feedSelection);
-
- // feed update frequency selection control
- feedUpdateFrequencySelection = new SelectionList(null, "Check for updates", updateFrequencyOptions);
- settingsView.addControl(feedUpdateFrequencySelection);
-
- // save settings button
- settingsSaveButton = new FormButton(null, "Save");
- settingsView.addControl(settingsSaveButton);
-
- // cancel settings button
- settingsCancelButton = new FormButton(null, "Cancel");
- settingsView.addControl(settingsCancelButton);
-</pre>
-
- <p>
-
- The two first arguments for the SelectionMenu and SelectionList constructors are the
- same as for most other controls: a unique identifier and a control caption. The third
- argument points to the array of options that the controls should display. You could
- also have omitted that argument from the constructor and instead called setOptions()
- later on, but why do it in two steps when you can do it in one?
- </p>
-
- <p>
-
- The user interface views are now done (minus the actual news items to display in the main
- view of course) but we still have some things to implement for the user interface. The
- buttons in the settings view don't do anything yet so let's fix that.
- </p>
-
- <p>
-
- The cancel button should take the user to the main view and the save button should
- start using the newly configured settings, save them, and then go to the main view.
- Our plan to implement this is to create a function for showing the main view, called
- "showMainView()", a similar function for showing the settings view that we will call
- "showSettings()", and a function that will be called when the save button is clicked
- called "saveSettingsClicked()". We will then add event listeners to the two buttons
- so that clicking the save button will result in a call to the saveSettingsClicked()
- function and clicking the cancel button will result in a call to the showMainView()
- function. Let's create empty placeholders for the functions first:
- </p>
-
-<pre>
-
-// Callback for settings view save button.
-function saveSettingsClicked() {
-}
-
-// Show main view.
-function showMainView() {
-}
-
-// Show settings view.
-function showSettings() {
-}
-</pre>
-
- <p>
-
- Now that we have those functions let's register the event listeners to the form
- buttons by adding these two lines of code immediately after where the buttons
- are created:
- </p>
-
-<pre>
-
-settingsSaveButton.addEventListener("ActionPerformed", saveSettingsClicked);
-settingsCancelButton.addEventListener("ActionPerformed", showMainView);
-</pre>
-
- <p>
-
- We are now ready to implement the functions to show the main view, settings view
- and react to the save button click. But we won't implement those just yet because
- we want to do one more thing before that. Let's create the custom Options menu.
- The Options menu isn't using any WRTKit code but rather the standard S60 Web Runtime
- widget menu functionality. We'll have two menu items: "Refresh" to schedule an immediate
- news feed update and "Settings" to go to the settings view. The Web Runtime Options
- menu works so that a callback function gets called when the user selections an Options
- menu item. In order to recognize which menu item was selected we'll need a unique
- identifier for each of them. Let's create those:
- </p>
-
-<pre>
-
-// Constants for menu item identifiers.
-var MENU_ITEM_SETTINGS = 0;
-var MENU_ITEM_REFRESH = 1;
-</pre>
-
- <p>
-
- Next we'll create the callback function that will be called when the menu items are
- selected:
- </p>
-
-<pre>
-
-// Callback for when menu items are selected.
-function menuItemSelected(id) {
- switch (id) {
- case MENU_ITEM_SETTINGS:
- showSettings();
- break;
- case MENU_ITEM_REFRESH:
- updateFeed();
- break;
- }
-}
-</pre>
-
- <p>
-
- This function gets the menu item identifier passed to it when the user selects
- a menu item. The switch-case will branch off to call showSettings() if the "Settings"
- menu item was selected and updateFeed() if the "Refresh" menu item was selected.
- But we haven't actually created the menu yet so let's do that by adding this to the
- init() function right after where we show the softkey bar. We want to have this piece
- of code inside the if-clause that checks if we're in the S60 Web Runtime because we
- don't have the Options menu functionality on a PC browser.
- </p>
-
-<pre>
-
-// 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);
-</pre>
-
- <p>
-
- The code simply creates two MenuItem objects, gives them a label and a unique
- identifier, specifies the callback function to call when selected and then adds
- them to the Options menu. The menu object is a global object that automatically
- exists in the S60 Web Runtime.
- </p>
-
- <p>
-
- Now let's return to the three functions we created but didn't implement. We will
- start with the showMainMenu() function. This function should perform all necessary
- steps to show the main menu. This includes the following: setting a caption for
- the main view, setting the right softkey to be the default "Exit" label and
- functionality, and then actually showing the main view by calling setView() in the
- user interface manager. We'll get the main view caption by checking which of the
- RSS feeds the user has currently selected. We do this by looping through the feed
- options and looking for the feed URL that is currently in use. If we can't find one
- we'll default to "RSS Reader".
- </p>
-
-<pre>
-
-// Show main view.
-function showMainView() {
- // set main view caption from feed name
- var feedName = null;
- for (var i = 0; i < feedOptions.length; i++) {
- if (feedOptions[i].value == feedURL) {
- feedName = feedOptions[i].text;
- break;
- }
- }
- var mainViewCaption = (feedName == null) ? "RSS Reader" : feedName;
- mainView.setCaption(mainViewCaption);
-
- // set right softkey to "exit"
- if (window.widget) {
- menu.setRightSoftkeyLabel("", null);
- }
-
- // show the main view
- uiManager.setView(mainView);
-}
-</pre>
-
- <p>
-
- When the settings view is shown we first want to place the controls into
- a state that reflects the current configuration. In other words we want
- the currently configured feed to be the one that's selected in the feed selection
- control. In the same way the currently configured feed update frequency should
- be selected in the feed update frequency selection control. There is a very
- convenient method available for this called getOptionForValue(). Using that
- function we can pass the currently configured feed URL and feed update frequency
- and get back the options object that corresponds to the configuration value.
- After this we can use that options object when we call setSelected() to select
- that option.
- </p>
-
- <p>
-
- If there is no valid configuration then we disable the cancel button and make
- the right softkey be "Exit". This is useful when the widget is started for the
- first time so that user has to enter a valid configuration before starting to
- use the widget. If there is a valid configuration we set the right softkey to
- "Cancel" and make it call the showMainView() function that we just created. The
- "Cancel" button will also be enabled.
- </p>
-
- <p>
-
- Finally we'll switch to the settings view by calling setView() in the user
- interface manager.
- </p>
-
-<pre>
-
-// Show settings view.
-function showSettings() {
- // URL (use first available feed if null)
- var feedOption = (feedURL == null) ? feedOptions[0] : feedSelection.getOptionForValue(feedURL);
- feedSelection.setSelected(feedOption);
-
- // frequency
- var feedUpdateFrequencyOption = feedUpdateFrequencySelection.getOptionForValue(feedUpdateFrequency);
- feedUpdateFrequencySelection.setSelected(feedUpdateFrequencyOption);
-
- if (feedURL == null) {
- // no valid configuration
- // disable cancel button - set right softkey to "exit"
- settingsCancelButton.setEnabled(false);
- if (window.widget) {
- menu.setRightSoftkeyLabel("", null);
- }
- } else {
- // we have a valid configuration
- // enable cancel button - set right softkey to "cancel"
- settingsCancelButton.setEnabled(true);
- if (window.widget) {
- menu.setRightSoftkeyLabel("Cancel", showMainView);
- }
- }
-
- // show the settings view
- uiManager.setView(settingsView);
-}
-</pre>
-
- <p>
-
- The third function to implement is the callback for when the save button is clicked.
- First we take the selected options from the feed selection and feed update frequency
- selection controls. Those selected values are copied to the feedURL and feedUpdateFrequency
- variables that are used by the widget during runtime. Next the settings are saved using
- the savePreferences() function that we implemented earlier. And finally we call the
- showMainView() method so that the widget shows the main view with the news items.
- </p>
-
-<pre>
-
-// Callback for settings view save button.
-function saveSettingsClicked() {
- // update feed URL
- var selectedFeed = feedSelection.getSelected();
- feedURL = (selectedFeed != null) ? selectedFeed.value : null;
-
- // update frequency
- var selectedFrequency = feedUpdateFrequencySelection.getSelected();
- feedUpdateFrequency = (selectedFrequency != null) ? selectedFrequency.value : -1;
-
- // save preferences
- savePreferences();
-
- // return to main view
- showMainView();
-}
-</pre>
-
- <p>
-
- The user interface is now nearly done but the init() function needs one more
- thing. We need to show a view after the function is done initializing
- the widget. The view to show depeneds on whether we have a valid
- configuration or not. If we do then we'll show the main view. If not then
- we'll show the settings view. Let's add this code to the end of the init()
- function, just before we start the update timer:
- </p>
-
-<pre>
-
-// display the main view if a feed has been configured
-// otherwise show the settings view
-if (feedURL != null) {
- showMainView();
- updateFeed();
-} else {
- showSettings();
-}
-</pre>
-
- <p>
-
- You can now go ahead and try out the widget either on a handset, emulator
- or in a PC browser. You should have a working settings view and when clicking
- the save button in the settings view you should end up in the main view. From
- there you can go to the settings by selecting "Settings" in the Options menu.
- </p>
-
- <p>
-
- There are no news items to show yet but that's our next task.
- </p>
-
- <div class="fignone" id="GUID-1083A0C4-A953-4B6E-A4D0-45A031E51C35__GUID-31A7B99C-BD6B-42E2-8430-631D210FAFC0"><a name="GUID-1083A0C4-A953-4B6E-A4D0-45A031E51C35__GUID-31A7B99C-BD6B-42E2-8430-631D210FAFC0"><!-- --></a><span class="figcap">Figure 1.
-RSS Reader settings view</span>
-
-
- <br /><img src="RSS_Reader_Settings_Screenshot_1.png" /><br />
- </div>
-
- </div>
-
- </div>
-
-<div>
-<div class="familylinks">
-<div class="parentlink"><strong>Parent topic:</strong> <a href="WRTKit_RSS_Reader_Tutorial-GUID-678d197f-c7b0-4e5e-85e2-f8549c75bbe8.html">RSS Reader</a></div>
-</div>
-</div>
-
-</body>
-</html>
\ No newline at end of file