// FreshTags v0.5
// Tag-Driven Blog Navigation
// www.greg-hill.id.au 2006
// This work is licensed under a Creative Commons Attribution-ShareAlike 2.1 Australia License.
// URL: http://ghill.customer.netspace.net.au/freshtags/
// Requires: 	del_user (delicious user account, blank means generic mode)
// 			anchor (filter by blog's common tag, blank means returns all tags)
//			archive (archive tag, blank means no archives)
//			defs (default tag, blank means no defaults)
//			maxposts (maximum number of posts to fetch from delicious)
//			Delicious.tags (previously fetched set of tags - not for generic mode)
//			Delicious.posts (previously fetched set of archive posts)

if(typeof(Delicious) == 'undefined') 
	Delicious = {}; 							// if missing, create null

Delicious.all_tags = Delicious.tags;				// store fetched tags

if (archive)
	Delicious.arch_posts = Delicious.posts;			// store archive posts

Delicious.posts=false;							// reset posts

anchor = anchor.replace(/ +/g,'+');
defs = defs.replace(/ +/g,'+');

if (!maxposts)
	maxposts = 100;

// Pick up current tags (if exists) from URL or referrer or search engine

curr_tags = fetchTags();						// string of + separated tags

if(defs && !curr_tags)							// set current tags to default
	curr_tags = defs;

if (curr_tags) 								// only bother if tags are currently selected!
{
	if (del_user)							// check if username supplied
	{
		// Fetch posts tagged with currently selected tags -> Delicious.posts
		writeScript('http://del.icio.us/feeds/json/'+del_user+'/'+anchor+'+'+curr_tags+'?count='+maxposts);

		// Fetch tag counts for currently selected tags    -> Delicious.tags

		writeScript('http://del.icio.us/feeds/json/tags/'+del_user+'/'+anchor+'+'+curr_tags+'?count=100&sort=freq');
	}
	else	// Fetch generic posts tagged with currently selected tags -> Delicious.posts

		writeScript('http://del.icio.us/feeds/json/tag/'+anchor+'+'+curr_tags+'?count='+maxposts);
}


