We apologize for untranslated text, you can use the Google Translation button to get an automatic translation of the web page in the language of your choice.

JCMS 6 : Pagination avec le tag <jalios:pager>

L'affichage d'un grand nombre de données nécessite généralement une pagination (découpage par page) de ces données. C'est le rôle du tag <jalios:pager>.
JCMS 6.0 améliore le système de pagination en ajoutant des modèles de présentation et le support du rafraîchissement en Ajax (via Ajax-Refresh).

1. Principes de fonctionnement

Le tag <jalios:pager> gère tout ce qui est nécessaire à la pagination d'une collection de données.
Il produit l'interface de navigation dans les pages, les liens de tri, et s'occupe du décodage et de la validation des paramètres de pagination et de tri.

Il s'utilise en 2 appels pour les cas simples (lorsque la taille de la collection est connue dès le début) et 3 appels ou plus pour les cas avancés :

  • Initialisation
         <jalios:pager name='myPagerHandler' action='init' .../>
  • Calcul (optionnel)
         <jalios:pager name='myPagerHandler' action='compute' .../>
  • Affichage (multiples appels possibles)
       <jalios:pager name='myPagerHandler' />

Le tag produit un objet PagerHandler qui fournit les informations de pagination et de tri. Ces données sont notamment utilisé par les tag de requêtes (<jalios:query>) et d'itérations (<jalios:foreach>).

2. Utilisation du tag

Chacun des appels du tag <jalios:pager> doit préciser les attributs suivants :

  • name : qui identifie le pager et dont la valeur doit rester la même durant tous les appels. C'est également cet attribut qui définit le nom de la variable PagerHandler qui sera déclaré.
  • action : qui définit le comportement du pager, à spécifier parmi les valeurs suivantes :
    • "init" : initialisation des paramètres du pager,
    • "compute" : calcul des variables du pager en fonction du nombre d'élément à paginer (en précisant l'attribut size),
    • "display", "show..." : affichage des liens de paginations (c.f. "2.3 Affichage" ci-dessous).

Les deux attributs suivants doivent être déclarés une seule et unique fois sur l'ensemble des appels du tag :

  • size : indique la taille de la collection à paginer. Doit être fournit lors de l'action "init" OU "compute".
  • declare="true" : pour déclarer la variable PagerHandler dans le jsp. Cette variable permet ensuite référencer les informations de pagination et de tri lors de l'appel aux autres tags Jalios. L'attribut declare doit être fournit lors de l'action "init" OU "compute",

2.1 Initialisation (action "init")

Ce premier appel avec l'action "init" est requis. C'est lui qui permet d'initialiser le pager pour être réutilisé ensuite.

C'est dans ce premier appel que doivent être déclarés les attributs optionnels du pager :

  • pageSize : le nombre d'éléments à afficher par défaut (taille de la page),
    Cette valeur doit être homogène avec la valeur spécifié dans l'objet java effectuant la récupération des élément affichés (QueryHandler ou autre).
  • sort : le critère de tri par défaut (c.f. Publication.getComparator(String, boolean)),
  • reverse : sens de tri par défaut, (croissant/descendant),
  • pageSizes : les différentes tailles de page proposées dans ce pager,
  • pagerAllLimit : le valeur limite du "Tout en une page",
  • paramPrefix : préfixe utilisé dans les paramètres des urls générées. Cet attribut permet de différencier les pagers de collections différentes lorsqu'ils sont plusieurs dans la même page,
  • parameterMap : une Map de paramètres qui seront ajoutés dans les urls générées par le pager.

Les deux actions "init" et "compute" ont été scindées pour permettre l'utilisation du tag <jalios:query> entre les deux appels. Après ce premier appel, vous pouvez récupérer et utiliser les informations suivantes de l'objet PagerHandler :

  • Le critere de tri, getSort() ;
  • Le sens de tri (croissant/décroissant), isReverse()

    à transmettre au tag <jalios:query> via l'attribut "comparator", en utilisant un comparateur Java.
<jalios:query name='resultSet' types='Article'
 comparator='<%= Publication.getComparator(myPagerHandler.getSort(),
                                           myPagerHandler.isReverse()) %>'
/>

2.2 Calcul (action "compute")

