Preface
Goal: Add indicator, and putting all pagination part together.
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. Most of the code below, especially middle pagination, copied and pasted from:
The rest is my modification.
2: Prepare
This step is required.
Configuration
As usual in Hexo - Pagination - Intro.
Layout: EJS Index
Consider use pagination/04-indicator layout, in index.ejs
-
- themes/tutor-05/layout/index.ejs
- gitlab.com/…/layout/index.ejs
<section class="section">
partial('pagination/04-indicator')
</section>
Layout: EJS Index for Screenshot
I omit the section tag for tutorial purpose, so that I can have enough width, for all pagination example, in 480px screen.
partial('pagination/04-indicator')
Layout: Minimal Pagination Code
You should have this minimal code, before you begin.
-
- themes/tutor-05/layout/pagination/04-indicator.ejs
- gitlab.com/…/layout/pagination/04-indicator.ejs.
<nav class="pagination is-small is-centered"
role="navigation" aria-label="pagination">
<% if (page.total > 1) { %>
<ul class="pagination-list">
<% if (page.total > max_links) { %>
...
<% } %>
</ul>
<% } %>
</nav>
Javascript: EJS Pagination Indicator
The javascript part is remain the same.
3: Preview: General
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 class="pagination is-small is-centered" ...>
<ul class="pagination-list">
<!-- Previous Page. -->
<li class="blog-previous"><a class="pagination-previous" ...>« </a></li>
<!-- First Page. -->
<li><a class="pagination-link" ...>1</a></li>
<!-- Early (More Pages) Indicator. -->
<li><span class="pagination-ellipsis">…</span></li>
<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>
<!-- Late (More Pages) Indicator. -->
<li><span class="pagination-ellipsis">…</span></li>
<!-- Last Page. -->
<li><a class="pagination-link" ...>9</a></li>
<!-- Next Page. -->
<li class="blog-next"><a class="pagination-next" ...> »</a></li>
</ul>
</nav>
Small Preview
This is the complete version.
Wide Preview
Wide version, in responsive context, is slightly different.
We will use responsive CSS later to achieve this effect.
Layout: Pagination Code Skeleton
As usual, the skeleton, to show the complexity.
-
- themes/tutor-05/layout/pagination/04-indicator.ejs
- gitlab.com/…/layout/pagination/04-indicator.ejs.
// Variable Initialization.
<nav role="navigation" aria-label="pagination">
<% if (page.total > 1) { %>
<ul class="pagination-list">
// Previous Page.
// First Page.
// Early (More Pages) Indicator.
<%
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.
...
<% } %>
// Late (More Pages) Indicator.
// Last Page.
// Next Page.
</ul>
<% } %>
</nav>
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: Variables: Initialization
Consider refresh our memory, about our variables initialization.
Javascript: EJS Pagination Indicator
The javascript part is remain similar. With a slight change, that this pagination is now capable of, handling many kind of standard pages [archive, category, tag].
/*
* Helper function
*/
function pagination_url(number) {
var path;
// default for index
var path = config.index_generator.path;
// dirty quick fix, avoid double (//)
if (path=='/') { path = '' }
if (is_archive()){
path = '/' + config.archive_dir;
if (is_month()){
// trailing zero
var month = ( page.month < 10 ? '0' + page.month : page.month );
path += '/' + page.year + '/' + month;
} else if (is_year()){
path += '/' + page.year;
}
} else if (is_category()){
path = '/' + config.category_dir + '/' + page.category;
} else if (is_tag()){
path = '/' + config.tag_dir + '/' + page.tag;
}
if (number>1) {
path = path + '/' + config.pagination_dir + '/' + number;
}
return url_for(path);
}
/*
* Pagination links
* https://glennmccomb.com/articles/how-to-build-custom-hugo-pagination/
* Adjacent: Number of links either side of the current page
*/
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;
- .
5: Navigation: Previous and Next
It is similar to our simple pagination. Except that, now we use dictionary.
Navigation: Previous
<!-- Previous Page. -->
<li class="blog-previous">
<% if (page.prev_link) { %>
<a class="pagination-previous"
href="<%= url_for(page.prev_link) %>"
rel="prev">« </a>
<% } else { %>
<a class="pagination-previous"
title="This is the first page"
disabled>« </a>
<% } %>
</li>
Navigation: Next
<!-- Next Page. -->
<li class="blog-next">
<% if (page.next_link) { %>
<a class="pagination-next"
href="<%= url_for(page.next_link) %>"
rel="next"> »</a>
<% } else { %>
<a class="pagination-next"
title="This is the last page"
disabled> »</a>
<% } %>
</li>
6: 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 (page.total > max_links) { %>
<% if (current - adjacent_links > 1) { %>
<!-- First Page. -->
<li>
<a href="<%= pagination_url(1) %>"
class="pagination-link"
aria-label="Goto page 1"
>1</a>
</li>
<% } %>
<% } %>
Navigation: Last
This will not be shown, if it is already be shown middle pagination.
<% if (page.total > max_links) { %>
<% if (current + adjacent_links < page.total) { %>
<!-- Last Page. -->
<li>
<a href="<%= pagination_url(page.total) %>"
class="pagination-link"
aria-label="Goto page <%= page.total %>"
><%= page.total %></a>
</li>
<% } %>
<% } %>
7: Indicator: Left and Right
These will only be shown, only if necessary.
Indicator: Left
<% if (page.total > max_links) { %>
<% if (current - adjacent_links > 2) { %>
<!-- Early (More Pages) Indicator. -->
<li>
<span class="pagination-ellipsis">…</span>
</li>
<% } %>
<% } %>
Indicator: Right
<% if (page.total > max_links) { %>
<% if (current + adjacent_links < page.total - 1) { %>
<!-- Late (More Pages) Indicator. -->
<li>
<span class="pagination-ellipsis">…</span>
</li>
<% } %>
<% } %>
8: Combined Code
It is about the right time to put all the code together.
-
- themes/tutor-05/layout/pagination/04-indicator.ejs
- gitlab.com/…/layout/pagination/04-indicator.ejs.
<%
/*
* Helper function
*/
function pagination_url(number) {
var path;
// default for index
var path = config.index_generator.path;
// dirty quick fix, avoid double (//)
if (path=='/') { path = '' }
if (is_archive()){
path = '/' + config.archive_dir;
if (is_month()){
// trailing zero
var month = ( page.month < 10 ? '0' + page.month : page.month );
path += '/' + page.year + '/' + month;
} else if (is_year()){
path += '/' + page.year;
}
} else if (is_category()){
path = '/' + config.category_dir + '/' + page.category;
} else if (is_tag()){
path = '/' + config.tag_dir + '/' + page.tag;
}
if (number>1) {
path = path + '/' + config.pagination_dir + '/' + number;
}
return url_for(path);
}
/*
* Pagination links
* https://glennmccomb.com/articles/how-to-build-custom-hugo-pagination/
* Adjacent: Number of links either side of the current page
*/
var current = page.current;
var adjacent_links = 2;
var max_links = (adjacent_links * 2) + 1;
var lower_limit = 1 + adjacent_links;
var upper_limit = page.total - adjacent_links;
%>
<nav class="pagination is-small is-centered"
role="navigation" aria-label="pagination">
<% if (page.total > 1) { %>
<ul class="pagination-list">
<!-- Previous Page. -->
<li class="blog-previous">
<% if (page.prev_link) { %>
<a class="pagination-previous"
href="<%= url_for(page.prev_link) %>"
rel="prev">« </a>
<% } else { %>
<a class="pagination-previous"
title="This is the first page"
disabled>« </a>
<% } %>
</li>
<% if (page.total > max_links) { %>
<% if (current - adjacent_links > 1) { %>
<!-- First Page. -->
<li>
<a href="<%= pagination_url(1) %>"
class="pagination-link"
aria-label="Goto page 1"
>1</a>
</li>
<% } %>
<% if (current - adjacent_links > 2) { %>
<!-- Early (More Pages) Indicator. -->
<li>
<span class="pagination-ellipsis">…</span>
</li>
<% } %>
<% } %>
<%
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.
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>
<% } /* if */ %>
<% } /* for */ %>
<% if (page.total > max_links) { %>
<% if (current + adjacent_links < page.total - 1) { %>
<!-- Late (More Pages) Indicator. -->
<li>
<span class="pagination-ellipsis">…</span>
</li>
<% } %>
<% if (current + adjacent_links < page.total) { %>
<!-- Last Page. -->
<li>
<a href="<%= pagination_url(page.total) %>"
class="pagination-link"
aria-label="Goto page <%= page.total %>"
><%= page.total %></a>
</li>
<% } %>
<% } %>
<!-- Next Page. -->
<li class="blog-next">
<% if (page.next_link) { %>
<a class="pagination-next"
href="<%= url_for(page.next_link) %>"
rel="next"> »</a>
<% } else { %>
<a class="pagination-next"
title="This is the last page"
disabled> »</a>
<% } %>
</li>
</ul>
<% } %>
</nav>
- .
9: Responsive: Simple
Before we continue to the next pagination article about responsive, consider having this very simple example using bulma.
This will show the word previous and next for tablet page.
SASS: Custom Pagination
I’m using Bulma breakpoints.
-
- themes/tutor-05/sass/css/_pagination.scss
- gitlab.com/…/sass/_pagination.scss.
+tablet
li.blog-previous a:after
content: " previous"
li.blog-next a:before
content: "next "
SASS: Bulma Breakpoint Variables.
Bulma 0.7 breakpoints are defined as below.
- themes/tutor-05/sass/vendors/bulma/utilities/initial-variables.sass
// The container horizontal gap,
// which acts as the offset for breakpoints
$gap : 64px !default
$tablet : 769px !default
$desktop : 960px + (2 * $gap) !default
$widescreen : 1152px + (2 * $gap) !default
$fullhd : 1344px + (2 * $gap) !default
What is Next ?
Consider continue reading [ Hexo - Pagination - Responsive ]. There are, some interesting topic about Pagination in Hexo.
Thank you for reading.