Showing a post tree using jekyll

I’ve been playing with jekyll to create my website over the past few days. Primarily, I’m doing it to play with Ruby, but its also nice to have a new website :)

Jekyll produces a static site, but does this using templates and markup. Its remarkably easy to set up a site, and to give it the look and feel that you want. Any dynamic capability can be provided by external services (e.g. I use disqus for comments) and javascript.

One thing that I wanted to do was have a post tree in the sidebar. By Post Tree, I mean a tree showing all my previous posts, broken down by year and month. Have a look to the right here and you should see it. Jekyll doesn’t provide the ability to do it out of the box, but it is very easy to extend, so I thought I’d write a plugin to do it.

Here’s the code I wrote. The first file is the ruby plugin, which would be placed in _plugins/postsintree.rb . Its responsibility is to set up the data in a format that is easy for the template to output:

module Jekyll
  # Extends Site to have an field that gives you a map of posts by year.
  class Site
    def postsbyyear

      # Create a tree of the posts by year and then month
      tree = {}
      self.posts.each do |post|
	 year = post.date.year
	 month = post.date.month
         if tree[year] == nil
	    tree[year] = { "number" => year, 
			   "count" => 0, 
			   "months" =>  {} 
			 }
	 end
	 if tree[year]["months"][month] == nil
	    tree[year]["months"][month] = { "number" => month, 
					    "name"=>Date::ABBR_MONTHNAMES[month],  
					    "count" => 0, 
					    "posts" => [] 
					  }
	 end
	 
	 tree[year]["months"][month]["posts"] << post
      end

      # Turn the tree into sorted arrays, so it is easier to interpret
      # in liquid
      years = tree.values.sort { |x, y| y["number"] <=> x["number"] }

      # Calculate counts of posts and sort each of the months as well
      years.each do |year|
	year["months"] = year["months"].values.sort { |x, y| y["number"] <=> x["number"] }

	year["months"].each do |month| 
	    month["count"] = month["posts"].size
	    month["posts"] = month["posts"].sort {|x,y| y.date <=> x.date }
	end

	sum = 0
	year["months"].each {|month| sum += month["count"] }
	year["count"] = sum
      end
      return years
    end

    # Redefine site_payload to include our posts by year.  This is ugly
    # but I don't know how else to do this without changing the jekyll code
    # itself.  #rubynoob
    def site_payload
      {"site" => self.config.merge({
          "time"       => self.time,
          "posts"      => self.posts.sort { |a,b| b <=> a },
          "pages"      => self.pages,
          "html_pages" => self.pages.reject { |page| !page.html? },
          "categories" => post_attr_hash('categories'),
          "tags"       => post_attr_hash('tags'),
          "postsbyyear" => self.postsbyyear
       })}
    end

  end

end

Now that we have the data in the right format, its just a matter of altering our page template to show the tree. This is facilitated by the following HTML:

    <ul id="posttree">
	{% for year in site.postsbyyear %}
	<li>{{ year.number }} ({{ year.count }})
	<ul>
	    {% for month in year.months %}
	    <li> {{ ({{ month.count }})
	    <ul>
		{% for post in month.posts %}
		<li><a href="{{ post.url }}">{{</a></li>
		{% endfor %}
	    </ul>
	    </li>
	    {% endfor %}
	</ul>
	</li>
	{% endfor %}
    </ul>

The List is then translated into a clickable, expandable tree using the JQuery Treeview plugin

    $("#posttree").treeview({
	collapsed:true
    });

All of this is available at the GIT repostiory of my website, available at GitHub

Comments

blog comments powered by Disqus