Cory Foy

Sunday, January 27, 2008

Adding Pseudo Previous/Next links on Blogger

I've been using Blogger for my blog for a long time. Recently, my wife joined the Blogosphere with her entry called ToddleBITS. She started off on Blogger and moved over to our own domain - a nice feature that Blogger has whereby they simply FTP over the files for the blog posts.

Anyway, one thing I never noticed was that there was no "previous posts" link on the front page. In order to see older posts, you have to click on the archive links on the right hand side. I did see some ways around that if you are actually hosted on BlogSpot, but we aren't so those didn't apply.

But, I was able to write something that got pretty close. At the bottom of the front page (and all post pages) on her blog, you'll see:

December Posts | January Posts | February Posts

Hyperlinked to the appropriate archive page. And it isn't anything manual - it dynamically updates based on the oldest post on the page. So how did I do it?

Javascript to the Rescue

It's been a while since I've gotten to dig around with some good ol fashioned Javascript. I used to dig heavily into it, and had a lot of fun writing scripts. So I knew I could work some mojo there. I also knew that Blogger outputs the date of the post on the page. So, I figured that combining the two I could figure out what the earliest post on the page was, and then write out links based on that date.

The first trick was capturing the dates. As I said above, I knew that Blogger output the post date on the page, and would loop over that if there were multiple dates. So I fixed up a little Javascript function in the head of the HTML:

var lastPostDate = new Date();

function updateLastPostDate(postDate)
{
  lastPostDate = new Date(Date.parse(postDate));
}

It turns out that the format Blogger uses - "Sunday, January 27, 2008" - is parsable by Javascript's Date.parse function. That makes life a lot easier. But now that I've got the function, how do I call it?

Simple. You should have in your Blogger template something that looks like:

<BlogDateHeader>
<h2 class="date-header"><$BlogDateHeaderDate$></h2>
</BlogDateHeader>

This will be called for each date that has blog posts that will be displayed on the current page. I simply modified it to look like:

<BlogDateHeader>
<h2 class="date-header"><$BlogDateHeaderDate$></h2>
<script language="javascript">updateLastPostDate("<$BlogDateHeaderDate$>")</script>
</BlogDateHeader>

With that working, I knew the other non-JS modification I'd have to make was to display the nav links. I chose to put mine down at the bottom, so I found the part of the template where the main section ends:

</ItemPage>
  <!-- End #comments -->

</Blogger>

  <hr />
</div><!-- End #main-content -->

And changed it to:

</ItemPage>
  <!-- End #comments -->

</Blogger>

  <script language="javascript">writeNavLinks();</script>
</div><!-- End #main-content -->

Note that I put it outside the Blogger tag. That's important so that we aren't included in any of the loops it does.

