Skip to content

Commit

Permalink
Merge pull request #16 from greystate/sorted-set
Browse files Browse the repository at this point in the history
Implement `sortBy` parameter for PaginationHelper
  • Loading branch information
greystate committed Aug 9, 2013
2 parents 8dd0fd4 + 302da85 commit 7ad0e3e
Show file tree
Hide file tree
Showing 13 changed files with 399 additions and 13 deletions.
2 changes: 2 additions & 0 deletions Release Notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Release Notes

* v0.8.5: Pagination Helper updated to 1.3
* v0.8.4: Pagination Helper updated to 1.2
* v0.8.3: Calendar Helper updated to 1.1, Media Helpers updated to 1.3
* v0.8.2: Media Helpers updated to 1.2
Expand All @@ -21,6 +22,7 @@

## Pagination Helper

* v1.3: Support sorting with pagination by way of the `sortBy` parameter
* v1.2: Use `pageLinksBeside` to specify number of links to show before & after current in the Pager
* v1.1: `perPage` parameter can now be overridden

Expand Down
2 changes: 1 addition & 1 deletion dist/xslt/_CalendarHelper.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- You need to set this to the name of the property/attribute on your event nodes that holds the "date" value -->
<!ENTITY eventDate "eventStartDateTime">
]>
<?umbraco-package XSLT Helpers v0.8.4 - CalendarHelper v1.1?>
<?umbraco-package XSLT Helpers v0.8.5 - CalendarHelper v1.1?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:umb="urn:umbraco.library" xmlns:freeze="http://xmlns.greystate.dk/2012/freezer" xmlns:date="urn:Exslt.ExsltDatesAndTimes" xmlns:make="urn:schemas-microsoft-com:xslt" version="1.0" exclude-result-prefixes="umb date make freeze">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
Expand Down
2 changes: 1 addition & 1 deletion dist/xslt/_GroupingHelper.xslt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<?umbraco-package XSLT Helpers v0.8.4 - GroupingHelper v1.0?>
<?umbraco-package XSLT Helpers v0.8.5 - GroupingHelper v1.0?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<!-- 'Groupify' template -->
Expand Down
2 changes: 1 addition & 1 deletion dist/xslt/_MediaHelper.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Enables simple retrieval of media by handling the GetMedia() call and error-checking
-->
<?umbraco-package XSLT Helpers v0.8.4 - MediaHelper v1.3?>
<?umbraco-package XSLT Helpers v0.8.5 - MediaHelper v1.3?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:umb="urn:umbraco.library" xmlns:freeze="http://xmlns.greystate.dk/2012/freezer" xmlns:get="urn:Exslt.ExsltMath" xmlns:make="urn:schemas-microsoft-com:xslt" xmlns:cropup="urn:Eksponent.CropUp" version="1.0" exclude-result-prefixes="umb get make cropup freeze">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
Expand Down
2 changes: 1 addition & 1 deletion dist/xslt/_NavigationHelper.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- You can change this to suit your environment -->
<!ENTITY subPages "*[@isDoc][not(@template = 0) and not(umbracoNaviHide = 1)]">
]>
<?umbraco-package XSLT Helpers v0.8.4 - NavigationHelper v1.1?>
<?umbraco-package XSLT Helpers v0.8.5 - NavigationHelper v1.1?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:umb="urn:umbraco.library" xmlns:freeze="http://xmlns.greystate.dk/2012/freezer" version="1.0" exclude-result-prefixes="umb freeze">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
Expand Down
68 changes: 64 additions & 4 deletions dist/xslt/_PaginationHelper.xslt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<?umbraco-package XSLT Helpers v0.8.4 - PaginationHelper v1.2?>
<?umbraco-package XSLT Helpers v0.8.5 - PaginationHelper v1.3?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:umb="urn:umbraco.library" xmlns:str="urn:Exslt.ExsltStrings" xmlns:make="urn:schemas-microsoft-com:xslt" version="1.0" exclude-result-prefixes="umb str make">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
Expand Down Expand Up @@ -52,7 +52,10 @@

<!-- This is the number of results you want per page -->
<xsl:param name="perPage" select="$perPage"/>


<!-- Specify which node() to sort by (as a string), e.g.: 'name', 'name DESC', '@updateDate ASC' etc. -->
<xsl:param name="sortBy"/>

