/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.richfaces.renderkit;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.ConverterException;
import javax.faces.model.SelectItem;
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.ScriptString;
import org.ajax4jsf.javascript.ScriptUtils;
import org.ajax4jsf.renderkit.HeaderResourcesRendererBase;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.util.InputUtils;
import org.ajax4jsf.util.SelectUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.component.UIInplaceSelect;
/**
* InplaceSelect base renderer implementation
* @author Anton Belevich
* @since 3.2.0
*/
public class InplaceSelectBaseRenderer extends HeaderResourcesRendererBase {
private static Log logger = LogFactory.getLog(InplaceSelectBaseRenderer.class);
//TODO: move duplicate constants to superclass
private static final String RICH_INPLACE_SELECT_CLASSES = "rich-inplace-select-item rich-inplace-select-font";
private static final String CONTROLS_FACET = "controls";
private static final String EMPTY_DEFAULT_LABEL = "\u00a0\u00a0\u00a0";
protected static final class PreparedSelectItem implements ScriptString {
private String label;
private String convertedValue;
public PreparedSelectItem(String convertedValue, String label) {
super();
this.convertedValue = convertedValue;
this.label = label;
}
public String getLabel() {
return label;
}
public String getConvertedValue() {
return convertedValue;
}
public void appendScript(StringBuffer functionString) {
functionString.append(this.toScript());
}
public String toScript() {
return "[" + ScriptUtils.toScript(label) + ", " + ScriptUtils.toScript(convertedValue) + "]";
}
}
@Override
protected void doDecode(FacesContext context, UIComponent component) {
UIInplaceSelect inplaceSelect = null;
if (component instanceof UIInplaceSelect) {
inplaceSelect = (UIInplaceSelect) component;
} else {
if (logger.isDebugEnabled()) {
logger.debug("No decoding necessary since the component " + component.getId()
+ " is not an instance or a sub class of UIInplaceSelect");
}
return;
}
String clientId = inplaceSelect.getClientId(context);
if (clientId == null) {
throw new NullPointerException("component client id is NULL");
}
if (InputUtils.isDisabled(inplaceSelect) || InputUtils.isReadOnly(inplaceSelect)) {
if (logger.isDebugEnabled()) {
logger.debug(("No decoding necessary since the component " + component.getId() + " is disabled"));
}
return;
}
Map <String,String> request = context.getExternalContext().getRequestParameterMap();
String newValue = (String) request.get(clientId);
if (newValue != null) {
inplaceSelect.setSubmittedValue(newValue);
} else {
inplaceSelect.setSubmittedValue(null);
}
}
protected boolean isAcceptableComponent(UIComponent component) {
return component != null && this.getComponentClass().isAssignableFrom(component.getClass());
}
protected String getConvertedStringValue(FacesContext context, UIComponent component, Object value) {
return InputUtils.getConvertedStringValue(context, component, value);
}
protected void encodeSuggestion(FacesContext context, UIComponent component, String value, String classes) throws IOException {
ResponseWriter writer = context.getResponseWriter();
if(writer != null) {
writer.startElement(HTML.SPAN_ELEM, component);
writer.writeAttribute(HTML.class_ATTRIBUTE, classes, null);
writer.writeText(value, null);
writer.endElement(HTML.SPAN_ELEM);
}
}
public List<PreparedSelectItem> prepareItems(FacesContext context, UIComponent component) {
if (!isAcceptableComponent(component)) {
return null;
}
List<PreparedSelectItem> itemsList = new ArrayList<PreparedSelectItem>();
UIInplaceSelect inplaceSelect = (UIInplaceSelect) component;
List<SelectItem> selectItems = SelectUtils.getSelectItems(context, inplaceSelect);
for (SelectItem selectItem : selectItems) {
String convertedValue = getConvertedStringValue(context, inplaceSelect, selectItem.getValue());
String label = selectItem.getLabel().trim();
itemsList.add(new PreparedSelectItem(convertedValue, label));
}
return itemsList;
}
public void encodeItems(FacesContext context, UIComponent component, List<PreparedSelectItem> items) throws IOException, IllegalArgumentException {
if (items != null) {
UIInplaceSelect inplaceSelect = (UIInplaceSelect) component;
for (PreparedSelectItem preparedSelectItem : items) {
encodeSuggestion(context, inplaceSelect, preparedSelectItem.getLabel(), RICH_INPLACE_SELECT_CLASSES);
}
}
}
public String encodeScriptAttributes(FacesContext context, UIComponent component) {
StringBuilder attributes = new StringBuilder();
attributes.append("var attributes = ");
ScriptOptions options = new ScriptOptions(component);
String defaultLabel = (String)component.getAttributes().get("defaultLabel");
if (defaultLabel == null || defaultLabel.trim().equals("")) {
defaultLabel = EMPTY_DEFAULT_LABEL;
}
options.addOption("defaultLabel", defaultLabel);
options.addOption("showControls");
options.addOption("editEvent");
options.addOption("verticalPosition", component.getAttributes().get("controlsVerticalPosition"));
options.addOption("horizontalPosition", component.getAttributes().get("controlsHorizontalPosition"));
options.addOption("inputWidth",component.getAttributes().get("selectWidth") );
options.addOption("minInputWidth", component.getAttributes().get("minSelectWidth"));
options.addOption("maxInputWidth", component.getAttributes().get("maxSelectWidth") );
options.addOption("openOnEdit");
options.addOption("showValueInView");
options.addOption("closeOnSelect", true);
attributes.append(options.toScript());
return attributes.toString();
}
public void encodeControlsFacet(FacesContext context, UIComponent component) throws IOException {
UIComponent facet = component.getFacet(CONTROLS_FACET);
if ((facet != null) && (facet.isRendered())) {
renderChild(context, facet);
}
}
public boolean isControlsFacetExists(FacesContext context, UIComponent component) {
UIComponent facet = component.getFacet(CONTROLS_FACET);
if (facet != null && facet.isRendered()) {
return true;
}
return false;
}
@Override
public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
if ("".equals(submittedValue)) {
return null;
} else {
return InputUtils.getConvertedValue(context, component, submittedValue);
}
}
protected Class<? extends UIComponent> getComponentClass() {
return UIInplaceSelect.class;
}
// public String getSelectedItemLabel(FacesContext context, UIInplaceSelect component) {
// String selectedItemLabel = (String)component.getSubmittedValue();
// if(selectedItemLabel == null || !component.isValid()) {
// Object value = component.getAttributes().get("value");
// if (value == null || "".equals(value)) {
// selectedItemLabel = createDefaultLabel(component);
// } else {
// selectedItemLabel = getItemLabel(context, component, value);
// }
// }
// return selectedItemLabel;
// }
public String getAsEventHandler(FacesContext context, UIComponent component, String attributeName) {
JSFunctionDefinition script = getUtils().getAsEventHandler(context, component, attributeName, null);
return ScriptUtils.toScript(script);
}
public String encodeJS(Object object) {
return ScriptUtils.toScript(object);
}
protected String getItemLabel(FacesContext context, UIInplaceSelect component, Object value) {
String itemLabel = null;
boolean equivValues;
// TODO: SelectUtils.getSelectItems is called minimum twice during encode
List<SelectItem> selectItems = SelectUtils.getSelectItems(context, component);
if (!selectItems.isEmpty()) {
for (SelectItem item : selectItems) {
if (value != null) {
equivValues = value.equals(item.getValue());
} else {
equivValues = item.getValue() == null;
}
if (equivValues) {
itemLabel = component.isShowValueInView() ? getConvertedStringValue(context, component, item.getValue()) : item.getLabel();
break;
}
}
}
return itemLabel;
}
protected String createDefaultLabel(UIComponent component) {
String defaultLabel = (String) component.getAttributes().get("defaultLabel");
if (defaultLabel == null || defaultLabel.trim().equals("")) {
defaultLabel = EMPTY_DEFAULT_LABEL;
}
return defaultLabel;
}
protected boolean isEmptyDefaultLabel(String defaultLabel) {
if (EMPTY_DEFAULT_LABEL.equals(defaultLabel)) {
return true;
}
return false;
}
}