With that out of the way, it was just a matter of parsing the current date, finding the previous and next months (making sure that the next month isn't past what today is) and outputting the links. So writeNavLinks looks like:

function writeNavLinks()
{
  previousMonthDate = new Date(lastPostDate);
  nextMonthDate = new Date(lastPostDate);

  previousMonthDate = new Date(previousMonthDate.setMonth(previousMonthDate.getMonth()-1));
  nextMonthDate = new Date(nextMonthDate.setMonth(nextMonthDate.getMonth()+1));

  previousLink = buildLink(previousMonthDate);
  currentLink = buildLink(lastPostDate);
  nextLink = buildLink(nextMonthDate);

  nextLinkText = "";
  if(shouldDisplayNextLink(nextMonthDate))
  {
    nextLinkText = nextLinkText = " | " + nextLink;
  }
  document.write(previousLink + " | " + currentLink + nextLinkText);
}

Pretty straightforward, eh? I did try using Date.prototype to add an addMonths method to the Date object, but ran into some issues and just stuck with TSTTCPW.

The full Javascript code is below. Just put it in the head part of your template, add the modifications above, and be sure to change your website. Have fun!

Updated 1/27/2008 11:54pm - Did some refactoring and added some additional functionality.

<script language="javascript">
/*********************************************
Code hacked together for this blog by Cory Foy
http://www.cornetdesign.com
Use at your own caution
*********************************************/
//Blogger Date Format: Sunday, November 27, 2005

var SITE_NAME = "http://www.toddlebits.com";
var BLOG_START_DATE = "12/16/2007";

var months = ["January", "February", "March", "April", "May", "June", "July",

"August", "September", "October", "November", "December"];

var lastPostDate = new Date();

function updateLastPostDate(postDate)
{
  lastPostDate = new Date(Date.parse(postDate));
}

function getYear(dateObj)
{
  //Fixup to be consistent across browsers
  var year = dateObj.getYear();
  if(year < 1900)
  {
    year += 1900;
  }
  return year;
}

function getRealMonth(dateObj)
{
  var calendarMonth = dateObj.getMonth() + 1;
  if(calendarMonth < 10)
  {
    return "0" + calendarMonth;
  }
  return calendarMonth;
}

function buildLink(dateObj)
{
  return '<a href="' + SITE_NAME + '/'
    + getYear(dateObj)
    + '_' + getRealMonth(dateObj)
    + '_01_archive.html">'
    + months[dateObj.getMonth()] 
    + ' Posts</a>';
}

function getPreviousLinkText(previousMonthDate, previousLink)
{
  blogStartDate = new Date(Date.parse(BLOG_START_DATE));
  blogStartDate.setDate(1);

  if(previousMonthDate < blogStartDate)
  {
     return "";
  }
  return previousLink + " | ";
}

function getNextLinkText(nextMonthDate, nextLink)
{
  today = new Date();
  if(nextMonthDate.getYear() > today.getYear()
    || (nextMonthDate.getYear() == today.getYear()
        && nextMonthDate.getMonth() > today.getMonth()))
  {
     return ""; 
  }
  return " | " + nextLink;
}

function writeNavLinks()
{
  previousMonthDate = new Date(lastPostDate);
  nextMonthDate = new Date(lastPostDate);

  previousMonthDate = new Date(previousMonthDate.setMonth(previousMonthDate.getMonth

()-1));
  nextMonthDate = new Date(nextMonthDate.setMonth(nextMonthDate.getMonth()+1));

  previousLink = buildLink(previousMonthDate);
  currentLink = buildLink(lastPostDate);
  nextLink = buildLink(nextMonthDate);

  previousLinkText = getPreviousLinkText(previousMonthDate, previousLink);
  nextLinkText = getNextLinkText(nextMonthDate, nextLink);
  document.write(previousLinkText + currentLink + nextLinkText);
}
</script>

5 Comments:

  • I find this article by google as I want to add something similar to my blogger. I'd like to ask is it possible to make a post list in the side bar which looks like (I only show 1 post in 1 page):

    title of second previous post
    title of previous post
    title of existing post
    title of next post
    title of second next post

    Looks like it has a similar function with your javascript here. I know only a little bit in javascript so I fail to modify your code to achieve my purpose.
    Can you please help me?

    By Anonymous Anonymous, at 8:41 AM  

  • Not that I know of. Javascript can't help you since it doesn't know what your posts are. I know that Blogger has a way to display the last x number of posts, but I don't know of a way to do what you are doing short of writing a server-side script (that you couldn't use if you were hosting on blogspot anyway)

    By Blogger Cory Foy, at 6:48 AM  

  • Thanks Cory. This code looks like it's really useful. Can I trouble you to mark up the final draft to show which bits goes where in our Blogger templates? That'd make a huge difference for JavaScript novices. Cheers.

    By Anonymous Steven Noble, at 11:07 PM  

  • Hi Steven,

    You can put the script (the main code) anywhere at the top of your template. Typically this needs to show up either after the head or body HTML tag, but wherever you see CSS definitions or other javascript is fine. It really just needs to be before the second script tag I put after the ending Blogger tag.

    You could head over to the site we used it on (http://www.toddlebits.com) and view source to see where it all ends up.

    By Blogger Cory Foy, at 11:16 PM  

  • Cheers! Got it working on my personal blog.

    By Anonymous Steven Noble, at 5:16 AM  

Post a Comment

Links to this post:

Create a Link

<< Home