function listTags(type, rows, prompt, cust_html)
{
// outputs formatted list of tags
// requires: Delicious.tags, Delicious.all_tags
// assumes: curr_tags is + separated list of currently selected tags
// will not work in generic mode

var outputHTML; 								// string containing returned HTML

//if (!del_user) return '';						// no user account, no tags

// defaults

if (!type) type="drop";  			// custom, flat(-multi), list(-multi), scroll, drop, sub, (cloud)
if (!rows) rows=0;							// 0 is unlimited
if (type=="custom" && !cust_html) 					// if no custom function, then use default
	type="drop";

// delicious branding

del_plug = '<a class="del_plug" href="http://del.icio.us/'+del_user+'/'+anchor+'+'+curr_tags+'"><img src="http://del.icio.us/static/img/delicious.small.gif" alt="delicious"></a><br/>'; 

delete Delicious.tags[anchor];					// delete anchor and default tags from list
delete Delicious.all_tags[anchor];
//delete Delicious.tags[defs];
//delete Delicious.all_tags[defs];

// based on type, get the template for the html to be written out [start, item, end, selected item]
// !url! -> new url !murl! -> multi url !tag! -> tag name  !count! -> tag count

switch(type)
{
	case "custom": raw_html=cust_html.split('@');
	break;

	case "flat": raw_html=['', '<a class="showtag" href="!url!">!tag! (!count!)</a> ', '  '+del_plug, '<a class="showtag" href="!murl!"><strong>!tag! (!count!)</strong></a> '];
	break;

	case "flat-multi": raw_html=['', '<a class="showtag" href="!murl!">!tag! (!count!)</a> ', '  '+del_plug, '<a class="showtag" href="!murl!"><strong>!tag! (!count!)</strong></a> '];
	break;

	case "list": raw_html=['<ul class="showtag">', '<li class="showtag"><a class="showtag" href="!url!">!tag! (!count!)</a></li>',del_plug+'</ul>', '<li class="showtag"><a href="!murl!"><strong>!tag! (!count!)</strong></a></li>'];
	break;

	case "list-multi": raw_html=['<ul class="showtag">', '<li class="showtag">[<a class="showtag" href="!murl!">+</a>]&nbsp;<a class="showtag" href="!url!">!tag! (!count!)</a></li>',del_plug+'</ul>', '<li class="showtag">[<a class="showtag" href="!murl!">--</a>]&nbsp;<a href="!url!"><strong>!tag! (!count!)</strong></a></li>'];
	break;

	case "scroll": raw_html=['<select class="showtag" multiple name="multimenu">', '<option class="showtag" value="!tag!">!tag! (!count!)</option>', '</select><br/><input class="showtag" type="button" value="Go" onClick="clickScroll();">&nbsp;&nbsp;'+del_plug, '<option class="showtag" selected value="!tag!">&gt;&gt;!tag! (!count!)</option>'];
	break;

	case "drop": raw_html=['<select class="showtag" name="dropmenu" size="1" onChange="document.location.href=makeURL(this.options[this.selectedIndex].value);">', '<option class="showtag" value="!tag!">!tag! (!count!)</option>', '</select>&nbsp;'+del_plug, '<option class="showtag" selected value="!tag!">&gt;&gt;!tag! (!count!)</option>'];
	break;

	case "sub": raw_html=['[ ', '!tag! (!count!) ', ']', '<strong>!tag! !count!</strong> '];
	break;

	default: alert("Bad type in listTags: "+type);
}

outputHTML = raw_html[0];						// write start code

if (prompt && type=="drop")						// insert prompt
	outputHTML += '<option selected value="">'+prompt+'</option>';

var loop=0;
var taglist=curr_tags.split('+');

for(var i in Delicious.all_tags)
{
	loop++;

	template = raw_html[1];						// item code template

	for(var j=0; j<taglist.length; j++)
		if (taglist[j].toLowerCase()==i.toLowerCase())	// if we're up to a currently selected tag ...
		{	
			template = raw_html[3]; 				// use "selected" item code template instead
			break;
		}
		
	template=template.replace(/!tag!/gi, i);				// insert tag

	template=template.replace(/!url!/gi, makeURL(i) );		// insert new URL

	template=template.replace(/!murl!/gi, makeURL(taggle(i)) );	// insert multiple URL

	c=Delicious.tags[i];						// test if we need sub-counts
	a=Delicious.all_tags[i];

	if (!a || a==0)
	{
		if (!c || c==0 || !curr_tags || c==a)
			cLabel = "";
		else
			cLabel = c;
	}
	else
	{	
		if (!c || c==0 || !curr_tags || c==a)
			cLabel = a;
		else
			cLabel = c+'/'+a;
	}

	template=template.replace(/!count!/gi, cLabel);			// insert count
	template=template.replace(/\(\)/gi,'');				// remove any empty brackets

	outputHTML+=template;

	if(loop>=rows && rows!=0)					// enforce row maximum
		break;
}

outputHTML+=raw_html[2];						// end code

return outputHTML;
}



