/* * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * 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. * * Contributors: * George Lefter * * $Id$ */ package org.nuxeo.ecm.platform.ui.web.directory; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.faces.component.UICommand; import javax.faces.component.UIGraphic; import javax.faces.component.html.HtmlInputHidden; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import org.apache.commons.lang.StringUtils; import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils; /** * @author <a href="mailto:glefter@nuxeo.com">George Lefter</a> * */ public class ChainSelectMany extends ChainSelectBase { public static final String ADD_BUTTON = "addButton"; private static final String REMOVE_BUTTON = "removeButton"; /* a hidden input set if the value of the component is empty */ private static final String EMPTY_VALUE_MARKER = "emptyValueMarker"; /* a hidden input to hold the remove entry id */ private static final String REMOVE_HIDDEN = "removeHidden"; /* a hidden input set if the user click the add button */ private static final String ADD_HIDDEN = "addHidden"; public ChainSelectMany() { FacesContext context = FacesContext.getCurrentInstance(); HtmlInputHidden emptyValueMarker = new HtmlInputHidden(); emptyValueMarker.setId("emptyValueMarker"); emptyValueMarker.setValue("true"); getFacets().put(EMPTY_VALUE_MARKER, emptyValueMarker); UICommand addButton = (UICommand) context.getApplication().createComponent( "org.ajax4jsf.ajax.CommandButton"); addButton.getAttributes().put("id", "addButton"); addButton.getAttributes().put("value", "add"); getFacets().put(ADD_BUTTON, addButton); HtmlInputHidden addHidden = new HtmlInputHidden(); addHidden.setId("addHidden"); getFacets().put(ADD_HIDDEN, addHidden); UICommand removeButton = (UICommand) context.getApplication().createComponent( "org.ajax4jsf.ajax.CommandLink"); UIGraphic image = new UIGraphic(); image.setValue("/icons/delete.png"); removeButton.getAttributes().put("id", "removeButton"); removeButton.getChildren().add(image); getFacets().put(REMOVE_BUTTON, removeButton); HtmlInputHidden removeHidden = new HtmlInputHidden(); removeHidden.setId("removeHidden"); getFacets().put(REMOVE_HIDDEN, removeHidden); } @Override public void decode(FacesContext context) { if (getDisplayValueOnly()) { return; } decodeSelection(context); decodeValue(context); setValid(true); } private void decodeValue(FacesContext context) { String emptyValueMarkerClientId = getFacet(EMPTY_VALUE_MARKER).getClientId( context); String removeEntryClientId = getFacet(REMOVE_HIDDEN).getClientId( context); String addEntryClientId = getFacet(ADD_HIDDEN).getClientId(context); Map<String, String> map = context.getExternalContext().getRequestParameterMap(); String removeEntryId = map.get(removeEntryClientId); boolean addButtonClicked = "true".equals(map.get(addEntryClientId)); String allValues = map.get(emptyValueMarkerClientId); String[] oldValue = StringUtils.split(allValues, ","); List<String> valueList = new ArrayList<String>(Arrays.asList(oldValue)); if (addButtonClicked) { String[] selection = getSelection(); if (validateEntry(context, selection)) { valueList.add(StringUtils.join(selection, getKeySeparator())); } } if (!StringUtils.isEmpty(removeEntryId)) { valueList.remove(removeEntryId); } String[] newValue = valueList.toArray(new String[valueList.size()]); setSubmittedValue(newValue); } @Override public String[] getSelection() { String clientId = getClientId(FacesContext.getCurrentInstance()); String[] selection = selectionMap.get(clientId); if (selection == null) { selection = new String[0]; selectionMap.put(clientId, selection); } return selection; } @Override public void encodeBegin(FacesContext context) throws IOException { if (getDisplayValueOnly()) { encodeReadOnly(context); } else { encodeReadWrite(context); } } public void encodeReadWrite(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); getChildren().clear(); writer.startElement("div", this); writer.writeAttribute("id", getClientId(context), "id"); String style = getStyle(); if (style != null) { writer.writeAttribute("style", style, "style"); } String styleClass = getStyleClass(); if (styleClass != null) { writer.writeAttribute("class", styleClass, "class"); } String[] selectedKeys = getSelection(); for (int level = 0; level < getDepth(); level++) { encodeListbox(context, level, selectedKeys); } encodeAddButton(context); encodeValue(context); writer.endElement("div"); } public void encodeReadOnly(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); String[] values = (String[]) getSubmittedValue(); if (values == null) { values = (String[]) getValue(); } if (values != null) { writer.startElement("div", this); for (String value: values) { String[] keys = StringUtils.split(value, getKeySeparator()); List<DirectoryEntry> nodes = resolveKeys(keys); List<String> labels = new ArrayList<String>(); for (DirectoryEntry node: nodes) { String itemValue = node.getId(); String itemLabel = node.getLabel(); itemLabel = computeItemLabel(context, itemValue, itemLabel); labels.add(itemLabel); } String concatenatedLabel = StringUtils.join(labels.iterator(), getKeySeparator()); writer.startElement("div", this); writer.write(concatenatedLabel); writer.endElement("div"); } writer.endElement("div"); } } private void encodeAddButton(FacesContext context) throws IOException { UICommand addButton = (UICommand) getFacet(ADD_BUTTON); HtmlInputHidden addHidden = (HtmlInputHidden) getFacet(ADD_HIDDEN); String addJs = String.format( "document.getElementById('%s').value = '%s'", addHidden.getClientId(context), "true"); addButton.getAttributes().put("onclick", addJs); addHidden.setValue(""); String reRender = getReRender(); if (reRender == null) { reRender = getId(); } addButton.getAttributes().put("reRender", reRender); ComponentUtils.encodeComponent(context, addButton); ComponentUtils.encodeComponent(context, addHidden); } @Override public boolean getRendersChildren() { return true; } @Override public void encodeChildren(FacesContext context) throws IOException { } private void encodeValue(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); String[] values = (String[]) getSubmittedValue(); if (values == null) { values = (String[]) getValue(); } String compValue = StringUtils.join(values, ","); compValue = compValue == null ? "" : compValue; HtmlInputHidden emptyValueMarker = (HtmlInputHidden) getFacet(EMPTY_VALUE_MARKER); emptyValueMarker.setValue(compValue); ComponentUtils.encodeComponent(context, emptyValueMarker); if (values != null) { HtmlInputHidden removeHidden = (HtmlInputHidden) getFacet(REMOVE_HIDDEN); removeHidden.setValue(""); ComponentUtils.encodeComponent(context, removeHidden); UICommand removeButton = (UICommand) getFacet(REMOVE_BUTTON); String reRender = getReRender(); if (reRender == null) { reRender = getId(); } removeButton.getAttributes().put("reRender", reRender); writer.startElement("div", this); for (String value: values) { String[] keys = StringUtils.split(value, getKeySeparator()); List<DirectoryEntry> nodes = resolveKeys(keys); List<String> labels = new ArrayList<String>(); for (DirectoryEntry node: nodes) { String itemValue = node.getId(); String itemLabel = node.getLabel(); itemLabel = computeItemLabel(context, itemValue, itemLabel); labels.add(itemLabel); } String concatenatedLabel = StringUtils.join( labels.iterator(), getKeySeparator()); writer.startElement("div", this); String removeJs = String.format( "document.getElementById('%s').value = '%s'", removeHidden.getClientId(context), value); removeButton.getAttributes().put("onclick", removeJs); ComponentUtils.encodeComponent(context, removeButton); writer.write(concatenatedLabel); writer.endElement("div"); } writer.endElement("div"); } } /* * the number of visible components */ public int getCurrentDepth() { return getDepth(); } @Override public String getFamily() { return "nxdirectory.ChainSelectMany"; } @Override public String getRendererType() { return null; } @Override public Object saveState(FacesContext context) { Object[] values = new Object[1]; values[0] = super.saveState(context); return values; } @Override public void restoreState(FacesContext context, Object state) { Object[] values = (Object[]) state; super.restoreState(context, values[0]); } }