JSF selectOneMenu:扩展MenuRenderer以在存在一项时显示纯文本 [英] JSF selectOneMenu: extending MenuRenderer for displaying a plain text when there is one item

查看:46
本文介绍了JSF selectOneMenu:扩展MenuRenderer以在存在一项时显示纯文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想显示类似的东西

<span ...>An item</span>

代替

<select ...>
 <option ...>An item</option>
</select>

当菜单的 plainText 选项设置为true且内部只有一个SelectItem时:

When menu's plainText option is set to true and there is only one SelectItem inside:

<h:selectOneMenu plainText="true" ...>
 <f:selectItems ... /> <!-- contains one item -->
</h:selectOneMenu>

我尝试创建一个自MenuRenderer扩展的自定义渲染器,但是它的代码并不是真正可附加的.你能帮忙吗?谢谢.

I've tried creating a custom renderer extended from MenuRenderer, but its code is not really appendable. Can you help with it? Thanks.

推荐答案

我们需要扩展 com.sun.faces.renderkit.html_basic.MenuRenderer 并覆盖 renderSelect renderOption 方法.它的代码大部分是从父级复制的.当我们需要将元素显示为跨度时, private boolean plainText 为true. 在 renderSelect 的开头部分,我们添加以下内容:

We need to extend com.sun.faces.renderkit.html_basic.MenuRenderer and override renderSelect and renderOption methods. Its code is mostly copied from the parent. private boolean plainText is true when we need to display element as a span. At the begginning of renderSelect we add this:

plainText = "true".equalsIgnoreCase((String) component.getAttributes().get("plainText"));
if (plainText) {
    SelectItemsIterator<SelectItem> items = RenderKitUtils.getSelectItems(context, component);
    items.next();
    plainText = !items.hasNext();
}

它首先检查 plainText 选项是否设置为 true ,然后检查是否只有selectItem.我认为这部分可以优化. 代替

It first checks if plainText option is set to true, than it checks if there is the only selectItem. I think this part can be optimised. Instead of

writer.startElement("select", component);

我们应该写

if (plainText) {
    writer.startElement("span", component);
} else {
    writer.startElement("select", component);
}

并使用writer.endElement进行同样的操作.

And do the same with writer.endElement.

renderOption 的中间,我们添加了一个代码,该代码将仅打印出唯一的选项而没有任何标签并离开.

In the middle of renderOption we add a code that will simply print out the only option without any tags and leave.

if (plainText) {
    if (curItem.isEscape()) {
        String label = curItem.getLabel();
        if (label == null) {
            label = valueString;
        }
        writer.writeText(label, component, "label");
    } else {
        writer.write(curItem.getLabel());
    }
    writer.writeText("\n", component, null);
    return true;
}

所有代码:

import com.sun.faces.io.FastStringWriter;
import com.sun.faces.renderkit.Attribute;
import com.sun.faces.renderkit.AttributeManager;
import com.sun.faces.renderkit.RenderKitUtils;
import com.sun.faces.renderkit.SelectItemsIterator;
import com.sun.faces.renderkit.html_basic.MenuRenderer;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import java.io.IOException;
import java.util.logging.Level;

public class ExtendedMenuRenderer extends MenuRenderer {
    private boolean plainText;

    private static final Attribute[] ATTRIBUTES =
            AttributeManager.getAttributes(AttributeManager.Key.SELECTMANYMENU);