function listTitles(type, rows, prompt, source, cust_html)
{
// outputs formatted list of titles, based on source
// requires: source ie Delicious.posts, Delicious.arch_posts etc

var outputHTML=""; 							// string containing returned HTML

if (typeof(navbar = document.forms["b-search"]) !='undefined')
	navbar.as_q.value=curr_tags;					// load up blogger navbar if present

var css_label='\"showtitle\"';

// defaults

if (!type) type="list";							// custom, flat, list, scroll, drop, sub, (cloud)
if (!rows) rows=0;							// 0 is unlimited
if (type=="custom" && !cust_html) 					// if no custom function, then use default
	type="list";
if (!source) source="posts";						// posts, archive, (related), (comment)

// based on source, get the JSON object with titles to be written out

switch(source)
{
	case "posts": entry = Delicious.posts; 
	break;

	case "archive": 	css_label='\"showarch\"'; 
				if (archive) entry = Delicious.arch_posts; 
				else { alert("No archive"); return ''; }
	
	break;

	default: alert("Bad source in listTitles: "+source);
}

if (!entry || entry.length==0) return '';				// return if nothing to display

if (rows==0) rows=entry.length;

rows=Math.min(rows, entry.length);

// based on type, get the template for the html to be written out [start, item, end]
// !url! -> new url  !title! -> post title 

switch(type)
{
	case "custom": raw_html=cust_html.split('@');
	break;

	case "flat": raw_html=['', '<a class='+css_label+' href="!url!">!title!</a> ', ''];
	break;

	case "list": raw_html=['<ul class='+css_label+'>', '<li class='+css_label+'><a class='+css_label+' href="!url!">!title!</a></li>','</ul>'];
	break;

	case "scroll": raw_html=['<select class='+css_label+' name="multilist" size="'+rows+'" onChange="document.location.href=this.options[this.selectedIndex].value">', '<option class='+css_label+' value="!url!">!title!</option>', '</select>'];
	break;

	case "drop": raw_html=['<select class='+css_label+' name="droplist" size="1" onchange="document.location.href=this.options[this.selectedIndex].value">', '<option class='+css_label+' value="!url!">!title!</option>', '</select>'];
	break;

	case "sub": raw_html=['[ ', '!title!, ', ']'];
	break;

	default: alert("Bad type in listTitles: "+type);
}

outputHTML+=raw_html[0];						// start code

if (prompt && type=="drop")						// insert prompt
	outputHTML+='<option selected value="">'+prompt+'</option>';

for(var i=0; i<entry.length; i++)
{
	descr = tidy(entry[i].d);
	if (source=="archive") 						// insert archive count
		descr +=' ('+entry[i].n+')'; 

	url = entry[i].u;
	if (curr_tags)							// pass tags
		url=makeURL(curr_tags, url);

	template = raw_html[1];						// item code template
	template=template.replace(/!title!/i, descr);			// insert title
	template=template.replace(/!url!/i, url);				// insert URL
	
	outputHTML+=template;							// write out item code

	if(i>=rows-1 && rows!=0)					// enforce row maximum
		break;
}

outputHTML+=raw_html[2];						// end code

return outputHTML;
}




function tidy(descr)
{
// eat title ie everything before first :

pos = descr.indexOf(':');

if(pos==-1) return descr;

return descr.substr(pos+1);
}

function list_post_tags(post_tags)
{
// included for legacy reasons only; not recommended!

	var selected, c, tags=post_tags.split(' ');

	document.write('<td align="center"><small>[&nbsp;');

	for(var i=0;i<tags.length;i++)
	{

		rexp = new RegExp( tags[i], 'i' );

		selected = (curr_tags.search(rexp)>=0);
		if (selected)
			document.write('<strong>');

		document.write('&nbsp;&nbsp;'+tags[i]);
		if (del_user) c = Delicious.all_tags[tags[i]];
		if (c && c>0)
			document.write('('+c+')');
		
		if (selected)
			document.write('</strong>');

	}
	document.write('&nbsp;&nbsp;&nbsp;]&nbsp;&nbsp;');

	var keep_curr_tags = curr_tags;
	curr_tags=post_tags.replace(/ +/gi,'+');
	document.write('<a href="'+makeURL(curr_tags)+'">&gt;&gt;</a></small></td>');
	curr_tags = keep_curr_tags;
	
	return;
}


function fetchTags( source, names )
{
// try matching tag in query string; 
// failing that try looking in referrer query string;
// if that fails, try looking in referrer pathname.

var ref=document.referrer.indexOf('?');					// separate out referrer query string
var ref_path=document.referrer;
var ref_query='';

if (ref>0)
{
	ref_path=document.referrer.substring(0,ref+1);
	ref_query=unescape(document.referrer.substr(ref));
}

if (!source && names)
	return '';

if (!source)
	return fetchTags( location.search, ['tags', 'tag', 'cat', 'label'] ) || fetchTags( ref_query, ['tags', 'q', 'p', 'tag', 'cat', 'query', 'search', 'topics', 'topic', 'label']) || fetchTags( ref_path, ['tag', 'tags', 'cat', 'category', 'wiki', 'search', 'topics', 'topic'] );

var peeker, i, tag;
for( i=0; i<names.length; i++ )
{
	if (source.indexOf('http:')==0)						// process path
		peeker = new RegExp( '[/]'+ names[i] +'[/]([^&/?]*)', 'i' );
	else											// process query string
		peeker = new RegExp( '[?&]'+ names[i] +'[=]([^&]*)', 'i' );

	if( (tag = peeker.exec( source )) )
		return filterTags(unescape( tag[1] ) );
	}
return '';
}

