/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.core.gui.components.form.flexible.impl.elements.richText; import java.util.List; import org.apache.commons.lang.StringEscapeUtils; import org.olat.core.dispatcher.impl.StaticMediaDispatcher; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.DefaultComponentRenderer; import org.olat.core.gui.components.form.flexible.impl.Form; import org.olat.core.gui.components.form.flexible.impl.FormJSHelper; import org.olat.core.gui.render.RenderResult; import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Formatter; /** * * Description:<br> * This class render the rich text element. It uses the TinyMCE javascript * library * * <P> * Initial Date: 21.04.2009 <br> * * @author gnaegi */ class RichTextElementRenderer extends DefaultComponentRenderer { /** * @see org.olat.core.gui.components.ComponentRenderer#render(org.olat.core.gui.render.Renderer, * org.olat.core.gui.render.StringOutput, * org.olat.core.gui.components.Component, * org.olat.core.gui.render.URLBuilder, * org.olat.core.gui.translator.Translator, * org.olat.core.gui.render.RenderResult, java.lang.String[]) */ @Override public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator, RenderResult renderResult, String[] args) { RichTextElementComponent teC = (RichTextElementComponent) source; RichTextElementImpl te = teC.getRichTextElementImpl(); int rows = teC.getRows(); // DOM ID used to identify the rich text element in the browser DOM String domID = teC.getFormDispatchId(); // Use an empty string as default value String value = te.getRawValue(); if (value == null) { value = ""; } if (!source.isEnabled()) { // Read only view sb.append("<div "); sb.append(FormJSHelper.getRawJSFor(te.getRootForm(), domID, te.getAction())); sb.append(" id=\""); sb.append(domID); sb.append("_disabled\" class='form-control-static o_disabled' style=\""); if (rows != -1) { sb.append(" min-height:").append(rows).append("em;"); } sb.append("\" >"); sb.append(Formatter.formatLatexFormulas(value)); sb.append("</div>"); } else { sb.append("<div id='").append(domID).append("_diw' class='o_richtext_mce"); if(!te.getEditorConfiguration().isPathInStatusBar()) { sb.append(" o_richtext_mce_without_path"); } sb.append("'>"); renderTinyMCE_4(sb, domID, teC, ubu, source.getTranslator()); sb.append("</div>"); } } private void renderTinyMCE_4(StringOutput sb, String domID, RichTextElementComponent teC, URLBuilder ubu, Translator translator) { RichTextElementImpl te = teC.getRichTextElementImpl(); RichTextConfiguration config = te.getEditorConfiguration(); List<String> onInit = config.getOnInit(); StringOutput configurations = new StringOutput(); config.appendConfigToTinyJSArray_4(configurations, translator); if(config.getAdditionalConfiguration() != null) { config.getAdditionalConfiguration().appendConfigToTinyJSArray_4(configurations, translator); } StringOutput baseUrl = new StringOutput(); StaticMediaDispatcher.renderStaticURI(baseUrl, "js/tinymce4/tinymce/tinymce.min.js", true); // Read write view if(config.isInline()) { renderInlineEditor(sb, domID, teC); } else { renderTextarea(sb, domID, teC); } Form form = te.getRootForm(); configurations.append("ffxhrevent: { formNam:\"").append(form.getFormName()).append("\", dispIdField:\"").append(form.getDispatchFieldId()).append("\",") .append(" dispId:\"").append(teC.getFormDispatchId()).append("\", eventIdField:\"").append(form.getEventFieldId()).append("\"}\n"); sb.append("<script type='text/javascript'>/* <![CDATA[ */\n"); //file browser url sb.append(" BTinyHelper.editorMediaUris.put('").append(domID).append("','"); ubu.buildURI(sb, null, null); sb.append("');\n"); sb.append(" jQuery('#").append(domID).append("').tinymce({\n") .append(" selector: '#").append(domID).append("',\n") .append(" script_url: '").append(baseUrl.toString()).append("',\n") .append(" setup: function(ed){\n") .append(" ed.on('init', function(e) {\n") .append(" ").append(onInit.get(0).replace(".curry(", "(")).append(";\n") .append(" });\n") .append(" ed.on('change', function(e) {\n") .append(" BTinyHelper.triggerOnChange('").append(domID).append("');\n") .append(" });\n"); if(config.isInline() || config.isSendOnBlur()) { sb.append(" ed.on('blur', function(e) {\n") .append(" o_ffXHREvent('").append(form.getFormName()).append("','").append(form.getDispatchFieldId()).append("','").append(teC.getFormDispatchId()).append("','").append(form.getEventFieldId()).append("', 2, false, false, false, 'cmd','saveinlinedtiny','").append(domID).append("',ed.getContent());\n") .append(" });\n"); } sb.append(" },\n") .append(configurations) .append(" });\n") .append("/* ]]> */</script>\n"); } private void renderInlineEditor(StringOutput sb, String domID, RichTextElementComponent teC) { RichTextElementImpl te = teC.getRichTextElementImpl(); int cols = teC.getCols(); int rows = teC.getRows(); String value = te.getRawValue(); // Read write view sb.append("<div id=\""); sb.append(domID); sb.append("\" name=\""); sb.append(domID); sb.append("\" "); StringBuilder rawData = FormJSHelper.getRawJSFor(te.getRootForm(), domID, te.getAction()); sb.append(rawData.toString()); sb.append(" style=\""); sb.append(" width:"); if (cols == -1) { sb.append("100%;"); } else { sb.append(cols); sb.append("em;"); } sb.append("height:"); if (rows == -1) { sb.append("100%;"); } else { sb.append(rows); sb.append("em;"); } sb.append("\" class=\"BGlossarIgnore\">"); sb.append(value); sb.append("</div>"); } private void renderTextarea(StringOutput sb, String domID, RichTextElementComponent teC) { RichTextElementImpl te = teC.getRichTextElementImpl(); int cols = teC.getCols(); int rows = teC.getRows(); String value = te.getRawValue(); // Read write view sb.append("<textarea id=\""); sb.append(domID); sb.append("\" name=\""); sb.append(domID); sb.append("\" "); StringBuilder rawData = FormJSHelper.getRawJSFor(te.getRootForm(), domID, te.getAction()); sb.append(rawData.toString()); sb.append(" style=\""); sb.append(" width:"); if (cols == -1) { sb.append("100%;"); } else { sb.append(cols); sb.append("em;"); } sb.append("height:"); if (rows == -1) { sb.append("100%;"); } else { sb.append(rows); sb.append("em;"); } sb.append("\" class=\"BGlossarIgnore\">"); // The value needs to be encoded when loading into the editor to properly display < > etc values. // See http://tinymce.moxiecode.com/punbb/viewtopic.php?id=1846 sb.append(StringEscapeUtils.escapeHtml(value)); sb.append("</textarea>"); } }