Subscribe

Friday 26 February 2010

How To Create Widgets Part3 RSS Feed



Hi there everybody, today's topic has been written about quite extensively and yet I have taken it up because of the way Yahoo Konfabulator handles it. Say for instance you have a favourite site maybe news or blog and while working on your desktop you would like to get the updates from this site quickly without having to install any third party software or toolbars etc.
With widgets this job becomes quite easy. First I will go into a bit of theory and then dive into the real coding part.


XMLHTTPRequest

To begin with we all know what can be done with this object called XMLHTTPRequest, unfortunately though, due to severe restrictions on cross domain request originating from the client side, it is impossible to have a standalone javascript. This object has to be used in conjunction to PHP or ASP.net sort of scripts.
Say I dont know PHP yet I want to have my news on my desktop.....?
Yahoo provides an object similar to the original XMLHTTPRequest but it is a standalone you do not require to understand or know the working of any server side script, Yahoo will take care of all that and more.
Lets see what Yahoo reference says about this object

"The  XMLHttpRequest  object is very much like the  URL  object that has existed in the Widget Engine since very early on.  XMLHttpRequest  is, however, a de facto standard for doing XML over HTTP in web browsers, so its addition here is to provide people with an easier migration path when moving AJAX code over to the Widget Engine, as well as simply trying to adhere to standards so developers find it more approachable."

A list of functions and attributes are provided here for reference

Attributes
XMLHttpRequest.autoRedirect
XMLHttpRequest.onreadystatechange
XMLHttpRequest.readyState
XMLHttpRequest.responseText
XMLHttpRequest.responseXML
XMLHttpRequest.status
XMLHttpRequest.statusText
XMLHttpRequest.timeout
Functions
XMLHttpRequest.abort()
XMLHttpRequest.getAllResponseHeaders()
XMLHttpRequest.getResponseHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
XMLHttpRequest.setRequestHeader()


Web



The web block in the XML file defines the initial placement and event handlers for an HTML rendering 
surface,




web objects can also be created and destroyed dynamically with the JavaScript engine.






In laymans term this this is the container where you can put all those pretty HTML codes, to make your widget look fab. If you are from a programming background it is quite similar to web browser object provided to you by VB.





Implementation

Lets build ourself a news feed,

News Feed To be used is http://feeds2.feedburner.com/NdtvNews-TopStories
We will bring the top news from my favourite news channel NDTV.

I want to refresh the feed every 12 hours
(To keep things simple in this post you are not allowed to change the widget preference, we will develop this concept further in later posts)

Firstly I will design my background which in this case is a simple semi-transparent black png of the size 400*300 pixel as shown below, if you are an accomplished designer please go nuts and do all the fancy things you ever wished for with your image editing software. I will stick to the basic.



Because most of this face will be covered by your web object we need someplace from where we can drag. Like the title bar of a window.(Objects inside the widget do not let you drag the window automatically). therefore I decided to make another image called winTitle to make it look like a window title bar


Lets just create window first nothing else


<?xml version="1.0" encoding="UTF-8"?>
<widget minimumVersion="4.5">
<window id="mainWin">
<name> RSS1</name>
<title>My First Widget</title>
<width>400</width>
<height>300</height>
<visible>true</visible>
<image>
<src>Resources/widget.png</src>
</image>
<image>
<src>Resources/wintitle.png</src>
<voffset>-1</voffset>
</image>
</window>

</widget>



As mentioned earlier it will just create window and do nothing.

Javascript Request

I will create a separate JS file called RssRead.js. One of the functions will be readRSS, which is the heart of this code.


function readRSS()
{
     xmlhttp=new XMLHttpRequest();
if (xmlhttp==null)
{
alert ("Something has gone wrong!");
return;
}
}


To begin we instantiate an object of the XMLHTTPRequest type and check if the object is not null if it is so then the function exits with a warning window

As we know that XMLHTTPRequest  gives us the chance of making an asynchronous call therefore we will define an anonymous function to handle the situation when our request returns.If complete the readyState is 4


xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{}
}



The response which is returned is an xml document and we can treat it so

xmldoc=xmlhttp.responseXML;

As we all know that RSS file structure is fixed and in XML thus making our life much easier, we will just read the elements that we want and ignore all the other. For more information on RSS File Structure click on the link


if (xmlhttp.status==200 && xmldoc!=null) //just to check for error or empty XML
{
      var titles=xmldoc.evaluate("rss/channel/item/title");//first line
      var links=xmldoc.evaluate("rss/channel/item/link");//second line
      var strAnswer=""
      for(var i = 0; i < titles.length; i++)
     {
strAnswer=strAnswer + "<a href='" + links.item(i).firstChild.data + "' target='_self' style='color:white; textDecoration:none'>;"+(i+1)+ " : " +titles.item(i).firstChild.data + "</a><br/>";
     }
}



