001/*
002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Anahide Tchertchian
016 */
017package org.nuxeo.ecm.platform.ui.web.renderer;
018
019import static com.sun.faces.renderkit.Attribute.attr;
020import static com.sun.faces.util.CollectionsUtils.ar;
021
022import java.io.IOException;
023import java.util.Map;
024import java.util.logging.Level;
025
026import javax.faces.component.UIComponent;
027import javax.faces.component.UIGraphic;
028import javax.faces.context.FacesContext;
029import javax.faces.context.ResponseWriter;
030
031import org.apache.commons.lang.StringUtils;
032
033import com.sun.faces.RIConstants;
034import com.sun.faces.renderkit.Attribute;
035import com.sun.faces.renderkit.RenderKitUtils;
036import com.sun.faces.renderkit.html_basic.ImageRenderer;
037
038/**
039 * Renderer that does not display an empty "img" tag as well as empty width and height attributes (as it's an issue for
040 * IE)
041 *
042 * @since 5.6
043 */
044public class NXImageRenderer extends ImageRenderer {
045
046    // remove attributes height and width from default attributes to avoid
047    // adding them when empty
048    protected static final Attribute[] ATTRIBUTES = ar(
049            //
050            attr("alt"),
051            //
052            attr("dir"),
053            //
054            // attr("height"),
055            //
056            attr("lang"),
057            //
058            attr("longdesc"),
059            //
060            attr("onclick", "click"),
061            attr("ondblclick", "dblclick"),
062            //
063            attr("onkeydown", "keydown"), attr("onkeypress", "keypress"), attr("onkeyup", "keyup"),
064            attr("onmousedown", "mousedown"),
065            //
066            attr("onmousemove", "mousemove"), attr("onmouseout", "mouseout"), attr("onmouseover", "mouseover"),
067            attr("onmouseup", "mouseup"),
068            //
069            attr("role"), attr("style"), attr("title"), attr("usemap")
070    //
071    // attr("width")
072    );
073
074    public static final String RENDERER_TYPE = "javax.faces.NXImage";
075
076    @Override
077    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
078
079        rendererParamsNotNull(context, component);
080
081        if (!shouldEncode(component)) {
082            return;
083        }
084
085        ResponseWriter writer = context.getResponseWriter();
086
087        // do not even render tag if url is empty
088        String src = src(context, component);
089        if (StringUtils.isBlank(src)) {
090            if (logger.isLoggable(Level.FINER)) {
091                logger.log(Level.FINER,
092                        "Do not render empty img tag with empty src value for component " + component.getId());
093            }
094        } else {
095            Map<String, Object> attrs = component.getAttributes();
096
097            // Get the attributes
098            String width = (String) attrs.get("width");
099            String height = (String) attrs.get("height");
100            String enableContainer = (String) attrs.get("enableContainer");
101
102            boolean hasDivContainer = false;
103            if (enableContainer != null && Boolean.parseBoolean(enableContainer) == true) {
104                hasDivContainer = true;
105            }
106
107            if (hasDivContainer) {
108                writer.startElement("div", component);
109                writer.writeAttribute("class", "pictureContainer", "class");
110
111                StringBuilder styleBuilder = new StringBuilder();
112                if (!StringUtils.isEmpty(width)) {
113                    styleBuilder.append("width:");
114                    styleBuilder.append(width);
115                    styleBuilder.append("px;");
116                }
117                if (!StringUtils.isEmpty(height)) {
118                    styleBuilder.append("height:");
119                    styleBuilder.append(height);
120                    styleBuilder.append("px;");
121                }
122                if (styleBuilder.length() > 0) {
123                    writer.writeAttribute("style", styleBuilder.toString(), "style");
124                }
125            }
126
127            writer.startElement("img", component);
128            writeIdAttributeIfNecessary(context, writer, component);
129            writer.writeURIAttribute("src", src, "value");
130
131            // if we're writing XHTML and we have a null alt attribute
132            if (writer.getContentType().equals(RIConstants.XHTML_CONTENT_TYPE) && null == attrs.get("alt")) {
133                // write out an empty alt
134                writer.writeAttribute("alt", "", "alt");
135            }
136
137            RenderKitUtils.renderPassThruAttributes(context, writer, component, ATTRIBUTES);
138            // If the container is not activated and the width and/or height are defined, these attributes are set on
139            // the img directly
140            if (!hasDivContainer) {
141                if (!StringUtils.isBlank(width)) {
142                    writer.writeAttribute("width", width, "width");
143                }
144                if (!StringUtils.isBlank(height)) {
145                    writer.writeAttribute("height", height, "height");
146                }
147            }
148
149            RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer, component);
150
151            String styleClass = (String) attrs.get("styleClass");
152            if (!StringUtils.isBlank(styleClass)) {
153                writer.writeAttribute("class", styleClass, "styleClass");
154            }
155
156            writer.endElement("img");
157
158            if (hasDivContainer) {
159                writer.endElement("div");
160            }
161        }
162
163        if (logger.isLoggable(Level.FINER)) {
164            logger.log(Level.FINER, "End encoding component " + component.getId());
165        }
166
167    }
168
169    protected static String src(FacesContext context, UIComponent component) {
170        String value = (String) ((UIGraphic) component).getValue();
171        if (value == null) {
172            return "";
173        }
174        value = context.getApplication().getViewHandler().getResourceURL(context, value);
175        return (context.getExternalContext().encodeResourceURL(value));
176    }
177
178}