Creating Categories in Blogger

Monday, August 07, 2006

Categorías dinámicas con Blogger

Presento a continuación una forma de crear categorías en los posts de Blogger. La idea se basa en el artículo How can I make show/hide links for my posts? aparecido en Blogger Help. Las entradas en el blog que pertenezcan a la categoría seleccionada se mostrarán y el resto se ocultan dinámicamente. Se puede saltar fácilmente de una categoría a otra. Un ejemplo de cómo funciona puede verse en mi otro blog: biominds.blogspot.com.

En primer lugar, se definen dos clases en la hoja de estilos (CSS), entre las tags o etiquetas <style> y </style> tags:

.posthidden {display:none}
.postshown {display:inline}



A continuación, añadimos el siguiente script entre las etiquetas <head> y </head>:
<script type="text/Javascript">
var numbers = new Array();
var dates = new Array();

function showcategory (tag) {

var reg = new RegExp(tag);
var showdate = new Array();
for (var i=numbers.length-1;i>=0;i--)
{
showdate[dates[numbers[i]]] = 0;
}

for (var i=numbers.length-1;i>=0;i--)
{
whichpost = document.getElementById(numbers[i]+'2');
mytags = whichpost.getElementsByTagName("tag");
hidepost = 1;
for(var j=mytags.length-1;j>=0;j--)
{
if (reg.test(mytags[j].getAttribute('label')))
{
hidepost = 0;
showdate[dates[numbers[i]]] = 1;
}
}
if (hidepost) {
whichpost.className="posthidden";
}
else {
whichpost.className="postshown";
}
}
for (var i=numbers.length-1;i>=0;i--)
{
whichdate = document.getElementById(dates[numbers[i]]);
if(showdate[dates[numbers[i]]]) {
whichdate.className="postshown";
} else {
whichdate.className="posthidden";
}
}
}

function listcategory (postid) {

whichpost = document.getElementById(postid);
mytags = whichpost.getElementsByTagName("tag");
for(var j=mytags.length-1;j>=0;j--)
{
label=mytags[j].getAttribute('label');
document.write('<a href="javascript:showcategory('
+"'"+label+"'"+')">'+label+'</a> ');
}
}

function sidebarcategories () {

var taghash = new Array();
var taglist = new Array();

document.write('<li><a href="javascript:showcategory('
+"''"+')">All</a></li>');
alltags = document.getElementsByTagName("tag");
for(var j=alltags.length-1;j>=0;j--)
{
taghash[alltags[j].getAttribute('label')]++;
}

for(x in taghash)
{
taglist[taglist.length] = x;
}

taglist.sort();
for(var j=0;j<taglist.length;j++)
{
count = taghash[taglist[j]];
document.write('<li><a href="javascript:showcategory('
+"'"+taglist[j]+"'"+')">'+taglist[j]+'</a> </li>');
}
}
</script>


Una vez hecho esto, hay que modificar la sección BlogDateHeader:
<BlogDateHeader>
<span class="postshown" id="$BlogDateHeaderDate$">
<script type="text/Javascript">currentdate ='<$BlogDateHeaderDate$>';</script>
<h2 class="date-header"><$BlogDateHeaderDate$></h2> </span>
</BlogDateHeader>


El siguiente paso es incluir el siguiente código al principio de la sección dedicada al post:
<!-- Begin .post -->

<span class="postshown" id="<$BlogItemNumber$2">
<script type="text/Javascript">
numbers[numbers.length] = '<$BlogItemNumber$>';
dates['<$BlogItemNumber$>']=currentdate;
</script>


Al final de la sección de post, puede añadirse una llamada a listcategory(), con lo cual se listarán las categorías a las que pertenece la entrada actual. Por otra parte, debe cerrarse la sección span que se había abierto:

<script type="text/Javascript"> listcategory('<$BlogItemNumber$>2');</script>
</div>
</span>
<!-- End .post -->


El paso final es colocar en la sidebar o barra lateral la lista de categorías:

<div class="Box">
<div class="Inner">
<h2 class="sidebar-title">Categories</h2>
<ul>
<script type="text/Javascript">sidebarcategories();</script>
</ul>
</div>
</div>

¿Cómo funciona?

