View Javadoc

1   /*
2    * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3    * Copyright (C) 2003-2008 Frederico Caldeira Knabben
4    * 
5    * == BEGIN LICENSE ==
6    * 
7    * Licensed under the terms of any of the following licenses at your
8    * choice:
9    * 
10   *  - GNU General Public License Version 2 or later (the "GPL")
11   *    http://www.gnu.org/licenses/gpl.html
12   * 
13   *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14   *    http://www.gnu.org/licenses/lgpl.html
15   * 
16   *  - Mozilla Public License Version 1.1 or later (the "MPL")
17   *    http://www.mozilla.org/MPL/MPL-1.1.html
18   * 
19   * == END LICENSE ==
20   */
21  
22  package net.fckeditor;
23  
24  import javax.servlet.http.HttpServletRequest;
25  
26  import net.fckeditor.handlers.PropertiesLoader;
27  import net.fckeditor.tool.Compatibility;
28  import net.fckeditor.tool.Utils;
29  import net.fckeditor.tool.XHtmlTagTool;
30  
31  /**
32   * Java represantation of the FCKeditor. This class creates the html code for
33   * the FCKeditor based on the following things:
34   * <ul>
35   * <li>browser capabilities</li>
36   * <li>different properties settings managed by the {@link PropertiesLoader}</li>
37   * <li>settings from the FCKeditor tag, template engines and other systems</li>
38   * </ul>
39   * 
40   * @version $Id: FCKeditor.java 2538 2008-10-10 18:27:19Z mosipov $
41   */
42  public class FCKeditor {
43  
44  	private FCKeditorConfig config;
45  	private String instanceName;
46  	private String value;
47  	private HttpServletRequest request;
48  
49  	// defaults
50  	private String toolbarSet = PropertiesLoader.getProperty("fckeditor.toolbarSet");
51  	private String width = PropertiesLoader.getProperty("fckeditor.width");
52  	private String height = PropertiesLoader.getProperty("fckeditor.height");
53  	private String basePath = PropertiesLoader.getProperty("fckeditor.basePath");
54  
55  	/**
56  	 * Main constructor.<br />
57  	 * All important settings are done here and will be preset by the defaults
58  	 * taken from {@link PropertiesLoader}. Any parameter except instanceName
59  	 * failing {@link Utils#isNotBlank(String)} will be ignored.
60  	 * 
61  	 * @param request
62  	 *            request object
63  	 * @param instanceName
64  	 *            unique name
65  	 * @param width
66  	 *            width
67  	 * @param height
68  	 *            height
69  	 * @param toolbarSet
70  	 *            toolbarSet name
71  	 * @throws IllegalArgumentException
72  	 *             when instanceName is not valid HTML id
73  	 */
74  	public FCKeditor(final HttpServletRequest request, final String instanceName,
75  	        final String width, final String height, final String toolbarSet, final String value,
76  	        final String basePath) {
77  		this.request = request;
78  		if (Utils.isBlank(instanceName))
79  			throw new IllegalArgumentException(
80  					"instanceName must be a valid HTML id");
81  		else
82  			this.instanceName = instanceName;
83  		if (Utils.isNotBlank(width))
84  			this.width = width;
85  		if (Utils.isNotBlank(height))
86  			this.height = height;
87  		if (Utils.isNotBlank(toolbarSet))
88  			this.toolbarSet = toolbarSet;
89  		// TODO Should be check here for empty or blank?
90  		if (Utils.isNotEmpty(value))
91  			this.value = value;
92  			else
93  				this.value = new String();
94  		if (Utils.isNotBlank(basePath))
95  			this.basePath = request.getContextPath().concat(basePath);
96  		else
97  			this.basePath = request.getContextPath().concat(this.basePath);
98  
99  		config = new FCKeditorConfig();
100 	}
101 
102 	/**
103 	 * Just a wrapper to {@link FCKeditor}.
104 	 * 
105 	 * @param request
106 	 *            request object
107 	 * @param instanceName
108 	 *            unique name
109 	 */
110 
111 	public FCKeditor(final HttpServletRequest request, final String instanceName) {
112 		this(request, instanceName, null, null, null, null, null);
113 	}
114 
115 	/**
116 	 * Set the unique name of the editor
117 	 * 
118 	 * @param instanceName
119 	 *            name
120 	 */
121 	public void setInstanceName(final String instanceName) {
122 		this.instanceName = instanceName;
123 	}
124 
125 	/**
126 	 * Set the initial value to be edited as HTML markup.
127 	 * 
128 	 * @param value
129 	 *            value
130 	 */
131 	public void setValue(final String value) {
132 		this.value = value;
133 	}
134 
135 	/**
136 	 * Sets the directory where the FCKeditor resides on the server.<br />
137 	 * <strong>Remarks</strong>: Avoid using relative paths. Use an absolute
138 	 * path from the context (e.g. /fckeditor).
139 	 * 
140 	 * @param basePath
141 	 *            path
142 	 */
143 	public void setBasePath(final String basePath) {
144 		this.basePath = basePath;
145 	}
146 
147 	/**
148 	 * Set the name of the toolbar to display
149 	 * 
150 	 * @param toolbarSet
151 	 *            toolbar name
152 	 */
153 	public void setToolbarSet(final String toolbarSet) {
154 		this.toolbarSet = toolbarSet;
155 	}
156 
157 	/**
158 	 * Set the width of the textarea
159 	 * 
160 	 * @param width
161 	 *            width
162 	 */
163 	public void setWidth(final String width) {
164 		this.width = width;
165 	}
166 
167 	/**
168 	 * Set the height of the textarea
169 	 * 
170 	 * @param height
171 	 *            height
172 	 */
173 	public void setHeight(final String height) {
174 		this.height = height;
175 	}
176 
177 	/**
178 	 * Get the advanced configuration set.<br />
179 	 * By adding elements to this collection you can override the settings
180 	 * specified in the config.js file.
181 	 * 
182 	 * @return configuration collection
183 	 */
184 	public FCKeditorConfig getConfig() {
185 		return config;
186 	}
187 	/**
188 	 * Set the advanced configuation set.
189 	 * 
190 	 * @param config
191 	 *            configuration collection
192 	 */
193 	public void setConfig(FCKeditorConfig config) {
194 		this.config = config;
195 	}
196 
197 	/**
198 	 * Escape base XML entities as specified <a
199 	 * href="http://en.wikipedia.org/wiki/Xml#Entity_references">here</a>.
200 	 * 
201 	 * @param str
202 	 *            Text to escape.
203 	 * @return Escaped text.
204 	 */
205 	private String escapeXml(String str) {
206 		if (Utils.isEmpty(str))
207 			return str;
208 		
209 		/*
210 		 * TODO Strings are inefficent. It should be done like in Commons Lang
211 		 * 2.4 StringUtils#replaceEach(String, String[], String[])
212 		 */
213 		str = str.replaceAll("&", "&amp;");
214 		str = str.replaceAll("<", "&lt;");
215 		str = str.replaceAll(">", "&gt;");
216 		str = str.replaceAll("\"", "&quot;");
217 		str = str.replaceAll("'", "&#39;");
218 		return str;
219 	}
220 	
221 	/*
222 	 * (non-Javadoc)
223 	 * 
224 	 * @see #createHtml()
225 	 */
226 	/**
227 	 * This method simply wraps to {@link #createHtml()}.
228 	 * @see #createHtml()
229 	 */
230 	@Override
231 	public String toString() {
232 		return createHtml();
233 	}
234 
235 	/**
236 	 * Minimum implementation, see ticket #27 for detailed information. Generate
237 	 * the HTML Code for the editor.<br />
238 	 * Evaluate the browser capabilities and generate the editor if compatible,
239 	 * or a simple textarea otherwise.
240 	 * 
241 	 * @return FCKeditor html code
242 	 */
243 	public String createHtml() {
244 		StringBuffer strEditor = new StringBuffer();
245 
246 		strEditor.append("<div>");
247 		String encodedValue = escapeXml(value.replaceAll("((\r?\n)+|\t*)", ""));
248 
249 		if (Compatibility.check(request.getHeader("user-agent"))) {
250 			strEditor.append(createInputForVariable(instanceName, instanceName, encodedValue));
251 
252 			// create config html
253 			String configStr = config.getUrlParams();
254 			if (Utils.isNotEmpty(configStr))
255 				strEditor.append(createInputForVariable(null, instanceName.concat("___Config"),
256 				        configStr));
257 
258 			// create IFrame
259 			String sLink = basePath.concat("/editor/fckeditor.html?InstanceName=").concat(
260 			        instanceName);
261 			if (Utils.isNotEmpty(toolbarSet))
262 				sLink += "&amp;Toolbar=".concat(toolbarSet);
263 			XHtmlTagTool iframeTag = new XHtmlTagTool("iframe", XHtmlTagTool.SPACE);
264 			iframeTag.addAttribute("id", instanceName.concat("___Frame"));
265 			iframeTag.addAttribute("src", sLink);
266 			iframeTag.addAttribute("width", width);
267 			iframeTag.addAttribute("height", height);
268 			iframeTag.addAttribute("frameborder", "0");
269 			iframeTag.addAttribute("scrolling", "no");
270 			strEditor.append(iframeTag);
271 
272 		} else {
273 			XHtmlTagTool textareaTag = new XHtmlTagTool("textarea", encodedValue);
274 			textareaTag.addAttribute("name", instanceName);
275 			textareaTag.addAttribute("rows", "4");
276 			textareaTag.addAttribute("cols", "40");
277 			textareaTag.addAttribute("wrap", "virtual");
278 			textareaTag.addAttribute("style", "width: ".concat(width).concat("; height: ").concat(
279 			        height));
280 		}
281 		strEditor.append("</div>");
282 		return strEditor.toString();
283 	}
284 
285 	private String createInputForVariable(final String name, final String id, final String value) {
286 		XHtmlTagTool tag = new XHtmlTagTool("input");
287 		if (Utils.isNotEmpty(id))
288 			tag.addAttribute("id", id);
289 		if (Utils.isNotEmpty(name))
290 			tag.addAttribute("name", name);
291 		tag.addAttribute("value", value);
292 		tag.addAttribute("type", "hidden");
293 		return tag.toString();
294 	}
295 }