still flowing

energy, thoughts, flow


octopress endless pagination

04 december 2013
programming, web development

I’ve grown accustomed to endless pagination on my content websites: Reddit via Reddit Enhancement Suite, various tumblr and WordPress blogs via whatever plugins they use, Google image search, etc.

I wanted endless pagination for my blog, but couldn’t find a solution on the internets. I decided to roll my own. The solution relies on consistent structure of your layouts, which when it comes to octopress is very achievable and more or less built-in. If the JS looks like shit, that might be because it is. Let me know how I can improve!

I threw up the code snippets here, with some explication (and also with some Disqus code snippets that allow Disqus to work with this endless pagination solution). I hope to give a fairly thorough picture of what’s going on in this blog post.

Consider the layout of my blog:

<header/>
<nav/>
<section class='main'>
  <article class='post'>
    Post1
  </article>
  <article class='post'>
    Post2
  </article>
  <div class='pagination'>
    {% if paginator.previous_page and page.url != '/' %}
    <div class='previous'>
      <a href='{% paginator.previous_page %}'>Newer</a>
    </div>
    {% endif %}
    <span>{% paginator.page %} of {% paginator.total_pages %}</span>
    {% if paginator.next_page %}
    <div class='next'>
      <a href='{% paginator.next_page %}'>Older</a>
    </div>
    {% endif %}
  </div>
</section>
<footer/>

Pretty basic. Of importance is the pagination div, which has links to take you back a page and forwards a page, using octopress’ built-in paginator. The .next link is the one we’ll be using for endless pagination.

Let’s add endless pagination to this. Here’s the js to add to the document ready:

$(function() {
  var curPage = setupPage();

  if (window.location.pathname == '/') {
    if ($('.next')) {
      $('.next').appear();
      var loaded = false;
      $(document.body).on('appear', '.next', function(e, $affected) {
        if (!loaded) {
          loaded = true;
          $('.next').fadeOut(function() {
            loadNextPage();
            curPage++;
            window.location.replace('#' + curPage);
            loaded = false;
          });
        }
      });
    }
  }
});

Let’s see what’s going on here. The first thing that happens is a call to setupPage(). Here’s the setupPage function:

function setupPage() {
  var curPage = 1;

  if (window.location.pathname == '/') {
    var position = parseInt(window.location.hash.slice(1, window.location.hash.slice.length));  
    if (!isNaN(position)) {
      for (var i = 0; i < position-1; i++) {
        curPage++;
        loadNextPage(curPage);
        $(window).scrollTop($('.next').offset().top);
      }
    }

    window.location.replace('#' + curPage);
  }

  return curPage;
}

setupPage() is effectively responsible for reloading the user to the point of endless pagination they were at before (i.e. if a user goes forward and then back). The method loadNextPage() updates window.location whenever we scroll to a new page. setupPage() can then load the correct # of paginations based on the value stored at window.location. Using window.location.replace ensures the page history won’t be flooded with endless pagination urls (e.g. user won’t have to click back through stillflowing.com/#3, stillflowing.com/#2, and stillflowing.com/#1 to get to the page they were previously browsing).

The next bit of code actually handles the appear event:

if (window.location.pathname == '/') {
  if ($('.next')) {
    $('.next').appear();
    var loaded = false;
    $(document.body).on('appear', '.next', function(e, $affected) {
      if (!loaded) {
        loaded = true;
        $('.next').fadeOut(function() {
          loadNextPage();
          curPage++;
          window.location.replace('#' + curPage);
          loaded = false;
        });
      }
    });
  }
}

The loaded var was necessary because I found that jquery.appear was triggering multiple times per appearance; we only want this action to occur once per appearance of each .next link. Maybe I’m using it incorrectly? Please let me know if I am!

Almost there. Here’s loadNextPage():

function loadNextPage(pageNum) {
  url = pageNum == null ? $('.next').attr('href') : '/page/'+pageNum;
  $.get(url, function(data) {
    $('.next').remove();
    $('section').append($(data).filter('section').children());

    $('.previous').css('display', 'none');    
  });
}

We determine what page to load either based on the pageNum passed in (which is called in setupPage()), or from the .next link. This relies on octopress’s blog url structure; namely that it begins at /page/1, older posts on /page/2, etc. Then, do a get request to grab the next page’s html, remove the current .next link, and append the new posts to the current page. This line - $(‘section’).append($(data).filter(‘section’).children()); - is also reliant on the structure of my blog. recall:

<header/>
<nav/>
<section class='main'>
  <article class='post'>
    Post1
  </article>
  <article class='post'>
    Post2
  </article>
  <div class='pagination'/>
</section>
<footer/>

Thus, in the JS we grab only the post content (i.e. the article elements) and the pagination div and append those to the main section of the current page, extending the post section while keeping the header, nav, and footer intact.

And that’s a wrap! Once again, comments or criticism welcomed with open mind. alex@stillflowing.com

comments

the first post

26 november 2013
personal

Hello there. I’m Alex; still flowing is my blog.

Up to this point, this blog has been a coding/design exercise for me, using octopress, which is described as a “blogging framework for hackers” [read: you need to have some basic code skillz to run a blog here… the word ‘hacker’ is thrown away so willy-nilly these days, as if anyone who knows a little html and css is a hacker… but i digress].

Having gotten my front-end practice in (the blog template’s pretty much done), I’m going to try to actually use this blog. I own the .com, github pages is awesome and free, and it’s quite easy to spin up new blog posts with octopress. So we’ll see how this goes. I’m hoping to be able to share some of the programming whatnots I discover while coding, but also to share some of my other interests…

These interests include: programming, yoga, fitness, health, politics, music, guitar, photography, film/tv, technology, literature, philosophy, etc etc etc… ! ! I’ve always felt like I’ve been a “jack of all trades, master of none” kinda dude. I’ve always been interested in things but I guess have had trouble focusing my attention on one activity for an extended period of time. At 25 years old, I think I’m ready to start focusing. Being well-rounded is admirable, but in-depth, domain-specific knowledge is also very admirable. My lack of focus has stemmed, at least in part, from my perfectionism (“I’m not as good as him/her!”), my social anxiety (“Are they going to like this?!”), and probably just a bit of good ol’ ADD (i.e. “There’s so much cool shit in the world, what should I pay attention to?”). So, I think sharing here, on the internet, will be good for me- I’ll have that level of impersonality provided by the internet, so my ego is protected, and I’ll have an online journal, which hopefully will help me to consolidate and focus my interests and efforts.

Also, here’s some cats (Bill Murray derping on the left and Ocean on the right):

BTW: do any github pages users know why serving .png works but serving .jpg does not? nevermind. it was simply .JPG vs .jpg, duh.

comments