<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!--
    Name: DATA SOURCE PAGINATION
    Version: 1.4
    Author: Nick Dunn <nick@nick-dunn.co.uk>
    URL: http://www.getsymphony.com/downloads/xslt/file/20482/

    Required Parameters:
    pagination:        XPath to the data source pagination element
    pagination-url:    URL used for page links, use $ as placeholder for the page number

    Optional Parameters:
    show-range:        Number of pages until the list gets shortened, defaults to 5
    show-navigation:   Show previous or next links, defaults to true()
    show-rotation:     Add rotation to next and previous links, defaults to false()
    label-next:        Custom "Next" label text
    label-previous:    Custom "Previous" label text

    Class options:
    class-pagination:  Class used for the pagination list
    class-page:        Class used for page items
    class-list-item:   Class used for list item
    class-next:        Class used for the next page link
    class-previous:    Class used for the previous page link
    class-selected:    Class used for the selected page
    class-disabled:    Class used for the disabled page link
-->

<xsl:template name="pagination">
    <xsl:param name="pagination" />
    <xsl:param name="pagination-url" />
    <xsl:param name="show-range" select="3" />
    <xsl:param name="show-navigation" select="true()" />
    <xsl:param name="show-rotation" select="false()" />
    <xsl:param name="label-next" select="'&#187;'" />
    <xsl:param name="label-previous" select="'&#171;'" />
    <xsl:param name="word-next" select="'Next'" />
    <xsl:param name="word-previous" select="'Previous'" />
    <xsl:param name="label-navigation" select="'Page navigation'" />
    <xsl:param name="class-pagination" select="'pagination'" />
    <xsl:param name="class-list-item" select="'page-item'" />
    <xsl:param name="class-page" select="'page-link'" />
    <xsl:param name="class-next" select="'page-link next'" />
    <xsl:param name="class-previous" select="'page-link previous'" />
    <xsl:param name="class-selected" select="'page-item current'" />
    <xsl:param name="class-ellipsis" select="'page-item ellipsis'" />
    <xsl:param name="class-disabled" select="'page-item disabled'" />
    <!-- Only show pagination if there are more than one page -->
    <xsl:if test="$pagination/@total-pages &gt; 1">
        <!-- Adjust range based on total page iterations -->
        <xsl:variable name="range">
            <xsl:choose>
                <xsl:when test="$show-range &lt; 3">3</xsl:when>
                <xsl:when test="$show-range &lt; $pagination/@total-pages">
                    <xsl:value-of select="$show-range" />
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$pagination/@total-pages - 1" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Current page -->
        <xsl:variable name="page-current">
            <xsl:choose>
                <xsl:when test="$pagination/@current-page = ''">1</xsl:when>
                <xsl:otherwise><xsl:value-of select="$pagination/@current-page" /></xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Previous page -->
        <xsl:variable name="page-previous">
            <xsl:choose>
                <xsl:when test="$page-current = 1"><xsl:value-of select="$pagination/@total-pages" /></xsl:when>
                <xsl:otherwise><xsl:value-of select="$page-current - 1" /></xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Next page -->
        <xsl:variable name="page-next">
            <xsl:choose>
                <xsl:when test="$page-current = $pagination/@total-pages">1</xsl:when>
                <xsl:otherwise><xsl:value-of select="$page-current + 1" /></xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Last range of page number -->
        <xsl:variable name="range-last">
            <xsl:value-of select="$pagination/@total-pages - $range + 1" />
        </xsl:variable>
        <!-- First page -->
        <xsl:variable name="page-first">
            <xsl:choose>
                <xsl:when test="$page-current &gt;= 1 and $page-current &lt; $range">
                    <xsl:text>1</xsl:text>
                </xsl:when>
                <xsl:when test="$page-current &gt; $range-last and $page-current &lt;= $pagination/@total-pages">
                    <xsl:value-of select="$range-last" />
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$page-current - (floor($range div 2))" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <!-- Last page -->
        <xsl:variable name="page-last">
            <xsl:value-of select="$page-first + $range - 1" />
        </xsl:variable>
        <nav aria-label="{$label-navigation}">
            <!-- Pagination -->
            <ul class="{$class-pagination}">
                <!-- Previous link -->
                <xsl:if test="$show-navigation = true()">
                    <xsl:if test="($pagination/@total-pages &gt; $show-range)">
                        <li class="{$class-list-item}">
                            <xsl:if test="$page-next = 2">
                                <xsl:attribute name="class">
                                    <xsl:value-of select="$class-disabled" />
                                </xsl:attribute>
                            </xsl:if>
                            <xsl:if test="$pagination/@current-page = 1">
                                <xsl:attribute name="class">
                                    <xsl:value-of select="$class-disabled" />
                                </xsl:attribute>
                            </xsl:if>
                            <xsl:choose>
                                <xsl:when test="$pagination/@current-page = 1">
                                    <span class="{$class-page}" aria-label="{$word-previous}">
                                        <xsl:value-of select="$label-previous" />
                                    </span>
                                </xsl:when>
                                <xsl:otherwise>
                                    <a class="{$class-previous}" aria-label="{$word-previous}">
                                        <xsl:if test="$page-next != 2 or $show-rotation = true()">
                                            <xsl:attribute name="href">
                                                <xsl:call-template name="pagination-url-replace">
                                                    <xsl:with-param name="string" select="$pagination-url"/>
                                                    <xsl:with-param name="search" select="'$'"/>
                                                    <xsl:with-param name="replace" select="string($page-previous)"/>
                                                </xsl:call-template>
                                            </xsl:attribute>
                                        </xsl:if>
                                        <span  aria-hidden="true">
                                            <xsl:value-of select="$label-previous" />
                                        </span>
                                    </a>
                                </xsl:otherwise>
                            </xsl:choose>
                        </li>
                    </xsl:if>
                </xsl:if>
                <!-- Page range -->
                <xsl:call-template name="pagination-numbers">
                    <xsl:with-param name="pagination-url" select="$pagination-url" />
                    <xsl:with-param name="page-first" select="$page-first" />
                    <xsl:with-param name="page-last" select="$page-last" />
                    <xsl:with-param name="page-current" select="$page-current" />
                    <xsl:with-param name="page-total" select="$pagination/@total-pages" />
                    <xsl:with-param name="class-page" select="$class-page" />
                    <xsl:with-param name="class-list-item" select="$class-list-item" />
                    <xsl:with-param name="class-selected" select="$class-selected" />
                    <xsl:with-param name="class-ellipsis" select="$class-ellipsis" />
                    <xsl:with-param name="iterations" select="$page-last - $page-first" />
                    <xsl:with-param name="class-disabled" select="$class-disabled"/>
                </xsl:call-template>
                <!-- Next link -->
                <xsl:if test="$show-navigation = true()">
                    <xsl:if test="($pagination/@total-pages &gt; $show-range)">
                        <li class="{$class-list-item}">
                            <xsl:if test="$page-next = 1">
                                <xsl:attribute name="class">
                                    <xsl:value-of select="$class-disabled" />
                                </xsl:attribute>
                            </xsl:if>
                            <xsl:choose>
                                <xsl:when test="$pagination/@current-page = $pagination/@total-pages">
                                    <span class="{$class-page}" aria-label="{$word-next}">
                                        <xsl:value-of select="$label-next" />
                                    </span>
                                </xsl:when>
                                <xsl:otherwise>
                                    <a class="{$class-next}" aria-label="{$word-next}">
                                        <xsl:if test="$page-next != 1 or $show-rotation = true()">
                                            <xsl:attribute name="href">
                                                <xsl:call-template name="pagination-url-replace">
                                                    <xsl:with-param name="string" select="$pagination-url" />
                                                    <xsl:with-param name="search" select="'$'" />
                                                    <xsl:with-param name="replace" select="string($page-next)" />
                                                </xsl:call-template>
                                            </xsl:attribute>
                                        </xsl:if>
                                        <span aria-hidden="true">
                                            <xsl:value-of select="$label-next" />
                                        </span>
                                    </a>
                                </xsl:otherwise>
                            </xsl:choose>
                        </li>
                    </xsl:if>
                </xsl:if>
            </ul>
        </nav>
    </xsl:if>
