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