/**
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.webui.form.wysiwyg;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.exoplatform.web.resource.config.xml.FCKConfigListener;
/**
* FCKeditor control class.<br>
*
* It creates the html code for the FCKeditor based on the following things:
* <ul>
* <li>browser's capabilities</li>
* <li>different properties settings managed by the {@link PropertiesLoader}</li>
* <li>settings from the 'caller', eg. jsp-pages</li>
* </ul>
*
* @version $Id: FCKeditor.java 1682 2008-03-05 17:27:06Z th-schwarz $
*/
public class FCKEditor {
private static final String DEFAULT_HEIGHT = "300".intern();
private static final String DEFAULT_WIDTH = "100%".intern();
private static final String DEFAULT_TOOLBAR = "Basic".intern();
private FCKEditorConfig config;
private String instanceName;
private String value;
private String basePath;
private HttpServletRequest request;
private String toolbarSet;
private String width;
private String height;
/**
* Main constructor.<br>
* All important settings are done here and will be preset by there defaults taken from {@link PropertiesLoader}.
*
* @param request request object
* @param instanceName unique name
* @param width width
* @param height height
* @param toolbarSet toolbarSet name
*/
public FCKEditor(final HttpServletRequest request, final String instanceName, final String width, final String height,
final String toolbarSet, final String value, final String basePath) {
this.request = request;
this.instanceName = instanceName;
this.width = width;
this.height = height;
this.toolbarSet = toolbarSet;
this.value = value;
// this.basePath = request.getContextPath().concat(basePath);
this.basePath = basePath;
config = new FCKEditorConfig();
}
/**
* Just a wrapper to {@link FCKEditor}.
*
* @param request request object
* @param instanceName unique name
*/
public FCKEditor(final HttpServletRequest request, final String instanceName) {
this(request, instanceName, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_TOOLBAR, null, FCKConfigListener.FCK_CONTEXT_PATH
+ "/fckeditor");
}
/**
* Set the unique name of the editor
*
* @param value name
*/
public void setInstanceName(final String value) {
instanceName = value;
}
/**
* Set the initial value to be edited.<br>
* In HTML code
*
* @param value value
*/
public void setValue(final String value) {
this.value = value;
}
/**
* Set the dir where the FCKeditor files reside on the server.<br>
* <b>Remarks</b>:<br>
* Avoid using relative paths. It is preferable to set the base path starting from the root (/).<br>
* Always finish the path with a slash (/).
*
* @param value path
*/
public void setBasePath(final String value) {
basePath = value;
}
/**
* Set the name of the toolbar to display
*
* @param value toolbar name
*/
public void setToolbarSet(final String value) {
toolbarSet = value;
}
/**
* Set the width of the textarea
*
* @param value width
*/
public void setWidth(final String value) {
width = value;
}
/**
* Set the height of the textarea
*
* @param value height
*/
public void setHeight(final String value) {
height = value;
}
/**
* Get the advanced configuation set.<br>
* Adding element to this collection you can override the settings specified in the config.js file.
*
* @return configuration collection
*/
public FCKEditorConfig getConfig() {
return config;
}
/**
* Set the advanced configuation set.
*
* @param value configuration collection
*/
public void setConfig(FCKEditorConfig value) {
config = value;
}
private String escapeXml(String txt) {
txt = txt.replaceAll("&", "&");
txt = txt.replaceAll("<", "<");
txt = txt.replaceAll(">", ">");
txt = txt.replaceAll("\"", """);
txt = txt.replaceAll("'", "'");
return txt;
}
/**
* Minimum implementation, see ticket #27 for detailed information.
*/
public String create() {
return createHtml();
}
@Override
public String toString() {
return createHtml();
}
/**
* Generate the HTML Code for the editor. <br>
* Evalute the browser capabilities and generate the editor if compatible, or a simple textarea otherwise.
*
* @return html code
*/
public String createHtml() {
StringBuffer strEditor = new StringBuffer();
strEditor.append("<div>");
String encodedValue = escapeXml(value.replaceAll("((\r?\n)+|\t*)", ""));
if (check(request.getHeader("user-agent"))) {
strEditor.append(createInputForVariable(instanceName, instanceName, encodedValue));
// create config html
String configStr = config.getUrlParams();
if (configStr != null && configStr.length() > 0) {
configStr = configStr.substring(1);
strEditor.append(createInputForVariable(null, instanceName.concat("___Config"), configStr));
}
// create IFrame
String sLink = basePath.concat("/editor/fckeditor.html?InstanceName=").concat(instanceName);
if (toolbarSet != null && toolbarSet.length() > 0) {
sLink += "&Toolbar=".concat(toolbarSet);
}
XHtmlTagTool iframeTag = new XHtmlTagTool("iframe", XHtmlTagTool.SPACE);
iframeTag.addAttribute("id", instanceName.concat("___Frame"));
iframeTag.addAttribute("src", sLink);
iframeTag.addAttribute("width", width);
iframeTag.addAttribute("height", height);
iframeTag.addAttribute("frameborder", "no");
iframeTag.addAttribute("scrolling", "no");
strEditor.append(iframeTag);
} else {
XHtmlTagTool textareaTag = new XHtmlTagTool("textarea", encodedValue);
textareaTag.addAttribute("name", instanceName);
textareaTag.addAttribute("rows", "4");
textareaTag.addAttribute("cols", "40");
textareaTag.addAttribute("wrap", "virtual");
textareaTag.addAttribute("style", "width: ".concat(width).concat("; height: ").concat(height));
}
strEditor.append("</div>");
return strEditor.toString();
}
private String createInputForVariable(final String name, final String id, final String value) {
XHtmlTagTool tag = new XHtmlTagTool("input");
// if (Utils.isNotEmpty(id))
tag.addAttribute("id", id);
// if (Utils.isNotEmpty(name))
tag.addAttribute("name", name);
tag.addAttribute("value", value);
tag.addAttribute("type", "hidden");
return tag.toString();
}
public boolean check(final String userAgentString) {
float version;
// IE 5.5+, check special keys like 'Opera' and 'mac', because there are some
// other browsers, containing 'MSIE' in there agent string!
if (userAgentString.indexOf("Opera") < 0 && userAgentString.indexOf("mac") < 0) {
version = getBrowserVersion(userAgentString, ".*MSIE ([\\d]+.[\\d]+).*");
if (version != -1f && version >= 5.5f)
return true;
}
// for mozilla only, because all firefox versions are supported
version = getBrowserVersion(userAgentString, ".*Gecko/([\\d]+).*");
if (version != -1f && version >= 20030210f)
return true;
// Opera 9.5+
version = getBrowserVersion(userAgentString, "Opera/([\\d]+.[\\d]+).*");
if (version != -1f && version >= 9.5f)
return true;
version = getBrowserVersion(userAgentString, ".*Opera ([\\d]+.[\\d]+)");
if (version != -1f && version >= 9.5f)
return true;
// Safari 3+
version = getBrowserVersion(userAgentString, ".*AppleWebKit/([\\d]+).*");
if (version != -1f && version >= 522f)
return true;
return false;
}
/**
* Helper method to get the the browser version from 'userAgent' with the regular expression 'regex'. The first group of the
* matches has to be the version number!
*
* @param userAgent
* @param regex
* @return The browser version, or -1f, if version con't find out.
*/
private float getBrowserVersion(final String userAgent, final String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(userAgent);
if (matcher.matches()) {
try {
return Float.parseFloat(matcher.group(1));
} catch (NumberFormatException e) {
return -1f;
}
}
return -1f;
}
}