The first line gets all the title elements, we are concerned with the headlines only not the description, we want to give the user a choice to read up on the headline he wants thus the link for that headline or title is required.
The second line gets all the links for the stories
As we all know only way to put a link is an HREF tag therefore I decided to create a string which will have the title inside an href tag with the corresponding link as the src. Simply run a loop for the number of titles in the array and use the variable as an index into the array of links.
This is for returning the value but we didnot make the real call yet so lets see that


xmlhttp.open("GET", "http://feeds2.feedburner.com/NdtvNews-TopStories", true)
xmlhttp.send(null)


most of it is easy except the last argument in the open function, if we make it false then the call will be synchronous but I want it to be async therefore I passed it a true value.

Thats about it..... wait what happened to the string we created with the links, We will find in the widget the object which will show the link, in my case it will be the web element with the id rss1

var result=widget.getElementById("rss1");
result.html=strAnswer;
the complete code is follows

function readRSS()
{

var timer=widget.getElementById("rss1timer");
if(timer!=null)
{
timer.ticking=false;

}
xmlhttp=new XMLHttpRequest();
if (xmlhttp==null)
{
alert ("Something has gone wrong!");
return;
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{
xmldoc=xmlhttp.responseXML;
if (xmlhttp.status==200 && xmldoc!=null)
{
var titles=xmldoc.evaluate("rss/channel/item/title");
var links=xmldoc.evaluate("rss/channel/item/link");
var strAnswer=""
for(var i = 0; i < titles.length; i++)
{
strAnswer=strAnswer + "<a href='" + links.item(i).firstChild.data + "' target='_self' style='color:white; textDecoration:none'>;"+(i+1)+ " : " +titles.item(i).firstChild.data + "</a><br/>";
}
var result=widget.getElementById("rss1");
result.html=strAnswer;
timer.ticking=true;
}
else
{
result.html="An error has occurred";
}
}

}
xmlhttp.open("GET", "http://feeds2.feedburner.com/NdtvNews-TopStories", true)
xmlhttp.send(null)

}


Lets create the web object in our kon or widget file

<web id="rss1" >
<font>Times New Roman</font>
<size>14</size>
<voffset>29</voffset>
<hoffset>20</hoffset>
<width>380</width>
<height>280</height>
<bgcolor>#ffaa55</bgcolor>
</web>

Now to give our widget a nice title

<text style="font-size: 24px">
<data>NDTV Top News</data>
<hoffset>15</hoffset>
<voffset>15</voffset>
<size>16</size>
<color>#ff4499</color>

</text>

That is all we are done except one tiny winy timer issue. We wanted this widget to upgrade itself every 12 hour. To achieve that we put in a timer object with 12*60*60 as interval. When the timer reaches that interval the onTimerFired event is raised. we just call our main readRSS function.



<timer name="rss1timer1" id="rss1timer" ticking="true" interval="43200" onTimerFired="readRSS();"></timer>

lastly the onLoad event must be handled so as we call call our main function without any need for user intervention like a click etc.


<action>
<trigger>onLoad</trigger>
readRSS();
</action>

Thus our full program will be something like this


<?xml version="1.0" encoding="UTF-8"?>
<widget minimumVersion="4.5">

<script src="RssRead.js" charset="utf-8">



</script>

<window id="mainWin">
<name> RSS1</name>
<title>My First Widget</title>
<width>400</width>
<height>300</height>
<visible>true</visible>
<image>
<src>Resources/widget.png</src>
</image>
<image>
<src>Resources/wintitle.png</src>
<voffset>-1</voffset>
</image>
<text style="font-size: 24px">
<data>NDTV Top News</data>
<hoffset>15</hoffset>
<voffset>15</voffset>
<size>16</size>
<color>#ff4499</color>

</text>
<web id="rss1" >
<font>Times New Roman</font>
<size>14</size>
<voffset>29</voffset>
<hoffset>20</hoffset>
<width>380</width>
<height>280</height>
<bgcolor>#ffaa55</bgcolor>
</web>

</window>
<timer name="rss1timer1" id="rss1timer" ticking="true" onTimerFired="readRSS();" interval="43200"></timer>

<action>
<trigger>onLoad</trigger>
readRSS();
</action>
</widget>

Please don't forget to check my youtube videos. We will develop this concept further to bring in user preferences database, registry keys etc in my future posts.

1 comment:

  1. Nice Blog! Well most of your content and image is original and informative. /many thanks for sharing this, cheers
    Buy Gadgets

    ReplyDelete

 
EatonWeb Blog Directory