<!-- Also, allow forcing specific options -->
<xsl:param name="options" select="$options"/>

Expand All @@ -65,8 +68,25 @@
<xsl:variable name="startIndex" select="$perPage * ($page - 1) + 1"/><!-- First item on this page -->
<xsl:variable name="endIndex" select="$page * $perPage"/><!-- First item on next page -->

<!-- Render the current page using apply-templates -->
<xsl:apply-templates select="$selection[position() &gt;= $startIndex and position() &lt;= $endIndex]"/>
<xsl:choose>
<!-- Do we need to pre-sort the selection? -->
<xsl:when test="normalize-space($sortBy)">
<xsl:variable name="sortedProxy">
<xsl:call-template name="preSort">
<xsl:with-param name="selection" select="$selection"/>
<xsl:with-param name="sortBy" select="$sortBy"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="sortedSelection" select="make:node-set($sortedProxy)/nodes/nodeId"/>
<xsl:apply-templates select="$selection[generate-id() = $sortedSelection[position() &gt;= $startIndex and position() &lt;= $endIndex]]">
<xsl:sort select="count($sortedSelection[. = generate-id(current())]/preceding-sibling::nodeId)" data-type="number" order="ascending"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<!-- Render the current page using apply-templates -->
<xsl:apply-templates select="$selection[position() &gt;= $startIndex and position() &lt;= $endIndex]"/>
</xsl:otherwise>
</xsl:choose>

<!-- Should we render the pager controls? -->
<xsl:if test="$showPager">
Expand Down Expand Up @@ -242,5 +262,45 @@
<xsl:value-of select="umb:RequestQueryString($key)"/>
</option>
</xsl:template>

<!-- Pre-sorting -->
<xsl:template name="preSort">
<xsl:param name="selection" select="/.."/>
<xsl:param name="sortBy"/>

<nodes>
<xsl:if test="normalize-space($sortBy)">
<xsl:variable name="sortNode">
<xsl:value-of select="substring-before($sortBy, ' ')"/>
<xsl:if test="not(contains($sortBy, ' '))">
<xsl:value-of select="$sortBy"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="sortDirection">
<xsl:value-of select="substring-after($sortBy, ' ')"/>
<xsl:if test="not(contains($sortBy, ' '))">
<xsl:value-of select="'ASC'"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="direction" select="translate(concat($sortDirection, 'ending'), 'ACDES', 'acdes')"/>
<xsl:choose>
<xsl:when test="starts-with($sortNode, '@')">
<xsl:apply-templates select="$selection" mode="presort">
<xsl:sort select="@*[name() = substring-after($sortNode, '@')]" data-type="text" order="{$direction}"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$selection" mode="presort">
<xsl:sort select="*[name() = $sortNode]" data-type="text" order="{$direction}"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</nodes>
</xsl:template>

<xsl:template match="*" mode="presort">
<nodeId><xsl:value-of select="generate-id()"/></nodeId>
</xsl:template>