Veamos cómo funcionan las categorías: cada vez que se añada un nuevo post, se puede asociar a este las etiquetas en HTML que se desee que aparezcan en la lista de categorías. Por ejemplo:
<tag label="hobbies"></tag> <tag label="music"></tag>


Los identificadores tag and label han sido elegidos de un modo un tanto arbitrario y pueden cambiarse por otros si fuera necesario.

¿Comentarios?

En esta entrada hemos dado simplemente una guía de referencia rápida. Estoy trabajando para publicar una descripción más detallada del código. Hasta ahora, este método me convence en cuanto que tiene muy buena respuesta interactiva, pero aún debería mejorarse en varios aspectos, especialmente es importante conseguir que este script muestre no sólo las categorías presentes en la página que se está mostrando, sino también en los mensajes anteriores guardados en los archivos.

Tuesday, August 01, 2006

"Ajax" in action

I've been playing for a while with the Ajax stuff. I think I will eventually work out the issue of having the complete categories list from the archives on the main page, but still need more testing.

For the moment, I copy below the Ajax Magic Spelling, and how to parse HTML code. Really impressive.



function getFile(pURL) {
if (window.XMLHttpRequest) { // code for Mozilla, Safari, etc
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=postFileReady;
xmlhttp.open("GET", pURL, true);
xmlhttp.send(null);
} else if (window.ActiveXObject) { //IE
xmlhttp=new ActiveXObject('Microsoft.XMLHTTP');
if (xmlhttp) {
xmlhttp.onreadystatechange=postFileReady;
xmlhttp.open('GET', pURL, false);
xmlhttp.send();
}
}
}

// function to handle asynchronous call
function postFileReady() {
if (xmlhttp.readyState==4) {
if (xmlhttp.status==200) {
document.getElementById('theDivToLoad').innerHTML=xmlhttp.responseText;
}
}
}



if (window.ActiveXObject){
vXMLDoc = new ActiveXObject("Microsoft.XMLDOM");
vXMLDoc.async = false;
//IE uses the loadXML method when the source document is NOT XML
vXMLDoc.loadXML(xmlhttp.responseText);
}else if(document.implementation.createDocument){
//Firefox requires a parser object to read the text
var vParser = new DOMParser();
vXMLDoc = vParser.parseFromString(xmlhttp.responseText, "text/xml");
}
if(vXMLDoc == null) alert("XML Doc Load Failed");

Keeping the quick guide updated

I've been testing and updating a little bit the code and the styles on this weblog. Any change will be always updated on the quick guide, so I keep the quick guide post as the main reference, and the welcome page.

Code internals

There are two global variables:
  • numbers : an array where we save the unique code assigned to each post by usign the span tag;
  • dates : a hash which has the post numbers as keys and their associated dates as values.

There are three functions in the script:
  • showcategory(tag): check for the tag in all posts, show the hits and hide the rest. Furthermore, show the dates for the hits;
  • listcategory(postid): list the categories for the current post;
  • sidebarcategories(tag): sort and list all the categories in the document;

Sunday, July 30, 2006

Browser dependences

Well, I know that the technologies that I am using (i.e. Javascript and the DOM model) are not completely standardized, and that we can expect strange behaviour in some browsers. I am happy to see that it is working on FireFox and Opera. Konqueror (the KDE windows manager browser) was not succesful.

I will check it on IE. I am assuming that it will also work on it, but I am not an expert in these issues...

Using categories in this blog

Blogger categories are now working in this blog, so it can be used as a demo of how it works, and you don't need to go to my other blog, which is a little bit cumbersome with mathml javascript stuff.

I have put another hack in this weblog, since my idea is that you find first the "quick guide" when you enter the main page, I have added the following script at the end of the post section:
<MainPage>
<script type="text/Javascript">showcategory('quick guide');</script>
</MainPage>
<ArchivePage>
<script type="text/Javascript">showcategory('');</script>
</ArchivePage>
<ItemPage>
<script type="text/Javascript">showcategory('');</script>
</ItemPage>

Therefore, you are now welcomed with the quick guide, and then you can navigate to the other posts, selecting the category on the sidebar.

Creating dynamic categories in Blogger

