##// END OF EJS Templates
Added source parameter to quotes
neko259 -
r755:8eb55ab8 default
parent child Browse files
Show More
@@ -1,164 +1,178 b''
1 1 # coding=utf-8
2 2
3 3 import re
4 4 import bbcode
5 5
6 6 import boards
7 7
8 8
9 9 __author__ = 'neko259'
10 10
11 11
12 12 REFLINK_PATTERN = re.compile(r'\d+')
13 13 MULTI_NEWLINES_PATTERN = re.compile(r'(\r?\n){2,}')
14 14 ONE_NEWLINE = '\n'
15 15
16 16
17 17 class TextFormatter():
18 18 """
19 19 An interface for formatter that can be used in the text format panel
20 20 """
21 21
22 22 def __init__(self):
23 23 pass
24 24
25 25 name = ''
26 26
27 27 # Left and right tags for the button preview
28 28 preview_left = ''
29 29 preview_right = ''
30 30
31 31 # Left and right characters for the textarea input
32 32 format_left = ''
33 33 format_right = ''
34 34
35 35
36 36 class AutolinkPattern():
37 37 def handleMatch(self, m):
38 38 link_element = etree.Element('a')
39 39 href = m.group(2)
40 40 link_element.set('href', href)
41 41 link_element.text = href
42 42
43 43 return link_element
44 44
45 45
46 46 class QuotePattern(TextFormatter):
47 47 name = 'q'
48 48 preview_left = '<span class="multiquote">'
49 49 preview_right = '</span>'
50 50
51 51 format_left = '[quote]'
52 52 format_right = '[/quote]'
53 53
54 54
55 55 class SpoilerPattern(TextFormatter):
56 56 name = 'spoiler'
57 57 preview_left = '<span class="spoiler">'
58 58 preview_right = '</span>'
59 59
60 60 format_left = '[spoiler]'
61 61 format_right = '[/spoiler]'
62 62
63 63 def handleMatch(self, m):
64 64 quote_element = etree.Element('span')
65 65 quote_element.set('class', 'spoiler')
66 66 quote_element.text = m.group(2)
67 67
68 68 return quote_element
69 69
70 70
71 71 class CommentPattern(TextFormatter):
72 72 name = ''
73 73 preview_left = '<span class="comment">// '
74 74 preview_right = '</span>'
75 75
76 76 format_left = '[comment]'
77 77 format_right = '[/comment]'
78 78
79 79
80 # TODO Use <s> tag here
80 81 class StrikeThroughPattern(TextFormatter):
81 82 name = 's'
82 83 preview_left = '<span class="strikethrough">'
83 84 preview_right = '</span>'
84 85
85 86 format_left = '[s]'
86 87 format_right = '[/s]'
87 88
88 89
89 90 class ItalicPattern(TextFormatter):
90 91 name = 'i'
91 92 preview_left = '<i>'
92 93 preview_right = '</i>'
93 94
94 95 format_left = '[i]'
95 96 format_right = '[/i]'
96 97
97 98
98 99 class BoldPattern(TextFormatter):
99 100 name = 'b'
100 101 preview_left = '<b>'
101 102 preview_right = '</b>'
102 103
103 104 format_left = '[b]'
104 105 format_right = '[/b]'
105 106
106 107
107 108 class CodePattern(TextFormatter):
108 109 name = 'code'
109 110 preview_left = '<code>'
110 111 preview_right = '</code>'
111 112
112 113 format_left = '[code]'
113 114 format_right = '[/code]'
114 115
115 116
116 117 def render_reflink(tag_name, value, options, parent, context):
117 118 if not REFLINK_PATTERN.match(value):
118 119 return u'>>%s' % value
119 120
120 121 post_id = int(value)
121 122
122 123 posts = boards.models.Post.objects.filter(id=post_id)
123 124 if posts.exists():
124 125 post = posts[0]
125 126
126 127 return u'<a href=%s>&gt;&gt;%s</a>' % (post.get_url(), post_id)
127 128 else:
128 129 return u'>>%s' % value
129 130
130 131
132 def render_quote(tag_name, value, options, parent, context):
133 source = u''
134 if 'source' in options:
135 source = options['source']
136
137 result = u''
138 if source:
139 result = u'<div class="multiquote"><div class="quote-header">%s</div><div class="quote-text">%s</div></div>' % (source, value)
140 else:
141 result = u'<div class="multiquote"><div class="quote-text">%s</div></div>' % value
142
143 return result
144
145
131 146 def preparse_text(text):
132 147 """
133 148 Performs manual parsing before the bbcode parser is used.
134 149 """
135 150
136 151 return MULTI_NEWLINES_PATTERN.sub(ONE_NEWLINE, text)
137 152
138 153
139 154 def bbcode_extended(markup):
140 155 parser = bbcode.Parser()
141 156 parser.add_formatter('post', render_reflink, strip=True)
142 parser.add_simple_formatter('quote',
143 u'<span class="multiquote">%(value)s</span>', strip=True)
157 parser.add_formatter('quote', render_quote, strip=True)
144 158 parser.add_simple_formatter('comment',
145 159 u'<span class="comment">//%(value)s</span>')
146 160 parser.add_simple_formatter('spoiler',
147 161 u'<span class="spoiler">%(value)s</span>')
148 162 parser.add_simple_formatter('s',
149 163 u'<span class="strikethrough">%(value)s</span>')
150 164 parser.add_simple_formatter('code',
151 165 u'<pre><code>%(value)s</pre></code>')
152 166
153 167 text = preparse_text(markup)
154 168 return parser.format(text)
155 169
156 170 formatters = [
157 171 QuotePattern,
158 172 SpoilerPattern,
159 173 ItalicPattern,
160 174 BoldPattern,
161 175 CommentPattern,
162 176 StrikeThroughPattern,
163 177 CodePattern,
164 178 ]
@@ -1,448 +1,456 b''
1 1 html {
2 2 background: #555;
3 3 color: #ffffff;
4 4 }
5 5
6 6 body {
7 7 margin: 0;
8 8 }
9 9
10 10 #admin_panel {
11 11 background: #FF0000;
12 12 color: #00FF00
13 13 }
14 14
15 15 .input_field_error {
16 16 color: #FF0000;
17 17 }
18 18
19 19 .title {
20 20 font-weight: bold;
21 21 color: #ffcc00;
22 22 }
23 23
24 24 .link, a {
25 25 color: #afdcec;
26 26 }
27 27
28 28 .block {
29 29 display: inline-block;
30 30 vertical-align: top;
31 31 }
32 32
33 33 .tag {
34 34 color: #FFD37D;
35 35 }
36 36
37 37 .post_id {
38 38 color: #fff380;
39 39 }
40 40
41 41 .post, .dead_post, .archive_post, #posts-table {
42 42 background: #333;
43 43 padding: 10px;
44 44 clear: left;
45 45 word-wrap: break-word;
46 46 border-top: 1px solid #777;
47 47 border-bottom: 1px solid #777;
48 48 }
49 49
50 50 .post + .post {
51 51 border-top: none;
52 52 }
53 53
54 54 .dead_post + .dead_post {
55 55 border-top: none;
56 56 }
57 57
58 58 .archive_post + .archive_post {
59 59 border-top: none;
60 60 }
61 61
62 62 .metadata {
63 63 padding-top: 5px;
64 64 margin-top: 10px;
65 65 border-top: solid 1px #666;
66 66 color: #ddd;
67 67 }
68 68
69 69 .navigation_panel, .tag_info {
70 70 background: #444;
71 71 margin-bottom: 5px;
72 72 margin-top: 5px;
73 73 padding: 10px;
74 74 border-bottom: solid 1px #888;
75 75 border-top: solid 1px #888;
76 76 color: #eee;
77 77 }
78 78
79 79 .navigation_panel .link {
80 80 border-right: 1px solid #fff;
81 81 font-weight: bold;
82 82 margin-right: 1ex;
83 83 padding-right: 1ex;
84 84 }
85 85 .navigation_panel .link:last-child {
86 86 border-left: 1px solid #fff;
87 87 border-right: none;
88 88 float: right;
89 89 margin-left: 1ex;
90 90 margin-right: 0;
91 91 padding-left: 1ex;
92 92 padding-right: 0;
93 93 }
94 94
95 95 .navigation_panel::after, .post::after {
96 96 clear: both;
97 97 content: ".";
98 98 display: block;
99 99 height: 0;
100 100 line-height: 0;
101 101 visibility: hidden;
102 102 }
103 103
104 104 p {
105 105 margin-top: .5em;
106 106 margin-bottom: .5em;
107 107 }
108 108
109 109 br {
110 110 margin-bottom: .5em;
111 111 }
112 112
113 113 .post-form-w {
114 114 background: #333344;
115 115 border-top: solid 1px #888;
116 116 border-bottom: solid 1px #888;
117 117 color: #fff;
118 118 padding: 10px;
119 119 margin-bottom: 5px;
120 120 margin-top: 5px;
121 121 }
122 122
123 123 .form-row {
124 124 width: 100%;
125 125 }
126 126
127 127 .form-label {
128 128 padding: .25em 1ex .25em 0;
129 129 vertical-align: top;
130 130 }
131 131
132 132 .form-input {
133 133 padding: .25em 0;
134 134 }
135 135
136 136 .form-errors {
137 137 font-weight: bolder;
138 138 vertical-align: middle;
139 139 }
140 140
141 141 .post-form input:not([name="image"]), .post-form textarea {
142 142 background: #333;
143 143 color: #fff;
144 144 border: solid 1px;
145 145 padding: 0;
146 146 font: medium sans-serif;
147 147 width: 100%;
148 148 }
149 149
150 150 .form-submit {
151 151 display: table;
152 152 margin-bottom: 1ex;
153 153 margin-top: 1ex;
154 154 }
155 155
156 156 .form-title {
157 157 font-weight: bold;
158 158 font-size: 2ex;
159 159 margin-bottom: 0.5ex;
160 160 }
161 161
162 162 .post-form input[type="submit"], input[type="submit"] {
163 163 background: #222;
164 164 border: solid 2px #fff;
165 165 color: #fff;
166 166 padding: 0.5ex;
167 167 }
168 168
169 169 input[type="submit"]:hover {
170 170 background: #060;
171 171 }
172 172
173 173 blockquote {
174 174 border-left: solid 2px;
175 175 padding-left: 5px;
176 176 color: #B1FB17;
177 177 margin: 0;
178 178 }
179 179
180 180 .post > .image {
181 181 float: left;
182 182 margin: 0 1ex .5ex 0;
183 183 min-width: 1px;
184 184 text-align: center;
185 185 display: table-row;
186 186 }
187 187
188 188 .post > .metadata {
189 189 clear: left;
190 190 }
191 191
192 192 .get {
193 193 font-weight: bold;
194 194 color: #d55;
195 195 }
196 196
197 197 * {
198 198 text-decoration: none;
199 199 }
200 200
201 201 .dead_post {
202 202 background-color: #442222;
203 203 }
204 204
205 205 .archive_post {
206 206 background-color: #000;
207 207 }
208 208
209 209 .mark_btn {
210 210 border: 1px solid;
211 211 min-width: 2ex;
212 212 padding: 2px 2ex;
213 213 }
214 214
215 215 .mark_btn:hover {
216 216 background: #555;
217 217 }
218 218
219 219 .quote {
220 220 color: #92cf38;
221 221 font-style: italic;
222 222 }
223 223
224 224 .multiquote {
225 225 border-left: solid 4px #ccc;
226 226 padding: 3px;
227 227 display: inline-block;
228 228 background: #222;
229 229 border-right: solid 1px #ccc;
230 230 border-top: solid 1px #ccc;
231 231 border-bottom: solid 1px #ccc;
232 232 }
233 233
234 234 .spoiler {
235 235 background: white;
236 236 color: white;
237 237 }
238 238
239 239 .spoiler:hover {
240 240 color: black;
241 241 }
242 242
243 243 .comment {
244 244 color: #eb2;
245 245 }
246 246
247 247 a:hover {
248 248 text-decoration: underline;
249 249 }
250 250
251 251 .last-replies {
252 252 margin-left: 3ex;
253 253 margin-right: 3ex;
254 254 }
255 255
256 256 .thread {
257 257 margin-bottom: 3ex;
258 258 margin-top: 1ex;
259 259 }
260 260
261 261 .post:target {
262 262 border: solid 2px white;
263 263 }
264 264
265 265 pre{
266 266 white-space:pre-wrap
267 267 }
268 268
269 269 li {
270 270 list-style-position: inside;
271 271 }
272 272
273 273 .fancybox-skin {
274 274 position: relative;
275 275 background-color: #fff;
276 276 color: #ddd;
277 277 text-shadow: none;
278 278 }
279 279
280 280 .fancybox-image {
281 281 border: 1px solid black;
282 282 }
283 283
284 284 .image-mode-tab {
285 285 background: #444;
286 286 color: #eee;
287 287 margin-top: 5px;
288 288 padding: 5px;
289 289 border-top: 1px solid #888;
290 290 border-bottom: 1px solid #888;
291 291 }
292 292
293 293 .image-mode-tab > label {
294 294 margin: 0 1ex;
295 295 }
296 296
297 297 .image-mode-tab > label > input {
298 298 margin-right: .5ex;
299 299 }
300 300
301 301 #posts-table {
302 302 margin-top: 5px;
303 303 margin-bottom: 5px;
304 304 }
305 305
306 306 .tag_info > h2 {
307 307 margin: 0;
308 308 }
309 309
310 310 .post-info {
311 311 color: #ddd;
312 312 margin-bottom: 1ex;
313 313 }
314 314
315 315 .moderator_info {
316 316 color: #e99d41;
317 317 float: right;
318 318 font-weight: bold;
319 319 }
320 320
321 321 .refmap {
322 322 font-size: 0.9em;
323 323 color: #ccc;
324 324 margin-top: 1em;
325 325 }
326 326
327 327 .fav {
328 328 color: yellow;
329 329 }
330 330
331 331 .not_fav {
332 332 color: #ccc;
333 333 }
334 334
335 335 .role {
336 336 text-decoration: underline;
337 337 }
338 338
339 339 .form-email {
340 340 display: none;
341 341 }
342 342
343 343 .footer {
344 344 margin: 5px;
345 345 }
346 346
347 347 .bar-value {
348 348 background: rgba(50, 55, 164, 0.45);
349 349 font-size: 0.9em;
350 350 height: 1.5em;
351 351 }
352 352
353 353 .bar-bg {
354 354 position: relative;
355 355 border-top: solid 1px #888;
356 356 border-bottom: solid 1px #888;
357 357 margin-top: 5px;
358 358 overflow: hidden;
359 359 }
360 360
361 361 .bar-text {
362 362 padding: 2px;
363 363 position: absolute;
364 364 left: 0;
365 365 top: 0;
366 366 }
367 367
368 368 .page_link {
369 369 background: #444;
370 370 border-top: solid 1px #888;
371 371 border-bottom: solid 1px #888;
372 372 padding: 5px;
373 373 color: #eee;
374 374 font-size: 2ex;
375 375 }
376 376
377 377 .skipped_replies {
378 378 margin: 5px;
379 379 }
380 380
381 381 .current_page {
382 382 border: solid 1px #afdcec;
383 383 padding: 2px;
384 384 }
385 385
386 386 .current_mode {
387 387 font-weight: bold;
388 388 }
389 389
390 390 .gallery_image {
391 391 border: solid 1px;
392 392 padding: 0.5ex;
393 393 margin: 0.5ex;
394 394 text-align: center;
395 395 }
396 396
397 397 code {
398 398 border: dashed 1px #ccc;
399 399 background: #111;
400 400 padding: 2px;
401 401 font-size: 1.2em;
402 402 display: inline-block;
403 403 }
404 404
405 405 pre {
406 406 overflow: auto;
407 407 }
408 408
409 409 .img-full {
410 410 background: #222;
411 411 border: solid 1px white;
412 412 }
413 413
414 414 .tag_item {
415 415 display: inline-block;
416 416 border: 1px dashed #666;
417 417 margin: 0.2ex;
418 418 padding: 0.1ex;
419 419 }
420 420
421 421 #id_models li {
422 422 list-style: none;
423 423 }
424 424
425 425 #id_q {
426 426 margin-left: 1ex;
427 427 }
428 428
429 429 ul {
430 430 padding-left: 0px;
431 431 }
432 432
433 .quote-header {
434 border-bottom: 2px solid #ddd;
435 margin-bottom: 1ex;
436 padding-bottom: .5ex;
437 color: #ddd;
438 font-size: 1.2em;
439 }
440
433 441 /* Reflink preview */
434 442 .post_preview {
435 443 border-left: 1px solid #777;
436 444 border-right: 1px solid #777;
437 445 }
438 446
439 447 /* Code highlighter */
440 448 .hljs {
441 449 color: #fff;
442 450 background: #000;
443 451 display: inline-block;
444 452 }
445 453
446 454 .hljs, .hljs-subst, .hljs-tag .hljs-title, .lisp .hljs-title, .clojure .hljs-built_in, .nginx .hljs-title {
447 455 color: #fff;
448 456 }
General Comments 0
You need to be logged in to leave comments. Login now