JSF selectOneMenu:扩展MenuRenderer以在存在一项时显示纯文本 [英] JSF selectOneMenu: extending MenuRenderer for displaying a plain text when there is one item
问题描述
我想显示类似的东西
<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屋!