Earlier today I noticed an entry on the PhoneGap forums from a user asking about an RSS reader. I thought I'd whip one up using PhoneGap and jQuery Mobile and see what it took. Here's what I came up, and as always, feel free to rip apart the code and write it better. I'll warn folks that I only wrote the code to support RSS2, not ATOM, but in theory, it should be possible without too much additional work. (You would simply look at the metadata, note it, and change how you get data.)

I began by creating a new PhoneGap project. I strongly recommend reading my entry from earlier today about the nice Eclipse PhoneGap plugin to make it quicker to setup your projects. I began by adding code to handle getting the RSS code. First, I setup two simple variables people could tweak:

//EDIT THESE LINES //Title of the blog var TITLE = "ColdFusion Jedi"; //RSS url var RSS = "http://feedproxy.google.com/RaymondCamdensColdfusionBlog";

My code listens for my initial page to load. When this happens, I want to get the XML from the feed and work with it. Here's that snippet.

$.get(RSS, {}, function(res, code) { var xml = $(res); var items = xml.find("item"); $.each(items, function(i, v) { entry = { title:$(v).find("title").text(), link:$(v).find("link").text(), description:$.trim($(v).find("description").text()) }; entries.push(entry); });

As a reminder, AJAX code in PhoneGap applications are not restricted by normal remote domain rules. I can easily open up the remote XML and parse it. Where did entries come from? Well this is where things get slightly complex. I'm going to store the parsed RSS in a global array called entries (hence the push to add things to the end). This will allow me to dynamically display the pages. But first, let's render out the list. My home page already has a blank list just for this purpose:

<div data-role="content"> <ul id="linksList" data-role="listview" data-inset="true"></ul> </div>

So my handler can simply append to it....

//now draw the list var s = ''; $.each(entries, function(i, v) { s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>'; }); $("#linksList").append(s); $("#linksList").listview("refresh");

Note two things here. First, every single link will be going to a new jQuery Mobile page, contentPage. But I store the ID of the item in a data attribute. Also note the use listview("refresh"). This tells jQuery Mobile to add unicorn magic prettiness to HTML I've added in the list. Serious - Unicorn Magic Prettiness is the official term.

Ok, so what's going on with the content page? I created it as a blank page, like so:

<div data-role="page" id="contentPage">

<div data-role="header"> <a href="#mainPage" data-rel="back">Home</a> <h1></h1> </div>

<div data-role="content" id="entryText"> </div>

</div>

And I've got a JavaScript click handler that notices the clicks and populates the data. First, the event listener for the link:

//listen for detail links $(".contentLink").live("click", function() { selectedEntry = $(this).data("entryid"); });

And then the page displayer...

//Listen for the content page to load $("#contentPage").live("pageshow", function(prepage) { //Set the title $("h1", this).text(entries[selectedEntry].title); var contentHTML = ""; contentHTML += entries[selectedEntry].description; contentHTML += '<p/><a href="'+entries[selectedEntry].link + '">Read Entry on Site</a>'; $("#entryText",this).html(contentHTML); });

Pretty simple, right? (I should point out jQuery Mobile does support completely virtualized pages too. ) Here's a quick screen shot...

And another one...

And finally, the complete code. If anyone wants the actual APK for this, just ask. The home page first:

<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title></title> <link rel="stylesheet" href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" /> <script src="http://code.jquery.com/jquery-1.6.2.min.js"></script> <script src="main.js"></script> <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script> </head> <body>

<div data-role="page" id="mainPage">

<div data-role="header"> <h1></h1> </div>

<div data-role="content"> <ul id="linksList" data-role="listview" data-inset="true"></ul> </div>

<div data-role="footer"> <h4>SimpleBlog by Raymond Camden</h4> </div>

</div>

<div data-role="page" id="contentPage">

<div data-role="header"> <a href="#mainPage" data-rel="back">Home</a> <h1></h1> </div>

<div data-role="content" id="entryText"> </div>

</div>

</body> </html>

And the main.js file:

$(document).ready(function() {

//EDIT THESE LINES //Title of the blog var TITLE = "ColdFusion Jedi"; //RSS url var RSS = "http://feedproxy.google.com/RaymondCamdensColdfusionBlog"; //Stores entries var entries = []; var selectedEntry = "";

//listen for detail links $(".contentLink").live("click", function() { selectedEntry = $(this).data("entryid"); });

//Listen for main page $("#mainPage").live("pageinit", function() {

//Set the title $("h1", this).text(TITLE);

$.get(RSS, {}, function(res, code) { var xml = $(res); var items = xml.find("item"); $.each(items, function(i, v) { entry = { title:$(v).find("title").text(), link:$(v).find("link").text(), description:$.trim($(v).find("description").text()) }; entries.push(entry); });

//now draw the list var s = ''; $.each(entries, function(i, v) { s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>'; }); $("#linksList").append(s); $("#linksList").listview("refresh"); });

});

//Listen for the content page to load $("#contentPage").live("pageshow", function(prepage) { //Set the title $("h1", this).text(entries[selectedEntry].title); var contentHTML = ""; contentHTML += entries[selectedEntry].description; contentHTML += '<p/><a href="'+entries[selectedEntry].link + '">Read Entry on Site</a>'; $("#entryText",this).html(contentHTML); });

});