Mercurial Hosting > luan
annotate core/src/luan/modules/parsers/BBCode.java @ 588:5fdbefa80146
BBCode now leaves it to CSS to handle quoted display
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 25 Aug 2015 10:07:37 -0600 |
parents | bb3818249dfb |
children | 6ea90dc10375 |
rev | line source |
---|---|
585 | 1 package luan.modules.parsers; |
2 | |
3 | |
4 public final class BBCode { | |
5 | |
6 public static String toHtml(String bbcode) { | |
7 return new BBCode(bbcode,true).parse(); | |
8 } | |
9 | |
10 public static String toText(String bbcode) { | |
11 return new BBCode(bbcode,false).parse(); | |
12 } | |
13 | |
14 private final Parser parser; | |
15 private final boolean toHtml; | |
16 | |
17 private BBCode(String text,boolean toHtml) { | |
18 this.parser = new Parser(text); | |
19 this.toHtml = toHtml; | |
20 } | |
21 | |
22 private String parse() { | |
23 StringBuilder sb = new StringBuilder(); | |
24 while( !parser.endOfInput() ) { | |
25 String block = parseBlock(); | |
26 if( block != null ) | |
27 sb.append(block); | |
28 else { | |
29 sb.append( parser.currentChar() ); | |
30 parser.anyChar(); | |
31 } | |
32 } | |
33 return sb.toString(); | |
34 } | |
35 | |
36 private String parseWellFormed() { | |
37 StringBuilder sb = new StringBuilder(); | |
38 while( !parser.endOfInput() ) { | |
39 String block = parseBlock(); | |
40 if( block != null ) { | |
41 sb.append(block); | |
42 continue; | |
43 } | |
44 if( couldBeTag() ) | |
45 break; | |
46 sb.append( parser.currentChar() ); | |
47 parser.anyChar(); | |
48 } | |
49 return sb.toString(); | |
50 } | |
51 | |
52 private boolean couldBeTag() { | |
53 if( parser.currentChar() != '[' ) | |
54 return false; | |
55 return parser.testIgnoreCase("[b]") | |
56 || parser.testIgnoreCase("[/b]") | |
57 || parser.testIgnoreCase("[i]") | |
58 || parser.testIgnoreCase("[/i]") | |
59 || parser.testIgnoreCase("[u]") | |
60 || parser.testIgnoreCase("[/u]") | |
61 || parser.testIgnoreCase("[url]") | |
62 || parser.testIgnoreCase("[url=") | |
63 || parser.testIgnoreCase("[/url]") | |
64 || parser.testIgnoreCase("[code]") | |
65 || parser.testIgnoreCase("[/code]") | |
66 || parser.testIgnoreCase("[img]") | |
67 || parser.testIgnoreCase("[/img]") | |
68 || parser.testIgnoreCase("[color=") | |
69 || parser.testIgnoreCase("[/color]") | |
70 || parser.testIgnoreCase("[size=") | |
71 || parser.testIgnoreCase("[/size]") | |
72 || parser.testIgnoreCase("[youtube]") | |
73 || parser.testIgnoreCase("[/youtube]") | |
74 || parser.testIgnoreCase("[quote]") | |
75 || parser.testIgnoreCase("[quote=") | |
76 || parser.testIgnoreCase("[/quote]") | |
77 ; | |
78 } | |
79 | |
80 private String parseBlock() { | |
81 if( parser.currentChar() != '[' ) | |
82 return null; | |
83 String s; | |
84 s = parseB(); if(s!=null) return s; | |
85 s = parseI(); if(s!=null) return s; | |
86 s = parseU(); if(s!=null) return s; | |
87 s = parseUrl1(); if(s!=null) return s; | |
88 s = parseUrl2(); if(s!=null) return s; | |
89 s = parseCode(); if(s!=null) return s; | |
90 s = parseImg(); if(s!=null) return s; | |
91 s = parseColor(); if(s!=null) return s; | |
92 s = parseSize(); if(s!=null) return s; | |
93 s = parseYouTube(); if(s!=null) return s; | |
94 s = parseQuote1(); if(s!=null) return s; | |
95 s = parseQuote2(); if(s!=null) return s; | |
96 return null; | |
97 } | |
98 | |
99 private String parseB() { | |
100 parser.begin(); | |
101 if( !parser.matchIgnoreCase("[b]") ) | |
102 return parser.failure(null); | |
103 String content = parseWellFormed(); | |
104 if( !parser.matchIgnoreCase("[/b]") ) | |
105 return parser.failure(null); | |
106 String rtn = toHtml ? "<b>"+content+"</b>" : content; | |
107 return parser.success(rtn); | |
108 } | |
109 | |
110 private String parseI() { | |
111 parser.begin(); | |
112 if( !parser.matchIgnoreCase("[i]") ) | |
113 return parser.failure(null); | |
114 String content = parseWellFormed(); | |
115 if( !parser.matchIgnoreCase("[/i]") ) | |
116 return parser.failure(null); | |
117 String rtn = toHtml ? "<i>"+content+"</i>" : content; | |
118 return parser.success(rtn); | |
119 } | |
120 | |
121 private String parseU() { | |
122 parser.begin(); | |
123 if( !parser.matchIgnoreCase("[u]") ) | |
124 return parser.failure(null); | |
125 String content = parseWellFormed(); | |
126 if( !parser.matchIgnoreCase("[/u]") ) | |
127 return parser.failure(null); | |
128 String rtn = toHtml ? "<u>"+content+"</u>" : content; | |
129 return parser.success(rtn); | |
130 } | |
131 | |
132 private String parseUrl1() { | |
133 parser.begin(); | |
134 if( !parser.matchIgnoreCase("[url]") ) | |
135 return parser.failure(null); | |
136 String url = parseRealUrl(); | |
137 if( !parser.matchIgnoreCase("[/url]") ) | |
138 return parser.failure(null); | |
139 String rtn = toHtml ? "<a href='"+url+"'>"+url+"</u>" : url; | |
140 return parser.success(rtn); | |
141 } | |
142 | |
143 private String parseUrl2() { | |
144 parser.begin(); | |
145 if( !parser.matchIgnoreCase("[url=") ) | |
146 return parser.failure(null); | |
147 String url = parseRealUrl(); | |
148 if( !parser.match(']') ) | |
149 return parser.failure(null); | |
150 String content = parseWellFormed(); | |
151 if( !parser.matchIgnoreCase("[/url]") ) | |
152 return parser.failure(null); | |
153 String rtn = toHtml ? "<a href='"+url+"'>"+content+"</u>" : content; | |
154 return parser.success(rtn); | |
155 } | |
156 | |
157 private String parseRealUrl() { | |
158 parser.begin(); | |
159 while( parser.match(' ') ); | |
160 int start = parser.currentIndex(); | |
161 if( !parser.matchIgnoreCase("http") ) | |
162 return parser.failure(null); | |
163 parser.matchIgnoreCase("s"); | |
164 if( !parser.matchIgnoreCase("://") ) | |
165 return parser.failure(null); | |
166 while( parser.noneOf(" []'") ); | |
167 String url = parser.textFrom(start); | |
168 while( parser.match(' ') ); | |
169 return parser.success(url); | |
170 } | |
171 | |
172 private String parseCode() { | |
173 parser.begin(); | |
174 if( !parser.matchIgnoreCase("[code]") ) | |
175 return parser.failure(null); | |
176 int start = parser.currentIndex(); | |
177 while( !parser.testIgnoreCase("[/code]") ) { | |
178 if( !parser.anyChar() ) | |
179 return parser.failure(null); | |
180 } | |
181 String content = parser.textFrom(start); | |
182 if( !parser.matchIgnoreCase("[/code]") ) throw new RuntimeException(); | |
183 String rtn = toHtml ? "<code>"+content+"</code>" : content; | |
184 return parser.success(rtn); | |
185 } | |
186 | |
187 private String parseImg() { | |
188 parser.begin(); | |
189 if( !parser.matchIgnoreCase("[img]") ) | |
190 return parser.failure(null); | |
191 String url = parseRealUrl(); | |
192 if( !parser.matchIgnoreCase("[/img]") ) | |
193 return parser.failure(null); | |
194 String rtn = toHtml ? "<img src='"+url+"'>" : ""; | |
195 return parser.success(rtn); | |
196 } | |
197 | |
198 private String parseColor() { | |
199 parser.begin(); | |
200 if( !parser.matchIgnoreCase("[color=") ) | |
201 return parser.failure(null); | |
202 int start = parser.currentIndex(); | |
203 parser.match('#'); | |
204 while( parser.inCharRange('0','9') | |
205 || parser.inCharRange('a','z') | |
206 || parser.inCharRange('A','Z') | |
207 ); | |
208 String color = parser.textFrom(start); | |
209 if( !parser.match(']') ) | |
210 return parser.failure(null); | |
211 String content = parseWellFormed(); | |
212 if( !parser.matchIgnoreCase("[/color]") ) | |
213 return parser.failure(null); | |
214 String rtn = toHtml ? "<span style='color: "+color+"'>"+content+"</span>" : content; | |
215 return parser.success(rtn); | |
216 } | |
217 | |
218 private String parseSize() { | |
219 parser.begin(); | |
220 if( !parser.matchIgnoreCase("[size=") ) | |
221 return parser.failure(null); | |
222 int start = parser.currentIndex(); | |
223 while( parser.match('.') || parser.inCharRange('0','9') ); | |
224 String size = parser.textFrom(start); | |
225 if( !parser.match(']') ) | |
226 return parser.failure(null); | |
227 String content = parseWellFormed(); | |
228 if( !parser.matchIgnoreCase("[/size]") ) | |
229 return parser.failure(null); | |
230 String rtn = toHtml ? "<span style='font-size: "+size+"em'>"+content+"</span>" : content; | |
231 return parser.success(rtn); | |
232 } | |
233 | |
234 private String parseYouTube() { | |
235 parser.begin(); | |
236 if( !parser.matchIgnoreCase("[youtube]") ) | |
237 return parser.failure(null); | |
238 int start = parser.currentIndex(); | |
239 while( parser.inCharRange('0','9') | |
240 || parser.inCharRange('a','z') | |
241 || parser.inCharRange('A','Z') | |
242 || parser.match('-') | |
243 || parser.match('_') | |
244 ); | |
245 String id = parser.textFrom(start); | |
246 if( id.length()==0 || !parser.matchIgnoreCase("[/youtube]") ) | |
247 return parser.failure(null); | |
248 String rtn = toHtml ? "<iframe width='420' height='315' src='https://www.youtube.com/embed/"+id+"' frameborder='0' allowfullscreen></iframe>" : ""; | |
249 return parser.success(rtn); | |
250 } | |
251 | |
252 private String parseQuote1() { | |
253 parser.begin(); | |
254 if( !parser.matchIgnoreCase("[quote]") ) | |
255 return parser.failure(null); | |
256 String content = parseWellFormed(); | |
257 if( !parser.matchIgnoreCase("[/quote]") ) | |
258 return parser.failure(null); | |
259 String rtn = toHtml ? "<blockquote>"+content+"</blockquote>" : ""; | |
260 return parser.success(rtn); | |
261 } | |
262 | |
263 private String parseQuote2() { | |
264 parser.begin(); | |
265 if( !parser.matchIgnoreCase("[quote=") ) | |
266 return parser.failure(null); | |
267 int start = parser.currentIndex(); | |
268 while( parser.noneOf("[];") ); | |
269 String name = parser.textFrom(start).trim(); | |
270 if( name.length() == 0 ) | |
271 return parser.failure(null); | |
272 String src = null; | |
273 if( parser.match(';') ) { | |
274 start = parser.currentIndex(); | |
275 while( parser.noneOf("[]'") ); | |
276 src = parser.textFrom(start).trim(); | |
277 if( src.length() == 0 ) | |
278 return parser.failure(null); | |
279 } | |
280 if( !parser.match(']') ) | |
281 return parser.failure(null); | |
282 String content = parseWellFormed(); | |
283 if( !parser.matchIgnoreCase("[/quote]") ) | |
284 return parser.failure(null); | |
285 if( !toHtml ) | |
286 return parser.success(""); | |
287 StringBuilder sb = new StringBuilder(); | |
288 sb.append( "<blockquote><div quoted>" ); | |
289 if( src != null ) | |
290 sb.append( "<a href='/thread?id=" ).append( src ).append( "'>" ); | |
588
5fdbefa80146
BBCode now leaves it to CSS to handle quoted display
Franklin Schmidt <fschmidt@gmail.com>
parents:
585
diff
changeset
|
291 sb.append( "<span quoted>" ).append( name ).append( "</span>" ); |
585 | 292 if( src != null ) |
293 sb.append( "</a>" ); | |
588
5fdbefa80146
BBCode now leaves it to CSS to handle quoted display
Franklin Schmidt <fschmidt@gmail.com>
parents:
585
diff
changeset
|
294 sb.append( "</div>" ).append( content ).append( "</blockquote>" ); |
585 | 295 return parser.success(sb.toString()); |
296 } | |
297 | |
298 } |