1

我已经覆盖了 SelectOneMenuRenderer 来为这个组件添加 OptionGroup-Support。现在显示选项组。伟大的!

但是当我有一个带有选项组的选择并单击此菜单中的一个项目时:
- 选择了下面的 SelectItem(在第一个选项组之后)
- 选择了下面的 SelectItem 两个(在第二个选项组之后)
- ...

一些 javascript 在这里把事情搞砸了,但我无法弄清楚究竟是哪个以及在哪里。

代码:

package org.primefaces.component.selectonemenu;

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

import javax.faces.component.UIComponent;
import javax.faces.component.UISelectOne;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.model.SelectItem;
import javax.faces.model.SelectItemGroup;

import org.primefaces.component.column.Column;
import org.primefaces.renderkit.SelectOneRenderer;
import org.primefaces.util.ComponentUtils;

public class SelectOneMenuRenderer extends SelectOneRenderer {

  @Override
  public void decode(final FacesContext context, final UIComponent component) {
    if (!shouldDecode(component)) {
      return;
    }

    SelectOneMenu menu = (SelectOneMenu)component;
    if (menu.isEditable()) {
      Map<String, String> params = context.getExternalContext().getRequestParameterMap();

      decodeBehaviors(context, menu);

      menu.setSubmittedValue(params.get(menu.getClientId(context) + "_editableInput"));
    }
    else {
      super.decode(context, component);
    }
  }

  @Override
  public Object getConvertedValue(final FacesContext context, final UIComponent component,
      final Object submittedValue) throws ConverterException
  {
    return context.getRenderKit().getRenderer("javax.faces.SelectOne", "javax.faces.Menu")
        .getConvertedValue(context, component, submittedValue);
  }

  @Override
  public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
    SelectOneMenu menu = (SelectOneMenu)component;