I am going to show you a way to create categories for your posts in Blogger. The idea is based on the article How can I make show/hide links for my posts? in Blogger Help. The posts belonging to the selected category are displayed, and the rest are dinamically hidden. You can easily jump from one category to another. You can see an example of how it works on this blog or on my another blog: biominds.blogspot.com.

First, of all, we define two clases on the style sheet (CSS), between the <style> and </style> tags:

.posthidden {display:none}
.postshown {display:inline}


Then, we add the following script between the <head> and </head> tags:
<script type="text/Javascript">
var numbers = new Array();
var dates = new Array();

function showcategory (tag) {

var reg = new RegExp(tag);
var showdate = new Array();
for (var i=numbers.length-1;i>=0;i--)
{
showdate[dates[numbers[i]]] = 0;
}

for (var i=numbers.length-1;i>=0;i--)
{
whichpost = document.getElementById(numbers[i]+'2');
mytags = whichpost.getElementsByTagName("tag");
hidepost = 1;
for(var j=mytags.length-1;j>=0;j--)
{
if (reg.test(mytags[j].getAttribute('label')))
{
hidepost = 0;
showdate[dates[numbers[i]]] = 1;
}
}
if (hidepost) {
whichpost.className="posthidden";
}
else {
whichpost.className="postshown";
}
}
for (var i=numbers.length-1;i>=0;i--)
{
whichdate = document.getElementById(dates[numbers[i]]);
if(showdate[dates[numbers[i]]]) {
whichdate.className="postshown";
} else {
whichdate.className="posthidden";
}
}
}

function listcategory (postid) {

whichpost = document.getElementById(postid);
mytags = whichpost.getElementsByTagName("tag");
for(var j=mytags.length-1;j>=0;j--)
{
label=mytags[j].getAttribute('label');
document.write('<a href="javascript:showcategory('
+"'"+label+"'"+')">'+label+'</a> ');
}
}

function sidebarcategories () {

var taghash = new Array();
var taglist = new Array();

document.write('<li><a href="javascript:showcategory('
+"''"+')">All</a></li>');
alltags = document.getElementsByTagName("tag");
for(var j=alltags.length-1;j>=0;j--)
{
taghash[alltags[j].getAttribute('label')]++;
}

for(x in taghash)
{
taglist[taglist.length] = x;
}

taglist.sort();
for(var j=0;j<taglist.length;j++)
{
count = taghash[taglist[j]];
document.write('<li><a href="javascript:showcategory('
+"'"+taglist[j]+"'"+')">'+taglist[j]+'</a> </li>');
}
}
</script>

After this, you have to modify your BlogDateHeader section:
<BlogDateHeader>
<span class="postshown" id="$BlogDateHeaderDate$">
<script type="text/Javascript">currentdate ='<$BlogDateHeaderDate$>';</script>
<h2 class="date-header"><$BlogDateHeaderDate$></h2> </span>
</BlogDateHeader>

Next step is to include the following code at the beginning of the post section:
<!-- Begin .post -->

<span class="postshown" id="<$BlogItemNumber$2">
<script type="text/Javascript">
numbers[numbers.length] = '<$BlogItemNumber$>';
dates['<$BlogItemNumber$>']=currentdate;
</script>

At the end of the post section, you can add a call to listcategory() which will list links to the categories of the current post, and you must close the span section:

<script type="text/Javascript"> listcategory('<$BlogItemNumber$>2');</script>
</div>
</span>
<!-- End .post -->

Our final step is to put also in the sidebar the list of categories:

<div class="Box">
<div class="Inner">
<h2 class="sidebar-title">Categories</h2>
<ul>
<script type="text/Javascript">sidebarcategories();</script>
</ul>
</div>
</div>

How it works?

Let's put the categories into play: every time you add a new post, you can add to it the HTML tags that you want to see in the list of categories. For instance:
<tag label="hobbies"></tag> <tag label="music"></tag>

I have somewhat arbitrarily chosen the identifiers tag and label, but you can change that in the script if you prefer another names.

Comments?

This post is just a quick guide. I am planning to post a more detailed description of the code. So far, I like its responsiveness and the way it gathers dynamically all the tag information. We can think on several ways to improve it. One issue is that the script is currently only showing the categories from the current posts on the main or archive page, but not for the complete archive.