1
22
23 package com.liferay.portlet.messageboards.util;
24
25 import com.liferay.portal.kernel.log.Log;
26 import com.liferay.portal.kernel.log.LogFactoryUtil;
27 import com.liferay.portal.kernel.util.GetterUtil;
28 import com.liferay.portal.kernel.util.HtmlUtil;
29 import com.liferay.portal.kernel.util.StringPool;
30 import com.liferay.portal.kernel.util.StringUtil;
31 import com.liferay.portlet.messageboards.model.MBMessage;
32
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37
38
43 public class BBCodeUtil {
44
45 static Map<Integer, String> fontSizes = new HashMap<Integer, String>();
46
47 static Map<String, String> listStyles = new HashMap<String, String>();
48
49 static String[][] emoticons = {
50 {"angry.gif", ":angry:"},
51 {"bashful.gif", ":bashful:"},
52 {"big_grin.gif", ":grin:"},
53 {"blink.gif", ":blink:"},
54 {"blush.gif", ":*)"},
55 {"bored.gif", ":bored:"},
56 {"closed_eyes.gif", "-_-"},
57 {"cold.gif", ":cold:"},
58 {"cool.gif", "B)"},
59 {"darth_vader.gif", ":vader:"},
60 {"dry.gif", "<_<"},
61 {"exclamation.gif", ":what:"},
62 {"girl.gif", ":girl:"},
63 {"glare.gif", ">_>"},
64 {"happy.gif", ":)"},
65 {"huh.gif", ":huh:"},
66 {"in_love.gif", "<3"},
67 {"karate_kid.gif", ":kid:"},
68 {"kiss.gif", ":#"},
69 {"laugh.gif", ":lol:"},
70 {"mad.gif", ":mad:"},
71 {"mellow.gif", ":mellow:"},
72 {"ninja.gif", ":ph34r:"},
73 {"oh_my.gif", ":O"},
74 {"pac_man.gif", ":V"},
75 {"roll_eyes.gif", ":rolleyes:"},
76 {"sad.gif", ":("},
77 {"sleep.gif", ":sleep:"},
78 {"smile.gif", ":D"},
79 {"smug.gif", ":smug:"},
80 {"suspicious.gif", "8o"},
81 {"tongue.gif", ":P"},
82 {"unsure.gif", ":unsure:"},
83 {"wacko.gif", ":wacko:"},
84 {"wink.gif", ":wink:"},
85 {"wub.gif", ":wub:"}
86 };
87
88 static {
89 fontSizes.put(new Integer(1), "<span style='font-size: 0.7em';>");
90 fontSizes.put(new Integer(2), "<span style='font-size: 0.8em';>");
91 fontSizes.put(new Integer(3), "<span style='font-size: 0.9em';>");
92 fontSizes.put(new Integer(4), "<span style='font-size: 1.0em';>");
93 fontSizes.put(new Integer(5), "<span style='font-size: 1.1em';>");
94 fontSizes.put(new Integer(6), "<span style='font-size: 1.3em';>");
95 fontSizes.put(new Integer(7), "<span style='font-size: 1.5em';>");
96
97 listStyles.put("1", "<ol style='list-style-type: decimal';>");
98 listStyles.put("i", "<ol style='list-style-type: lower-roman';>");
99 listStyles.put("I", "<ol style='list-style-type: upper-roman';>");
100 listStyles.put("a", "<ol style='list-style-type: lower-alpha';>");
101 listStyles.put("A", "<ol style='list-style-type: upper-alpha';>");
102
103 for (int i = 0; i < emoticons.length; i++) {
104 String[] emoticon = emoticons[i];
105
106 String image = emoticon[0];
107 String code = emoticon[1];
108
109 emoticon[0] =
110 "<img alt='emoticon' src='@theme_images_path@/emoticons/" +
111 image + "' />";
112 emoticon[1] = HtmlUtil.escape(code);
113 }
114 }
115
116 public static final String[][] EMOTICONS = emoticons;
117
118 public static String getHTML(MBMessage message) {
119 String body = message.getBody();
120
121 try {
122 body = getHTML(body);
123 }
124 catch (Exception e) {
125 _log.error(
126 "Could not parse message " + message.getMessageId() + " " +
127 e.getMessage());
128 }
129
130 return body;
131 }
132
133 public static String getHTML(String bbcode) {
134 String html = HtmlUtil.escape(bbcode);
135
136 html = StringUtil.replace(html, _BBCODE_TAGS, _HTML_TAGS);
137
138 for (int i = 0; i < emoticons.length; i++) {
139 String[] emoticon = emoticons[i];
140
141 html = StringUtil.replace(html, emoticon[1], emoticon[0]);
142 }
143
144 BBCodeTag tag = null;
145
146 StringBuilder sb = null;
147
148 while ((tag = getFirstTag(html, "code")) != null) {
149 String preTag = html.substring(0, tag.getStartPos());
150 String postTag = html.substring(tag.getEndPos());
151
152 String code = tag.getElement().replaceAll(
153 "\t", StringPool.FOUR_SPACES);
154 String[] lines = code.split("\\n");
155 int digits = String.valueOf(lines.length + 1).length();
156
157 sb = new StringBuilder(preTag);
158
159 sb.append("<div class='code'>");
160
161 for (int i = 0; i < lines.length; i++) {
162 String index = String.valueOf(i + 1);
163 int ld = index.length();
164
165 sb.append("<span class='code-lines'>");
166
167 for (int j = 0; j < digits - ld; j++) {
168 sb.append(" ");
169 }
170
171 lines[i] = StringUtil.replace(lines[i], " ",
172 StringPool.NBSP + StringPool.SPACE + StringPool.NBSP);
173 lines[i] = StringUtil.replace(lines[i], " ",
174 StringPool.NBSP + StringPool.SPACE);
175
176 sb.append(index + "</span>");
177 sb.append(lines[i]);
178
179 if (index.length() < lines.length) {
180 sb.append("<br />");
181 }
182 }
183
184 sb.append("</div>");
185 sb.append(postTag);
186
187 html = sb.toString();
188 }
189
190 while ((tag = getFirstTag(html, "color")) != null) {
191 String preTag = html.substring(0, tag.getStartPos());
192 String postTag = html.substring(tag.getEndPos());
193
194 sb = new StringBuilder(preTag);
195
196 if (tag.hasParameter()) {
197 sb.append("<span style='color: ");
198 sb.append(tag.getParameter() + ";'>");
199 sb.append(tag.getElement() + "</span>");
200 }
201 else {
202 sb.append(tag.getElement());
203 }
204
205 sb.append(postTag);
206
207 html = sb.toString();
208 }
209
210 while ((tag = getFirstTag(html, "email")) != null) {
211 String preTag = html.substring(0, tag.getStartPos());
212 String postTag = html.substring(tag.getEndPos());
213
214 String mailto = GetterUtil.getString(
215 tag.getParameter(), tag.getElement().trim());
216
217 sb = new StringBuilder(preTag);
218
219 sb.append("<a href='mailto: " + mailto + "'>");
220 sb.append(tag.getElement() + "</a>");
221 sb.append(postTag);
222
223 html = sb.toString();
224 }
225
226 while ((tag = getFirstTag(html, "font")) != null) {
227 String preTag = html.substring(0, tag.getStartPos());
228 String postTag = html.substring(tag.getEndPos());
229
230 sb = new StringBuilder(preTag);
231
232 if (tag.hasParameter()) {
233 sb.append("<span style='font-family: ");
234 sb.append(tag.getParameter() + "';>");
235 sb.append(tag.getElement() + "</span>");
236 }
237 else {
238 sb.append(tag.getElement());
239 }
240
241 sb.append(postTag);
242
243 html = sb.toString();
244 }
245
246 while ((tag = getFirstTag(html, "img")) != null) {
247 String preTag = html.substring(0, tag.getStartPos());
248 String postTag = html.substring(tag.getEndPos());
249
250 sb = new StringBuilder(preTag);
251
252 sb.append("<img alt='' src='" + tag.getElement().trim() + "' />");
253 sb.append(postTag);
254
255 html = sb.toString();
256 }
257
258 while ((tag = getFirstTag(html, "list")) != null) {
259 String preTag = html.substring(0, tag.getStartPos());
260 String postTag = html.substring(tag.getEndPos());
261
262 String[] items = _getListItems(tag.getElement());
263
264 sb = new StringBuilder(preTag);
265
266 if (tag.hasParameter() &&
267 listStyles.containsKey(tag.getParameter())) {
268
269 sb.append(listStyles.get(tag.getParameter()));
270
271 for (int i = 0; i < items.length; i++) {
272 if (items[i].trim().length() > 0) {
273 sb.append("<li>" + items[i].trim() + "</li>");
274 }
275 }
276
277 sb.append("</ol>");
278 }
279 else {
280 sb.append("<ul style='list-style-type: disc';>");
281
282 for (int i = 0; i < items.length; i++) {
283 if (items[i].trim().length() > 0) {
284 sb.append("<li>" + items[i].trim() + "</li>");
285 }
286 }
287
288 sb.append("</ul>");
289 }
290
291 sb.append(postTag);
292
293 html = sb.toString();
294 }
295
296 while ((tag = getFirstTag(html, "quote")) != null) {
297 String preTag = html.substring(0, tag.getStartPos());
298 String postTag = html.substring(tag.getEndPos());
299
300 sb = new StringBuilder(preTag);
301
302 if (tag.hasParameter()) {
303 sb.append("<div class='quote-title'>");
304 sb.append(tag.getParameter() + ":</div>");
305 }
306
307 sb.append("<div class='quote'>");
308 sb.append("<div class='quote-content'>");
309 sb.append(tag.getElement());
310 sb.append("</div></div>");
311 sb.append(postTag);
312
313 html = sb.toString();
314 }
315
316 while ((tag = getFirstTag(html, "size")) != null) {
317 String preTag = html.substring(0, tag.getStartPos());
318 String postTag = html.substring(tag.getEndPos());
319
320 sb = new StringBuilder(preTag);
321
322 if (tag.hasParameter()) {
323 Integer size = new Integer(
324 GetterUtil.getInteger(tag.getParameter()));
325
326 if (size.intValue() > 7) {
327 size = new Integer(7);
328 }
329
330 if (fontSizes.containsKey(size)) {
331 sb.append(fontSizes.get(size));
332 sb.append(tag.getElement() + "</span>");
333 }
334 else {
335 sb.append(tag.getElement());
336 }
337 }
338 else {
339 sb.append(tag.getElement());
340 }
341
342 sb.append(postTag);
343
344 html = sb.toString();
345 }
346
347 while ((tag = getFirstTag(html, "url")) != null) {
348 String preTag = html.substring(0, tag.getStartPos());
349 String postTag = html.substring(tag.getEndPos());
350
351 String url = GetterUtil.getString(
352 tag.getParameter(), tag.getElement().trim());
353
354 sb = new StringBuilder(preTag);
355
356 sb.append("<a href='" + url + "'>");
357 sb.append(tag.getElement() + "</a>");
358 sb.append(postTag);
359
360 html = sb.toString();
361 }
362
363 html = StringUtil.replace(html, "\n", "<br />");
364
365 return html;
366 }
367
368 public static BBCodeTag getFirstTag(String bbcode, String name) {
369 BBCodeTag tag = new BBCodeTag();
370
371 String begTag = "[" + name;
372 String endTag = "[/" + name + "]";
373
374 String preTag = StringUtil.extractFirst(bbcode, begTag);
375
376 if (preTag == null) {
377 return null;
378 }
379
380 if (preTag.length() != bbcode.length()) {
381 tag.setStartPos(preTag.length());
382
383 String remainder = bbcode.substring(
384 preTag.length() + begTag.length());
385
386 int cb = remainder.indexOf("]");
387 int end = _getEndTagPos(remainder, begTag, endTag);
388
389 if (cb > 0 && remainder.startsWith("=")) {
390 tag.setParameter(remainder.substring(1, cb));
391 tag.setElement(remainder.substring(cb + 1, end));
392 }
393 else if (cb == 0) {
394 try {
395 tag.setElement(remainder.substring(1, end));
396 }
397 catch (StringIndexOutOfBoundsException sioobe) {
398 _log.error(bbcode);
399
400 throw sioobe;
401 }
402 }
403 }
404
405 if (tag.hasElement()) {
406 int length =
407 begTag.length() + 1 + tag.getElement().length() +
408 endTag.length();
409
410 if (tag.hasParameter()) {
411 length += 1 + tag.getParameter().length();
412 }
413
414 tag.setEndPos(tag.getStartPos() + length);
415
416 return tag;
417 }
418
419 return null;
420 }
421
422 private static int _getEndTagPos(
423 String remainder, String begTag, String endTag) {
424
425 int nextBegTagPos = remainder.indexOf(begTag);
426 int nextEndTagPos = remainder.indexOf(endTag);
427
428 while ((nextBegTagPos < nextEndTagPos) && (nextBegTagPos >= 0)) {
429 nextBegTagPos = remainder.indexOf(
430 begTag, nextBegTagPos + begTag.length());
431 nextEndTagPos = remainder.indexOf(
432 endTag, nextEndTagPos + endTag.length());
433 }
434
435 return nextEndTagPos;
436 }
437
438 private static String[] _getListItems(String tagElement) {
439 List<String> items = new ArrayList<String>();
440
441 StringBuilder sb = new StringBuilder();
442
443 int nestLevel = 0;
444
445 for (String item : StringUtil.split(tagElement, "[*]")) {
446 item = item.trim();
447
448 if (item.length() == 0) {
449 continue;
450 }
451
452 int begTagCount = StringUtil.count(item, "[list");
453
454 if (begTagCount > 0) {
455 nestLevel += begTagCount;
456 }
457
458 int endTagCount = StringUtil.count(item, "[/list]");
459
460 if (endTagCount > 0) {
461 nestLevel -= endTagCount;
462 }
463
464 if (nestLevel == 0) {
465 if ((begTagCount == 0) && (endTagCount == 0)) {
466 items.add(item);
467 }
468 else if (endTagCount > 0) {
469 if (sb.length() > 0) {
470 sb.append("[*]");
471 }
472
473 sb.append(item);
474
475 items.add(sb.toString());
476
477 sb.delete(0, sb.length());
478 }
479 }
480 else {
481 if (sb.length() > 0) {
482 sb.append("[*]");
483 }
484
485 sb.append(item);
486 }
487 }
488
489 return items.toArray(new String[items.size()]);
490 }
491
492 private static final String[] _BBCODE_TAGS = {
493 "[b]", "[/b]", "[i]", "[/i]", "[u]", "[/u]", "[s]", "[/s]",
494 "[img]", "[/img]",
495 "[left]", "[center]", "[right]", "[indent]",
496 "[/left]", "[/center]", "[/right]", "[/indent]", "[tt]", "[/tt]"
497 };
498
499 private static final String[] _HTML_TAGS = {
500 "<b>", "</b>", "<i>", "</i>", "<u>", "</u>", "<strike>", "</strike>",
501 "<img alt='' src='", "' />",
502 "<div style='text-align: left'>", "<div style='text-align: center'>",
503 "<div style='text-align: right'>", "<div style='margin-left: 15px'>",
504 "</div>", "</div>", "</div>", "</div>", "<tt>", "</tt>"
505 };
506
507 private static Log _log = LogFactoryUtil.getLog(BBCodeUtil.class);
508
509 }