Saturday, December 30, 2006

Blogger Tag Cloud

One good thing about the blogger beta is that it supports Labels a.k.a. Categories/Tags (at last!), so one can categorize his posts. Blogger also allows showing the list of labels from your blogs and allows user to filter posts based on the labels. The problem is that the layout of labels is not customizable or is it? Actually, with some (not so elegant) lines of javascript and css, we can make these labels display as a tag-cloud pretty much what other blog platforms support. Here's what we need to do:
Preamble: Edit 2: Edit the template to give the ul tag (which displays the labels) an Id (for e.g. labelUl), this can be done by clicking on "Expand Widget Template" checkbox and scrolling to the code in template which has a div with ID: "Label1". The UL would be contained within this. Enclose the (<data:label.count/>) within a span and save the template.

1) Firstly we'll make the list appear horizontally instead of vertically, that way we can free up some screen real-estate. So we add the respective styles for the ul and li elements within the style tag under head:
#Label1 {display:none;word-wrap:break-word;}
#labelUL {list-style:none;margin:0px;padding:0px;}
#labelUL li{padding:0px 3px 0px 0px;margin:0px;display:inline;}
Add the noscript tag to display the label div, in case user has js turned off
<noscript>
<style type='text/css'>
#Label1 {display:block;}
</style&g;
</noscript>
So at least we've got the list to display horizontally instead of vertically.
2) Now we need to change the font sizes of the labels based on their weights (i.e. the larger the number of posts tagged to a label, the bigger the text size for that).
For that we hook our DOM walk-through javascript to window.load, this is what I've done:


<script type='text/javascript'>
window.onload = function(){
var labelDiv = document.getElementById("Label1");
var ul= document.getElementById("labelUL");

try{
if(ul.childNodes.length>=0)
{
var weights = new Array();
//should be a div
var li,text, re;
var textNode;

var lis = ul.getElementsByTagName("li");
for(var i=0;i<lis.length;i++)
{
li = lis[i];
textNode = li.getElementsByTagName('span')[0];
text = textNode.innerHTML;
re = new RegExp("[^0-9]", "g");
text = text.replace(re,"");
li.title = text + " posts";
weights.push(new category(text,li));
textNode.innerHTML = "";
}
weights.sort(sortNumber);
var mean = Math.floor((parseInt(weights[0].weight)+parseInt(weights[weights.length-1].weight))/2);
//lets go
var weightFactor = 1;
for(i=0;i<weights.length;i++)
{
weightFactor = parseInt(weights[i].weight)*100/mean;
if(weightFactor<80)
weightFactor = 80 + weightFactor*.1;
else if(weightFactor>250)
weightFactor = 250;

weights[i].li.style.fontSize = weightFactor + "%";
}
weights = null;
labelDiv.style.display = "block";
};
}
catch(e){
if(labelDiv!=null)
labelDiv.style.display = "block";
}
}

function category(weightParam,e)
{
this.li = e;
this.weight = weightParam;

}

function sortNumber(a,b)
{
return a.weight - b.weight;
}
<script>


I don't let any tag to be less than 80% of normal text size, you don't want any label to be illegible due to it's size. The js is simple enough to understand and as I said it isn't the most elegant piece of code that you'd come across but hey it works for me. I tested this out on IE 7 and Fx and I'd guess it should either work or downgrade silently on other browsers, worst case the Labels section would look a little whacko but I promise it wouldn't steal your credit card information or conduct any phishing attacks :-).

Edit:Just figured out that in the template if you click on "Expand Widgets.." checkbox, you can set the Id for the ul element and even perhaps write a javascript inline without having to resort to a onload function. I am too lazy to change the code on my page though (don't fix it if it ain't broke).

No comments:

Post a Comment