Xpages从视图重复控制/文档 - 最佳实践

时间:2017-06-06 09:34:01

标签: javascript xpages lotus-notes lotus-domino

我想在最近的应用程序中实现的是使用我自己的分页 - 所以我需要知道(分类)视图中有多少文档来计算所需的页面。

<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

1 个答案:

答案 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;
    }

}

这是我在上一个项目中一直使用的课程。基本上它重新实现了寻呼机所做的一切,以便控制组件的外观 - 毕竟它被称为渲染器。你可以尝试在这里和那里调整它,看看页面上的各种事情是如何运作的。这是一个学习过程。