Le second appel du tag avec l'action "compute" permet d'indiquer au pager le nombre d'éléments à paginer, via l'attribut size. Cet appel est inutile si l'attribut size a déjà été fourni lors du premier appel.

Après l'action "compute", l'objet PagerHandler permet d'obtenir les informations suivantes (pour l'itération) :

  • L'index de départ de l'itération des éléments, getStart() ;
    à transmettre au tag <jalios:foreach> via l'attribut "skip".
  • Le nombre d'éléments à afficher, c'est à dire la taille de la page courante, getPageSize() ;
    à transmettre au tag <jalios:foreach> via l'attribut "max".
<jalios:foreach name='itArticle' type='Article' collection='<%= resultSet %>'
                max='<%= myPagerHandler1.getPageSize() %>'
                skip='<%= myPagerHandler1.getStart() %>'>

D'autres informations sont également disponibles via l'objet PagerHandler, notamment :

  • isPagerAll() : pour savoir si le pager est actuellement en mode "tout en une page".
  • getItemsNbr() : pour connaître le nombre d'éléments paginés (== size).
  • getPagesNbr() : pour connaître le nombre de pages.
  • getCurrentPage() : pour connaître la page en cours d'affichage.
  • isFirstPage() : pour savoir si la page affichée est la première.
  • isLastPage() : pour savoir si la page affichée est la dernière.

2.3 Affichage

L'action "display" déclenche l'affichage complet du pager. C'est l'action par défaut lorsque l'attribut action n'est pas précisé.
Avec cette action, il est possible de préciser l'attribut template pour utiliser un gabarit de présention spécifique (c.f. "5.1 Gabarits de présentation" ci-dessous). Si l'attribut template n'est pas précisé, c'est la gabarit de présentation par défaut qui s'applique.

Les actions "show..." permettent l'affichage de tout ou parti du pager.
Ces actions n'utilisent pas les gabarits de présentation.

  • "showAll" : affichage complet du pager ;
  • "showFirst" : affichage du lien vers la première page ;
  • "showPrevious" : affichage du lien vers la page précédente ;
  • "showPages" : affichage des liens vers les différentes pages ;
  • "showNext" : affichage du lien vers la page suivante ;
  • "showLast" : affichage du lien vers la dernière page ;
  • "showSort" : affichage d'un lien de tri (en précisant l'attribut sort).
Les actions d'affichages doivent être appelées après les actions "init" et "compute".

3 Exemples

3.1 Exemple basique (2 actions)

Dans cet exemple, on utilise le pager dans sa configuration la plus simple. Avec les 2 actions principales du tag pager ("init", "showAll") et en utilisant la configuration par défaut (c.f. "4. Configuration") pour afficher l'ensemble des contenus du site.

pager_list
Pagination basique dans un tableau

<jalios:query name='resultSet' types='Content' />
<%--
Premier appel du pager, action "init"
=> declare='true': on demande au tag d'instancier une
variable PagerHandler myPagerHandler1,
=> On précise l'attribute size, pas besoin du second appel "compute".
--%>

<jalios:pager name='myPagerHandler1' declare='true' action='init'
size='<%= resultSet.size() %>'/>
<table border="1" cellspacing="0" cellpadding="2">
<%-- Itération paginée sur les résultats --%>
<jalios:foreach name='itContent' type='Content' collection='<%= resultSet %>'
max='<%= myPagerHandler1.getPageSize() %>'
skip='<%= myPagerHandler1.getStart() %>'>
  <tr>
    <td><%= myPagerHandler1.getStart() + itCounter.intValue() %></td>
    <td><%= itContent %></td>
  </tr>
</jalios:foreach>
<%-- Affichage du pager (action implicite showAll) --%>
  <tr><td colspan="2"> <jalios:pager name='myPagerHandler1' /> </td></tr>
</table>

3.2 Exemple simple (3 actions)

Dans cet exemple, on affiche l'ensemble des Articles du site dans un tableau où l'on propose à l'utilisateur des liens de tri. On utilise 3 actions principales du tag pager ("init", "compute", "showAll").

pager_table
Pagination simple dans un tableau

<%--
Premier appel du pager, action "init"
=> declare='true': on demande au tag d'instancier une
variable PagerHandler myPagerHandler2,
=> On ne précise pas l'attribute size
(on ne connait pas encore le nombre de publications).
=> Utilisation de la sdate (sort date) comme tri par défaut.
=> Utilisation d'un préfixe "p2_" pour le distinguer des autre pager de la page.
--%>

