001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others.
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-2.1.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 *     Thomas Roger
016 */
017
018package org.nuxeo.ecm.platform.ui.web.component.message;
019
020import java.io.IOException;
021import java.util.Iterator;
022
023import javax.faces.application.FacesMessage;
024import javax.faces.component.UIComponent;
025import javax.faces.component.UIMessages;
026import javax.faces.context.FacesContext;
027import javax.faces.context.ResponseWriter;
028
029import org.apache.commons.lang.StringEscapeUtils;
030import org.nuxeo.runtime.api.Framework;
031
032import com.sun.faces.renderkit.html_basic.MessagesRenderer;
033
034/**
035 * Handles rendering of {@link javax.faces.application.FacesMessage} through jQuery Ambiance plugin.
036 *
037 * @since 5.7.3
038 */
039public class NXMessagesRenderer extends MessagesRenderer {
040
041    public static final String RENDERER_TYPE = "javax.faces.NXMessages";
042
043    @Override
044    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
045        rendererParamsNotNull(context, component);
046
047        if (!shouldEncode(component)) {
048            return;
049        }
050
051        // If id is user specified, we must render
052        boolean mustRender = shouldWriteIdAttribute(component);
053
054        UIMessages messages = (UIMessages) component;
055        ResponseWriter writer = context.getResponseWriter();
056        assert (writer != null);
057
058        String clientId = ((UIMessages) component).getFor();
059        // if no clientId was included
060        if (clientId == null) {
061            // and the author explicitly only wants global messages
062            if (messages.isGlobalOnly()) {
063                // make it so only global messages get displayed.
064                clientId = "";
065            }
066        }
067
068        // "for" attribute optional for Messages
069        Iterator messageIter = getMessageIter(context, clientId, component);
070
071        assert (messageIter != null);
072
073        if (!messageIter.hasNext()) {
074            if (mustRender) {
075                // no message to render, but must render anyway
076                // but if we're writing the dev stage messages,
077                // only write it if messages exist
078                if ("javax_faces_developmentstage_messages".equals(component.getId())) {
079                    return;
080                }
081                writer.startElement("div", component);
082                writeIdAttributeIfNecessary(context, writer, component);
083                writer.endElement("div");
084            } // otherwise, return without rendering
085            return;
086        }
087
088        boolean showDetail = messages.isShowDetail();
089
090        while (messageIter.hasNext()) {
091            FacesMessage curMessage = (FacesMessage) messageIter.next();
092            if (curMessage.isRendered() && !messages.isRedisplay()) {
093                continue;
094            }
095            curMessage.rendered();
096
097            // make sure we have a non-null value for summary and
098            // detail.
099            String summary = (null != (summary = curMessage.getSummary())) ? summary : "";
100            // Default to summary if we have no detail
101            String detail = (null != (detail = curMessage.getDetail())) ? detail : summary;
102
103            String severityStyleClass = null;
104            String errorType = "default";
105            long timeout = 5;
106            if (curMessage.getSeverity() == FacesMessage.SEVERITY_INFO) {
107                severityStyleClass = (String) component.getAttributes().get("infoClass");
108                errorType = "info";
109            } else if (curMessage.getSeverity() == FacesMessage.SEVERITY_WARN) {
110                severityStyleClass = (String) component.getAttributes().get("warnClass");
111                errorType = "warn";
112            } else if (curMessage.getSeverity() == FacesMessage.SEVERITY_ERROR) {
113                severityStyleClass = (String) component.getAttributes().get("errorClass");
114                errorType = "error";
115                timeout = 0;
116            } else if (curMessage.getSeverity() == FacesMessage.SEVERITY_FATAL) {
117                severityStyleClass = (String) component.getAttributes().get("fatalClass");
118                errorType = "fatal";
119                timeout = 0;
120            }
121
122            // ensure message stays visible when running tests
123            if (Framework.getProperty("org.nuxeo.ecm.tester.name") != null) {
124                timeout = 0;
125            }
126
127            writer.startElement("script", messages);
128            writer.writeAttribute("type", "text/javascript", null);
129
130            String scriptContent = "jQuery(document).ready(function() {\n" + "  jQuery.ambiance({\n" + "    "
131                    + "message: \"%s\",\n" + "    title: \"%s\",\n" + "    type: \"%s\",\n"
132                    + "    className: \"%s\",\n" + "    timeout: \"%d\"" + "  })\n" + "});\n";
133            String formattedScriptContent;
134            if (showDetail) {
135                formattedScriptContent = String.format(scriptContent, StringEscapeUtils.escapeJavaScript(detail),
136                        StringEscapeUtils.escapeJavaScript(summary), errorType, severityStyleClass, timeout);
137            } else {
138                formattedScriptContent = String.format(scriptContent, "", StringEscapeUtils.escapeJavaScript(summary),
139                        errorType, severityStyleClass, timeout);
140            }
141            writer.writeText(formattedScriptContent, null);
142            writer.endElement("script");
143
144        }
145    }
146}