/********************************************************************************************************
                                  Script to parse RSS/Atom XML data files
                                        Written by Mark Wilton-Jones
                            version 3.1.0 updated 12/10/2005 to add OPML support

Please see http://www.howtocreate.co.uk/jslibs/ for details and a demo of this script
Please see http://www.howtocreate.co.uk/tutorials/jsexamples/rss.html for a demo and description
Please see http://www.howtocreate.co.uk/jslibs/termsOfUse.html for terms of use
********************************************************************************************************/

//display image enclosures: 0 = none, 1 = inside link to item, 2 = after item description
var displayEnclosures = 2;

//display atom links: 0 = before item description, 1 = after item description
var displayAtomLinks = 1;

function cloneTree(oFrom,oTo) { try {
	for( var i = 0, n; i < oFrom.childNodes.length; i++ ) {
		n = oFrom.childNodes[i];
		if( n.tagName ) {
			var oTag = document.createElement(n.tagName);
			oTo.appendChild(oTag);
			for( var j = 0; j < n.attributes.length; j++ ) {
				try { oTag.setAttribute(n.attributes[j].nodeName,n.attributes[j].nodeValue); } catch(e) {}
			}
			cloneTree(n,oTag);
		} else if( n.nodeType == 3 ) {
			oTo.appendChild(document.createTextNode(n.nodeValue));
		}
	}
} catch(e) { alert(oFrom.tagName+' '+n.nodeValue); throw(e); } }
function prepHTMLCode(oFrom) {
	return oFrom.replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
function getUnNestedTextNodes(oFrom) {
	var oStr = '';
	for( var i = 0; i < oFrom.childNodes.length; i++ ) {
		if( ( oFrom.childNodes[i].nodeType == 3 ) || ( oFrom.childNodes[i].nodeType == 4 ) ) { oStr += oFrom.childNodes[i].nodeValue; }
	}
	return oStr;
}
function parseRSS(oDocObj) {

	//check if the browser interpreted the XML correctly
	if( oDocObj.documentElement && ( !oDocObj.documentElement.tagName || ( oDocObj.documentElement.tagName && oDocObj.documentElement.tagName.toUpperCase() == 'HTML' ) ) ) {
		setTimeout('alert(\'For no apparent reason, your browser has turned the RSS feed into HTML based garbage.\\nScript aborted.\');',50); return; }
	var chanEl = oDocObj.getElementsByTagName('channel')[0];
	if( !chanEl ) { chanEl = oDocObj.getElementsByTagName('atomSpoof')[0]; }
//alert(oDocObj.getElementsByTagName('atomSpoof')[0]);
	if( !chanEl ) {
		if( oDocObj.getElementsByTagName('opml')[0] || oDocObj.getElementsByTagName('outlineDocument')[0] ) {
			getListOfFeeds(oDocObj);
		} else {
			alert('Format was not recognised as a valid RSS feed');
		}
		return;
	}
	var RSSversion = oDocObj.getElementsByTagName('rssSpoof')[0] ? oDocObj.getElementsByTagName('rssSpoof')[0].getAttribute('version') : ( oDocObj.getElementsByTagName('atomSpoof')[0] ? ( 'atomfeed' + oDocObj.getElementsByTagName('atomSpoof')[0].getAttribute('version') ) : '' );

	//get the information about the feed
	for( var x = 0, y, feedInfo = [], tagName2, tagName3; x < chanEl.childNodes.length; x++ ) {
		y = chanEl.childNodes[x];
		if( y.tagName ) {
			tagName2 = y.tagName.toLowerCase();
			if( tagName2 == 'fiximage' ) {
				feedInfo['image'] = [];
				for( var i = 0, j; i < y.childNodes.length; i++ ) {
					j = y.childNodes[i];
					if( j.tagName ) {
						tagName3 = j.tagName.toLowerCase();
						feedInfo['image'][tagName3] = getUnNestedTextNodes(j);
						if( RSSversion.match(/0?\.91/) ) { feedInfo['image'][tagName3] = prepHTMLCode(feedInfo['image'][tagName3]); }
					}
				}
			} else if( tagName2 != 'item' && tagName2 != 'entry' ) {
				if( tagName2 != 'fixlink' || !y.getAttribute('rel') ) {
					feedInfo[tagName2] = getUnNestedTextNodes(y);
					if( RSSversion.match(/0?\.91/) ) { feedInfo[tagName2] = prepHTMLCode(feedInfo[tagName2]); }
				}
			}
		}
	}

	if( !feedInfo['lastbuilddate'] ) { feedInfo['lastbuilddate'] = feedInfo['pubdate']; }

	//parse each news item
	var y = oDocObj.getElementsByTagName('item');
	if( !y.length ) { y = oDocObj.getElementsByTagName('entry'); }
	for( var x = 0, newsItems = []; x < y.length; x++ ) {
		newsItems[x] = [];
		newsItems[x]['links'] = {alternate:[],related:[],via:[]};
		newsItems[x]['content'] = '';
		for( var i = 0, j, theRel; i < y[x].childNodes.length; i++ ) {
			j = y[x].childNodes[i];
			if( j.tagName ) {
				tagName2 = j.tagName.toLowerCase();
				theRel = j.getAttribute('rel');
				if( theRel ) { theRel = theRel.toLowerCase(); }
				theType = j.getAttribute('type');
				if( theType ) { theType = theType.toLowerCase(); }
				if( tagName2 == 'enclosure' || ( ( tagName2 == 'fixlink' ) && ( theRel == 'enclosure' ) ) ) {
					if( !newsItems[x]['enclosure'] ) { newsItems[x]['enclosure'] = []; }
					newsItems[x]['enclosure'][newsItems[x]['enclosure'].length] = [];
					for( var k = 0, l, atn; l = j.attributes[k]; k++ ) {
						atn = l.nodeName.toLowerCase();
						if( atn == 'href' ) { atn = 'url'; }
						newsItems[x]['enclosure'][newsItems[x]['enclosure'].length-1][atn] = l.nodeValue;
					}
				} else if( tagName2 == 'fixlink' ) {
					if( !theRel || ( theRel == 'alternate' ) ) {
						newsItems[x]['links']['alternate'][0] = prepHTMLCode( j.firstChild ? getUnNestedTextNodes(j) : j.getAttribute('href') );
					} else if( ( theRel == 'via' ) || ( theRel == 'related' ) ) {
						newsItems[x]['links'][theRel][newsItems[x]['links'][theRel].length] = [prepHTMLCode(j.getAttribute('href')),prepHTMLCode(j.getAttribute('title'))];
					}
				} else if( tagName2 == 'summary' ) {
					if( !theType || ( theType == 'text' ) || theType.match(/^text\/plain$/) ) {
						newsItems[x]['description'] = prepHTMLCode(getUnNestedTextNodes(j));
					} else if( ( theType == 'html' ) || ( theType == 'text\/html' ) ) {
						newsItems[x]['description'] = getUnNestedTextNodes(j);
					} else if( ( theType == 'xhtml' ) || theType.match(/^application\/.*\+xml$/) ) {
						var foo = document.createElement('div');
						cloneTree(j,foo);
						newsItems[x]['description'] = foo.innerHTML;
					}
				} else if( tagName2 == 'content' ) {
					if( !theType || ( theType == 'text' ) || theType.match(/^text\/plain$/) ) {
						newsItems[x]['content'] += (newsItems[x]['content']?'<br>':'')+prepHTMLCode(getUnNestedTextNodes(j));
					} else if( ( theType == 'html' ) || ( theType == 'text\/html' ) ) {
						newsItems[x]['content'] += (newsItems[x]['content']?'<br>':'')+getUnNestedTextNodes(j);
					} else if( ( theType == 'xhtml' ) || theType.match(/^application\/.*\+xml$/) ) {
						var foo = document.createElement('div');
						cloneTree(j,foo);
						newsItems[x]['content'] += (newsItems[x]['content']?'<br>':'')+foo.innerHTML;
					}
				} else {
					newsItems[x][tagName2] = getUnNestedTextNodes(j);
					if( RSSversion.match(/0?\.91/) ) { newsItems[x][tagName2] = prepHTMLCode(newsItems[x][tagName2]); }
				}
			}
		}
	}

	//now that the entire feed has been converted into JavaScript arrays, it is time to write it out
	document.title = feedInfo['title'] ? ( 'News feed: ' + feedInfo['title'] ) : 'Untitled newsfeed';

	//headers
	var oFeedStr = '<div class="rssarea"><div class="newsitems">\n'
	//items
	for( var x = 0, y; y = newsItems[x]; x++ ) {
		var oEncl = '';
		if( displayEnclosures && y['enclosure'] ) { for( var p = 0, q; q = y['enclosure'][p]; p++ ) {
			if( q['url'] && q['type'] && q['type'].match(/^image\/(gif|png|jpeg)$/i) ) {
				oEncl += '<img src="'+prepHTMLCode(q['url'])+'" alt="Image">';
			}
		} }
		//special atom links
		var oAtomLinks = '', oLtypes = [['related','Related links'],['via','Cited sources']];
		for( var oTyp = 0, oETyp; oETyp = oLtypes[oTyp]; oTyp++ ) {
			if( y['links'][oETyp[0]].length ) {
				oAtomLinks += '<h4 class="'+oETyp[0]+'">'+oETyp[1]+':<\/h4><ul class="'+oETyp[0]+'">';
				for( var oLn = 0, oEach; oEach = y['links'][oETyp[0]][oLn]; oLn++ ) {
					oAtomLinks += '<li><a href="'+oEach[0]+'">'+oEach[1]?oEach[1]:oEach[0]+'<\/a><\/li>';
				}
				oAtomLinks += '</ul>';
			}
		}
		oFeedStr += '<div class="feeditem"><li><a href="'+y['links']['alternate']+'">';
		if( displayEnclosures == 1 ) { oFeedStr += oEncl; }
		oFeedStr += (y['title']?prepHTMLCode(y['title']):'Untitiled')+'<\/a><\/li>';
		if( !displayAtomLinks ) { oFeedStr += oAtomLinks; }
		//oFeedStr += y['description']?('<div class="descr">'+y['description']+'<\/div>'):'';
		//oFeedStr += y['content']?('<div class="conte">'+y['content']+'<\/div>'):'';
		if( displayAtomLinks ) { oFeedStr += oAtomLinks; }
		if( displayEnclosures == 2 ) { oFeedStr += oEncl; }
		oFeedStr += '<\/div>\n';
	}

	//footer
	oFeedStr += '<\/div>'+
		(feedInfo['copyright']?('<div class="footers"><p><b>Copyright:<\/b> '+prepHTMLCode(feedInfo['copyright'])+'<\/p><\/div>'):'')+
		'<\/div>\n';

	//output
	document.getElementById('feedcontainer').innerHTML = oFeedStr;

}

//using a link from an OPML file - change this if you change the layout
function fromOPML(oURL,oFix91) {
	window.storedFeedTitle = document.title;
	window.backToFoo = document.getElementById('feedcontainer').innerHTML;
	window.backToFooURL = document.forms['feedForm'].feedURL.value;
	if( !window.backBut ) {
		window.backBut = document.createElement('a');
		window.backBut.style.marginRight = '7px';
		window.backBut.appendChild(document.createTextNode('<< List'));
		window.backBut.setAttribute('href','javascript:doBackBut();');
		window.backBut.setAttribute('target','_self');
		window.backBut.setAttribute('title','Back to last imported feed list');
		document.getElementsByTagName('h1')[0].appendChild(window.backBut);
	}
	document.forms['feedForm'].fix091.checked = oFix91;
	document.forms['feedForm'].feedURL.value = oURL;
	document.forms['feedForm'].onsubmit();
	return false;
}

//going back after using a link from an OPML file - change this if you change the layout
function doBackBut() {
	document.getElementById('feedcontainer').innerHTML = backToFoo;
	document.forms['feedForm'].feedURL.value = window.backToFooURL;
	window.backBut.parentNode.removeChild(window.backBut);
	window.backBut = null;
	document.title = window.storedFeedTitle;
}

//parse OPML
function getListOfFeeds(oDoc) {

	//get the list title
	var allText = oDoc.getElementsByTagName('title')[0];
	document.title = ( allText && allText.firstChild ) ? ( 'Feed collection: ' + getUnNestedTextNodes( allText ) ) : 'Untitled feed collection';
	allText = '<h2>' + prepHTMLCode(document.title) + '<\/h2>';

	//get the feed list - and try to cope with different formats - no promises
	var oOutline = oDoc.getElementsByTagName('outline'), oAllLinks = '';
	for( var i = 0, j; i < oOutline.length; i++ ) {
		j = oOutline[i];
		var xmlUrl = j.getAttribute('xmlUrl');
		if( !xmlUrl ) { continue; }
		var oTitle = j.getAttribute('title');
		if( !oTitle ) { oTitle = j.getAttribute('text'); }
		if( !oTitle ) { oTitle = xmlUrl; }
		oTitle = prepHTMLCode(oTitle);
		xmlUrl = prepHTMLCode(xmlUrl);
		oAllLinks += '<li><a onclick="return fromOPML(this.href,'+((j.getAttribute('fix091')=='yes')?true:false)+');" href="'+prepHTMLCode(xmlUrl)+'" target="_self">'+prepHTMLCode(oTitle)+'<\/a><\/li>';
	}
	allText += oAllLinks ? ('<ul>'+oAllLinks+'<\/ul>') : '<p>No feeds found<\/p>';

	//output
	document.getElementById('feedcontainer').innerHTML = allText;

}