<jalios:pager name='myPagerHandler2' declare='true' action='init' sort='sdate' paramPrefix='p2_'/>
<%-- Utilisation du tag "jalios:query" avec les informations de tri renvoyées par le pager --%>
<jalios:query name='resultSet' types='Article'
comparator='<%= Publication.getComparator(myPagerHandler2.getSort(),
myPagerHandler2.isReverse()) %>'/>
<%--
Deuxième appel du pager "myPagerHandler2", action "compute"
=> On précise l'attribut size pour que le pager effectue
ses calculs internes pour les liens à générés
--%>

<jalios:pager name='myPagerHandler2' action='compute' size='<%= resultSet.size() %>'/>
<table class='listBorder' cellspacing='1' cellpadding='3'>
<tr>
<td class='listHeader'></td>
<td class='listHeader'>
<%-- Appel du tag avec l'action showSort pour générer des liens de tri dans l'entete du tableau --%>
<jalios:pager name='myPagerHandler2' action='showSort' sort='title'
sortTitle='ui.com.lbl.title'/>
</td>
<td class='listHeader'>
<jalios:pager name='myPagerHandler2' action='showSort' sort='sdate'
sortTitle='ui.com.lbl.sdate-long'/>
</td>
</tr>
<%-- Itération paginée sur les résultats --%>
<jalios:foreach name='itArticle' type='Article'
collection='<%= resultSet %>'
max='<%= myPagerHandler2.getPageSize() %>'
skip='<%= myPagerHandler2.getStart() %>'>
<tr class='<%= (itCounter.intValue() % 2 == 0) ? "listOddRow" : "listEvenRow" %>'>
<td><%= myPagerHandler2.getStart() + itCounter.intValue() %></td>
<td><%= itArticle.getTitle() %></td>
<td><jalios:date date='<%= itArticle.getSdate() %>'/> <jalios:time date='<%= itArticle.getSdate() %>'/></td>
</tr>
</jalios:foreach>
</table>
<%-- Affichage du pager (action implicite showAll) --%>
<jalios:pager name='myPagerHandler2' />

4. Paramétrage du comportement par défaut du tag

Les configurations ci-dessous s'appliquent comme valeur par défaut du tag <jalios:pager/> lorsqu'il est utilisé sans autre précision que ses attributs requis.

La modification de ces propriétés impact l'ensemble du site (front-office et back-office).

4.1 Taille des pages proposées

Par défaut, le pager affiche des tranches de 10, 20 ou 50 éléments par page.
Ces valeurs peuvent être changées en modifiant la propriété pager.page-sizes.

pager.page-sizes: 10 20 50

4.2 Limite du "Tout en une page"

Par défaut, le pager affiche un lien "Tout en une page" lorsque le nombre d'éléments à paginer n'excède pas 500 publications. Si le nombre d'éléments dépasse cette limite, le lien "Tout en une page" est remplacé par un lien pour afficher autant d'éléments que la limite.
Cette limite peut être changée en modifiant la propriété pager.pager-all-limit.

pager.pager-all-limit: 500

4.3 Taille de page par défaut

Par défaut, le pager afficher 10 éléments par page.
Cette valeur peut être changée en modifiant la propriété pager.default-page-size.

pager.default-page-size: 10

4.4 Tri par défaut

Le critère de tri est représenté par une chaîne de caractère identique à celles précisées dans les méthodes suivantes :

Les critères de tri les plus commun sont :

  • "cdate" : date de création ;
  • "mdate" : date de modification ;
  • "udate" : date de modification majeure ;
  • "pdate" : date de publication ;
  • "sdate" : date de tri ;
  • "title" : titre de la publication.

Le tri appliqué par défaut est vide, c'est donc le tri par date de création qui est utilisé.
Cette valeur peut être changé en modifiant la propriété pager.default-sort.

pager.default-sort: 

5. Modification de la présentation

Cette section explique comment modifier l'apparence du pager.

5.1 Ajout de garbarits de présentation

Depuis JCMS 6.0, il est possible d'utiliser le pager avec des gabarits de présentation dans vos interfaces.

