我想在最近的应用程序中实现的是使用我自己的分页 - 所以我需要知道(分类)视图中有多少文档来计算所需的页面。
<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>
this known problem我必须做一个解决方法,通过重复控制来查询文档数量。
<xp:repeat id="blindRepeat" rows="0" value="#{viewStories}"></xp:repeat>
我使用this sample code来获得重复控制的正确迭代次数。
<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>
但就在这里我遇到了一个Catch 22: 我只能使用重复控件,因为我无法直接从视图中获取大量文档,如Knut Herrmann(1),但重复控件不可用,所以我不能像Per Henrik Lausten那样使用它(2)提出。
一位同事建议在一个脚本块中填充数组,该块嵌套在盲目重复控制之后(因此应该绘制)但是在分页重复控制之前(所以viewScope应该保持正确的数字),但这个解决方案似乎相当片状对我来说。
所以我在询问是否存在针对这种情况的“最佳实践” - 我想正确解决这个问题而不是以某种方式及时执行某些javascript
答案 0 :(得分:3)
考虑到您在评论中给出的问题,我建议您为寻呼机实现自己的自定义渲染器。
在faces-config.xml
声明如下:
<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
是渲染类。显然你可以随意命名。只需在两个地方使用相同的名称。
渲染器看起来像这样:
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;
}
}
这是我在上一个项目中一直使用的课程。基本上它重新实现了寻呼机所做的一切,以便控制组件的外观 - 毕竟它被称为渲染器。你可以尝试在这里和那里调整它,看看页面上的各种事情是如何运作的。这是一个学习过程。