2017-06-06 2 views
0

Ce que je voulais réaliser dans une application récente était d'utiliser ma propre pagination - j'ai donc besoin de savoir combien de documents sont dans une vue (catégorisée) pour calculer les pages nécessaires.Xpages Répétition Contrôle/Documents from View - meilleure pratique

<xp:repeat id="repeat1" rows="30" 
       value="#{javascript:viewScope.counterArray}" 
       indexVar="counter" var="row" disableTheme="true" 
       removeRepeat="true"> 
       <li> 
        <xp:link escape="true" 
         text="#{javascript:(counter + 1) + ' (' + row.toString() + ')'}" id="link3" 
         disableTheme="true"> 
         <xp:eventHandler event="onclick" 
          submit="true"> 
          <xp:this.action> 
           <xp:executeScript> 
            <xp:this.script><![CDATA[#{javascript:viewScope.put("repeatFirstIndex", row);}]]></xp:this.script> 
           </xp:executeScript> 
          </xp:this.action> 
         </xp:eventHandler> 
        </xp:link> 
       </li> 
      </xp:repeat> 

Becaue de this known problem je dois faire une solution de contournement, interroger le nombre de documents via une commande de répétition.

<xp:repeat id="blindRepeat" rows="0" value="#{viewStories}"></xp:repeat> 

J'utilise this sample code pour obtenir le bon nombre d'itérations pour le contrôle de répétition.

<xp:this.beforePageLoad><![CDATA[#{javascript: 
var counterArray = []; 
var numberOfStories = getComponent("blindRepeat").getRowCount(); 
var numberOfPagesNecessary = Math.ceil(numberOfStories/sessionScope.get("ListPagerPerPage")); 
for (var i = 0; i < (numberOfPagesNecessary - 1); i++) { 
    counterArray[i] = i*sessionScope.get("ListPagerPerPage"); 
    viewScope.lastPage = i*sessionScope.get("ListPagerPerPage"); 
} 
viewScope.counterArray = counterArray;}]]></xp:this.beforePageLoad> 

Mais ici est là que je lance dans un Catch 22: Je ne peux utiliser un contrôle de répétition, parce que je ne peux pas obtenir le nombre richt de documents de la vue directement, comme Knut Herrmann (1) fait, mais le contrôle de répétition n'est pas disponible, donc je ne peux pas l'utiliser comme le propose Per Henrik Lausten (2). Un collègue a proposé de remplir le tableau dans un bloc de script imbriqué derrière le contrôle de répétition aveugle (donc il devrait être dessiné) mais avant le contrôle de répétition de pagination (donc viewScope devrait contenir les bons chiffres), mais cette solution semble plutôt floconneux pour moi.

Je suis curieux s'il y a une « meilleure pratique » pour ce genre de situation - Je voudrais résoudre ce bien et non d'une manière qui dépend de l'exécution en temps opportun de javascript

+0

Et la raison pour laquelle vous ne voulez pas utiliser le '' est? – shillem

+0

Parce que le (comme de nombreux éléments xp:) ne peut pas être adapté pour ressembler à la pagination dans le modèle que j'ai reçu –

+1

Ce n'est pas vrai: vous pouvez utiliser une combinaison d'instructions de thème et de moteurs de rendu personnalisés. – shillem

Répondre

3

Considéré comme le raison pour laquelle vous avez donné le commentaire à votre question, je vous suggère d'implémenter votre propre moteur de rendu personnalisé pour le pager.

Dans le faces-config.xml Déclarons ce qui suit:

<render-kit> 
    <renderer> 
     <component-family>com.ibm.xsp.Pager 
     </component-family> 
     <renderer-type>com.ibm.xsp.XPager 
     </renderer-type> 
     <renderer-class>com.irc.xsp.renderer.UIPagerRenderer 
     </renderer-class> 
    </renderer> 
</render-kit> 

com.irc.xsp.renderer.UIPagerRenderer est la classe de rendu. Évidemment, vous pouvez le nommer comme vous voulez. Utilisez simplement le même nom aux deux endroits.

Le moteur de rendu pourrait ressembler à ceci:

package com.irc.xsp.renderer; 

import java.io.IOException; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 

import javax.faces.component.UIComponent; 
import javax.faces.context.FacesContext; 
import javax.faces.context.ResponseWriter; 

import com.ibm.commons.util.StringUtil; 
import com.ibm.xsp.FacesExceptionEx; 
import com.ibm.xsp.component.UIPager; 
import com.ibm.xsp.component.UIPagerControl; 
import com.ibm.xsp.component.xp.XspPager; 
import com.ibm.xsp.component.xp.XspPagerControl; 
import com.ibm.xsp.context.FacesContextEx; 
import com.ibm.xsp.event.PagerEvent; 
import com.ibm.xsp.extsn.ResourceHandler; 
import com.ibm.xsp.renderkit.html_extended.XPagerRenderer; 
import com.ibm.xsp.util.AjaxUtilEx; 
import com.ibm.xsp.util.FacesUtil; 
import com.ibm.xsp.util.JavaScriptUtil; 
import com.ibm.xsp.util.TypedUtil; 

public class UIPagerRenderer extends XPagerRenderer { 

    public static final String VAR_PAGE = "page"; //$NON-NLS-1$ 

    private enum Property { 
     LIST_ITEM_CLASS, PAGER_LINK_CLASS, ACTIVE_CLASS("active"), DISABLED_CLASS("disabled"); 

     String className; 

     Property() { 
     } 

     Property(String s) { 
      this.className = s; 
     } 

     String getClassName() { 
      return className; 
     } 

    } 

    @Override 
    public void decode(FacesContext context, UIComponent component) { 
     super.decode(context, component); 

     // check that this component cause the submit 
     if (decodeCausedSubmit(context, component)) { 
      PagerEvent pagerEvent = new PagerEvent(component); 

      String hiddenValue = FacesUtil.getHiddenFieldValue(context); 
      if (StringUtil.isNotEmpty(hiddenValue)) { 
       int pos = hiddenValue.lastIndexOf('_'); 
       if (pos > -1) { 
        hiddenValue = hiddenValue.substring(pos + 1); 
        if (isFirst(hiddenValue)) { 
         pagerEvent.setAction(PagerEvent.ACTION_FIRST); 
        } else if (isLast(hiddenValue)) { 
         pagerEvent.setAction(PagerEvent.ACTION_LAST); 
        } else if (isNext(hiddenValue)) { 
         pagerEvent.setAction(PagerEvent.ACTION_NEXT); 
        } else if (isPrevious(hiddenValue)) { 
         pagerEvent.setAction(PagerEvent.ACTION_PREVIOUS); 
        } else { 
         try { 
          int value = Integer.parseInt(hiddenValue); 
          pagerEvent.setAction(PagerEvent.ACTION_GOTOPAGE); 
          pagerEvent.setPage(value); 
         } catch (NumberFormatException nfe) { 
          return; // just don't queue the event 
         } 
        } 
       } else { 
        return; 
       } 
      } 
      ((UIPager) component).queueEvent(pagerEvent); 
     } 
    } 

    private boolean decodeCausedSubmit(FacesContext context, UIComponent component) { 
     String currentClientId = component.getClientId(context); 
     String hiddenValue = FacesUtil.getHiddenFieldValue(context); 

     if (currentClientId != null && hiddenValue != null) { 
      return StringUtil.indexOfIgnoreCase(hiddenValue, currentClientId) > -1; 
     } 
     return false; 
    } 

    @Override 
    public boolean getRendersChildren() { 
     return true; 
    } 

    @Override 
    public void encodeChildren(FacesContext context, UIComponent component) throws IOException { 
     if (context == null || component == null) { 
      throw new IOException(); 
     } 

     List<?> controls = component.getChildren(); 

     if (controls.isEmpty()) { 
      return; 
     } 

     XspPager pager = (XspPager) component; 
     UIPager.PagerState pagerState = ((UIPager) component).createPagerState(); 

     if (pagerState == null) { 
      throw new FacesExceptionEx(ResourceHandler.getString("PagerRenderer.Pagerisnotassociatedwithanydataco")); 
     } 

     encodePagerContent(context, context.getResponseWriter(), pager, pagerState, controls, false); 
    } 

    protected void encodePagerContent(FacesContext context, ResponseWriter writer, XspPager pager, 
      UIPager.PagerState pagerState, List<?> controls, boolean rtl) throws IOException { 
     // Compute the pages that should be displayed 
     int pageCount = pagerState.getPageCount(); 
     int startCount = getStartCount(pagerState, pageCount); 
     int endCount = getEndCount(pagerState, pageCount, startCount); 

     String pagerId = pager.getClientId(context); 

     String pagerRole = pager.getRole(); 
     String pagerTitle = pager.getTitle(); 
     String pagerOuterClass = pager.getOuterStyleClass(); 
     String pagerAriaLabel = pager.getAriaLabel(); 
     boolean closeOuterTag = false; 

     if (isAnyAssigned(pagerRole, pagerTitle, pagerOuterClass, pagerAriaLabel)) { 
      writer.startElement("div", null); // $NON-NLS-1$ 

      writeNonNullAttributeOnly(writer, "role", pagerRole); 
      writeNonNullAttributeOnly(writer, "title", pagerTitle); 
      writeNonNullAttributeOnly(writer, "class", pagerOuterClass); 
      writeNonNullAttributeOnly(writer, "aria-label", pagerAriaLabel); 

      closeOuterTag = true; 
     } 

     writer.startElement("ul", null); 

     writeNonNullAttributeOnly(writer, "class", pager.getStyleClass()); 
     writeNonNullAttributeOnly(writer, "id", pagerId); 

     Iterator<?> it = controls.iterator(); 

     while (it.hasNext()) { 
      Object obj = it.next(); 

      if (obj instanceof XspPagerControl) { 
       XspPagerControl control = (XspPagerControl) obj; 
       String type = control.getType(); 

       if (StringUtil.isNotEmpty(type)) { 
        if (isFirst(type) || isNext(type) || isPrevious(type) 
          || (isLast(type) && pager.isAlwaysCalculateLast())) { 
         encodeAction(context, writer, pager, pagerState, pagerId, control, type, startCount, endCount, 
           rtl); 

         continue; 
        } else if (isLast(type) && !pager.isAlwaysCalculateLast()) { 
         if (!pagerState.hasMoreRows()) { 
          encodeAction(context, writer, pager, pagerState, pagerId, control, type, startCount, 
            endCount, rtl); 
         } else { 
          writer.startElement("li", null); 
          writeNonNullAttributeOnly(writer, "class", com.irc.util.StringUtil.concat(Property.LIST_ITEM_CLASS 
            .getClassName(), Property.DISABLED_CLASS.getClassName())); 

          writer.startElement("a", null); 
          writeNonNullAttributeOnly(writer, "class", Property.PAGER_LINK_CLASS.getClassName()); 
          writer.writeText(getMayBeMorePages(), null); 
          writer.endElement("a"); 

          writer.endElement("li"); 
         } 

         continue; 
        } else if (type.equalsIgnoreCase(UIPagerControl.TYPE_GROUP)) { 
         encodeGroup(context, writer, pager, pagerState, pagerId, control, startCount, endCount); 

         continue; 
        } else if (type.equalsIgnoreCase(UIPagerControl.TYPE_STATUS)) { 
         encodeStatus(context, writer, pager, pagerState, control, startCount, endCount); 

         continue; 
        } else if (isSeparator(type)) { 
         encodeSeparator(context, writer, control, type); 

         continue; 
        } else if (type.equalsIgnoreCase(UIPagerControl.TYPE_GOTO)) { 
         encodeGoto(); 

         continue; 
        } 
       } 

       // "Unknown control type {0}" 
       String msg = com.ibm.xsp.extsn.ResourceHandler.getString("PagerRenderer.Unknowncontroltype0"); //$NON-NLS-1$ 
       msg = StringUtil.format(msg, type); 
       throw new FacesExceptionEx(msg); 
      } 
     } 

     writer.endElement("ul"); 

     if (closeOuterTag) { 
      writer.endElement("div"); 
     } 
    } 

    protected void encodeAction(FacesContext context, ResponseWriter writer, XspPager pager, 
      UIPager.PagerState pagerState, String pagerId, XspPagerControl control, String type, int startCount, 
      int endCount, boolean rtl) throws IOException { 
     String controlId = pagerId + "__" + type; 
     String defaultText = ""; 
     String ariaLabel = ""; 
     boolean renderLink = true; 

     //TODO need to handle BIDI here for the unicode symbols 
     if (isFirst(type)) { 
      renderLink = pagerState.getCurrentPage() > startCount; 
      // "\u00AB" FirstSymbol 
      defaultText = "\u00AB"; //$NON-NLS-1$ 
      // "First page" 
      ariaLabel = ResourceHandler.getString("PagerRenderer.First"); //$NON-NLS-1$ 
     } else if (isPrevious(type)) { 
      renderLink = pagerState.getCurrentPage() > startCount; 
      // "\u2039" PreviousSymbol 
      defaultText = "\u2039"; //$NON-NLS-1$ 
      // "Previous page" 
      ariaLabel = ResourceHandler.getString("PagerRenderer.Previous"); //$NON-NLS-1$ 
     } else if (isNext(type)) { 
      renderLink = pagerState.getCurrentPage() < endCount - 1; 
      // "\u203A" NextSymbol 
      defaultText = "\u203A"; //$NON-NLS-1$; 
      // "Next page" 
      ariaLabel = ResourceHandler.getString("PagerRenderer.Next"); //$NON-NLS-1$ 
     } else if (isLast(type)) { 
      renderLink = pagerState.getCurrentPage() < endCount - 1; 
      // "\u00BB" LastSymbol 
      defaultText = "\u00BB"; //$NON-NLS-1$ 
      // "Last page" 
      ariaLabel = ResourceHandler.getString("PagerRenderer.Last"); //$NON-NLS-1$ 
     } 

     writer.startElement("li", null); 
     String listItemClass = Property.LIST_ITEM_CLASS.getClassName(); 

     if (!renderLink) { 
      //If current page is the first, disable first/previous pagers 
      //and if current page is the last, disable last/next pagers 
      listItemClass = com.irc.util.StringUtil.concat(listItemClass, Property.DISABLED_CLASS.getClassName()); 
     } 

     writeNonNullAttributeOnly(writer, "class", listItemClass); 

     // Generate the image link 
     String val = (String) control.getValue(); 

     if (StringUtil.isEmpty(val)) { 
      val = defaultText; 
     } 

     // Generate the text link 
     if (StringUtil.isNotEmpty(val)) { 
      writer.startElement("a", null); // $NON-NLS-1$ 

      if (renderLink) { 
       writer.writeAttribute("aria-disabled", "false", null); // $NON-NLS-1$ $NON-NLS-2$ 
       writer.writeAttribute("href", "#", null); // $NON-NLS-1$ $NON-NLS-2$ 
      } else { 
       //add a11y attributes 
       writer.writeAttribute("aria-disabled", "true", null); // $NON-NLS-1$ $NON-NLS-2$ 
      } 

      writeNonNullAttributeOnly(writer, "class", Property.PAGER_LINK_CLASS.getClassName()); 

      writer.writeAttribute("id", controlId + "__lnk", null); // $NON-NLS-1$ $NON-NLS-2$ 
      writer.writeAttribute("role", "button", null); // $NON-NLS-1$ $NON-NLS-2$ 
      writer.writeAttribute("aria-label", ariaLabel, null); // $NON-NLS-1$ 
      writer.writeText(val, null); 
      writer.endElement("a"); // $NON-NLS-1$ 

      if (renderLink) { 
       setupSubmitOnClick(context, pager, pagerState, controlId, controlId + "__lnk"); // $NON-NLS-1$ 
      } 
     } 

     writer.endElement("li"); // $NON-NLS-1$ 
    } 

    protected void encodeGroup(FacesContext context, ResponseWriter writer, XspPager pager, 
      UIPager.PagerState pagerState, String pagerId, XspPagerControl control, int startCount, int endCount) 
      throws IOException { 
     // Save the old page value 
     Map<String, Object> requestMap = TypedUtil.getRequestMap(context.getExternalContext()); 
     Object oldPage = requestMap.get(VAR_PAGE); 
     String controlId = pagerId + "__" + control.getType();//$NON-NLS-1$ 

     // Encode the pages 
     for (int i = startCount; i < endCount; i++) { 
      // Push the page number 
      requestMap.put(VAR_PAGE, i + 1); 
      boolean renderLink = (i != pagerState.getCurrentPage()); 

      writer.startElement("li", null); // $NON-NLS-1$ 
      String listItemClass = Property.LIST_ITEM_CLASS.getClassName(); 

      if (!renderLink) { 
       listItemClass = com.irc.util.StringUtil.concat(listItemClass, Property.ACTIVE_CLASS.getClassName()); 
      } 

      writeNonNullAttributeOnly(writer, "class", listItemClass); 

      // Generate the image link 
      String val = (String) control.getValue(); 

      if (StringUtil.isEmpty(val)) { 
       val = Integer.toString(i + 1); 
      } 

      // Generate the text link 
      if (StringUtil.isNotEmpty(val)) { // Generate the text link 
       writer.startElement("a", control); //$NON-NLS-1$ 
       writer.writeAttribute("id", controlId + "__lnk__" + i, null); // $NON-NLS-1$ $NON-NLS-2$ 
       // "Page {0}" 
       String ariaLabel = ResourceHandler.getString("PagerRenderer.Gotopage0"); //$NON-NLS-1$ 
       ariaLabel = StringUtil.format(ariaLabel, val); 
       writer.writeAttribute("aria-label", ariaLabel, null); // $NON-NLS-1$ 
       writer.writeAttribute("role", "button", null); // $NON-NLS-1$ $NON-NLS-2$ 

       writeNonNullAttributeOnly(writer, "class", Property.PAGER_LINK_CLASS.getClassName()); 

       if (renderLink) { //make sure the a is tab-able     
        writer.writeAttribute("tabindex", "0", null); // $NON-NLS-1$ $NON-NLS-2$ 
        writer.writeAttribute("aria-pressed", "false", null); // $NON-NLS-1$ $NON-NLS-2$ 
       } else { 
        writer.writeAttribute("aria-pressed", "true", null); // $NON-NLS-1$ $NON-NLS-2$ 
       } 

       writer.writeText(val, null); 
       writer.endElement("a"); // $NON-NLS-1$ 

       if (renderLink) { 
        setupSubmitOnClick(context, pager, pagerState, controlId + "__lnk__" + i, controlId + "__lnk__" + i); // $NON-NLS-1$ $NON-NLS-2$ 
       } 
      } 

      writer.endElement("li"); // $NON-NLS-1$ 
     } 

     // Encode after the pages 
     if (!pager.isAlwaysCalculateLast()) { 
      if (endCount < pagerState.getLastPage() || pagerState.hasMoreRows()) { 
       writer.startElement("li", null); // $NON-NLS-1$ 
       writeNonNullAttributeOnly(writer, "class", com.irc.util.StringUtil.concat(Property.LIST_ITEM_CLASS.getClassName(), 
         Property.DISABLED_CLASS.getClassName())); 

       writer.startElement("a", control); //$NON-NLS-1$ 
       writeNonNullAttributeOnly(writer, "class", Property.PAGER_LINK_CLASS.getClassName()); 
       writer.writeText(getMayBeMorePages(), null); 
       writer.endElement("a"); // $NON-NLS-1$ 
       writer.endElement("li"); // $NON-NLS-1$ 
      } 
     } 

     // Restore the old page value 
     if (oldPage != null) { 
      requestMap.put(VAR_PAGE, oldPage); 
     } else { 
      requestMap.remove(VAR_PAGE); 
     } 

    } 

    protected void setupSubmitOnClick(FacesContext context, XspPager component, UIPager.PagerState st, String clientId, 
      String sourceId) { 
     boolean immediate = false; 

     UIComponent subTree = ((FacesContextEx) context).getSubTreeComponent(); 

     boolean partialExec = component.isPartialExecute(); 
     String execId = null; 
     if (partialExec) { 
      execId = component.getClientId(context); 
      immediate = true; 
     } else { 
      if (subTree != null) { 
       partialExec = true; 
       execId = subTree.getClientId(context); 
       immediate = true; 
      } 
     } 

     boolean partialRefresh = component.isPartialRefresh(); 
     String refreshId = null; 
     if (partialRefresh) { 
      UIComponent refreshComponent = component.findSharedDataPagerParent(); 
      if (null == refreshComponent) { 
       refreshComponent = (UIComponent) st.getDataIterator(); 
      } 
      refreshId = AjaxUtilEx.getRefreshId(context, refreshComponent); 
     } else { 
      if (subTree != null) { 
       partialRefresh = true; 
       refreshId = subTree.getClientId(context); 
      } 
     } 

     // call some JavaScript in xspClient.js 
     final String event = "onclick"; // $NON-NLS-1$ 
     // Note, the onClick event is also triggered if the user tabs to the 
     // image\link and presses enter (Not just when clicked with a 
     // mouse). 

     // When the source is clicked, put its id in the hidden field and 
     // submit the form. 
     StringBuilder buff = new StringBuilder(); 
     if (partialRefresh) { 
      JavaScriptUtil.appendAttachPartialRefreshEvent(buff, clientId, sourceId, execId, event, 
      /* clientSideScriptName */null, immediate ? JavaScriptUtil.VALIDATION_NONE 
        : JavaScriptUtil.VALIDATION_FULL, 
      /* refreshId */refreshId, 
      /* onstart */getOnStart(component), 
      /* oncomplete */getOnComplete(component), 
      /* onerror */getOnError(component)); 
     } else { 
      JavaScriptUtil.appendAttachEvent(buff, clientId, sourceId, execId, event, 
      /* clientSideScriptName */null, 
      /* submit */true, immediate ? JavaScriptUtil.VALIDATION_NONE : JavaScriptUtil.VALIDATION_FULL); 
     } 
     String script = buff.toString(); 

     // Add the script block we just generated. 
     JavaScriptUtil.addScriptOnLoad(script); 
    } 

    protected String getOnStart(XspPager component) { 
     return (String) component.getAttributes().get("onStart"); // $NON-NLS-1$ 
    } 

    protected String getOnComplete(XspPager component) { 
     return (String) component.getAttributes().get("onComplete"); // $NON-NLS-1$ 
    } 

    protected String getOnError(XspPager component) { 
     return (String) component.getAttributes().get("onError"); // $NON-NLS-1$ 
    } 

    protected void encodeStatus(FacesContext context, ResponseWriter writer, XspPager pager, 
      UIPager.PagerState pagerState, XspPagerControl control, int startCount, int endCount) throws IOException { 
     writer.startElement("li", null); // $NON-NLS-1$ 
     writeNonNullAttributeOnly(writer, "class", com.irc.util.StringUtil.concat(Property.LIST_ITEM_CLASS.getClassName(), 
       Property.DISABLED_CLASS.getClassName())); 

     String val = (String) control.getValue(); 

     if (StringUtil.isEmpty(val)) { 
      val = "{0}"; // $NON-NLS-1$ 
     } 

     if (pagerState.getLastPage() > 0) { 
      writer.startElement("a", null); // $NON-NLS-1$ 
      writeNonNullAttributeOnly(writer, "class", Property.PAGER_LINK_CLASS.getClassName()); 
      writer.writeAttribute("role", "button", null); // $NON-NLS-2$ $NON-NLS-1$ 
      val = StringUtil.format(val, pagerState.getCurrentPage() + 1, pagerState.getLastPage(), startCount, 
        endCount); 
      writer.writeText(val, null); 
      writer.endElement("a"); // $NON-NLS-1$ 
     } 

     writer.endElement("li"); // $NON-NLS-1$ 
    } 

    protected void encodeSeparator(FacesContext context, ResponseWriter writer, XspPagerControl control, String type) 
      throws IOException { 
     String val = (String) control.getValue(); 

     writer.startElement("li", null); // $NON-NLS-1$ 

     if (StringUtil.isEmpty(val)) { 
      String defaultSeparator = "|"; // $NON-NLS-1$ 

      if (type.equalsIgnoreCase(UIPagerControl.TYPE_SEPARATORPAGE)) { 
       // "Page" 
       defaultSeparator = com.ibm.xsp.extsn.ResourceHandler.getString("PagerRenderer.Page"); //$NON-NLS-1$ 
      } 

      val = defaultSeparator; 
     } 

     writeNonNullAttributeOnly(writer, "class", com.irc.util.StringUtil.concat(Property.LIST_ITEM_CLASS.getClassName(), 
       Property.DISABLED_CLASS.getClassName())); 

     // Generate the text link 
     if (StringUtil.isNotEmpty(val)) { 
      writer.startElement("a", null); // $NON-NLS-1$ 
      writeNonNullAttributeOnly(writer, "class", Property.PAGER_LINK_CLASS.getClassName()); 
      writer.writeText(val, null); 
      writer.endElement("a"); // $NON-NLS-1$ 
     } 

     writer.endElement("li"); // $NON-NLS-1$ 
    } 

    protected void encodeGoto() { 
     // Do not exists in core XPages yet.. 
    } 

    protected int getStartCount(UIPager.PagerState st, int pageCount) { 
     int start = (st.getFirst()/st.getRows()) - pageCount/2; 
     start = Math.min(Math.max(0, st.getLastPage() - pageCount), Math.max(0, start)); 
     return start; 
    } 

    protected int getEndCount(UIPager.PagerState st, int pageCount, int start) { 
     int sizeOfPageRange = Math.min(start + pageCount, st.getLastPage()) - start; 
     int end = start + sizeOfPageRange; 
     return end; 
    } 

    protected boolean isFirst(String type) { 
     return (type.equalsIgnoreCase(UIPagerControl.TYPE_FIRST) 
       || type.equalsIgnoreCase(UIPagerControl.TYPE_FIRSTARROW) || type 
       .equalsIgnoreCase(UIPagerControl.TYPE_FIRSTIMAGE)); 
    } 

    protected boolean isNext(String type) { 
     return (type.equalsIgnoreCase(UIPagerControl.TYPE_NEXT) || type.equalsIgnoreCase(UIPagerControl.TYPE_NEXTARROW) || type 
       .equalsIgnoreCase(UIPagerControl.TYPE_NEXTIMAGE)); 
    } 

    protected boolean isLast(String type) { 
     return (type.equalsIgnoreCase(UIPagerControl.TYPE_LAST) || type.equalsIgnoreCase(UIPagerControl.TYPE_LASTARROW) || type 
       .equalsIgnoreCase(UIPagerControl.TYPE_LASTIMAGE)); 
    } 

    protected boolean isPrevious(String type) { 
     return (type.equalsIgnoreCase(UIPagerControl.TYPE_PREVIOUS) 
       || type.equalsIgnoreCase(UIPagerControl.TYPE_PREVIOUSARROW) || type 
       .equalsIgnoreCase(UIPagerControl.TYPE_PREVIOUSIMAGE)); 
    } 

    protected boolean isSeparator(String type) { 
     return (type.equalsIgnoreCase(UIPagerControl.TYPE_SEPARATOR) || type 
       .equalsIgnoreCase(UIPagerControl.TYPE_SEPARATORPAGE)); 
    } 

    protected String getMayBeMorePages() { 
     return "..."; // $NON-NLS-1$ 
    } 

    private void writeNonNullAttributeOnly(ResponseWriter writer, String attributeName, String attributeValue) 
      throws IOException { 
     if (attributeValue != null && !attributeValue.isEmpty()) { 
      writer.writeAttribute(attributeName, attributeValue, null); 
     } 
    } 

    private boolean isAnyAssigned(String... objs) { 
     for (String s : objs) { 
      if (s != null && !s.isEmpty()) 
       return true; 
     } 

     return false; 
    } 

} 

C'est une classe que je me sers dans mon dernier projet. Fondamentalement, il réimplémente tout ce que le pager fait pour avoir le contrôle de l'aspect et de la convivialité du composant - c'est ce qu'on appelle le rendu. Vous pourriez essayer de le modifier ici et là pour voir comment les différentes choses fonctionnent sur la page. C'est un processus d'apprentissage.