I am developing a blog using the RainLab.Blog plugin where I want the Post List component to paginate with 7 posts a page. However, the default output for the pagination does not include ellipsis to shorten the pagination, so I tried copying this snippet from the forum plugin which works very well, this is my implementation:
<div class="pagination">
{% if posts.currentPage > 1 %}
<a href="{{ this.page.baseFileName | page({ (blogPosts.pageParam): (posts.currentPage - 1) }) }}" class="previous">Prev</a>
{% endif %}
{# How many pages to display around the current page #}
{% set radius = 1 %}
{% set startOffset = max((posts.currentPage - 1) - radius, 0) %}
{% if (startOffset + 2 * radius + 1) > (posts.lastPage - 1) %}
{% set startOffset = max(posts.lastPage - 2 * radius - 1, 0) %}
{% endif %}
{% set pageLinks = [] %}
{% for page in 1..posts.lastPage %}
{% set pageLinks = pageLinks | merge([page]) %}
{% endfor %}
{% set activeBlock = pageLinks | slice(startOffset, 2 * radius + 1) %}
{% set pageSet = [] %}
{% if startOffset > 0 %}
{% set pageSet = pageSet | merge([1]) %}
{% if startOffset > 1 %}
{% set pageSet = pageSet | merge(['...']) %}
{% endif %}
{% endif %}
{% set pageSet = pageSet | merge(activeBlock) %}
{% set diffToEnd = (posts.lastPage - 1) - (startOffset + 2 * radius + 1) + 1 %}
{% if diffToEnd > 0 %}
{% if diffToEnd > 1 %}
{% set pageSet = pageSet | merge(['...']) %}
{% endif %}
{% set pageSet = pageSet | merge([posts.lastPage]) %}
{% endif %}
{% for page in pageSet %}
{% if page == '...' %}
<span class="extra">…</span>
{% else %}
<a href="{{ this.page.baseFileName | page({ (blogPosts.pageParam): page }) }}" class="page {{ posts.currentPage == page ? 'active' : null }}">{{ page }}</a>
{% endif %}
{% endfor %}
{% if posts.lastPage > posts.currentPage %}
<a href="{{ this.page.baseFileName | page({ (blogPosts.pageParam): (posts.currentPage + 1) }) }}" class="next">Next</a>
{% endif %}
</div>
Results
This implementation gets me very far in the sense that the pagination is no longer outputting every single page as a link, but as I find the reference code not very self-documenting, I’m struggling to tweak it to suit my needs.
Desired Outcome
I want not only the current page to be padded with two page links in either direction, but also on both ends of the pagination.
So instead of something like this:
< Prev 1 … 14 15 16 17 18 … 100 Next >
I want something like this:
< Prev 1 2 3 … 14 15 16 17 18 … 98 99 100 Next >
How would I go about padding by two pages from the first page and last page?
Cheers, guys.
This is a tough one. The current logic is designed to build a middle set of pages and use the first and last pages as endcaps - 1 and posts.lastPage. Expanding the end caps to be three pages in length would require a rewrite of this logic.
However, you might be able to tweak the current code to expand the endcaps to a predefined set of padded numbers - [1,2,3] and [lastPage - 2, lastPage - 1, lastPage].
It’s not a perfect solution but might give some ideas. First define the size of the endcaps.
{% set padding = 3 %}
Then define them using a counter, and include logic to exclude page numbers we already know about (activeBlock).
{% set activeBlock = pageLinks | slice(startOffset, 2 * radius + 1) %}
{% set startBlock = [] %}
{% for pad in 1..padding %}
{% if pad not in activeBlock %}
{% set startBlock = startBlock | merge([pad]) %}
{% endif %}
{% endfor %}
{% set endBlock = [] %}
{% for pad in padding..1 %}
{% if posts.lastPage - pad + 1 not in activeBlock %}
{% set endBlock = endBlock | merge([posts.lastPage - pad + 1]) %}
{% endif %}
{% endfor %}
Then instead of merging in a static endcap, we merge in the new ones we created.
{% set pageSet = pageSet | merge([1]) %}{# old endcap #}
{% set pageSet = pageSet | merge(startBlock) %}{# new endcap #}
{% set pageSet = pageSet | merge([posts.lastPage]) %}{# old endcap #}
{% set pageSet = pageSet | merge(endBlock) %}{# new endcap #}
Here is a complete example:
{% if posts.currentPage > 1 %}
<a href="{{ this.page.baseFileName | page({ page: (posts.currentPage - 1) }) }}" class="previous">Prev</a>
{% endif %}
{# How many pages to display around the current page #}
{% set radius = 1 %}
{# How many pages to display at the start and end #}
{% set padding = 3 %}
{% set startOffset = max((posts.currentPage - 1) - radius, 0) %}
{% if (startOffset + 2 * radius + 1) > (posts.lastPage - 1) %}
{% set startOffset = max(posts.lastPage - 2 * radius - 1, 0) %}
{% endif %}
{% set pageLinks = [] %}
{% for page in 1..posts.lastPage %}
{% set pageLinks = pageLinks | merge([page]) %}
{% endfor %}
{% set activeBlock = pageLinks | slice(startOffset, 2 * radius + 1) %}
{% set startBlock = [] %}
{% for pad in 1..padding %}
{% if pad not in activeBlock %}
{% set startBlock = startBlock | merge([pad]) %}
{% endif %}
{% endfor %}
{% set endBlock = [] %}
{% for pad in padding..1 %}
{% if posts.lastPage - pad + 1 not in activeBlock %}
{% set endBlock = endBlock | merge([posts.lastPage - pad + 1]) %}
{% endif %}
{% endfor %}
{% set pageSet = [] %}
{% if startOffset > 0 %}
{% set pageSet = pageSet | merge(startBlock) %}
{% if startOffset > 1 + padding %}
{% set pageSet = pageSet | merge(['...']) %}
{% endif %}
{% endif %}
{% set pageSet = pageSet | merge(activeBlock) %}
{% set diffToEnd = (posts.lastPage - 1) - (startOffset + 2 * radius + 1) + 1 %}
{% if diffToEnd > 0 %}
{% if diffToEnd > 1 %}
{% set pageSet = pageSet | merge(['...']) %}
{% endif %}
{% set pageSet = pageSet | merge(endBlock) %}
{% endif %}
{% for page in pageSet %}
{% if page == '...' %}
<span class="extra">…</span>
{% else %}
<a href="{{ this.page.baseFileName | page({ page: page }) }}" class="page {{ posts.currentPage == page ? 'active' : null }}">{{ page }}</a>
{% endif %}
{% endfor %}
{% if posts.lastPage > posts.currentPage %}
<a href="{{ this.page.baseFileName | page({ page: (posts.currentPage + 1) }) }}" class="next">Next</a>
{% endif %}