    @Override
    protected void renderSelect(FacesContext context,
                                UIComponent component) throws IOException {
        plainText = "true".equalsIgnoreCase((String) component.getAttributes().get("plainText"));
        if (plainText) {
            SelectItemsIterator<SelectItem> items = RenderKitUtils.getSelectItems(context, component);
            items.next();
            plainText = !items.hasNext();
        }

        ResponseWriter writer = context.getResponseWriter();
        assert (writer != null);

        if (logger.isLoggable(Level.FINER)) {
            logger.log(Level.FINER, "Rendering 'select'");
        }
        if (plainText) {
            writer.startElement("span", component);
        } else {
            writer.startElement("select", component);
        }
        writeIdAttributeIfNecessary(context, writer, component);
        writer.writeAttribute("name", component.getClientId(context),
                "clientId");
        // render styleClass attribute if present.
        String styleClass;
        if (null !=
                (styleClass =
                        (String) component.getAttributes().get("styleClass"))) {
            writer.writeAttribute("class", styleClass, "styleClass");
        }
        if (!getMultipleText(component).equals("")) {
            writer.writeAttribute("multiple", true, "multiple");
        }

        // Determine how many option(s) we need to render, and update
        // the component's "size" attribute accordingly;  The "size"
        // attribute will be rendered as one of the "pass thru" attributes
        SelectItemsIterator<SelectItem> items = RenderKitUtils.getSelectItems(context, component);

        // render the options to a buffer now so that we can determine
        // the size
        FastStringWriter bufferedWriter = new FastStringWriter(128);
        context.setResponseWriter(writer.cloneWithWriter(bufferedWriter));
        int count = renderOptions(context, component, items);
        context.setResponseWriter(writer);
        // If "size" is *not* set explicitly, we have to default it correctly
        Integer size = (Integer) component.getAttributes().get("size");
        if (size == null || size == Integer.MIN_VALUE) {
            size = count;
        }
        writeDefaultSize(writer, size);

        RenderKitUtils.renderPassThruAttributes(context,
                writer,
                component,
                ATTRIBUTES,
                getNonOnChangeBehaviors(component));
        RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer,
                component);

        RenderKitUtils.renderOnchange(context, component, false);

        // Now, write the buffered option content
        writer.write(bufferedWriter.toString());

        if (plainText) {
            writer.endElement("span");
        } else {
            writer.endElement("select");
        }

    }

    @Override
    protected boolean renderOption(FacesContext context,
                                   UIComponent component,
                                   UIComponent selectComponent,
                                   Converter converter,
                                   SelectItem curItem,
                                   Object currentSelections,
                                   Object[] submittedValues,
                                   OptionComponentInfo optionInfo) throws IOException {

        Object valuesArray;
        Object itemValue;
        String valueString = getFormattedValue(context, component,
                curItem.getValue(), converter);
        boolean containsValue;
        if (submittedValues != null) {
            containsValue = containsaValue(submittedValues);
            if (containsValue) {
                valuesArray = submittedValues;
                itemValue = valueString;
            } else {
                valuesArray = currentSelections;
                itemValue = curItem.getValue();
            }
        } else {
            valuesArray = currentSelections;
            itemValue = curItem.getValue();
        }

        boolean isSelected = isSelected(context, component, itemValue, valuesArray, converter);
        if (optionInfo.isHideNoSelection()
                && curItem.isNoSelectionOption()
                && currentSelections != null
                && !isSelected) {
            return false;
        }

        ResponseWriter writer = context.getResponseWriter();
        assert (writer != null);
        writer.writeText("\t", component, null);

        if (plainText) {
            if (curItem.isEscape()) {
                String label = curItem.getLabel();
                if (label == null) {
                    label = valueString;
                }
                writer.writeText(label, component, "label");
            } else {
                writer.write(curItem.getLabel());
            }
            writer.writeText("\n", component, null);
            return true;
        }

        writer.startElement("option", (null != selectComponent) ? selectComponent : component);
        writer.writeAttribute("value", valueString, "value");

        if (isSelected) {
            writer.writeAttribute("selected", true, "selected");
        }

        // if the component is disabled, "disabled" attribute would be rendered
        // on "select" tag, so don't render "disabled" on every option.
        if ((!optionInfo.isDisabled()) && curItem.isDisabled()) {
            writer.writeAttribute("disabled", true, "disabled");
        }

        String labelClass;
        if (optionInfo.isDisabled() || curItem.isDisabled()) {
            labelClass = optionInfo.getDisabledClass();
        } else {
            labelClass = optionInfo.getEnabledClass();
        }
        if (labelClass != null) {
            writer.writeAttribute("class", labelClass, "labelClass");
        }

        if (curItem.isEscape()) {
            String label = curItem.getLabel();
            if (label == null) {
                label = valueString;
            }
            writer.writeText(label, component, "label");
        } else {
            writer.write(curItem.getLabel());
        }
        writer.endElement("option");
        writer.writeText("\n", component, null);
        return true;
    }
}

在faces-config.xml中添加:

In faces-config.xml add:

<render-kit>
    <renderer>
        <component-family>javax.faces.SelectOne</component-family>
        <renderer-type>javax.faces.Menu</renderer-type>
        <renderer-class>ru.mycityseason.extentions.ExtendedMenuRenderer</renderer-class>
    </renderer>
</render-kit>

这篇关于JSF selectOneMenu:扩展MenuRenderer以在存在一项时显示纯文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