Lors de l'appel du tag avec l'action display, il est possible de préciser l'attribut template : l'affichage du pager s'effectue alors en utilisant le JSP défini par la propriété pager.template.value, (value étant la valeur spécifiée pour l'attribut template).

Voici les 3 gabarits présent en standard :

pager.template.legacy:  /jcore/pager/pagerTemplateLegacy.jsp
pager.template.default: /jcore/pager/pagerTemplateDefault.jsp
pager.template.pqf:     /jcore/pager/pagerTemplateDefault.jsp

Pour définir et utiliser un gabarit de présentation :

1. Développement : Créez un JSP de présentation dans lequel vous incluez /jcore/doInitPage.jsp et /jcore/pager/pagerTemplateInit.jspf afin de bénéficier notamment des variables suivantes :
  • PagerHandler handler : l'objet PagerHandler créer par le tag.
  • int[] pagesLinksNbrs : les liens de pages à proposer à l'utilisateur (e.g: 3, 4, 5)
  • int[] pageSizes : les tailles de pages à proposer à l'utilisateur (e.g: 10, 20, 50)
  • String linkCss : les classes CSS à utiliser dans les liens (utilisées pour le rafraichissement ajax, cf section 6.1)
Inspirez-vous des gabarits existant pour mieux cerner l'utilisation de l'API.
Exemple (simpliste et minimaliste) dans /plugins/MyPlugin/jsp/myPagerTemplate.jsp :
<%@ include file='/jcore/doInitPage.jsp' %><%
%><%@ include file='/jcore/pager/pagerTemplateInit.jspf' %><%
%><div class="mypager"><%
for (int i = 0; i < pagesLinksNbrs.length ; i++) {
int pageNbr = pagesLinksNbrs[i];
%><a href="<%= handler.getPageLinkURL(pageNbr) %>" class="<%= linkCss %>" title="<%= glp("ui.pager.goto-page", pageNbr) %>"><%= pageNbr %></a> <%
}
%></div>

2. Déclaration : Ajoutez une propriété pointant vers votre JSP.
Exemple dans /WEB-INF/plugins/MyPlugin/properties/plugin.prop :
pager.template.mytemplate:     /plugins/MyPlugin/jsp/myPagerTemplate.jsp

3. Utilisation : Appelez le tag pager avec le nom de votre gabarit
<jalios:pager name="somePagerHandler" template="mytemplate" />

5.2 Liens de paginations

Il est possible de modifier l'apparance du pager uniquement en CSS si vous ne souhaitez pas développer un gabarit de présentation spécifique.

Copiez et surchargez les CSS du pager définis dans le fichier /css/jalios/misc.css  dans votre fichier CSS.