</xsl:template>

<!--
    PAGINATION NUMBERS
    Generate list of pages
-->
<xsl:template name="pagination-numbers">
    <xsl:param name="pagination-url" />
    <xsl:param name="page-first" />
    <xsl:param name="page-last" />
    <xsl:param name="page-current" />
    <xsl:param name="page-total" />
    <xsl:param name="class-page" />
    <xsl:param name="class-list-item" />
    <xsl:param name="class-selected" />
    <xsl:param name="class-ellipsis" />
    <xsl:param name="iterations" />
    <xsl:param name="class-disabled"/>
    <!-- Page number  -->
    <xsl:variable name="page" select="$page-last - $iterations" />
    <!-- Generate ellipsis at the beginning -->
    <xsl:if test="$page = $page-first and $page-first &gt; 1">
        <li class="{$class-list-item}">
            <a class="{$class-page}">
                <xsl:attribute name="href">
                    <xsl:call-template name="pagination-url-replace">
                        <xsl:with-param name="string" select="$pagination-url" />
                        <xsl:with-param name="search" select="'$'" />
                        <xsl:with-param name="replace" select="'1'" />
                    </xsl:call-template>
                </xsl:attribute>
                <xsl:text>1</xsl:text>
            </a>
        </li>
        <xsl:if test="$page != 2">
            <li class="{$class-ellipsis}" aria-hidden="true"><span class="{$class-page}">&#8230;</span></li>
        </xsl:if>
    </xsl:if>
    <!-- Generate page -->
    <li class="{$class-list-item}">
        <xsl:choose>
            <xsl:when test="$page = $page-current">
                <xsl:attribute name="class">
                    <xsl:value-of select="$class-selected" />
                </xsl:attribute>
                <a class="{$class-page}">
                    <xsl:attribute name="href">
                        <xsl:call-template name="pagination-url-replace">
                            <xsl:with-param name="string" select="$pagination-url" />
                            <xsl:with-param name="search" select="'$'" />
                            <xsl:with-param name="replace" select="string($page)" />
                        </xsl:call-template>
                    </xsl:attribute>
                    <xsl:attribute name="aria-current">
                        <xsl:text>page</xsl:text>
                    </xsl:attribute>
                    <xsl:value-of select="$page" />
                </a>
            </xsl:when>
            <xsl:otherwise>
                <a class="{$class-page}">
                    <xsl:attribute name="href">
                        <xsl:call-template name="pagination-url-replace">
                            <xsl:with-param name="string" select="$pagination-url" />
                            <xsl:with-param name="search" select="'$'" />
                            <xsl:with-param name="replace" select="string($page)" />
                        </xsl:call-template>
                    </xsl:attribute>
                    <xsl:value-of select="$page" />
                </a>
            </xsl:otherwise>
        </xsl:choose>
    </li>
    <!-- Generate ellipsis at the end -->
    <xsl:if test="$page = $page-last and $page-last &lt; $page-total">
        <xsl:if test="$page != ($page-total - 1)">
            <li class="{$class-ellipsis}" aria-hidden="true"><span class="{$class-page}">&#8230;</span></li>
        </xsl:if>
        <li class="{$class-list-item}">
            <a class="{$class-page}">
                <xsl:attribute name="href">
                    <xsl:call-template name="pagination-url-replace">
                        <xsl:with-param name="string" select="$pagination-url" />
                        <xsl:with-param name="search" select="'$'" />
                        <xsl:with-param name="replace" select="string($page-total)" />
                    </xsl:call-template>
                </xsl:attribute>
                <xsl:value-of select="$page-total" />
            </a>
        </li>
    </xsl:if>
    <!-- Generate next page number -->
    <xsl:if test="$iterations &gt; 0">
        <xsl:call-template name="pagination-numbers">
            <xsl:with-param name="pagination-url" select="$pagination-url" />
            <xsl:with-param name="page-first" select="$page-first" />
            <xsl:with-param name="page-last" select="$page-last" />
            <xsl:with-param name="page-current" select="$page-current" />
            <xsl:with-param name="page-total" select="$page-total" />
            <xsl:with-param name="class-page" select="$class-page" />
            <xsl:with-param name="class-list-item" select="$class-list-item" />
            <xsl:with-param name="class-selected" select="$class-selected" />
            <xsl:with-param name="class-ellipsis" select="$class-ellipsis" />
            <xsl:with-param name="iterations" select="$iterations - 1" />
            <xsl:with-param name="class-disabled" select="$class-disabled"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<!--
    PAGINATION URL
    Replace wildcard by page number
--> 
<xsl:template name="pagination-url-replace">
    <xsl:param name="string" />
    <xsl:param name="search" />
    <xsl:param name="replace" />

    <xsl:choose>
        <!-- Special case: page 1 → return basis URL without ?page=1 (avoid duplicate content) -->
        <xsl:when test="$replace = '1'">
            <xsl:value-of select="substring-before($string, '?')" />
        </xsl:when>
        <!-- all other pages -->
        <xsl:otherwise>
            <xsl:value-of select="concat(substring-before($string, $search), $replace, substring-after($string, $search))" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>
