Categories:

An RSS + Ajax + JavaScript ticker

We've come to the final piece of the puzzle for the RSS ticker script. What's needed now is the front end JavaScript for spinning a ticker out of an RSS feed that's returned as a XML object. I'm going to keep it simple- no crazy transitional effects here. So with that said, here's the complete code for my Ajax RSS ticker:

<script type="text/javascript">

function createAjaxObj(){
var httprequest=false
if (window.XMLHttpRequest){ // if Mozilla, Safari etc
httprequest=new XMLHttpRequest()
if (httprequest.overrideMimeType)
httprequest.overrideMimeType('text/xml')
}
else if (window.ActiveXObject){ // if IE
try {
httprequest=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e){
try{
httprequest=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e){}
}
}
return httprequest
}

// -------------------------------------------------------------------
// Main RSS Ticker Object function
// rss_ticker(RSS_id, cachetime, divId, divClass, delay, optionalswitch)
// -------------------------------------------------------------------

function rss_ticker(RSS_id, cachetime, divId, divClass, delay, optionalswitch){
this.RSS_id=RSS_id //Array key indicating which RSS feed to display
this.cachetime=cachetime //Time to cache feed, in minutes. 0=no cache.
this.tickerid=divId //ID of ticker div to display information
this.delay=delay //Delay between msg change, in miliseconds.
this.logicswitch=(typeof optionalswitch!="undefined")? optionalswitch : -1
this.mouseoverBol=0 //Boolean to indicate whether mouse is currently over ticker (and pause it if it is)
this.pointer=0
this.ajaxobj=createAjaxObj()
document.write('<div id="'+divId+'" class="'+divClass+'">Initializing ticker...</div>')
this.getAjaxcontent()
}

// -------------------------------------------------------------------
// getAjaxcontent()- Makes asynchronous GET request to "rssfetch.php" with the supplied parameters
// -------------------------------------------------------------------

rss_ticker.prototype.getAjaxcontent=function(){
if (this.ajaxobj){
var instanceOfTicker=this
var parameters="id="+encodeURIComponent(this.RSS_id)+"&cachetime="+this.cachetime+"&bustcache="+new Date().getTime()
this.ajaxobj.onreadystatechange=function(){instanceOfTicker.initialize()}
this.ajaxobj.open('GET', "rssfetch.php?"+parameters, true)
this.ajaxobj.send(null)
}
}

// -------------------------------------------------------------------
// initialize()- Initialize ticker method.
// -Gets contents of RSS content and parse it using JavaScript DOM methods
// -------------------------------------------------------------------

rss_ticker.prototype.initialize=function(){
if (this.ajaxobj.readyState == 4){ //if request of file completed
if (this.ajaxobj.status==200){ //if request was successful
var xmldata=this.ajaxobj.responseXML
if (xmldata.getElementsByTagName("item").length==0){ //if no <item> elements found in returned content
document.getElementById(this.tickerid).innerHTML="<b>Error</b> fetching remote RSS feed!<br />"+this.ajaxobj.responseText
return
}
var instanceOfTicker=this
this.feeditems=xmldata.getElementsByTagName("item")

//Cycle through RSS XML object and store each piece of the item element as an attribute of the element
for (var i=0; i<this.feeditems.length; i++){
this.feeditems[i].setAttribute("ctitle", this.feeditems[i].getElementsByTagName("title")[0].firstChild.nodeValue)
this.feeditems[i].setAttribute("clink", this.feeditems[i].getElementsByTagName("link")[0].firstChild.nodeValue)
this.feeditems[i].setAttribute("cdescription", this.feeditems[i].getElementsByTagName("description")[0].firstChild.nodeValue)
}
document.getElementById(this.tickerid).onmouseover=function(){instanceOfTicker.mouseoverBol=1}
document.getElementById(this.tickerid).onmouseout=function(){instanceOfTicker.mouseoverBol=0}
this.rotatemsg()
}
}
}