.pager { font-family: Arial, Helvetica, sans-serif; font-size: 9pt; color: black; text-align: center; }
.pager img { padding: 0px 3px; border: 0px solid transparent; }
.pager a { text-decoration: none; margin: 0px 0px; }
.pager a:hover { text-decoration: underline; color: #2B4D86; }
.pager .currentPage { }

5.3 Liens de tri

Lorsque vous utilisez l'action showSort, les liens de tri sont générés (en interne par le pager) de la façon suivante :

<a href='url-de-tri' title='{sort-text} {sort-order}'>{tag-sort-title} {sort-link}</a>

où :

  • {sort-text} correspond à la propriété ui.pager.sort.text.<sort> avec <sort> est remplacé par le mode de tri actuel (mdate par exemple).
  • {sort-order} correspond à une de ces propriétés :
    • ui.pager.sort.order.ascending, si tri est par ordre croissant.
    • ui.pager.sort.order.descending, si le tri est par ordre décroissant.
  • {tag-sort-title} est la valeur de l'attribut sortTitle du tag pager (optionnel).
  • {sort-link} correspond à une de ces propriétés :
    • ui.pager.sort.link.not-selected si le lien ne porte pas sur le tri actuellement en utilisation
    • ui.pager.sort.link.default si le lien porte sur le tri actuel, en ordre croisssant
    • ui.pager.sort.link.reverse si le lien porte sur le tri actuel, en ordre décroisssant

Pour modifier les liens de tri générés par le pager, récupérez ces différentes propriétés du pager dans les fichiers en.prop et fr.prop, et modifiez les dans vos fichiers de propriétés de plugin /WEB-INF/plugins/MyPlugin/properties/{lang}.prop .

Exemple pour modifier le texte de l'ordre de tri :

# [/WEB-INF/plugins/MyPlugin/properties/fr.prop]
ui.pager.sort.order.ascending: (ordre croissant)
ui.pager.sort.order.descending: (ordre décroissant)
# [/WEB-INF/plugins/MyPlugin/properties/en.prop]
ui.pager.sort.order.ascending: (ascending order)
ui.pager.sort.order.descending: (descending order)

6. Exemples avancés

6.1 Rafraichissement ajax (Ajax-Refresh)

Avec le gabarit de présentation par défaut, les liens de pagination déclenchent automatiquement un rafraichissement Ajax des portlets en front office (les liens utilisent la classe CSS "ajax-refresh"). 

Désactivation : Pour désactiver l'utilisation de ajax-refresh dans vos développements spécifiques, précisez une classe CSS (ou une chaine vide) dans l'attribut linkCss du tag (lors de l'appel avec l'action display).

Utilisation hors du portail : Si vous intégrez le pager dans une interface externe au portail, vous pouvez également bénéficier de cette mécanique en vous assurant de respecter les contraintes définies par Ajax-Refresh (c.f. articleAjax à paraître).

Note : Si vous développez un gabarit de présentation spécifique du pager, assurez-vous de bien réutilisez les classes linkCss dans vos liens de paginations.

6.2 Utilisation des actions de portlet

Par défaut, les informations de pagination sont récupérées par le pager depuis les paramètres HTTP. Ainsi en l'absence de ces paramètres dans l'URL, le pager ne conserve pas les informations de pagination (page courante, tri, etc.) sur toute la durée d'une session utilisateur.

Si vous souhaitez conserver ces informations de pagination pour l'utilisateur, indépendamment de son parcours sur le site, vous pouvez indiquer au tag <jalios:pager> de lire les paramètres depuis la session. Pour cela il faut préciser l'attribut paramPrefix du tag <jalios:pager> pour qu'il utilise la mécanique des "actions de portlet" de JCMS. Cette mécanique convertit tous les paramètres GET préfixés par une constante interne à JCMS en attributs de sessions.
Pour préciser l'attribut paramPrefix au tag <jalios:pager> il faut utiliser la méthode PortalManager.getActionParam(PortalElement, String) en lui précisant une action vide de telle sorte que seul le préfixe soit retourné :

Si le pager se trouve dans une portlet, vous pouvez récupérer le préfixe de cette façon :

  paramPrefix='<%= PortalManager.getActionParam(maPortlet, "") %>' />

Si le pager porte sur une liste d'éléments quelconques, vous pouvez récupérer un préfixe comme ceci :

  paramPrefix='<%= PortalManager.getActionParam(null, "") %>' />

Voici un exemple complet d'utilisation des actions de portlet pour le pager, où l'on affiche l'ensemble des pages web (WebPage) du site en conservant les informations de pagination dans la session :

<jalios:query name='wpResultSet' types='WebPage' />
<jalios:pager name='myPagerHandler3' declare='true' action='init'
size='<%= wpResultSet.size() %>'
paramPrefix='<%= PortalManager.getActionParam(null, "") %>' />
<jalios:foreach name='itWebPage' type='WebPage' collection='<%= wpResultSet %>'
max='<%= myPagerHandler3.getPageSize() %>'
skip='<%= myPagerHandler3.getStart() %>'>
<a href="<%= itWebPage.getUrl() %>"><%= itWebPage %></a><br>
</jalios:foreach>
<jalios:pager name='myPagerHandler3' />

6.3 Modifier les Portlets Requêtes/Itération pour ne pas utiliser des actions de portlet

Par défaut, les pagers qui se trouvent dans les portlets requêtes itération utilisent les actions de portlet (c.f "6.2 Utilisation des actions de portlet"). Ceci permet à la mécanique des caches de portail de JCMS de prendre en compte les changements de page de chacune des portlets. En effet, si une portlet est configurée pour utiliser un cache, alors l'affichage de la page 2 ne doit évidement pas réutiliser ce cache.

Cependant, pour des sites Internet, les caches peuvent parfois être gérés par un système de cache frontal distinct de JCMS. Dans ce cas là, et UNIQUEMENT dans ce cas là, il peut être souhaitable de modifier la mécanique des pagers de portlet JCMS, pour que les changements de page d'une portlet soient répercutés dans l'URL de navigation de telle sorte que le système de cache frontal puisse le prendre en compte.

Pour cela vous pouvez éditer le fichier types/PortletQueryForeach/doForeachHeader.jsp et modifier l'attribut paramPrefix du pager utilisé par les Portlet Requête/Itération comme suit :

Remplacez

paramPrefix='<%= PortalManager.PORTAL_ACTION+"_"+box.getId()+"_" %>'

par

paramPrefix='<%= "cache_"+box.getId()+"_" %>'

Et indiquer au système de cache frontal de prendre en compte les paramètres commençant par "cache_".

Il est IMPERATIF dans ce cas de ne pas utiliser les caches de JCMS qui ne fonctionneraient plus.

6.4 Surcharger les paramètres du pager

Comme nous l'avons vu précédemment, le pager récupère ses informations de pagination soit depuis les paramètres HTTP soit depuis les attributs de session. Il est cependant possible de forcer certaines de ces informations en ajoutant en attributs de requête les valeurs que l'on souhaite leur attribuer :

  request.setAttribute(com.jalios.jcms.handler.PagerHandler.FORCED_PARAM_PREFIX
+ prefixeDuPager + nomDuParametreAForcer,
valeurForcee);

nomDuParametreAForcer est l'une des valeurs suivantes :

  • "pageSize" : force la taille de la page
  • "sort" : force le critère de tri
  • "reverse" : force l'ordre de tri
  • "pagerAll" : force l'utilisation du mode "Tout en une page"
  • "start" : force l'index de départ de l'affichage (le premier élément de la page courante)

Note: les paramètres pageSize, sort et reverse, ne peuvent être forcés qu'avant l'action "init". Les paramètres pagerAll et start peuvent être forcés avant les actions "init" ou "compute".

Cas pratique: Vous souhaitez fournir un lien vers une page du portail dans laquelle se trouve une portlet requête/itération, et vous voudriez que ce lien positionne le pager de cette portlet directement à la page précise ou se trouve une publication donnée.

Première étape, dans un jsp, on génére une action de portlet pagerPubId (paramètre spécifique à cet exemple) :

<a href="display.jsp?id=j_5&amp;<%= PortalManager.getActionParam(null, "pagerPubId") %>=<%= pub.getId() %>">
<%= pub.getTitle(userLang) %>
</a>

Deuxième étape, on ajoute la récupération et le traitement de cette action de portlet, dans le gabarit de la portlet requête/itération (doPortletQueryForeachResults.jsp par exemple), juste avant l'inclusion du fichier doForeachHeader.jsp :

<%!
/**
* Returns the index in the collection of the first occurrence of the specified element,
* or -1 if the collection does not contain the element.
* @param coll the Collection in which to find the object.
* @param obj the Object to find.
* @return the index in the collection of the first occurrence of the specified element,
* or -1 if the collection does not contain the element.
*/
public int indexOf(Collection coll, Object obj) {
int index = 0;
for (Iterator it = coll.iterator(); it.hasNext(); index++) {
Object cur = it.next();
if (cur == obj) {
return index;
}
}
return -1;
}
%><%
// On lit et retire l'action de portlet
Publication pagerPub = channel.getPublication(PortalManager.removeAction(request, null, "pagerPubId"));
if (pagerPub != null) {
// on trouve l'index de la publication dans la collection de la portlet requête/itération
int pubIndex = indexOf(collection, pagerPub);
if (pubIndex != -1) {
// On force le paramètre start du pager, en utilisant bien le préfixe du
// pager tel qu'il est défini dans doForeachHeader.jsp
request.setAttribute(com.jalios.jcms.handler.PagerHandler.FORCED_PARAM_PREFIX +
PortalManager.getActionParam(box, "") + "start",
String.valueOf(pubIndex));

}
}
%>
<%@ include file='doForeachHeader.jsp' %>

Note: On utilise une action de portlet de telle sorte que l'action puisse être lue une seule et unique fois dans le gabarit de la portlet requête/itération, et immédiatement retirée grâce à PortalManager.removeAction(...), ceci afin de conserver la navigation du pager après le premier accès.