    encodeMarkup(context, menu);
    encodeScript(context, menu);
  }

  protected void encodeMarkup(final FacesContext context, final SelectOneMenu menu) throws IOException {

    boolean isOptionGroup = false;

    ResponseWriter writer = context.getResponseWriter();
    List<SelectItem> selectItems = getSelectItems(context, menu);
    String clientId = menu.getClientId(context);
    Converter converter = menu.getConverter();
    Object values = getValues(menu);
    Object submittedValues = getSubmittedValues(menu);
    boolean valid = menu.isValid();

    String style = menu.getStyle();
    String styleClass = menu.getStyleClass();
    styleClass = styleClass == null ? SelectOneMenu.STYLE_CLASS : SelectOneMenu.STYLE_CLASS + " "
        + styleClass;
    styleClass = !valid ? styleClass + " ui-state-error" : styleClass;
    styleClass = menu.isDisabled() ? styleClass + " ui-state-disabled" : styleClass;

    writer.startElement("div", menu);
    writer.writeAttribute("id", clientId, "id");
    writer.writeAttribute("class", styleClass, "styleclass");
    if (style != null) {
      writer.writeAttribute("style", style, "style");
    }

    // filter selectItems // values
    List<SelectItem> selectGroupedItems = new ArrayList<SelectItem>();
    for (Object item : selectItems) {
      if (item instanceof SelectItemGroup) {
        isOptionGroup = true; // Flag, um den (Render-)Modus auf "Optiongroup" umzuschalten
        ((SelectItemGroup)item).setNoSelectionOption(true);
        ((SelectItemGroup)item).setDisabled(true);
        selectGroupedItems.add((SelectItem)item); // Nicht: SelectItemGroup

        SelectItem[] innerItems = ((SelectItemGroup)item).getSelectItems();
        for (SelectItem innerItem : innerItems) {
          selectGroupedItems.add(innerItem);
        }
        continue;
      }
      selectGroupedItems.add((SelectItem)item);
    }

    // Encode tags
    encodeInput(context, menu, clientId, selectGroupedItems, values, submittedValues, converter);
    encodeLabel(context, menu, selectGroupedItems);
    encodeMenuIcon(context, menu, valid);
    encodePanel(context, menu, selectGroupedItems, isOptionGroup);

    writer.endElement("div");
  }

  protected void encodeInput(final FacesContext context, final SelectOneMenu menu, final String clientId,
      final List<SelectItem> selectItems, final Object values, final Object submittedValues,
      final Converter converter) throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    String inputId = clientId + "_input";

    writer.startElement("div", menu);
    writer.writeAttribute("class", "ui-helper-hidden-accessible", null);

    writer.startElement("select", menu);
    writer.writeAttribute("id", inputId, "id");
    writer.writeAttribute("name", inputId, null);
    if (menu.isDisabled()) {
      writer.writeAttribute("disabled", "disabled", null);
    }
    if (menu.getTabindex() != null) {
      writer.writeAttribute("tabindex", menu.getTabindex(), null);
    }
    if (menu.getOnkeydown() != null) {
      writer.writeAttribute("onkeydown", menu.getOnkeydown(), null);
    }
    if (menu.getOnkeyup() != null) {
      writer.writeAttribute("onkeyup", menu.getOnkeyup(), null);
    }

    encodeSelectItems(context, menu, selectItems, values, submittedValues, converter);

    writer.endElement("select");

    writer.endElement("div");
  }

  protected void encodeLabel(final FacesContext context, final SelectOneMenu menu,
      final List<SelectItem> selectItems) throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    String valueToRender = ComponentUtils.getValueToRender(context, menu);

    if (menu.isEditable()) {
      writer.startElement("input", null);
      writer.writeAttribute("type", "text", null);
      writer.writeAttribute("name", menu.getClientId() + "_editableInput", null);
      writer.writeAttribute("class", SelectOneMenu.LABEL_CLASS, null);
      writer.writeAttribute("tabindex", -1, null);
      writer.writeAttribute("autocomplete", "off", null);
      if (menu.isDisabled()) {
        writer.writeAttribute("disabled", "disabled", null);
      }

      if (valueToRender != null) {
        writer.writeAttribute("value", valueToRender, null);
      }

      writer.endElement("input");
    }
    else {
      writer.startElement("label", null);
      writer.writeAttribute("id", menu.getClientId() + "_label", null);
      writer.writeAttribute("class", SelectOneMenu.LABEL_CLASS, null);
      writer.write("&nbsp;");
      writer.endElement("label");
    }
  }

  protected void encodeMenuIcon(final FacesContext context, final SelectOneMenu menu, final boolean valid)
    throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    String iconClass = valid ? SelectOneMenu.TRIGGER_CLASS : SelectOneMenu.TRIGGER_CLASS + " ui-state-error";

    writer.startElement("div", menu);
    writer.writeAttribute("class", iconClass, null);

    writer.startElement("span", menu);
    writer.writeAttribute("class", "ui-icon ui-icon-triangle-1-s", null);
    writer.endElement("span");

    writer.endElement("div");
  }

  protected void encodePanel(final FacesContext context, final SelectOneMenu menu,
      final List<SelectItem> selectItems, final boolean isOptionGroup) throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    boolean customContent = menu.getVar() != null;
    int height = calculatePanelHeight(menu, selectItems.size());
    String panelStyle = menu.getPanelStyle() != null ? menu.getPanelStyle() : "";
    String panelStyleClass = menu.getPanelStyleClass();
    panelStyleClass = panelStyleClass == null ? SelectOneMenu.PANEL_CLASS : SelectOneMenu.PANEL_CLASS + " "
        + panelStyleClass;

    if (height != -1) {
      panelStyle += ";height:" + height + "px";
    }

    writer.startElement("div", null);
    writer.writeAttribute("id", menu.getClientId(context) + "_panel", null);
    writer.writeAttribute("class", panelStyleClass, null);

    if (!isValueEmpty(panelStyle)) {
      writer.writeAttribute("style", panelStyle, null);
    }

    if (customContent) {
      writer.startElement("table", menu);
      writer.writeAttribute("class", SelectOneMenu.TABLE_CLASS, null);
      writer.startElement("tbody", menu);
      encodeOptionsAsTable(context, menu, selectItems, isOptionGroup);
      writer.endElement("tbody");
      writer.endElement("table");
    }
    else {
      writer.startElement("ul", menu);
      writer.writeAttribute("class", SelectOneMenu.LIST_CLASS, null);
      encodeOptionsAsList(context, menu, selectItems, isOptionGroup);
      writer.endElement("ul");
    }

    writer.endElement("div");
  }

  protected void encodeOptionsAsTable(final FacesContext context, final SelectOneMenu menu,
      final List<SelectItem> selectItems, final boolean isOptionGroup) throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    String var = menu.getVar();
    List<Column> columns = menu.getColums();
    Object value = menu.getValue();

    for (SelectItem selectItem : selectItems) {
      Object itemValue = selectItem.getValue();

      context.getExternalContext().getRequestMap().put(var, selectItem.getValue());

      writer.startElement("tr", null);
      writer.writeAttribute("class", SelectOneMenu.ROW_CLASS, null);
      if (selectItem.getDescription() != null) {
        writer.writeAttribute("title", selectItem.getDescription(), null);
      }

      if (itemValue instanceof String) {
        writer.startElement("td", null);
        writer.writeAttribute("colspan", columns.size(), null);

        if (isOptionGroup) {
          if (selectItem instanceof SelectItemGroup) {
            writer.writeAttribute("class", "ui-selectonemenu-optiongroup-header", null);
          }
          else {
            writer.writeAttribute("class", SelectOneMenu.ITEM_CLASS + " ui-selectonemenu-optiongroup-items",
                null);
          }
        }

        writer.writeText(selectItem.getLabel(), null);
        writer.endElement("td");
      }
      else {
        for (Column column : columns) {
          writer.startElement("td", null);
          column.encodeAll(context);
          writer.endElement("td");
        }
      }

      writer.endElement("tr");
    }

    context.getExternalContext().getRequestMap().put(var, null);
  }

  protected void encodeOptionsAsList(final FacesContext context, final SelectOneMenu menu,
      final List<SelectItem> selectItems, final boolean isOptionGroup) throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    Object value = menu.getValue();

    for (int i = 0; i < selectItems.size(); i++) {
      SelectItem selectItem = selectItems.get(i);
      String itemLabel = selectItem.getLabel();
      itemLabel = isValueBlank(itemLabel) ? "&nbsp;" : itemLabel;

      writer.startElement("li", null);
      if (selectItem instanceof SelectItemGroup) {
        writer.writeAttribute("class", " ui-selectonemenu-optiongroup-header", null);
      }
      else {
        if (isOptionGroup) {
          writer.writeAttribute("class", SelectOneMenu.ITEM_CLASS + " ui-selectonemenu-optiongroup-items",
              null);
        }
        else {
          writer.writeAttribute("class", SelectOneMenu.ITEM_CLASS, null);
        }
      }
      if (selectItem.getDescription() != null) {
        writer.writeAttribute("title", selectItem.getDescription(), null);
      }

      if (itemLabel.equals("&nbsp;")) {
        writer.write(itemLabel);
      }
      else {
        if (selectItem.isEscape()) {
          writer.writeText(itemLabel, "value");
        }
        else {
          writer.write(itemLabel);
        }
      }
      writer.endElement("li");

    }
  }

  protected void encodeScript(final FacesContext context, final SelectOneMenu menu) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String clientId = menu.getClientId(context);

    startScript(writer, clientId);

    writer.write("$(function(){");
    writer.write("PrimeFaces.cw('SelectOneMenu','" + menu.resolveWidgetVar() + "',{");
    writer.write("id:'" + clientId + "'");
    writer.write(",effect:'" + menu.getEffect() + "'");

    if (menu.getEffectDuration() != 400) {
      writer.write(",effectDuration:" + menu.getEffectDuration());
    }
    if (menu.isEditable()) {
      writer.write(",editable:true");
    }
    if (menu.getOnchange() != null) {
      writer.write(",onchange:function() {" + menu.getOnchange() + "}");
    }

    encodeClientBehaviors(context, menu);

    writer.write("});});");

    endScript(writer);
  }

  protected void encodeSelectItems(final FacesContext context, final SelectOneMenu menu,
      final List<SelectItem> selectItems, final Object values, final Object submittedValues,
      final Converter converter) throws IOException
  {
    for (SelectItem selectItem : selectItems) {
      encodeOption(context, menu, selectItem, values, submittedValues, converter);
    }
  }

  protected void encodeOption(final FacesContext context, final SelectOneMenu menu, final SelectItem option,
      final Object values, final Object submittedValues, final Converter converter) throws IOException
  {
    ResponseWriter writer = context.getResponseWriter();
    String itemValueAsString = getOptionAsString(context, menu, converter, option.getValue());
    boolean disabled = option.isDisabled();

    Object valuesArray;
    Object itemValue;
    if (submittedValues != null) {
      valuesArray = submittedValues;
      itemValue = itemValueAsString;
    }
    else {
      valuesArray = values;
      itemValue = option.getValue();
    }

    boolean selected = isSelected(context, menu, itemValue, valuesArray, converter);
    if (option.isNoSelectionOption() && values != null && !selected) {
      return;
    }

    String elem = "option";
    if (option instanceof SelectItemGroup) {
      selected = false;
    }

    writer.startElement(elem, null);

    writer.writeAttribute("value", itemValueAsString, null);
    if (disabled) {
      writer.writeAttribute("disabled", "disabled", null);
    }
    if (selected) {
      writer.writeAttribute("selected", "selected", null);
    }

    if (option.isEscape()) {
      writer.writeText(option.getLabel(), "value");
    }
    else {
      writer.write(option.getLabel());
    }

    writer.endElement(elem);
  }

  protected int calculatePanelHeight(final SelectOneMenu menu, final int itemSize) {
    int height = menu.getHeight();

    if (height != Integer.MAX_VALUE) {
      return height;
    }
    else if (itemSize > 10) {
      return 200;
    }

    return -1;
  }

  @Override
  public void encodeChildren(final FacesContext facesContext, final UIComponent component) throws IOException
  {
    // Rendering happens on encodeEnd
  }

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

  @Override
  protected String getSubmitParam(final FacesContext context, final UISelectOne selectOne) {
    return selectOne.getClientId(context) + "_input";
  }
}

任何提示是什么原因造成的?

强尼

4

1 回答 1

1

使用素面 3.5。该版本于上周发布。

于 2013-02-05T18:27:55.723 回答