// -------------------------------------------------------------------
// rotatemsg()- Rotate through RSS messages and displays them
// -------------------------------------------------------------------

rss_ticker.prototype.rotatemsg=function(){
var instanceOfTicker=this
if (this.mouseoverBol==1) //if mouse is currently over ticker, do nothing (pause it)
setTimeout(function(){instanceOfTicker.rotatemsg()}, 100)
else{
var tickerDiv=document.getElementById(this.tickerid)
var tickercontent='<a href="'+this.feeditems[this.pointer].getAttribute("clink")+'">'+this.feeditems[this.pointer].getAttribute("ctitle")+'</a>'
if (this.logicswitch=="showdescription")
tickercontent+="<br />"+this.feeditems[this.pointer].getAttribute("cdescription")
tickerDiv.innerHTML=tickercontent
this.pointer=(this.pointer<this.feeditems.length-1)? this.pointer+1 : 0
setTimeout(function(){instanceOfTicker.rotatemsg()}, this.delay) //update container every second
}
}

</script>

The JavaScript ticker object is invoked on the page as follows:

<script type="text/javascript">
//rss_ticker(RSS_id, cachetime, divId, divClass, delay, optionalswitch)
//1) RSS_id: "Array key of RSS feed in PHP script"
//2) cachetime: Time to cache the feed in minutes (0 for no cache)
//3) divId: "ID of DIV to display ticker in. DIV id dynamically created"
//4) divClass: "Class name of this ticker, for styling purposes"
//5) delay: delay between message change, in miliseconds
//6) optionalswitch: "optional arbitrary" string to create additional logic in call back function

new rss_ticker("CNN", 60, "cnnbox", "cnnclass", 2000)
new rss_ticker("dynamicdrive", 120, "newsbox", "newsclass", 3000, "showdescription")
</script>

Demo:

In the case, a CNN and Dynamic Drive ticker are displayed, with the later also showing each item's description. The "120" value dictates that the RSS feed should be cached locally for 2 hours.

Notice among the parameters passed using Ajax, the code at the very end:

var parameters="id="+encodeURIComponent(this.RSS_id)+"&cachetime="+this.cachetime+"&bustcache="+new Date().getTime()

I've added a "burstcache" parameter and set it to the current time to prevent IE from potentially caching the request, as the current time changes for every second passed.

The initialize() method is probably the most important function here- it parses the XML object and separates each RSS item's title, link and description and stores them inside a corresponding attribute for retrieval later:

this.feeditems=xmldata.getElementsByTagName("item")
//Cycle through RSS XML object and store each piece of the item element as an attribute of the element
for (var i=0; i<this.feeditems.length; i++){
this.feeditems[i].setAttribute("ctitle", this.feeditems[i].getElementsByTagName("title")[0].firstChild.nodeValue)
this.feeditems[i].setAttribute("clink", this.feeditems[i].getElementsByTagName("link")[0].firstChild.nodeValue)
this.feeditems[i].setAttribute("cdescription", this.feeditems[i].getElementsByTagName("description")[0].firstChild.nodeValue)
}

The code:

this.feeditems[i].getElementsByTagName("title")[0].firstChild.nodeValue

for example uses the DOM to access the value of the TITLE element for the item in question. I then store each value retrieved inside a custom attribute, for the RSS titles, in the "ctitle" attribute. I'm sure there are much more elegant ways to do this, but you get the idea.

And there you have it. For your reference here are the 3 files that make up a complete RSS Ajax ticker:

- demo.htm
- rssfetch.php
- rssticker.js
- ajaxticker.zip (all 3 files)

What's left?

Like any script there's room for improvement with this one, especially if you plan on using it on a production site. One important feature is to add additional code inside the PHP script to account for the remote RSS file being inaccessible, such as a routine to revert back to the cached version of the file (if it's available) in such an event. That I leave for you to implement, along with a cool transitional effect between message change that is!