001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS (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 *     <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
016 *
017 * $Id: HtmlEditorRenderer.java 28610 2008-01-09 17:13:52Z sfermigier $
018 */
019
020package org.nuxeo.ecm.platform.ui.web.component.editor;
021
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Locale;
027import java.util.Map;
028
029import javax.faces.component.UIComponent;
030import javax.faces.component.UIInput;
031import javax.faces.context.FacesContext;
032import javax.faces.context.ResponseWriter;
033
034import org.apache.commons.lang.StringUtils;
035import org.nuxeo.ecm.platform.ui.web.htmleditor.api.HtmlEditorPluginService;
036import org.nuxeo.runtime.api.Framework;
037
038import com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer;
039
040/**
041 * Renderer for html editor component.
042 * <p>
043 * Uses TinyMCE javascript editor.
044 *
045 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
046 */
047public class HtmlEditorRenderer extends HtmlBasicInputRenderer {
048
049    private static Map<String, String> pluginsOptions;
050
051    private static Map<String, String> toolbarPluginsOptions;
052
053    @Override
054    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
055        if (!component.isRendered()) {
056            return;
057        }
058
059        UIHtmlEditor editorComp = (UIHtmlEditor) component;
060        ResponseWriter writer = context.getResponseWriter();
061        Locale locale = context.getViewRoot().getLocale();
062
063        // tiny MCE generic scripts now included in every page header
064
065        // script to actually init tinyMCE with configured options
066        String editorSelector = editorComp.getEditorSelector();
067        // plugins registration
068        if (pluginsOptions == null) {
069            final HtmlEditorPluginService pluginService = Framework.getLocalService(HtmlEditorPluginService.class);
070            pluginsOptions = new HashMap<String, String>();
071            pluginsOptions.put("plugins", pluginService.getFormattedPluginsNames());
072            toolbarPluginsOptions = new HashMap<String, String>();
073            toolbarPluginsOptions.put("toolbar", pluginService.getFormattedToolbarsButtonsNames());
074        }
075
076        String clientId = editorComp.getClientId(context);
077        boolean disableHtmlInit = Boolean.TRUE.equals(editorComp.getDisableHtmlInit());
078
079        // input text area
080        writer.startElement("textarea", editorComp);
081        writer.writeAttribute("id", clientId, null);
082        writer.writeAttribute("name", clientId, null);
083        if (Boolean.TRUE.equals(editorComp.getDisableHtmlInit())) {
084            writer.writeAttribute("class", editorSelector + ",disableMCEInit", null);
085        } else {
086            writer.writeAttribute("class", editorSelector, null);
087        }
088        writer.writeAttribute("rows", editorComp.getRows(), null);
089        writer.writeAttribute("cols", editorComp.getCols(), null);
090        Object currentValue = getCurrentValue(editorComp);
091        if (currentValue != null) {
092            writer.writeText(currentValue, null);
093        } else {
094            writer.writeText("", null);
095        }
096        writer.endElement("textarea");
097
098        if (!disableHtmlInit) {
099            writer.startElement("script", editorComp);
100            writer.writeAttribute("type", "text/javascript", null);
101            // Since 5.7.3, use unique clientId instead of editorSelector value
102            // so that tiny mce editors are initialized individually: no need
103            // anymore to specify a class to know which one should or should
104            // not be initialized
105            String scriptContent = String.format("initTinyMCE(%s, %s, '%s', '%s', '%s', '%s');", editorComp.getWidth(),
106                    editorComp.getHeight(), clientId, pluginsOptions.get("plugins"), locale.getLanguage(),
107                    toolbarPluginsOptions.get("toolbar"));
108            writer.writeText(scriptContent, null);
109            String ajaxScriptContent = String.format(
110                    "jsf.ajax.addOnEvent(function(data) {if (data.status == \"success\") {%s}});", scriptContent);
111            writer.writeText(ajaxScriptContent, null);
112            String scriptContent2 = String.format(
113                    "jQuery(document.getElementById('%s')).closest('form').bind('ajaxsubmit', function() { var editor = tinyMCE.editors['%s']; if (editor != undefined) {editor.save()};});",
114                    clientId, clientId);
115            writer.writeText(scriptContent2, null);
116            writer.endElement("script");
117        }
118
119        writer.flush();
120    }
121
122    protected static Object getCurrentValue(UIInput comp) {
123        Object submitted = comp.getSubmittedValue();
124        if (submitted != null) {
125            return submitted;
126        }
127        return comp.getValue();
128    }
129
130    protected static String generateOptions(Map<String, String> options) {
131        List<String> strOptions = new ArrayList<String>();
132        for (Map.Entry<String, String> option : options.entrySet()) {
133            strOptions.add(String.format("%s : \"%s\"", option.getKey(), option.getValue()));
134        }
135        StringBuilder res = new StringBuilder();
136        res.append('{');
137        res.append(StringUtils.join(strOptions.toArray(), ", "));
138        res.append('}');
139        return res.toString();
140    }
141
142}