/* Class: RSSTicker A Javascript class for displaying RSS feeds on a web page. About: Version 1.0.1 (October 2, 2007) About: Author Chris Froese About: Dependencies prototype.js, animator.js */ var RSSTicker = Class.create(); RSSTicker.prototype = { /* Constructor: RSSTicker Initializes the object. Parameters: containerId - Id of the container element. url - URL of the rss feed. options - Options object. *Options* + refresh: true - If refresh is set to true the RSS will be requested after the last headline is shown. + frequency: 5 - The number of seconds to show an item before advancing to the next. + transition: fade - The type of transition, can be either "fade" or "default". + transitionDuration: 1000 - Duration of transition in miliseconds. + controls: false - If set to true "Start Stop Previous Next" will be inserted into the foot of the container element. Example: (start example)
(end) */ initialize: function(containerId, url, options) { this.container = containerId; // the id of the containing element this.url = url; // url of RSS feed this.items = []; // array of items from RSS feed this.title = ''; // feed title this.description = ''; // feed description this.timer = null; // timer id this.currentItem = 0; // current item this.prevItem = 0; // last item -- used for finding previous items this.isReady = false; // if the ticker has been initilized this.isPlaying = false; this.itemTemplate = new Template('
\n
New, #{time}<\/div>

#{title}<\/a>

\n'); // default options this.options = { refresh:true, // call XHR after reaching the end of the items? frequency:5, // how often to rotate transition:'', // the type of effect to apply transitionDuration:1000, controls:false }; this.setOptions(options); }, /* Function: start Builds the DOM element and starts the ticker. start() should be called after the document is loaded. Example: (start example) (end) */ start: function() { if (this.timer && this.isPlaying) { /* console.log('Already playing.'); */ return; } if(!this.isReady) { this.initTicker(); return true; } this.isPlaying = true; this.callback = this.advance; this.frequency = this.options.frequency; this.currentlyExecuting = false; this.registerCallback(); }, /* Function: stop Stops the ticker. stop() is automatically attached to the control element if options.controls is set to 'true'. */ stop: function() { if (!this.timer && !this.isPlaying) { return; } this.isPlaying = false; clearInterval(this.timer); this.timer = null; }, /* Function: next Moves the ticker to the next item. */ next: function() { if(this.isPlaying) { this.stop(); this.advance(); this.start(); } else { this.advance(); } }, /* Function: previous Moves the ticker to the previous item. */ previous: function() { if(this.isPlaying) { this.stop(); } this.prevItem = this.currentItem; this.currentItem--; if(this.currentItem < 0) this.currentItem = (this.items.length - 1); this.applyTransition(); if(this.isPlaying) { this.start(); } }, /* Function: jumpTo Moves the ticker to a selected item. */ jumpTo: function(i) { if(this.isPlaying) { this.stop(); this.currentItem = i; this.applyTransition(); this.start(); } else { this.currentItem = i; this.applyTransition(); } }, /* Function: setItemTemplate Defines a new template for RSS items. Parameters: template - A string containing the template. Template Syntax: The template string should be in the form of HTML fragment. *Available Template tags* - The following tags can be used when assigning a new item template: + #{id}: The containing element id of the RSS item. *Note:* The element (ie.
tag) wraping the item must have this. + #{pubDate}: The publication date of the item if one exists. + #{title}: The item title. + #{description}: the item description. + #{link}: The item link. Example: (start example)
(end) */ setItemTemplate: function(template) { this.itemTemplate = new Template(template); }, /************************************** * CLASS FUNCTIONS **************************************/ // Advance to the next item advance: function() { /*console.log(this.currentItem);*/ if(this.currentItem >= (this.items.length - 1)) { this.prevItem = this.currentItem; this.currentItem = 0; if(this.options.refresh) { this.stop(); this.timer = null; $(this.container).getElementsByClassName('ticker-body')[0].innerHTML = '
Checking for updates...
'; this.getFeed(); } else { this.applyTransition(); } } else { this.prevItem = this.currentItem; this.currentItem++; this.applyTransition(); } }, // transition between between last and next item applyTransition: function() { switch(this.options.transition) { case 'fade': var anime = new Animator({ duration: this.options.transitionDuration }) .addSubject(new NumericalStyleSubject($(this.container+'-item-'+this.currentItem), 'opacity', 0, 1)) .addSubject(new NumericalStyleSubject($(this.container+'-item-'+this.prevItem), 'opacity', 1, 0)); $(this.container+'-item-'+this.currentItem).setStyle({zIndex: '1001'}); $(this.container+'-item-'+this.prevItem).setStyle({zIndex: '1'}); anime.play(); break; case 'swap': var anime = new Animator({ duration: this.options.transitionDuration }) .addSubject(new NumericalStyleSubject($(this.container+'-item-'+this.currentItem), 'left', -640, 10)) .addSubject(new NumericalStyleSubject($(this.container+'-item-'+this.prevItem), 'left', 10, -640)); $(this.container+'-item-'+this.currentItem).setStyle({zIndex: '1001'}); $(this.container+'-item-'+this.prevItem).setStyle({zIndex: '1'}); anime.play(); break; default: $(this.container+'-item-'+this.currentItem).show(); $(this.container+'-item-'+this.prevItem).hide(); } }, // Build the ticker HTML // If options.controls = true the controls will be put in the ticker footer. buildTicker: function() { var tickerInnerHTML = '\n
\n
\\n'; $(this.container).innerHTML = tickerInnerHTML; // build the controls if if(this.options.controls) { var controlsHTML = '
Stop Start Next Previous
'; $(this.container).getElementsByClassName('ticker-footer')[0].innerHTML = controlsHTML; var _this = this; // correct the scope of Event.observe Event.observe($(this.container).getElementsByClassName('ticker-stop')[0], 'click', function() { _this.stop() }); Event.observe($(this.container).getElementsByClassName('ticker-start')[0], 'click', function() { _this.start() }); Event.observe($(this.container).getElementsByClassName('ticker-next')[0], 'click', function() { _this.next() }); Event.observe($(this.container).getElementsByClassName('ticker-previous')[0], 'click', function() { _this.previous() }); } }, // get the RSS feed. getFeed: function() { var _this = this; // needed this for scope new Ajax.Request( this.url, { method: 'get', onSuccess: function(t) { _this.parseFeed(t.responseXML); }, onFailure: function(t, e) { /*console.log(e);*/ }, onException: function(t, e) { /*console.log(e);*/ } }); }, // parse the feed into a object // called if start() is called and isReady is false. parseFeed: function(xml) { // get the blog title if(!this.title) { try { this.title = xml.getElementsByTagName('title')[0].firstChild.data; } catch(e) { this.title = ''; /* console.log(e); */ } } // get the blog link try { this.link = xml.getElementsByTagName('link')[0].firstChild.data; } catch(e) { this.link = ''; /* console.log(e); */ } // get the blog link try { this.description = xml.getElementsByTagName('description')[0].firstChild.data; } catch(e) { this.link = ''; /* console.log(e); */ } // try to get the items from the feed try { var items = xml.getElementsByTagName('item'); } catch(e) { /* console.log(e); */ return false; } // make sure there are items in this feed. if(items.length <= 0) { $(this.container).hide(); /* console.log('No items in feed.'); */ return false; } // this holds the html for the items var itemsHTML = ''; // iterate over the items for(var i=0; i 1) { this.start(); } }, // initialize the ticker initTicker: function() { this.isReady = true; this.buildTicker(); this.getFeed(); }, parse8601Date: function(dateTime) { // break up the date and time parts var dateTimeParts = dateTime.split('T'); var datePart = dateTimeParts[0]; var timePart = dateTimeParts[1]; var time24 = timePart.split('-')[0]; var time24Parts = time24.split(':'); var hour = time24Parts[0]; var min = time24Parts[1]; var ampm = ''; // am or pm? if(hour > 12) { ampm = 'p.m.'; hour = hour - 12; } else if(hour == 12) { ampm = 'p.m.'; } else { ampm = 'a.m.'; } var time = hour + ':' + min + ' ' + ampm; var dateParts = datePart.split('-'); var d = dateParts[2]; var m = dateParts[1]; var y = dateParts[0]; var returnDate = m + '/' + d + '/' + y + ' @ ' + time; return returnDate; }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.callback(this); } finally { this.currentlyExecuting = false; } } }, setOptions: function(options) { Object.extend(this.options, options || {}); } }