ssg  
Article Series

Jekyll in General

Jekyll Plain

Where to Discuss?

Local Group

Preface

Goal: Explaining Glenn McComb Pagination using Math and Table

Source Code

This article use tutor-05 theme. We will create it step by step.


1: Source

I respect copyright. Most of the code below, especially middle pagination, copied and pasted from:

The rest is my modification.


2: Prepare

Just a reminder.

Layout Liquid: Blog

Consider use pagination-v1/04-indicator.html partial, in _layouts/blog.html.

{% include pagination-v1/04-indicator.html %}

3: Preview: General

This is what we want to achieve in this tutorial.

Jekyll Pagination: Adjacent Pagination with Indicator

Structure

This consist of at least seven parts:

  • Previous Page: «

  • First Page: always 1

  • Left Indicator

  • Middle Pagination: Glenn McComb

  • Right Indicator

  • Last Page: always the same number

  • Next Page: »

We will not discuss about Middle Pagination, as it has already been discussed in previous article.

HTML Preview

The HTML that we want to achieve is similar as below.

<nav role="navigation">
    <!-- Previous Page. -->
      [ <a href="/pages/blog-4" rel="prev">&laquo;</a> ]

    <!-- First Page. -->
      [ <a href="/pages">1</a> ]
    <!-- Early (More Pages) Indicator. -->
      [ &hellip; ]

    <!-- Page numbers. -->
      [ <a href="/pages/blog-3">3</a> ]
      [ <a href="/pages/blog-4">4</a> ]
      [ 5 ]
      [ <a href="/pages/blog-6">6</a> ]
      [ <a href="/pages/blog-7">7</a> ]

    <!-- Late (More Pages) Indicator. -->
      [ &hellip; ]
    <!-- Last Page. -->
      [ <a href="/pages/blog-9">9</a> ]

    <!-- Next Page. -->
      [ <a href="/pages/blog-6" rel="next">&raquo;</a> ]
</nav>

Small Preview

This is the complete version.

Jekyll Pagination: Combined Animation

Partial: Indicator Skeleton

As usual, the skeleton, to show the complexity.

{% if totalPages > 1 %}
<nav role="navigation">

    <!-- Previous Page. -->
    <!-- First Page. -->
    <!-- Early (More Pages) Indicator. -->

    <!-- Page numbers. -->
    {% for page_cursor in (1..total_pages) %}
      <!-- Flag Calculation -->
      ...
      <!-- Show Pager. -->
      ...
    {% endfor %}

    <!-- Late (More Pages) Indicator. -->
    <!-- Last Page. -->
    <!-- Next Page. -->

</nav>
{% endif %}

Each Pagination

Consider again, have a look at the animation above, frame by frame.

We have from first page (1), to last page (9).

Jekyll Pagination: Indicator Page 1

Jekyll Pagination: Indicator Page 2

Jekyll Pagination: Indicator Page 3

Jekyll Pagination: Indicator Page 4

Jekyll Pagination: Indicator Page 5

Jekyll Pagination: Indicator Page 6

Jekyll Pagination: Indicator Page 7

Jekyll Pagination: Indicator Page 8

Jekyll Pagination: Indicator Page 9


4: Navigation: Previous and Next

It is similar to our number pagination.

    <!-- Previous Page. -->
    {% if paginator.previous_page %}
      {% assign p_prev = paginator.previous_page_path
                       | prepend: site.baseurl %}
      [ <a href="{{ p_prev }}" rel="prev">&laquo;</a> ]
    {% else %}
      [ &laquo; ]
    {% endif %}
    <!-- Next Page. -->
    {% if paginator.next_page %}
      {% assign p_next = paginator.next_page_path
                       | prepend: site.baseurl %}
      [ <a href="{{ p_next }}" rel="next">&raquo;</a> ]
    {% else %}
      [ &raquo; ]
    {% endif %}

5: Navigation: First and Last

It is different to our simple pagination. Although it is based on the same logic.

This will not be shown, if it is already be shown middle pagination.

    {% if total_pages > link_max %}
      <!-- First Page. -->
      {% if lower_offset > 1 %}
        [ <a href="{{ p_first }}">1</a> ]
      {% endif %}
    {% endif %}

This will not be shown, if it is already be shown middle pagination.

    {% if total_pages > link_max %}
      <!-- Late (More Pages) Indicator. -->
      {% if upper_offset < upper_indicator %}
        [ &hellip; ]
      {% endif %}
    {% endif %}

6: Indicator: Left and Right

These will only be shown, only if necessary.

Indicator: Left

    {% if total_pages > link_max %}
      <!-- Early (More Pages) Indicator. -->
      {% if lower_offset > lower_indicator %}
        [ &hellip; ]
      {% endif %}
    {% endif %}

Indicator: Right

    {% if total_pages > link_max %}
      <!-- Last Page. -->
      {% if upper_offset < total_pages %}
        [ <a href="{{ p_last }}">{{ total_pages }}</a> ]
      {% endif %}
    {% endif %}

7: Combined Code

It is about the right time to put all the code together.

Pagination v1

{% capture spaceless %}
  {% assign total_pages = paginator.total_pages %}
{% endcapture %}

