Search code examples
javascriptgruntjsassemble

How to provide a link to the 'next post'


In a blog project that I'm playing with I have 'posts'. Here's the assemble block from my Gruntfile:

assemble: {
  options: {
    layout: ['src/layouts/default.hbs'],
    data: ['src/data/*.{json,yml}']
  },
  pages: {
    src: ['src/posts/**/*.md'],
    dest: 'tmp/posts/'
  }
}    

Each post is represented in markdown, with a dash of YFM, like so:

---
date: '20131129'
latitude: 7.113309999999999
longitude: -73.120468
city: Bucaramanga
country: Colombia


---

# A familiar face...

And then more blog content here...

Now, in my default.hbs, I have the standard things. I did a quick {{inspect page}} to see what variables I have handy. I can see in there, I have a few pieces of information that could be useful in this matter:

 "index": 46,
 "next": 47,
 "prev":45

I can think of a way to handle this by writing a custom handlebars helper, but it seems that given the presence of those variables, this functionality already exists somewhere... I'm just not finding it. The solution I have in mind seems disproportionately complex.

Thanks a bunch!


Solution

  • I want to add this as "AN" answer, but hopefully not "THE" answer. Here is a handebars helper that I threw together in order to spit out a next path. This is the complete file with comments that probably make it look more intimidating than it is.

    var _ = require('underscore');
    
    var postPath = function(post){
      //pass a post object in, get back its path for linking
      var out = post['dest'].replace(/^tmp/, '');
      return out;
    };
    
    module.exports.register = function (Handlebars, options)  {
      Handlebars.registerHelper('nextPost', function (obj)  {
        var thisPage = obj['page']; // Created a local var for easier reading
    
        // The "this" object gets passed in as "obj" and contains an array of
        // pages. The trick is, this list isn't necessarily in order, even though
        // the folders are all named by date. Here I sort them. This seems rather
        // heavy handed, as the tax to process these increases exponentially with the
        // number of blog posts.
        // Also, I'm using underscore here to make the code much simpler.
        var sortedPages = _.sortBy(obj['pages'], function(page){ return page['data']['date']; });
    
        // Go through all of the sorted pages to find the matching data and get the index of where that is,
        // this way we can add one, to find the next element in the sorted array.
        var currentIndex = sortedPages.map(function(page) {return page['data']; }).indexOf(thisPage['data']);
        var nextIndex = currentIndex + 1;
        var out = '';
    
        // Don't wig out if it's the last one, just return a blank string instead.
        if (nextIndex > (sortedPages.length - 1)){
          out = '';
        }else{
          // Make a pretty path for use in our view
          out = postPath(sortedPages[nextIndex]);
        }
        return  out;
      });
    
    };
    

    A few of these lines can be taken out and put into their own methods for re-use for a "previousPost" helper method. But, something just stinks about this, and I would love it if someone could help me freshen it up, or point me in another direction.