org.symbian.tools.wrttools.doc.WRTKit/html/WRTKit_Feed_updates-GUID-25cd0e54-0516-4469-965e-c5781cf44dc9.html
changeset 230 7848c135d915
equal deleted inserted replaced
229:716254ccbcc0 230:7848c135d915
       
     1 <?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">
       
     2 <html lang="en" xml:lang="en">
       
     3 <head>
       
     4 <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
       
     5 <meta name="copyright" content="(C) Copyright 2005" />
       
     6 <meta name="DC.rights.owner" content="(C) Copyright 2005" />
       
     7 <meta content="concept" name="DC.Type" />
       
     8 <meta name="DC.Title" content="Feed updates" />
       
     9 <meta scheme="URI" name="DC.Relation" content="WRTKit_RSS_Reader_Tutorial-GUID-678d197f-c7b0-4e5e-85e2-f8549c75bbe8.html" />
       
    10 <meta content="XHTML" name="DC.Format" />
       
    11 <meta content="GUID-25CD0E54-0516-4469-965E-C5781CF44DC9" name="DC.Identifier" />
       
    12 <meta content="en" name="DC.Language" />
       
    13 <link href="commonltr.css" type="text/css" rel="stylesheet" />
       
    14 <title>
       
    15 Feed updates</title>
       
    16 </head>
       
    17 <body id="GUID-25CD0E54-0516-4469-965E-C5781CF44DC9"><a name="GUID-25CD0E54-0516-4469-965E-C5781CF44DC9"><!-- --></a>
       
    18 
       
    19 
       
    20 
       
    21     <h1 class="topictitle1">
       
    22 Feed updates</h1>
       
    23 
       
    24     <div>
       
    25 
       
    26         <div class="section"><h2 class="sectiontitle">
       
    27 Fetching news items</h2>
       
    28 
       
    29             
       
    30             <p>
       
    31 
       
    32                 Before we can show any news items we have to fetch them. So let's take
       
    33                 a break in implementing the user interface and write the code that fetches
       
    34                 the news items. The majority of that code is in the FeedUpdateBroker.js file
       
    35                 in a JavaScript class called FeedUpdateBroker. We'll only be using one single
       
    36                 method from that class: fetchFeed(). But how do we hook that up to our widget?
       
    37             </p>
       
    38 
       
    39             <p>
       
    40 
       
    41                 The actual call to fetchFeed() will be done from the timer function updateFeedTimerFunc()
       
    42                 that runs once a second. There we'll need an if-clause that checks if it's time
       
    43                 to update the feeds, if another update is already going on, if we have a valid URL
       
    44                 that we can fetch and if we're in the main view. If all of these tests tell us
       
    45                 that it's time to update the feed, we'll check if the feed update was manually
       
    46                 commanded or automatically triggered because it was time to update the feed in
       
    47                 the background. If this is a manual update then we'll popup a progress notification 
       
    48                 dialog. Next we'll create a new instance of the FeedUpdateBroker class and call
       
    49                 the fetchFeed() method to start the AJAX-based RSS feed update. We need to pass
       
    50                 two arguments to this method: the feed URL that we have in the feedURL variable
       
    51                 and a callback function that should be called when the update is completed.
       
    52             </p>
       
    53 
       
    54             <p>
       
    55 
       
    56                 We don't have that function yet so that's the first thing we need to implement.
       
    57                 We'll leave it empty for now but return to it in a bit:
       
    58             </p>
       
    59 
       
    60 <pre>
       
    61 
       
    62 // Callback function that gets called when a feed update has completed.
       
    63 function feedUpdateCompleted(event) {
       
    64 }
       
    65 </pre>
       
    66 
       
    67             <p>
       
    68 
       
    69                 After we call the fetchFeed() function we'll schedule the next feed update. In
       
    70                 theory we shouldn't do this until the feed update completes since there is a risk
       
    71                 that we do two updates at the same time. But because we're adding a check to
       
    72                 only do feed updates if another update isn't on-going this risk isn't actually
       
    73                 real. Now that we have a plan for how to update the feed, let's write the code.
       
    74                 First we need to declare a variable for the feed update broker instance that
       
    75                 we'll create:
       
    76             </p>
       
    77 
       
    78 <pre>
       
    79 
       
    80 // Feed update broker.
       
    81 var feedUpdateBroker = null;
       
    82 </pre>
       
    83 
       
    84             <p>
       
    85 
       
    86                 Then the actual implementation for the updateFeedTimerFunc() timer function:
       
    87             </p>
       
    88 
       
    89 <pre>
       
    90 
       
    91 // Timer function for feed updates - called once every second.
       
    92 function updateFeedTimerFunc() {
       
    93     var now = new Date().getTime();
       
    94     
       
    95     // check if a feed update has been scheduled, if it's time to update now,
       
    96     // and if there's no update currently in progress and if we're in the main view
       
    97     if ((feedURL != null) &amp;&amp;
       
    98                 (feedUpdateTime != -1) &amp;&amp;
       
    99                 (now &gt; feedUpdateTime) &amp;&amp;
       
   100                 (feedUpdateBroker == null) &amp;&amp; 
       
   101                 (uiManager.getView() == mainView)) {
       
   102         // show progress dialog if this is a commanded feed update
       
   103         if (feedUpdateCommanded) {
       
   104             // no auto hiding, wait-type notification, unknown progress
       
   105             uiManager.showNotification(-1, "wait", "Loading feed...", -1);
       
   106         }
       
   107         
       
   108         // fetch the feed from the specified URL
       
   109         feedUpdateBroker = new FeedUpdateBroker();
       
   110         feedUpdateBroker.fetchFeed(feedURL, feedUpdateCompleted);
       
   111         
       
   112         if (feedUpdateFrequency != -1) {
       
   113             // schedule next update
       
   114             feedUpdateTime = now + feedUpdateFrequency;
       
   115         } else {
       
   116             // feed update frequency is "never"
       
   117             feedUpdateTime = -1;
       
   118         }
       
   119     }
       
   120 }
       
   121 </pre>
       
   122 
       
   123             <p>
       
   124 
       
   125                 The progress dialog is created so that it has a display time of -1 so that
       
   126                 it doesn't automatically hide but rather has to be commanded to go away. The
       
   127                 notification dialog type is "wait" and we'll give a progress of -1 since we
       
   128                 don't know how far along in the feed updating process we are. A negative 
       
   129                 progress value like -1 means "unknown progress" and will result in an animated
       
   130                 progress indicator that shows that something is going on but the exact time
       
   131                 that it will take is unknown.
       
   132             </p>
       
   133 
       
   134             <p>
       
   135 
       
   136                 Our feed updating should now be working and whenever a feed update is completed
       
   137                 there should be a call to the empty feedUpdateCompleted() function. Let's 
       
   138                 continue the implementation there.
       
   139             </p>
       
   140 
       
   141             <p>
       
   142 
       
   143                 When the feedUpdateCompleted() function is called it receives an event object
       
   144                 from the FeedUpdateBroker. This object contains a status that is either "ok"
       
   145                 or "error", a "lastModifiedTime" string that contains the time when the RSS
       
   146                 feed was last modified to help us decide if there are any new news items to
       
   147                 display, as well as an array of news item objects in a property called "items".
       
   148                 If the status is "error" then we'll show an error notification dialog. Keep in
       
   149                 mind that there might or might not be a progress dialog already showing at this
       
   150                 time. Either way we can just call the showNotification() function in the user
       
   151                 interface manager because if another dialog is already visible then it will simply
       
   152                 replace it with the one that we asked it to show. If the status is "ok" then we'll
       
   153                 call hideNotification() in the user interface manager. This will hide the progress
       
   154                 dialog if it's showing and if the dialog wasn't showing then the call will just
       
   155                 be ignored.
       
   156             </p>
       
   157 
       
   158             <p>
       
   159 
       
   160                 We'll then need to compare the lastModifiedTime against the last news feed that
       
   161                 we have. That means we'll need to track the lastModifiedTime of whatever news
       
   162                 feed that we are showing, and that means we need a new global variable:
       
   163             </p>
       
   164 
       
   165 <pre>
       
   166 
       
   167 // Time when the feed was last modified.
       
   168 var feedLastModified = null;
       
   169 </pre>
       
   170 
       
   171             <p>
       
   172 
       
   173                 If the lastModifiedTime is different from the one that we are storing in the
       
   174                 feedLastModified variable then we know that there's new news items to show.
       
   175                 If this is the case then we'll update the feedLastModified time and set the news
       
   176                 items to the main view. We could do something fancy and only update the news items
       
   177                 that have been modified but to keep the tutorial simple we'll just simply remove
       
   178                 all the current items and replace them with the new items and then focus the first
       
   179                 of the items. But before we move on to that we'll write as much as we can of the
       
   180                 feedUpdateCompleted() function:
       
   181             </p>
       
   182 
       
   183 <pre>
       
   184 
       
   185 // Callback function that gets called when a feed update has completed.
       
   186 function feedUpdateCompleted(event) {
       
   187     if (event.status == "ok") {
       
   188         // if there aren't any feed items yet, we'll hide the progress dialog
       
   189         if (feedUpdateCommanded) {
       
   190             uiManager.hideNotification();
       
   191         }
       
   192         
       
   193         // check if the feed has updated
       
   194         if (event.lastModified != feedLastModified) {
       
   195             // remember the last modified timestamp
       
   196             feedLastModified = event.lastModified;
       
   197             
       
   198             // update news item controls here
       
   199         }
       
   200     } else {
       
   201         // show error message
       
   202         uiManager.showNotification(3000, "warning", "Error while updating feed!&lt;br/&gt;(check network settings)");
       
   203     }
       
   204     
       
   205     // null the broker reference to indicate that there's no current
       
   206     // update in progress
       
   207     feedUpdateBroker = null;
       
   208         
       
   209     // reset commanded feed update flag
       
   210     feedUpdateCommanded = false;
       
   211 }
       
   212 </pre>
       
   213 
       
   214             <p>
       
   215 
       
   216                 We wrote a comment "update news item controls here" at the spot where we will
       
   217                 actually create and add news feed items to the main view. We'll replace that in
       
   218                 a bit with the actual code to do the job, but first we need to write some code
       
   219                 that we'll need to do that.
       
   220             </p>
       
   221 
       
   222         </div>
       
   223 
       
   224         <div class="section"><h2 class="sectiontitle">
       
   225 Showing news items</h2>
       
   226 
       
   227             
       
   228             <p>
       
   229 
       
   230                 The news feed items will be shown using ContentPanel controls. We'll need a way
       
   231                 to keep track of the ones we're showing so that we can easily remove them when
       
   232                 there is new news items to show. Let's create an array to track them:
       
   233             </p>
       
   234 
       
   235 <pre>
       
   236 
       
   237 // Reference to current feed items controls.
       
   238 var feedItemControls = [];
       
   239 </pre>
       
   240 
       
   241             <p>
       
   242 
       
   243                 Now we can implement a function that will remove all controls that are tracked
       
   244                 by this array from the main view. We'll use this as the first step when we want
       
   245                 to display news items.
       
   246             </p>
       
   247 
       
   248 <pre>
       
   249 
       
   250 // Removes feed items.
       
   251 function removeFeedItems() {
       
   252     // remove all current feed items from the main view
       
   253     for (var i = 0; i &lt; feedItemControls.length; i++) {
       
   254         mainView.removeControl(feedItemControls[i]);
       
   255     }
       
   256     
       
   257     // reset feed item control array
       
   258     feedItemControls = [];
       
   259 }
       
   260 </pre>
       
   261 
       
   262             <p>
       
   263 
       
   264                 The function simply loops through the array and calls the removeControl() method
       
   265                 in the main view to remove each of the feed item controls from the view, one at a time.
       
   266                 Finally we'll reset the feedItemControls array so that it reflects the fact that
       
   267                 there are no more controls in the main view.
       
   268             </p>
       
   269 
       
   270             <p>
       
   271 
       
   272                 What about adding news items? We'll do that in a function that we'll call from the
       
   273                 feedUpdateCompleted() function. Let's call the function setFeedItems(). The function
       
   274                 will start by calling the removeFeedItems() function we just created to empty the 
       
   275                 main view from news items before we start adding new ones to it. After this we'll
       
   276                 loop through the news feed items that were handed to us from the FeedUpdateBroker.
       
   277                 For each one we need a ContentPanel control. We'll be recycling the controls instead
       
   278                 of constantly creating new ones over and over again as new news items come in. To
       
   279                 this end we'll need a way to track ContentPanel controls that we have already
       
   280                 created. We'll do this by creating an array called feedItemControlPool, which will
       
   281                 be a global variable:
       
   282             </p>
       
   283 
       
   284 <pre>
       
   285 
       
   286 // Feed item control pool.
       
   287 var feedItemControlPool = [];
       
   288 </pre>
       
   289 
       
   290             <p>
       
   291 
       
   292                 If we have enough controls in the pool we'll just take them from there. Otherwise
       
   293                 we'll create a new ContentPanel and add it to the pool. Either way we'll end up with
       
   294                 a ContentPanel control that is ready to be used. We'll need to reset its state since we
       
   295                 recycled it, so we make sure it's collapsed rather than expanded, we'll set its caption
       
   296                 to the title of the news item and we'll generate some HTML from the news item summary
       
   297                 that we'll set as the content for the ContentPanel. And then finally we'll add the
       
   298                 ContentPanel to the main view.
       
   299             </p>
       
   300 
       
   301             <p>
       
   302 
       
   303                 Lets create the code but skip the HTML for the news item summary for now:
       
   304             </p>
       
   305 
       
   306 <pre>
       
   307 
       
   308 // Sets feed items.
       
   309 function setFeedItems(items) {
       
   310     // start by removing all current feed items
       
   311     removeFeedItems();
       
   312     
       
   313     // create new feed items and add them to the main view
       
   314     // use feed item pool to recycle controls
       
   315     for (var i = 0; i &lt; items.length; i++) {
       
   316         // get a feed item control from the pool or create one and
       
   317         // place it in the pool if there aren't enough feed item controls
       
   318         var feedItemControl;
       
   319         if (i == feedItemControlPool.length) {
       
   320             feedItemControl = new ContentPanel(null, null, null, true);
       
   321             feedItemControlPool.push(feedItemControl);
       
   322         } else {
       
   323             feedItemControl = feedItemControlPool[i];
       
   324         }
       
   325         
       
   326         // initialize feed item control
       
   327         var item = items[i];
       
   328         feedItemControl.setCaption(item.title);
       
   329         feedItemControl.setContent("placeholder");
       
   330         feedItemControl.setExpanded(false);
       
   331         
       
   332         // add the feed item control to the main view
       
   333         feedItemControls.push(feedItemControl);
       
   334         mainView.addControl(feedItemControl);
       
   335     }
       
   336 }
       
   337 </pre>
       
   338 
       
   339             <p>
       
   340 
       
   341                 The items argument contains the array of news items that we received in the event
       
   342                 object argument to the feedUpdateCompleted() callback function. The items are in
       
   343                 the "items" property of the event object. Note how the feedItemControl is either
       
   344                 created or taken from the feedItemControlPool. If it's created it is given four
       
   345                 arguments: a null unique identifier because we don't need one, a null caption and
       
   346                 a null content because we will set both every time before we show it, and finally
       
   347                 a value of true to the "foldable" argument in the ContentPanel constructor. This
       
   348                 flag determines whether the ContentPanel can be folded (expanded and collapsed) or
       
   349                 not. We want a foldable one so we pass true to this argument.
       
   350             </p>
       
   351 
       
   352             <p>
       
   353 
       
   354                 Once we have the ContentPanel (either from the pool or newly created) we set its
       
   355                 state: caption, content and expanded state. Note that for now we'll just set a
       
   356                 placeholder string as the content. Also note that we set the expanded state to false
       
   357                 to collapse the news items by default. Finally we add the content panels to the main
       
   358                 view and to the feedItemControls array that tracks all the ContentPanels that we use
       
   359                 for the news items.
       
   360             </p>
       
   361 
       
   362             <p>
       
   363 
       
   364                 Now that we have written the code to create and add news items to the main view
       
   365                 we have to hook that up to the feedUpdateCompleted() function. Remember we added
       
   366                 a comment in the spot where we should return to do this? Let's replace that comment
       
   367                 with the following:
       
   368             </p>
       
   369 
       
   370 <pre>
       
   371 
       
   372 // set feed items to the main view
       
   373 setFeedItems(event.items);
       
   374 
       
   375 // focus the first feed item control
       
   376 // (but only if we are in the main view)
       
   377 if (uiManager.getView() == mainView &amp;&amp; feedItemControls.length &gt; 0) {
       
   378     feedItemControls[0].setFocused(true);
       
   379 }
       
   380 </pre>
       
   381 
       
   382             <p>
       
   383 
       
   384                 We just call the setFeedItems() function we just wrote, passing it the feed items
       
   385                 that the FeedUpdateBroker fetched and parsed for us, and then if we're in the main
       
   386                 view we'll focus the first of the news feed item controls.
       
   387             </p>
       
   388 
       
   389             <p>
       
   390 
       
   391                 Now that we have all the code needed to fetch and update news feed items we'll go
       
   392                 back and add some more functionality to a function we wrote a little bit earlier:
       
   393                 the saveSettingsClicked() function.
       
   394             </p>
       
   395 
       
   396             <p>
       
   397 
       
   398                 The functionality that we're adding will handle updates of the feed items in the
       
   399                 main view after the user has modified the settings. We didn't write this earlier
       
   400                 because we didn't have all the necessary support code in place but we can add it now.
       
   401                 First we add some code to the end of the saveSettingsClicked() function to force an
       
   402                 update of the news items after the users saves the settings:
       
   403             </p>
       
   404 
       
   405 <pre>
       
   406 
       
   407 // update the feed
       
   408 feedLastModified = null;
       
   409 updateFeed();
       
   410 </pre>
       
   411 
       
   412             <p>
       
   413 
       
   414                 We update the feed by setting the feedLastModified variable to null to force an update
       
   415                 and then calling updateFeed(). This causes an immediate feed update and we also get the
       
   416                 progress notification dialog, which is what we want because this was a manual
       
   417                 update that was caused by the user clicking "save".
       
   418             </p>
       
   419 
       
   420             <p>
       
   421 
       
   422                 Let's also add some code that checks if a new feed was selected and removes all the
       
   423                 news items from the main view if the user selected a new feed. To do this we'll first
       
   424                 copy the old feedURL to a variable that we'll call oldFeedURL at the very beginning
       
   425                 of the function:
       
   426             </p>
       
   427 
       
   428 <pre>
       
   429 
       
   430 // remember the old feed URL
       
   431 var oldFeedURL = feedURL;
       
   432 </pre>
       
   433 
       
   434             <p>
       
   435 
       
   436                 Then we'll add the following just before we show the main view:
       
   437             </p>
       
   438 
       
   439 <pre>
       
   440 
       
   441 // remove all feed items if the user selected a new feed
       
   442 if (feedURL != oldFeedURL) {
       
   443     removeFeedItems();
       
   444 }
       
   445 </pre>
       
   446 
       
   447             <p>
       
   448 
       
   449                 We can now test this in a PC browser, handset or emulator. Everything should work
       
   450                 except that there's still nothing but a placeholder for the actual content in each
       
   451                 ContentPanel. You can still expand and collapse the ContentPanels and the settings
       
   452                 and automatic and manual updates are working. We're almost done but we still need
       
   453                 to implement the code that will actually show news item summaries in the content
       
   454                 panels.
       
   455             </p>
       
   456 
       
   457             <p>
       
   458 
       
   459                 Remember we said that we would implement news items so that there's a link from
       
   460                 each news item to the website where the full article is. When you open links
       
   461                 to external websites in the S60 Web Runtime you should use the widget.openURL()
       
   462                 function. But PC browsers don't have that function so we'll need to create a wrapper
       
   463                 function that either calls widget.openURL() if we're in the Web Runtime or just
       
   464                 opens a new window if we're in a PC browser.
       
   465             </p>
       
   466 
       
   467 <pre>
       
   468 
       
   469 // Opens a URL.
       
   470 function openURL(url) {
       
   471     if (window.widget) {
       
   472         // in WRT
       
   473         widget.openURL(url);
       
   474     } else {
       
   475         // outside WRT
       
   476         window.open(url, "NewWindow");
       
   477     }
       
   478 }
       
   479 </pre>
       
   480 
       
   481             <p>
       
   482 
       
   483                 Content in a ContentPanel control is a fragment of HTML. In other words it's a
       
   484                 piece of HTML that will be inserted into the control using code. That means that
       
   485                 in order to display the news item we will have to generate some HTML for it.
       
   486                 We need a function that will take a news item object and return some HTML that
       
   487                 we can give to thet setContent() method in the ContentPanel control. Let's write
       
   488                 that function:
       
   489             </p>
       
   490 
       
   491 <pre>
       
   492 
       
   493 // Returns the content HTML for a feed item.
       
   494 function getContentHTMLForFeedItem(item) {
       
   495     var buf = "";
       
   496     
       
   497     // item date
       
   498     if (item.date != null) {
       
   499         buf += "&lt;div class=\"FeedItemDate\"&gt;" + item.date + "&lt;/div&gt;";
       
   500     }
       
   501     
       
   502     // item description
       
   503     if (item.description != null) {
       
   504         buf += "&lt;div class=\"FeedItemDescription\"&gt;" + item.description + "&lt;/div&gt;";
       
   505     }
       
   506     
       
   507     // item URL
       
   508     if (item.url != null) {
       
   509         buf += "&lt;div class=\"FeedItemLink\"&gt;";
       
   510             buf += "&lt;a href=\"JavaScript:openURL('" + item.url + "');\"&gt;";
       
   511             buf += "Read more...";
       
   512             buf += "&lt;/a&gt;";
       
   513         buf += "&lt;/div&gt;";
       
   514     }
       
   515     
       
   516     return buf;
       
   517 }
       
   518 </pre>
       
   519 
       
   520             <p>
       
   521 
       
   522                 The function uses the properties in the news item object that the FeedUpdateBroker
       
   523                 created for us. There's a date property that has the publish date of the news item.
       
   524                 There's a description that contains the actual summary, and there's a URL that points
       
   525                 to the website where the full article is. Note that we're using the openURL() wrapper
       
   526                 function that we just wrote for the link to the full article.
       
   527             </p>
       
   528 
       
   529             <p>
       
   530 
       
   531                 Our HTML is very simple: three div-tags that have the date, description and a link as
       
   532                 their content. And ech of them has a CSS class so that we can match them with some
       
   533                 style rules. Since we have three different pieces of data we need three CSS rules:
       
   534                 FeedItemDate for the date, FeedItemDescription for the news item summary and finally
       
   535                 FeedItemLink for the link to the website. Let's create these in the RSSReader.css
       
   536                 stylesheet file:
       
   537             </p>
       
   538 
       
   539 <pre>
       
   540 
       
   541 
       
   542 /* Feed item date */
       
   543 .FeedItemDate {
       
   544     font-style: italic;
       
   545 }
       
   546 
       
   547 /* Feed item text */
       
   548 .FeedItemDescription {
       
   549     padding: 4px 0px;
       
   550 }
       
   551 
       
   552 /* Feed item links */
       
   553 .FeedItemLink {
       
   554     
       
   555 }
       
   556 
       
   557 /* Anchor tags in the context of a feed item link */
       
   558 .FeedItemLink a {
       
   559     text-decoration: underline;
       
   560     font-weight: bold;
       
   561     color: rgb(0,0,255);
       
   562 }
       
   563 
       
   564 /* Focused anchor tags */
       
   565 .FeedItemLink a:focus {
       
   566     background: rgb(0,0,255);
       
   567     color: rgb(255,255,255);
       
   568 }
       
   569 </pre>
       
   570 
       
   571             <p>
       
   572 
       
   573                 The rule for links can be left empty because we will just use default ContentPanel
       
   574                 content styling. However we'll change the way the link looks in the context of that
       
   575                 FeedItemLink div. We'll make links blue, bold and underlined in their normal state
       
   576                 and inverse with a blue background and white text color when focused.
       
   577             </p>
       
   578 
       
   579             <p>
       
   580 
       
   581                 Now that we have a function that generates HTML for the ContentPanel we can remove
       
   582                 the placeholder content replace it with a call to our function:
       
   583             </p>
       
   584 
       
   585 <pre>
       
   586 
       
   587 feedItemControl.setContent(getContentHTMLForFeedItem(item));
       
   588 </pre>
       
   589 
       
   590             <p>
       
   591 
       
   592                 We're done! Now you can try the widget in a PC browser and then on the handset
       
   593                 or emulator.
       
   594             </p>
       
   595 
       
   596             <div class="fignone" id="GUID-25CD0E54-0516-4469-965E-C5781CF44DC9__GUID-F7A5DBAA-7F9F-4C48-A25A-0DACE463CBF4"><a name="GUID-25CD0E54-0516-4469-965E-C5781CF44DC9__GUID-F7A5DBAA-7F9F-4C48-A25A-0DACE463CBF4"><!-- --></a><span class="figcap">Figure 1. 
       
   597 RSS Reader main view</span>
       
   598 
       
   599                 
       
   600                 <br /><img src="RSS_Reader_Main_Screenshot_1.png" /><br />
       
   601             </div>
       
   602 
       
   603         </div>
       
   604 
       
   605         <div class="section"><h2 class="sectiontitle">
       
   606 What we have learned</h2>
       
   607 
       
   608             
       
   609             <p>
       
   610 
       
   611                 The RSS Reader tutorial has taught us several things. We have learned to create a widget
       
   612                 that has more than just one view. We have learned how to use several new WRTKit controls.
       
   613                 We used the SelectionList, SelectionMenu and FormButton controls in our settings view, 
       
   614                 and in the main view we used the ContentPanel control that allowed us to add our own
       
   615                 content as a seamless part of the rest of the user interface using HTML fragments that
       
   616                 we styled with CSS rules. We have learned to modify a view while the widget runs by adding
       
   617                 and removing controls. And we have learned how to separate our widget code so that the
       
   618                 user interface code doesn't contain any logic code and so that the logic code doesn't
       
   619                 contain any user interface code.
       
   620             </p>
       
   621 
       
   622         </div>
       
   623 
       
   624     </div>
       
   625 
       
   626 <div>
       
   627 <div class="familylinks">
       
   628 <div class="parentlink"><strong>Parent topic:</strong> <a href="WRTKit_RSS_Reader_Tutorial-GUID-678d197f-c7b0-4e5e-85e2-f8549c75bbe8.html">RSS Reader</a></div>
       
   629 </div>
       
   630 </div>
       
   631 
       
   632 </body>
       
   633 </html>