Where to Discuss?

Local Group

Preface

Goal: Apply Glenn McComb Pagination using Hexo.

Source Code

You can download the source code of this article here.

Extract and run on CLI using $ npm install.


1: Source

I respect copyright. The code below copied, and pasted from:

I made a slight modification. But of course the logic remain the same.

I mostly write it down in my blog, because I do not want to forget what I learn. An easier place for me to find the modified version of this good code.


2: Preview: General

It is not easy to explain by words. Let me explain what we want to achive by using these images below. The blue box, is the active page. since we have 17 articles and 3 page for each pagination, then we have 9 pages of pagination. We have from first page (1), to last page (9).

Animation: Combined Version

This is the complete version. We will achieve this later.

Hexo Pagination: Combined Animation

Animation: Stripped Version

I’m following Glenn McComb code, combined with my own code, and this is the result.

Hexo Pagination: Adjacent Animation

Sample: An Example

Consider get one frame, a sample, because we need an example. This is what we want to achieve in this tutorial.

Hexo Pagination: Adjacent Page 5

HTML Preview

The HTML that we want to achieve in this article, is similar as below.

<nav class="pagination is-small is-centered" ...>
    <ul class="pagination-list">
      <li><a class="pagination-link" ...>3</a></li>
      <li><a class="pagination-link" ...>4</a></li>
      <li><a class="pagination-link is-current" >5</a></li>
      <li><a class="pagination-link" ...>6</a></li>
      <li><a class="pagination-link" ...>7</a></li>
    </ul>
</nav>

Or in detail, you can breakdown each as below:

<nav class="pagination is-small is-centered" 
     role="navigation" 
     aria-label="pagination">

    <ul class="pagination-list">

      <li>
        <a href="/blog/page/3"
           class="pagination-link"
           aria-label="Goto page 3">3
        </a>
      </li>

      <li>
        <a href="/blog/page/4" 
           class="pagination-link" 
           aria-label="Goto page 4">4
        </a>
      </li>

      <li>
        <a class="pagination-link is-current"
           aria-label="Page 5">5
        </a>
      </li>


      <li>
        <a href="/blog/page/6" 
           class="pagination-link" 
           aria-label="Goto page 6">6
        </a>
      </li>


      <li>
        <a href="/blog/page/7" 
           class="pagination-link" 
           aria-label="Goto page 7">7
        </a>
      </li>

    </ul>
</nav>

We will achieve this with Hexo code.

The Riddle

How do we achieve this ?


3: Prepare

This step is required.

Configuration

As usual.

# Home page setting
index_generator:
  path: '/blog'
  per_page    : 2
  order_by: -date

# Pagination
pagination_dir: page

Layout: EJS Index

Consider use pagination/03-adjacent layout, in index.ejs

Layout: Pagination Code Skeleton

This is just skeleton, as we will discuss this later.

// Variable Initialization.

<nav role="navigation" aria-label="pagination">
  <% if (page.total > 1) { %>
    <ul class="pagination-list">

    <% 
  var cursor; 
  for (cursor = 1; cursor <= page.total; cursor++) { 
    // Variable Initialization

    if (page.total > max_links) {
      // Complex page numbers.

      // Check between these three:
      // * Lower limit pages, or
      // * Upper limit pages, or
      // * Middle pages.

    } else {
      // Simple page numbers.
      ...
    }

    // Show Pager.
    ...

    <% } %>
    </ul>
  <% } %>
</nav>

4: Math: Basic Algebra

Assumption

Consider our previous example, a blog post contain seventeen posts. This time with two adjacent. It means, two indicators before selected page, and another two indicators after selected page,

# CONST

Total Post   = 17
Per Page     = 2

adjacent_links = 2

# COMPUTED

page.total   = 9

Equation

We should manually, do the math.

EQUATION

max_links   = (adjacent_links * 2) + 1 = 5
lower_limit =  1 + $adjacent_links     = 3
upper_limit =  9 - $adjacent_links     = 7

The real code is shown as below:

const adjacent_links = 2;
var current          = page.current;
var max_links        = (adjacent_links * 2) + 1;
var lower_limit      = 1 + adjacent_links;
var upper_limit      = page.total - adjacent_links;

Again, that source above are, ported from:

Table

The result is on this table below.

# ALGEBRA

+-------------+-------+-------+-------+-------+-------+
| pagination  |   2   |   3   |   5   |  10   |  20   |
+-------------+-------+-------+-------+-------+-------+
| VARIABLE                                            |
| page.total  |   9   |   6   |   4   |   2   |  N/A  |
| max_links   |   5   |   5   |   5   |   5   |  N/A  |
| lower_limit |   3   |   3   |   3   |   3   |  N/A  |
| upper_limit |   7   |   4   |   2   |   0   |  N/A  |
+-------------+-------+-------+-------+-------+-------+

5: Adjacent Code

This utilized show_cursor_flag with complex algorithm.

Skeleton

In every loop, this flag should be check first and use later.

    <% 
  var cursor; 
  for (cursor = 1; cursor <= page.total; cursor++) { 
    var show_cursor_flag = false;

    // Set Flag: Complex code.
    ...

    // Use Flag: Show Pager.
    ...
    <% } %>

Checking The Flag

This show_cursor_flag should be checked in every loop.

    <% 
  var cursor; 
  for (cursor = 1; cursor <= page.total; cursor++) { 
    var show_cursor_flag = false;

    if (page.total > max_links) {
      // Complex page numbers.

      if (current <= lower_limit) {
        // Lower limit pages.
        // If the user is on a page which is in the lower limit.
        if (cursor <= max_links) {
          // If the current loop page is less than max_links.
          show_cursor_flag = true;
        }
      } else if (current >= upper_limit) {
        // Upper limit pages.
        // If the user is on a page which is in the upper limit.
        if (cursor > (page.total - max_links)) {
          // If the current loop page is less than max_links.
          show_cursor_flag = true;
        }
      } else {
        // Middle pages.
        if ( (cursor >= current - adjacent_links) 
        &&   (cursor <= current + adjacent_links) ) {
          show_cursor_flag = true;
        }
      }
    } else {
      // Simple page numbers.
      show_cursor_flag = true;
    }

    // Show Pager.
    ...
    <% } %>

Using The Flag

And showing the number whenever the show_cursor_flag comes out. With similar code as previous article.

    <% 
  var cursor; 
  for (cursor = 1; cursor <= page.total; cursor++) { 
    var show_cursor_flag = false;

    if (page.total > max_links) {
      // Complex page numbers.
      ...
    }

    // Show Pager.
    if (show_cursor_flag) { %>
      <li>
        <% if (current != cursor) { %>
        <a href="<%= pagination_url(cursor) %>"
           class="pagination-link" 
           aria-label="Goto page <%= cursor %>">
          <%= cursor %>
        </a>
        <% } else { %>
        <a class="pagination-link is-current" 
           aria-label="Page <%= current %>">
          <%= current %>
        </a>
        <% } %>
      </li>
      <% } %>
    <% } %>

The Same Riddle

How does it works ?

Really! It is confusing.

Luckily, there is explanation for this, for the curious one.

Math in Details

I provide separate article with thorough explanation of the logic, used by this Glenn McComb Pagination.


What is Next ?

Consider continue reading [ Hexo - Pagination - Logic ]. There are, some interesting topic about Pagination in Hexo.

Thank you for reading.