<nav role="navigation">
  {% if total_pages > 1 %}

    <!-- Previous Page. -->
    {% if paginator.previous_page %}
      {% assign p_prev = paginator.previous_page_path
                       | prepend: site.baseurl %}
      [ <a href="{{ p_prev }}" rel="prev">&laquo;</a> ]
    {% else %}
      [ &laquo; ]
    {% endif %}

    {% capture spaceless %}
      <!--
        Pagination links 
        * https://glennmccomb.com/articles/how-to-build-custom-hugo-pagination/
      -->

      <!-- Get paginate_root from page in frontmatter -->
      {% if page.paginate_root == nil %}
        {% assign paginate_root = "/" %}
      {% else %}    
        {% assign paginate_root = page.paginate_root %}
      {% endif %}

      {% assign p_first = paginate_root 
                        | prepend: site.baseurl %}
      {% assign p_last = site.paginate_path
                       | relative_url 
                       | replace: ':num', total_pages %}

      {% assign page_current  = paginator.page %}

      {% assign link_offset   = 2 %}  
      {% assign link_max      = link_offset   | times: 2 | plus: 1 %}

      {% assign limit_lower   = link_offset   | plus: 1 %}
      {% assign limit_upper   = total_pages   | minus: link_offset %}
  
      {% assign min_lower     = link_max %}  
      {% assign max_upper     = total_pages   | minus: link_max %}
    
      {% assign lower_offset  = page_current  | minus: link_offset %}  
      {% assign upper_offset  = page_current  | plus: link_offset %}  

      {% assign lower_indicator = 2 %}
      {% assign upper_indicator = total_pages | minus: 1 %}

    {% endcapture %}

    {% if total_pages > link_max %}
      <!-- First Page. -->
      {% if lower_offset > 1 %}
        [ <a href="{{ p_first }}">1</a> ]
      {% endif %}

      <!-- Early (More Pages) Indicator. -->
      {% if lower_offset > lower_indicator %}
        [ &hellip; ]
      {% endif %}
    {% endif %}

    <!-- Page numbers. -->
    {% for page_cursor in (1..total_pages) %}

      {% capture spaceless %}
        <!-- Flag Calculation -->
        {% assign page_current_flag = false %}

        {% if total_pages > link_max %}
        <!-- Complex page numbers. -->

          <!-- Lower limit pages. -->
          <!-- If the user is on a page which is in the lower limit.  -->
          {% if page_current <= limit_lower %}
            <!-- If the current loop page is less than max_links. -->
            {% if page_cursor <= min_lower %}
              {% assign page_current_flag = true %}
            {% endif %}

          <!-- Upper limit pages. -->
          <!-- If the user is on a page which is in the upper limit. -->
          {% elsif page_current >= limit_upper %}
            <!-- If the current loop page is greater than total pages minus $max_links -->
            {% if page_cursor > max_upper %}
              {% assign page_current_flag = true %}
            {% endif %}

          <!-- Middle pages. -->
          {% else %}
          
            {% if (page_cursor >= lower_offset) and (page_cursor <= upper_offset) %}
              {% assign page_current_flag = true %}
            {% endif %}

          {% endif %}

        {% else %}
        <!-- Simple page numbers. -->

          {% assign page_current_flag = true %}
        {% endif %}
      {% endcapture %}

      <!-- Show Pager. -->
      {% if page_current_flag == true %}
        {% if page_cursor == page_current %} 
          [ {{ page_cursor }} ]
        {% else %}

          {% capture spaceless %}
          {% if page_cursor == 1 %}
            {% assign p_link = p_first %}
          {% else %}
            {% assign p_link = site.paginate_path
                             | relative_url
                             | replace: ':num', page_cursor %}
          {% endif %}
          {% endcapture %}

          [ <a href="{{ p_link }}">{{ page_cursor }}</a> ]
        {% endif %}
      {% endif %}

    {% endfor %}

    {% if total_pages > link_max %}
      <!-- Late (More Pages) Indicator. -->
      {% if upper_offset < upper_indicator %}
        [ &hellip; ]
      {% endif %}

      <!-- Last Page. -->
      {% if upper_offset < total_pages %}
        [ <a href="{{ p_last }}">{{ total_pages }}</a> ]
      {% endif %}
    {% endif %}

    <!-- Next Page. -->
    {% if paginator.next_page %}
      {% assign p_next = paginator.next_page_path
                       | prepend: site.baseurl %}
      [ <a href="{{ p_next }}" rel="next">&raquo;</a> ]
    {% else %}
      [ &raquo; ]
    {% endif %}

  {% endif %}
</nav>

Pagination v2

pagination-v2 code is slightly different.

While in pagination-v1, the last URL computed by this:

      {% assign p_last = site.paginate_path
                       | relative_url
                       | replace: ':num', total_pages %}

In pagination-v2, the last URL computed by this:

      {% assign p_last = site.pagination.permalink
                       | prepend: paginate_root
                       | relative_url
                       | replace: ':num', total_pages
       %}

What is Next ?

Consider continue reading [ Jekyll Plain - Plugin - Simple ].

Thank you for reading.