</xsl:stylesheet>
23 changes: 23 additions & 0 deletions paginationhelper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@ output, you can turn them off with the `showPager` parameter by supplying `false
can manually output the controls by calling `RenderPager`, using the same `selection` parameter as you called the
`PaginateSelection` template with, to get the paging controls where you want them.

## Sorting the output

Sometimes, the data you want to paginate is actually also being sorted when rendered, e.g. like this common scenario:

```xslt
<xsl:apply-templates select="$currentPage/Textpage">
<xsl:sort select="@createDate" order="descending" />
</xsl:apply-templates>
```

The problem with introducing pagination here, is that most often you get the pagination happening *before* sorting, but you really want to *sort* the results first and then perform the pagination. For that you use the `sortBy` parameter:

```xslt
<xsl:call-template name="PaginateSelection">
<xsl:with-param name="selection" select="$currentPage/Textpage" />
<xsl:with-param name="sortBy" select="'@createDate DESC'" />
</xsl:call-template>
```

*Note that it's a string combining the name of the element or attribute to sort by and the direction (`ASC` or `DESC`), separated by a space. `ASC` is the default so you don't even need to specify the direction, unless it's `DESC`.*

It won't cover every scenario, e.g. it doesn't do numerical sorting yet, and you can only sort by a single element/attribute, where the element has to be a direct child of the node being sorted. Still, this should cover **a lot** of use cases.

## QueryString options

The pager links rendered will include all existing querystring options on the original page (i.e., "page 1"), so if
Expand Down
66 changes: 63 additions & 3 deletions paginationhelper/_PaginationHelper.xslt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@

<!-- This is the number of results you want per page -->
<xsl:param name="perPage" select="$perPage" />


<!-- Specify which node() to sort by (as a string), e.g.: 'name', 'name DESC', '@updateDate ASC' etc. -->
<xsl:param name="sortBy" />

<!-- Also, allow forcing specific options -->
<xsl:param name="options" select="$options" />

Expand All @@ -85,8 +88,25 @@
<xsl:variable name="startIndex" select="$perPage * ($page - 1) + 1" /><!-- First item on this page -->
<xsl:variable name="endIndex" select="$page * $perPage" /><!-- First item on next page -->

<!-- Render the current page using apply-templates -->
<xsl:apply-templates select="$selection[position() &gt;= $startIndex and position() &lt;= $endIndex]" />
<xsl:choose>
<!-- Do we need to pre-sort the selection? -->
<xsl:when test="normalize-space($sortBy)">
<xsl:variable name="sortedProxy">
<xsl:call-template name="preSort">
<xsl:with-param name="selection" select="$selection" />
<xsl:with-param name="sortBy" select="$sortBy" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="sortedSelection" select="make:node-set($sortedProxy)/nodes/nodeId" />
<xsl:apply-templates select="$selection[generate-id() = $sortedSelection[position() &gt;= $startIndex and position() &lt;= $endIndex]]">
<xsl:sort select="count($sortedSelection[. = generate-id(current())]/preceding-sibling::nodeId)" data-type="number" order="ascending" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<!-- Render the current page using apply-templates -->
<xsl:apply-templates select="$selection[position() &gt;= $startIndex and position() &lt;= $endIndex]" />
</xsl:otherwise>
</xsl:choose>

<!-- Should we render the pager controls? -->
<xsl:if test="$showPager">
Expand Down Expand Up @@ -262,5 +282,45 @@
<xsl:value-of select="&GetQueryStringValueForKey;" />
</option>
</xsl:template>

<!-- Pre-sorting -->
<xsl:template name="preSort">
<xsl:param name="selection" select="/.." />
<xsl:param name="sortBy" />

<nodes>
<xsl:if test="normalize-space($sortBy)">
<xsl:variable name="sortNode">
<xsl:value-of select="substring-before($sortBy, ' ')" />
<xsl:if test="not(contains($sortBy, ' '))">
<xsl:value-of select="$sortBy" />
</xsl:if>
</xsl:variable>
<xsl:variable name="sortDirection">
<xsl:value-of select="substring-after($sortBy, ' ')" />
<xsl:if test="not(contains($sortBy, ' '))">
<xsl:value-of select="'ASC'" />
</xsl:if>
</xsl:variable>
<xsl:variable name="direction" select="translate(concat($sortDirection, 'ending'), 'ACDES', 'acdes')" />
<xsl:choose>
<xsl:when test="starts-with($sortNode, '@')">
<xsl:apply-templates select="$selection" mode="presort">
<xsl:sort select="@*[name() = substring-after($sortNode, '@')]" data-type="text" order="{$direction}" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$selection" mode="presort">
<xsl:sort select="*[name() = $sortNode]" data-type="text" order="{$direction}" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</nodes>
</xsl:template>

<xsl:template match="*" mode="presort">
<nodeId><xsl:value-of select="generate-id()" /></nodeId>
</xsl:template>

</xsl:stylesheet>
27 changes: 27 additions & 0 deletions paginationhelper/test/PaginationHelperSortedSample.xslt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

<xsl:template match="/">
<body>
<xsl:apply-templates />
</body>
</xsl:template>

<xsl:template match="people">
<xsl:call-template name="PaginateSelection">
<xsl:with-param name="sortBy" select="'@nickname'" />
</xsl:call-template>
</xsl:template>

<xsl:template match="person">
<p>
<xsl:value-of select="name" />
</p>
</xsl:template>

<xsl:include href="../_PaginationHelper.xslt" />

</xsl:stylesheet>
Loading

0 comments on commit 7ad0e3e

Please sign in to comment.