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