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