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.
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">«</a> ]
<!-- First Page. -->
[ <a href="/pages">1</a> ]
<!-- Early (More Pages) Indicator. -->
[ … ]
<!-- 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. -->
[ … ]
<!-- Last Page. -->
[ <a href="/pages/blog-9">9</a> ]
<!-- Next Page. -->
[ <a href="/pages/blog-6" rel="next">»</a> ]
</nav>
Small Preview
This is the complete version.
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).
4: Navigation: Previous and Next
It is similar to our number pagination.
Navigation: Previous
<!-- Previous Page. -->
{% if paginator.previous_page %}
{% assign p_prev = paginator.previous_page_path
| prepend: site.baseurl %}
[ <a href="{{ p_prev }}" rel="prev">«</a> ]
{% else %}
[ « ]
{% endif %}
Navigation: Next
<!-- Next Page. -->
{% if paginator.next_page %}
{% assign p_next = paginator.next_page_path
| prepend: site.baseurl %}
[ <a href="{{ p_next }}" rel="next">»</a> ]
{% else %}
[ » ]
{% endif %}
5: Navigation: First and Last
It is different to our simple pagination. Although it is based on the same logic.
Navigation: First
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 %}
Navigation: Last
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 %}
[ … ]
{% 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 %}
[ … ]
{% 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">«</a> ]
{% else %}
[ « ]
{% 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 %}
[ … ]
{% 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 %}
[ … ]
{% 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">»</a> ]
{% else %}
[ » ]
{% 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.