// <![CDATA[

String.prototype.trim = function()
{
	return this.replace( /^\s+|\s+$/g, '' );
}

/*
 *	whiteList
 *	tags + attributes and method to validate them
 */
HTMLElement.prototype.whiteList =
{
	'A':
	{
	 '__precondition__':function( node )
	 {
			return node.hasAttribute('href') && node.whiteList['A'].href.call( {value:node.getAttribute('href')}, node );
	 },
		'href':function( node )
		{
			return null!=this.value.match( /^https?:\/\//i );
		},
		'title':true
	}
	,'IMG':
	{
	 '__precondition__':function( node )
	 {
			node.setAttribute( 'title', node.getAttribute('title')||node.getAttribute('src') )
			return node.hasAttribute('src') && node.whiteList['IMG'].src.call( {value:node.getAttribute('src')}, node );
	 },
		'src':function( node )
		{
			return null!=this.value.match( /^https?:\/\//i );
		},
		'alt':true,
		'title':true
	}
	,'P':{}
	,'PRE':{}
	,'UL':{}
	,'OL':{}
	,'LI':{}
	,'DL':{}
	,'DT':{}
	,'H1':{}
	,'H2':{}
	,'H3':{}
	,'H4':{}
	,'H5':{}
	,'H6':{}
	,'BR':{}
}
/**
 *	Prototype extension to simplify adding and sanitizing markup to an element.
 *	arguments = some strings containing the HTML markup to sanitize and append
 */
HTMLElement.prototype.appendMarkup = function( content, maxLength )
{
	var maxLength = maxLength||Infinity,
	 dummy = document.createElement('div');
	dummy.innerHTML = content;

 // sanitize using the whiteList
	dummy.sanitize();

	//	append DOM tree of dummy in this
	var i = 0, node;
	while( maxLength>this.textContent.length && dummy.firstChild )
	{
		this.appendChild( dummy.firstChild );
 i++;
 }

 //maxLength = Infinity;
 if( dummy.firstChild && maxLength!=Infinity )
 {
 this.cutOff( maxLength );
 }


 return this;
}
/**
 *	Prototype extension to sanitize the attributes and HTMLElements
 *	whiteList = { 'NODENAME_0':{'attribute_0':function(){},'attribute_1':function(){}} }
 */
HTMLElement.prototype.sanitize = function()
{
	// recurse
	var i=0, previousNodeName='/', currentNode;
	while( currentNode=this.childNodes[i] )
	{
		var nodeName	= currentNode.nodeName;

		if
 (
 currentNode.nodeType==1
 &&
 (
 !this.whiteList[nodeName]
 || ( this.whiteList[nodeName] && this.whiteList[nodeName].__precondition__ && !this.whiteList[nodeName].__precondition__(currentNode) )
 || ( nodeName=='BR' && ( previousNodeName=='BR' || previousNodeName=='P' ) )
 )
 )
		{
 		// either it's not in the whiteList or does not meet the preconditions or is an extra BR -> replace currentNode by its content
 		while( currentNode.firstChild )
 		{
 			this.insertBefore( currentNode.firstChild.cloneNode( true ), currentNode );
 			currentNode.removeChild( currentNode.firstChild );
 		}
 this.removeChild( currentNode );
		}
		else
	 {
	 if( currentNode.nodeType==1 )
	 {
 			// in the whiteList and meet the preconditions
 			//	-> sanitize the attributes
 			for( var j=currentNode.attributes.length,attribute; attribute=currentNode.attributes[--j]; )
 		 {
 var attrSanity = this.whiteList[nodeName][attribute.name];
 				if( attrSanity===undefined || ( attrSanity!==true && false==attrSanity.apply(attribute,[currentNode] ) ) )
 				{
						currentNode.removeAttribute( attribute.name );
 				}
 }

 // -> and recurse
 			currentNode.sanitize();
 	 previousNodeName = nodeName;
	 }
	 // => next!
	 i++;
	 }
	}
}
/*
 *	Prototype extension to cutOff a DOM tree so as to get a textContent <= maxLength
 */
Element.prototype.cutOff = function( maxLength, base )
{
 var base = base||this;
 while( this.lastChild )
 {
 if( this.lastChild.nodeType==3 && this.lastChild.nodeValue.length>base.textContent.length-maxLength )
 {
 this.lastChild.nodeValue = this.lastChild.nodeValue.slice( 0, this.lastChild.nodeValue.length-base.textContent.length+maxLength ) +'...';
 return true;
 }
 if( this.lastChild.nodeType==1 && this.lastChild.cutOff( maxLength, base ) )
 {
 return true;
 }
 this.removeChild( this.lastChild );
 }
 return false;
}


// failsafe for opera.locale.getLocaleString
opera.locale=opera.locale||{'getLocaleString':function(){return ''}};

/*
 * outputFeed
 */
function outputFeed( feed, status )
{
 if( !feed )
 {
 var statusName = ['NO FEED ITEMS','CANCELED','REFRESH POSTPONED','NOT MODIFIED','OUT OF MEMORY','SERVER TIMEOUT','LOADING ERROR','PARSING ERROR']
 document.body.className = 'error #'+ status +' ( '+ statusName[ status ] +' )';
 return false;
 }

 // l10n the 'footer' note including a link
 var footer = document.getElementById('footer'),
 splitText = (opera.locale.getLocaleString( 'S_WEBFEEDS_FOOTER' )||'This page was generated by Opera from %s').split('%s');

 footer.firstChild.nodeValue = splitText.shift()||'';
 footer.lastChild.nodeValue = splitText.join(' ')||'';


 // l10n the 'learn' link
 (document.getElementById('learn')||{firstChild:{}}).firstChild.nodeValue = opera.locale.getLocaleString( 'S_WEBFEEDS_SUBSCRIBE_HINT' )||'Learn more about feeds';

 // subscribeNative?
 var button = document.getElementById('subscribe');
 if( button )
 {
 if( 'function'==typeof(opera.feeds.subscribeNative) )
 {
 button.addEventListener( 'click', function(){ opera.feeds.subscribeNative(location.href); }, false );
 // l10n the 'subscribe' button
 button.firstChild.nodeValue = opera.locale.getLocaleString( 'S_MINI_FEED_SUBSCRIBE' )||'Subscribe';
 }
 else
 {
 button.parentNode.removeChild( button );
 }
 }

 // set title
 top.document.title = document.getElementById('feedTitle').firstChild.nodeValue = document.createElement( 'div' ).appendMarkup( feed.title.data ).textContent.trim()||feed.uri;
 document.body.removeAttribute( 'class' );

 // walk the feed items
 var cutOff = 768,
 hItemsUl = document.getElementById('itemsUl'),
 noTilteStr = opera.locale.getLocaleString( 'M_BREW_NO_TITLE' )||'<No Title>';
 for( var i=0,feedEntry; feedEntry=feed.entries[i++]; )
 {
 var itemLi = hItemsUl.lastChild.cloneNode( true );

 // set the href
 itemLi.firstChild.firstChild.setAttribute( 'href', feedEntry.uri||'#' );

 // set the title
 itemLi.firstChild.firstChild.firstChild.nodeValue = document.createElement( 'div' ).appendMarkup( feedEntry.title.data ).textContent.trim()||noTilteStr;

 // write content
 if( feedEntry.content.isMarkup )
 {
 itemLi.lastChild.appendMarkup( (feedEntry.content.data.trim()||'\xa0'), cutOff );
 }
 else if( feedEntry.content.isPlainText )
 {
 itemLi.lastChild.appendChild( document.createTextNode( (feedEntry.content.data.trim()||'\xa0').slice( 0, cutOff ) ) );
 }
 else
 {
 itemLi.lastChild.appendChild( document.createTextNode( (feedEntry.content.data||'\xa0').slice( 0, cutOff ) ) );
 }

 // append itemLi to hItemsUl
 hItemsUl.insertBefore( itemLi, hItemsUl.lastChild );
 }

 return true;
}

// ]]>