function archive_count(arch_URL)
{

// match the given URL against archives; if found, return the note value (ie post count)

for(var i=0; i<Delicious.arch_posts.length; i++)
{
	post = Delicious.arch_posts[i];
	url= post.u;
	note = post.n;

	if (url==arch_URL)
		return note;
}
return;
}

function show_count(count)
{

// only show the count (in braces) if it exists

if (count>0)
	document.write(' ('+count+')');
return;
}

function writeScript( src )
{
  document.write( '<script type="text/javascript" src="'+ src +'"><\/script>' );
}

function taggle(new_tag)
{
// toggles presence (absence) of a new_tag in the currently selected tags list
// returns taggled string


var present=false, tagstring='', old_tags = curr_tags.split('+');

for(var i=0; i<old_tags.length; i++)
	if(old_tags[i].toLowerCase()!= new_tag.toLowerCase() )
		tagstring+=old_tags[i]+'+';
	else
		present=true;

if (!present) tagstring+=new_tag;

tagstring=tagstring.replace(/\++/gi, '+');
tagstring=tagstring.replace(/^\+/gi, '');				// tidy up
tagstring=tagstring.replace(/\+$/gi, '');

return tagstring;
}

function makeURL(tags, url)
{
// creates a new URL based on passed in tags

var pos;

if(!url) url = document.location.href;

if (url.indexOf('?')==-1) url+="?";

pos = url.search(/tags=/i);						// find start of "tags=..." parameter
if (pos==-1) 
{
	url+="&";
	pos=url.length;
}

endpos=url.indexOf('&',pos);						// find end of "tags=..." parameter
if (endpos==-1) endpos=url.length;

url=url.substr(0,pos)+"tags="+tags+url.substr(endpos);

return url;
}

function clickScroll()
{
// Processes multiple select scroll box 

var menus=document.getElementsByName('multimenu');
var len = menus.length;

var tagstring="";

for (var i=0; i<len; i++)						// For each menu ...
	for (var j=0; j<menus[i].options.length; j++)		// go through each option
		if (menus[i].options[j].selected)
			tagstring+=menus[i].options[j].value+"+";	// building currently selected tags

tagstring=tagstring.replace(/\+$/gi, '');

document.location.href=makeURL(tagstring);			// Submit selection

return;
}

function filterTags( tags )
{
// returns filtered tagstring, dropping non-tags (or unlikely tags, for generic mode)

tags=tags.replace(/[+]/g, ' ');
var black = 'also another could every find from have here into I just many more most much next only really same should show still such that their them then there these they thing this those very well were what when where which while will with without would'; 

var white = 'art bbc css diy irc job fun law log mac map net osx pda php rdf rss tag tax tv web win xml';
var match = [], i, rexp, stop;

tags = tags.replace(/[!?\"#]/g,'');					// knock out punctuation

if (del_user)
{
	for(i in Delicious.all_tags )
		if( (new RegExp('\\b('+ i +')\\b', 'i')).test(tags) )
			match.push(i);
	return match.join('+');
}

// stop list is: known black words + (lowercase words shorter than 4) - known white words

rexp = new RegExp('\\b([a-z]{1,3})\\b','g'); 				// lowercase words <4

if (tags.match(rexp))
	black += ' '+tags.match(rexp).join(' ');

rexp = new RegExp('\\b('+white.replace(/ +/g,'|')+')\\b','ig');	// | separted white list
black = black.replace(rexp,'');

stop = new RegExp('\\b('+black.replace(/ +/g,'|')+')\\b', 'ig');
tags = tags.replace(stop, '').replace(/ +/g, '+');
return tags.replace(/^\+|\+$/g, '');
}

