~widelands-dev/widelands-website/trunk

200 by Holger Rapp
Fixed line endings in some python files
1
# -*- coding: UTF-8 -*-
2
3
"""
4
Post Markup
5
Author: Will McGugan (http://www.willmcgugan.com)
6
"""
7
438.1.6 by franku
run the script
8
__version__ = '1.1.3'
200 by Holger Rapp
Fixed line endings in some python files
9
10
import re
532.1.1 by franku
converted to python 3.6 using 2to3 script
11
from urllib.parse import quote, unquote, quote_plus
12
from urllib.parse import urlparse, urlunparse
200 by Holger Rapp
Fixed line endings in some python files
13
14
pygments_available = True
15
try:
16
    from pygments import highlight
17
    from pygments.lexers import get_lexer_by_name, ClassNotFound
18
    from pygments.formatters import HtmlFormatter
19
except ImportError:
20
    # Make Pygments optional
21
    pygments_available = False
22
23
24
def annotate_link(domain):
438.1.6 by franku
run the script
25
    """This function is called by the url tag. Override to disable or change
26
    behaviour.
200 by Holger Rapp
Fixed line endings in some python files
27
28
    domain -- Domain parsed from url
29
30
    """
532.1.1 by franku
converted to python 3.6 using 2to3 script
31
    return " [%s]" % _escape(domain)
438.1.6 by franku
run the script
32
33
34
re_url = re.compile(
35
    r"((https?):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.MULTILINE | re.UNICODE)
36
37
38
re_html = re.compile('<.*?>|\&.*?\;')
39
40
200 by Holger Rapp
Fixed line endings in some python files
41
def textilize(s):
438.1.6 by franku
run the script
42
    """Remove markup from html."""
43
    return re_html.sub('', s)
200 by Holger Rapp
Fixed line endings in some python files
44
45
re_excerpt = re.compile(r'\[".*?\]+?.*?\[/".*?\]+?', re.DOTALL)
46
re_remove_markup = re.compile(r'\[.*?\]', re.DOTALL)
47
438.1.6 by franku
run the script
48
200 by Holger Rapp
Fixed line endings in some python files
49
def remove_markup(post):
50
    """Removes html tags from a string."""
438.1.6 by franku
run the script
51
    return re_remove_markup.sub('', post)
52
200 by Holger Rapp
Fixed line endings in some python files
53
54
def get_excerpt(post):
55
    """Returns an excerpt between ["] and [/"]
56
438.1.6 by franku
run the script
57
    post -- BBCode string
58
59
    """
200 by Holger Rapp
Fixed line endings in some python files
60
61
    match = re_excerpt.search(post)
62
    if match is None:
438.1.6 by franku
run the script
63
        return ''
200 by Holger Rapp
Fixed line endings in some python files
64
    excerpt = match.group(0)
532.1.1 by franku
converted to python 3.6 using 2to3 script
65
    excerpt = excerpt.replace('\n', "<br/>")
200 by Holger Rapp
Fixed line endings in some python files
66
    return remove_markup(excerpt)
67
438.1.6 by franku
run the script
68
200 by Holger Rapp
Fixed line endings in some python files
69
def strip_bbcode(bbcode):
438.1.6 by franku
run the script
70
    """Strips bbcode tags from a string.
200 by Holger Rapp
Fixed line endings in some python files
71
72
    bbcode -- A string to remove tags from
73
74
    """
75
532.1.1 by franku
converted to python 3.6 using 2to3 script
76
    return "".join([t[1] for t in PostMarkup.tokenize(bbcode) if t[0] == PostMarkup.TOKEN_TEXT])
200 by Holger Rapp
Fixed line endings in some python files
77
78
79
def create(include=None, exclude=None, use_pygments=True, **kwargs):
80
    """Create a postmarkup object that converts bbcode to XML snippets.
81
82
    include -- List or similar iterable containing the names of the tags to use
83
               If omitted, all tags will be used
84
    exclude -- List or similar iterable containing the names of the tags to exclude.
85
               If omitted, no tags will be excluded
86
    use_pygments -- If True, Pygments (http://pygments.org/) will be used for the code tag,
87
                    otherwise it will use <pre>code</pre>
438.1.6 by franku
run the script
88
200 by Holger Rapp
Fixed line endings in some python files
89
    """
90
91
    postmarkup = PostMarkup()
92
    postmarkup_add_tag = postmarkup.tag_factory.add_tag
93
94
    def add_tag(tag_class, name, *args, **kwargs):
95
        if include is None or name in include:
96
            if exclude is not None and name in exclude:
97
                return
98
            postmarkup_add_tag(tag_class, name, *args, **kwargs)
99
100
    add_tag(SimpleTag, 'b', 'strong')
101
    add_tag(SimpleTag, 'i', 'em')
102
    add_tag(SimpleTag, 'u', 'u')
103
    add_tag(SimpleTag, 's', 'strike')
104
105
    add_tag(LinkTag, 'link', **kwargs)
106
    add_tag(LinkTag, 'url', **kwargs)
107
108
    add_tag(QuoteTag, 'quote')
109
532.1.1 by franku
converted to python 3.6 using 2to3 script
110
    add_tag(SearchTag, 'wiki',
111
            "http://en.wikipedia.org/wiki/Special:Search?search=%s", 'wikipedia.com', **kwargs)
112
    add_tag(SearchTag, 'google',
113
            "http://www.google.com/search?hl=en&q=%s&btnG=Google+Search", 'google.com', **kwargs)
114
    add_tag(SearchTag, 'dictionary',
115
            "http://dictionary.reference.com/browse/%s", 'dictionary.com', **kwargs)
116
    add_tag(SearchTag, 'dict',
117
            "http://dictionary.reference.com/browse/%s", 'dictionary.com', **kwargs)
118
119
    add_tag(ImgTag, 'img')
120
    add_tag(ListTag, 'list')
121
    add_tag(ListItemTag, '*')
122
123
    add_tag(SizeTag, "size")
124
    add_tag(ColorTag, "color")
125
    add_tag(CenterTag, "center")
200 by Holger Rapp
Fixed line endings in some python files
126
127
    if use_pygments:
438.1.6 by franku
run the script
128
        assert pygments_available, 'Install Pygments (http://pygments.org/) or call create with use_pygments=False'
532.1.1 by franku
converted to python 3.6 using 2to3 script
129
        add_tag(PygmentsCodeTag, 'code', **kwargs)
200 by Holger Rapp
Fixed line endings in some python files
130
    else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
131
        add_tag(CodeTag, 'code', **kwargs)
200 by Holger Rapp
Fixed line endings in some python files
132
133
    return postmarkup
134
135
136
_postmarkup = None
438.1.6 by franku
run the script
137
138
139
def render_bbcode(bbcode, encoding='ascii', exclude_tags=None, auto_urls=True):
200 by Holger Rapp
Fixed line endings in some python files
140
    """Renders a bbcode string in to XHTML. This is a shortcut if you don't
141
    need to customize any tags.
142
143
    bbcode -- A string containing the bbcode
144
    encoding -- If bbcode is not unicode, then then it will be encoded with
145
    this encoding (defaults to 'ascii'). Ignore the encoding if you already have
146
    a unicode string
147
148
    """
149
150
    global _postmarkup
151
    if _postmarkup is None:
152
        _postmarkup = create(use_pygments=pygments_available)
153
154
    return _postmarkup(bbcode, encoding, exclude_tags=exclude_tags, auto_urls=auto_urls)
155
156
157
class TagBase(object):
158
159
    def __init__(self, name, enclosed=False, auto_close=False, inline=False, strip_first_newline=False, **kwargs):
160
        """Base class for all tags.
161
162
        name -- The name of the bbcode tag
163
        enclosed -- True if the contents of the tag should not be bbcode processed.
164
        auto_close -- True if the tag is standalone and does not require a close tag.
165
        inline -- True if the tag generates an inline html tag.
166
167
        """
168
169
        self.name = name
170
        self.enclosed = enclosed
171
        self.auto_close = auto_close
172
        self.inline = inline
173
        self.strip_first_newline = strip_first_newline
174
175
        self.open_pos = None
176
        self.close_pos = None
177
        self.open_node_index = None
178
        self.close_node_index = None
179
180
    def open(self, parser, params, open_pos, node_index):
438.1.6 by franku
run the script
181
        """Called when the open tag is initially encountered."""
200 by Holger Rapp
Fixed line endings in some python files
182
        self.params = params
183
        self.open_pos = open_pos
184
        self.open_node_index = node_index
185
186
    def close(self, parser, close_pos, node_index):
438.1.6 by franku
run the script
187
        """Called when the close tag is initially encountered."""
200 by Holger Rapp
Fixed line endings in some python files
188
        self.close_pos = close_pos
189
        self.close_node_index = node_index
190
191
    def render_open(self, parser, node_index):
438.1.6 by franku
run the script
192
        """Called to render the open tag."""
200 by Holger Rapp
Fixed line endings in some python files
193
        pass
194
195
    def render_close(self, parser, node_index):
438.1.6 by franku
run the script
196
        """Called to render the close tag."""
200 by Holger Rapp
Fixed line endings in some python files
197
        pass
198
199
    def get_contents(self, parser):
200
        """Returns the string between the open and close tag."""
201
        return parser.markup[self.open_pos:self.close_pos]
202
203
    def get_contents_text(self, parser):
438.1.6 by franku
run the script
204
        """Returns the string between the the open and close tag, minus bbcode
205
        tags."""
532.1.1 by franku
converted to python 3.6 using 2to3 script
206
        return "".join(parser.get_text_nodes(self.open_node_index, self.close_node_index))
200 by Holger Rapp
Fixed line endings in some python files
207
208
    def skip_contents(self, parser):
209
        """Skips the contents of a tag while rendering."""
210
        parser.skip_to_node(self.close_node_index)
211
212
    def __str__(self):
438.1.6 by franku
run the script
213
        return '[%s]' % self.name
200 by Holger Rapp
Fixed line endings in some python files
214
215
216
class SimpleTag(TagBase):
217
438.1.6 by franku
run the script
218
    """A tag that can be rendered with a simple substitution."""
200 by Holger Rapp
Fixed line endings in some python files
219
220
    def __init__(self, name, html_name, **kwargs):
221
        """ html_name -- the html tag to substitute."""
222
        TagBase.__init__(self, name, inline=True)
223
        self.html_name = html_name
224
225
    def render_open(self, parser, node_index):
532.1.1 by franku
converted to python 3.6 using 2to3 script
226
        return "<%s>" % self.html_name
200 by Holger Rapp
Fixed line endings in some python files
227
228
    def render_close(self, parser, node_index):
532.1.1 by franku
converted to python 3.6 using 2to3 script
229
        return "</%s>" % self.html_name
200 by Holger Rapp
Fixed line endings in some python files
230
231
232
class DivStyleTag(TagBase):
233
234
    """A simple tag that is replaces with a div and a style."""
235
236
    def __init__(self, name, style, value, **kwargs):
237
        TagBase.__init__(self, name)
238
        self.style = style
239
        self.value = value
240
241
    def render_open(self, parser, node_index):
532.1.1 by franku
converted to python 3.6 using 2to3 script
242
        return '<div style="%s:%s;">' % (self.style, self.value)
200 by Holger Rapp
Fixed line endings in some python files
243
244
    def render_close(self, parser, node_index):
532.1.1 by franku
converted to python 3.6 using 2to3 script
245
        return '</div>'
200 by Holger Rapp
Fixed line endings in some python files
246
247
248
class LinkTag(TagBase):
249
250
    def __init__(self, name, annotate_links=True, **kwargs):
251
        TagBase.__init__(self, name, inline=True)
252
253
        self.annotate_links = annotate_links
254
255
    def render_open(self, parser, node_index):
256
532.1.1 by franku
converted to python 3.6 using 2to3 script
257
        self.domain = ''
200 by Holger Rapp
Fixed line endings in some python files
258
        tag_data = parser.tag_data
438.1.6 by franku
run the script
259
        nest_level = tag_data['link_nest_level'] = tag_data.setdefault(
260
            'link_nest_level', 0) + 1
200 by Holger Rapp
Fixed line endings in some python files
261
262
        if nest_level > 1:
532.1.1 by franku
converted to python 3.6 using 2to3 script
263
            return ""
200 by Holger Rapp
Fixed line endings in some python files
264
265
        if self.params:
266
            url = self.params.strip()
267
        else:
268
            url = self.get_contents_text(parser).strip()
269
438.1.6 by franku
run the script
270
        self.domain = ''
271
        # Unquote the url
200 by Holger Rapp
Fixed line endings in some python files
272
        self.url = unquote(url)
273
438.1.6 by franku
run the script
274
        # Disallow javascript links
532.1.1 by franku
converted to python 3.6 using 2to3 script
275
        if "javascript:" in self.url.lower():
438.1.6 by franku
run the script
276
            return ''
200 by Holger Rapp
Fixed line endings in some python files
277
438.1.6 by franku
run the script
278
        # Disallow non http: links
200 by Holger Rapp
Fixed line endings in some python files
279
        url_parsed = urlparse(self.url)
532.1.1 by franku
converted to python 3.6 using 2to3 script
280
        if url_parsed[0] and not url_parsed[0].lower().startswith('http'):
438.1.6 by franku
run the script
281
            return ''
200 by Holger Rapp
Fixed line endings in some python files
282
438.1.6 by franku
run the script
283
        # Prepend http: if it is not present
200 by Holger Rapp
Fixed line endings in some python files
284
        if not url_parsed[0]:
438.1.6 by franku
run the script
285
            self.url = 'http://' + self.url
200 by Holger Rapp
Fixed line endings in some python files
286
            url_parsed = urlparse(self.url)
287
438.1.6 by franku
run the script
288
        # Get domain
200 by Holger Rapp
Fixed line endings in some python files
289
        self.domain = url_parsed[1].lower()
290
438.1.6 by franku
run the script
291
        # Remove www for brevity
532.1.1 by franku
converted to python 3.6 using 2to3 script
292
        if self.domain.startswith('www.'):
200 by Holger Rapp
Fixed line endings in some python files
293
            self.domain = self.domain[4:]
294
438.1.6 by franku
run the script
295
        # Quote the url
200 by Holger Rapp
Fixed line endings in some python files
296
        #self.url="http:"+urlunparse( map(quote, (u"",)+url_parsed[1:]) )
532.1.1 by franku
converted to python 3.6 using 2to3 script
297
        self.url = str(urlunparse(
438.1.6 by franku
run the script
298
            [quote(component.encode('utf-8'), safe='/=&?:+') for component in url_parsed]))
200 by Holger Rapp
Fixed line endings in some python files
299
300
        if not self.url:
532.1.1 by franku
converted to python 3.6 using 2to3 script
301
            return ""
200 by Holger Rapp
Fixed line endings in some python files
302
303
        if self.domain:
532.1.1 by franku
converted to python 3.6 using 2to3 script
304
            return '<a href="%s">' % self.url
200 by Holger Rapp
Fixed line endings in some python files
305
        else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
306
            return ""
200 by Holger Rapp
Fixed line endings in some python files
307
308
    def render_close(self, parser, node_index):
309
310
        tag_data = parser.tag_data
311
        tag_data['link_nest_level'] -= 1
312
313
        if tag_data['link_nest_level'] > 0:
532.1.1 by franku
converted to python 3.6 using 2to3 script
314
            return ''
200 by Holger Rapp
Fixed line endings in some python files
315
316
        if self.domain:
532.1.1 by franku
converted to python 3.6 using 2to3 script
317
            return '</a>' + self.annotate_link(self.domain)
200 by Holger Rapp
Fixed line endings in some python files
318
        else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
319
            return ''
200 by Holger Rapp
Fixed line endings in some python files
320
321
    def annotate_link(self, domain=None):
322
323
        if domain and self.annotate_links:
324
            return annotate_link(domain)
325
        else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
326
            return ""
200 by Holger Rapp
Fixed line endings in some python files
327
328
329
class QuoteTag(TagBase):
330
331
    def __init__(self, name, **kwargs):
332
        TagBase.__init__(self, name, strip_first_newline=True)
333
334
    def open(self, parser, *args):
335
        TagBase.open(self, parser, *args)
336
337
    def close(self, parser, *args):
338
        TagBase.close(self, parser, *args)
339
340
    def render_open(self, parser, node_index):
341
        if self.params:
532.1.1 by franku
converted to python 3.6 using 2to3 script
342
            return '<blockquote><em>%s</em><br/>' % (PostMarkup.standard_replace(self.params))
200 by Holger Rapp
Fixed line endings in some python files
343
        else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
344
            return '<blockquote>'
200 by Holger Rapp
Fixed line endings in some python files
345
346
    def render_close(self, parser, node_index):
532.1.1 by franku
converted to python 3.6 using 2to3 script
347
        return "</blockquote>"
200 by Holger Rapp
Fixed line endings in some python files
348
349
350
class SearchTag(TagBase):
351
438.1.6 by franku
run the script
352
    def __init__(self, name, url, label='', annotate_links=True, **kwargs):
200 by Holger Rapp
Fixed line endings in some python files
353
        TagBase.__init__(self, name, inline=True)
354
        self.url = url
355
        self.label = label
356
        self.annotate_links = annotate_links
357
358
    def render_open(self, parser, node_idex):
359
360
        if self.params:
438.1.6 by franku
run the script
361
            search = self.params
200 by Holger Rapp
Fixed line endings in some python files
362
        else:
438.1.6 by franku
run the script
363
            search = self.get_contents(parser)
532.1.1 by franku
converted to python 3.6 using 2to3 script
364
        link = '<a href="%s">' % self.url
365
        if '%' in link:
438.1.6 by franku
run the script
366
            return link % quote_plus(search.encode('UTF-8'))
200 by Holger Rapp
Fixed line endings in some python files
367
        else:
368
            return link
369
370
    def render_close(self, parser, node_index):
371
372
        if self.label:
532.1.1 by franku
converted to python 3.6 using 2to3 script
373
            ret = '</a>'
200 by Holger Rapp
Fixed line endings in some python files
374
            if self.annotate_links:
375
                ret += annotate_link(self.label)
376
            return ret
377
        else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
378
            return ''
200 by Holger Rapp
Fixed line endings in some python files
379
380
381
class PygmentsCodeTag(TagBase):
382
383
    def __init__(self, name, pygments_line_numbers=False, **kwargs):
384
        TagBase.__init__(self, name, enclosed=True, strip_first_newline=True)
385
        self.line_numbers = pygments_line_numbers
386
387
    def render_open(self, parser, node_index):
388
389
        contents = self.get_contents(parser)
390
        self.skip_contents(parser)
391
392
        try:
393
            lexer = get_lexer_by_name(self.params, stripall=True)
394
        except ClassNotFound:
395
            contents = _escape(contents)
396
            return '<div class="code"><pre>%s</pre></div>' % contents
397
438.1.6 by franku
run the script
398
        formatter = HtmlFormatter(linenos=self.line_numbers, cssclass='code')
200 by Holger Rapp
Fixed line endings in some python files
399
        return highlight(contents, lexer, formatter)
400
401
402
class CodeTag(TagBase):
403
404
    def __init__(self, name, **kwargs):
405
        TagBase.__init__(self, name, enclosed=True, strip_first_newline=True)
406
407
    def render_open(self, parser, node_index):
408
409
        contents = _escape_no_breaks(self.get_contents(parser))
410
        self.skip_contents(parser)
411
        return '<div class="code"><pre>%s</pre></div>' % contents
412
413
414
class ImgTag(TagBase):
415
416
    def __init__(self, name, **kwargs):
417
        TagBase.__init__(self, name, inline=True)
418
419
    def render_open(self, parser, node_index):
420
421
        contents = self.get_contents(parser)
422
        self.skip_contents(parser)
423
532.1.1 by franku
converted to python 3.6 using 2to3 script
424
        contents = strip_bbcode(contents).replace('"', '%22')
200 by Holger Rapp
Fixed line endings in some python files
425
532.1.1 by franku
converted to python 3.6 using 2to3 script
426
        return '<img src="%s"></img>' % contents
200 by Holger Rapp
Fixed line endings in some python files
427
428
429
class ListTag(TagBase):
430
431
    def __init__(self, name,  **kwargs):
432
        TagBase.__init__(self, name, strip_first_newline=True)
433
434
    def open(self, parser, params, open_pos, node_index):
435
        TagBase.open(self, parser, params, open_pos, node_index)
436
437
    def close(self, parser, close_pos, node_index):
438
        TagBase.close(self, parser, close_pos, node_index)
439
440
    def render_open(self, parser, node_index):
441
532.1.1 by franku
converted to python 3.6 using 2to3 script
442
        self.close_tag = ""
200 by Holger Rapp
Fixed line endings in some python files
443
444
        tag_data = parser.tag_data
438.1.6 by franku
run the script
445
        tag_data.setdefault('ListTag.count', 0)
200 by Holger Rapp
Fixed line endings in some python files
446
438.1.6 by franku
run the script
447
        if tag_data['ListTag.count']:
532.1.1 by franku
converted to python 3.6 using 2to3 script
448
            return ""
200 by Holger Rapp
Fixed line endings in some python files
449
438.1.6 by franku
run the script
450
        tag_data['ListTag.count'] += 1
451
452
        tag_data['ListItemTag.initial_item'] = True
453
454
        if self.params == '1':
532.1.1 by franku
converted to python 3.6 using 2to3 script
455
            self.close_tag = "</li></ol>"
456
            return "<ol><li>"
438.1.6 by franku
run the script
457
        elif self.params == 'a':
532.1.1 by franku
converted to python 3.6 using 2to3 script
458
            self.close_tag = "</li></ol>"
459
            return '<ol style="list-style-type: lower-alpha;"><li>'
438.1.6 by franku
run the script
460
        elif self.params == 'A':
532.1.1 by franku
converted to python 3.6 using 2to3 script
461
            self.close_tag = "</li></ol>"
462
            return '<ol style="list-style-type: upper-alpha;"><li>'
200 by Holger Rapp
Fixed line endings in some python files
463
        else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
464
            self.close_tag = "</li></ul>"
465
            return "<ul><li>"
200 by Holger Rapp
Fixed line endings in some python files
466
467
    def render_close(self, parser, node_index):
468
469
        tag_data = parser.tag_data
438.1.6 by franku
run the script
470
        tag_data['ListTag.count'] -= 1
200 by Holger Rapp
Fixed line endings in some python files
471
472
        return self.close_tag
473
474
475
class ListItemTag(TagBase):
476
477
    def __init__(self, name, **kwargs):
478
        TagBase.__init__(self, name)
479
        self.closed = False
480
481
    def render_open(self, parser, node_index):
482
483
        tag_data = parser.tag_data
438.1.6 by franku
run the script
484
        if not tag_data.setdefault('ListTag.count', 0):
532.1.1 by franku
converted to python 3.6 using 2to3 script
485
            return ""
200 by Holger Rapp
Fixed line endings in some python files
486
438.1.6 by franku
run the script
487
        if tag_data['ListItemTag.initial_item']:
488
            tag_data['ListItemTag.initial_item'] = False
200 by Holger Rapp
Fixed line endings in some python files
489
            return
490
532.1.1 by franku
converted to python 3.6 using 2to3 script
491
        return "</li><li>"
200 by Holger Rapp
Fixed line endings in some python files
492
493
494
class SizeTag(TagBase):
495
438.1.6 by franku
run the script
496
    valid_chars = frozenset('0123456789')
200 by Holger Rapp
Fixed line endings in some python files
497
498
    def __init__(self, name, **kwargs):
499
        TagBase.__init__(self, name, inline=True)
500
501
    def render_open(self, parser, node_index):
502
503
        try:
438.1.6 by franku
run the script
504
            self.size = int(
505
                ''.join([c for c in self.params if c in self.valid_chars]))
200 by Holger Rapp
Fixed line endings in some python files
506
        except ValueError:
507
            self.size = None
508
509
        if self.size is None:
532.1.1 by franku
converted to python 3.6 using 2to3 script
510
            return ""
200 by Holger Rapp
Fixed line endings in some python files
511
512
        self.size = self.validate_size(self.size)
513
532.1.1 by franku
converted to python 3.6 using 2to3 script
514
        return '<span style="font-size:%spx">' % self.size
200 by Holger Rapp
Fixed line endings in some python files
515
516
    def render_close(self, parser, node_index):
517
518
        if self.size is None:
532.1.1 by franku
converted to python 3.6 using 2to3 script
519
            return ""
200 by Holger Rapp
Fixed line endings in some python files
520
532.1.1 by franku
converted to python 3.6 using 2to3 script
521
        return '</span>'
200 by Holger Rapp
Fixed line endings in some python files
522
523
    def validate_size(self, size):
524
525
        size = min(64, size)
526
        size = max(4, size)
527
        return size
528
529
530
class ColorTag(TagBase):
531
438.1.6 by franku
run the script
532
    valid_chars = frozenset('#0123456789abcdefghijklmnopqrstuvwxyz')
200 by Holger Rapp
Fixed line endings in some python files
533
534
    def __init__(self, name, **kwargs):
535
        TagBase.__init__(self, name, inline=True)
536
537
    def render_open(self, parser, node_index):
538
539
        valid_chars = self.valid_chars
540
        color = self.params.split()[0:1][0].lower()
438.1.6 by franku
run the script
541
        self.color = ''.join([c for c in color if c in valid_chars])
200 by Holger Rapp
Fixed line endings in some python files
542
543
        if not self.color:
532.1.1 by franku
converted to python 3.6 using 2to3 script
544
            return ""
200 by Holger Rapp
Fixed line endings in some python files
545
532.1.1 by franku
converted to python 3.6 using 2to3 script
546
        return '<span style="color:%s">' % self.color
200 by Holger Rapp
Fixed line endings in some python files
547
548
    def render_close(self, parser, node_index):
549
550
        if not self.color:
532.1.1 by franku
converted to python 3.6 using 2to3 script
551
            return ''
552
        return '</span>'
200 by Holger Rapp
Fixed line endings in some python files
553
554
555
class CenterTag(TagBase):
556
557
    def render_open(self, parser, node_index, **kwargs):
558
532.1.1 by franku
converted to python 3.6 using 2to3 script
559
        return '<div style="text-align:center">'
200 by Holger Rapp
Fixed line endings in some python files
560
561
    def render_close(self, parser, node_index):
562
532.1.1 by franku
converted to python 3.6 using 2to3 script
563
        return '</div>'
200 by Holger Rapp
Fixed line endings in some python files
564
565
# http://effbot.org/zone/python-replace.htm
438.1.6 by franku
run the script
566
567
200 by Holger Rapp
Fixed line endings in some python files
568
class MultiReplace:
569
570
    def __init__(self, repl_dict):
571
572
        # string to string mapping; use a regular expression
532.1.1 by franku
converted to python 3.6 using 2to3 script
573
        keys = list(repl_dict.keys())
438.1.6 by franku
run the script
574
        keys.sort()  # lexical order
575
        keys.reverse()  # use longest match first
532.1.1 by franku
converted to python 3.6 using 2to3 script
576
        pattern = "|".join([re.escape(key) for key in keys])
200 by Holger Rapp
Fixed line endings in some python files
577
        self.pattern = re.compile(pattern)
578
        self.dict = repl_dict
579
580
    def replace(self, s):
581
        # apply replacement dictionary to string
582
583
        def repl(match, get=self.dict.get):
584
            item = match.group(0)
585
            return get(item, item)
586
        return self.pattern.sub(repl, s)
587
588
    __call__ = replace
589
590
591
def _escape(s):
592
    return PostMarkup.standard_replace(s.rstrip('\n'))
593
438.1.6 by franku
run the script
594
200 by Holger Rapp
Fixed line endings in some python files
595
def _escape_no_breaks(s):
596
    return PostMarkup.standard_replace_no_break(s.rstrip('\n'))
597
438.1.6 by franku
run the script
598
200 by Holger Rapp
Fixed line endings in some python files
599
class TagFactory(object):
600
601
    def __init__(self):
602
603
        self.tags = {}
604
605
    @classmethod
606
    def tag_factory_callable(cls, tag_class, name, *args, **kwargs):
438.1.6 by franku
run the script
607
        """Returns a callable that returns a new tag instance."""
200 by Holger Rapp
Fixed line endings in some python files
608
        def make():
609
            return tag_class(name, *args, **kwargs)
610
611
        return make
612
613
    def add_tag(self, cls, name, *args, **kwargs):
614
615
        self.tags[name] = self.tag_factory_callable(cls, name, *args, **kwargs)
616
617
    def __getitem__(self, name):
618
619
        return self.tags[name]()
620
621
    def __contains__(self, name):
622
623
        return name in self.tags
624
625
    def get(self, name, default=None):
626
627
        if name in self.tags:
628
            return self.tags[name]()
629
630
        return default
631
632
633
class _Parser(object):
634
438.1.6 by franku
run the script
635
    """This is an interface to the parser, used by Tag classes."""
200 by Holger Rapp
Fixed line endings in some python files
636
637
    def __init__(self, post_markup):
638
639
        self.pm = post_markup
640
        self.tag_data = {}
641
        self.render_node_index = 0
642
643
    def skip_to_node(self, node_index):
438.1.6 by franku
run the script
644
        """Skips to a node, ignoring intermediate nodes."""
645
        assert node_index is not None, 'Node index must be non-None'
200 by Holger Rapp
Fixed line endings in some python files
646
        self.render_node_index = node_index
647
648
    def get_text_nodes(self, node1, node2):
438.1.6 by franku
run the script
649
        """Retrieves the text nodes between two node indices."""
200 by Holger Rapp
Fixed line endings in some python files
650
651
        if node2 is None:
438.1.6 by franku
run the script
652
            node2 = node1 + 1
200 by Holger Rapp
Fixed line endings in some python files
653
654
        return [node for node in self.nodes[node1:node2] if not callable(node)]
655
656
    def begin_no_breaks(self):
438.1.6 by franku
run the script
657
        """Disables replacing of newlines with break tags at the start and end
658
        of text nodes.
200 by Holger Rapp
Fixed line endings in some python files
659
660
        Can only be called from a tags 'open' method.
661
662
        """
438.1.6 by franku
run the script
663
        assert self.phase == 1, 'Can not be called from render_open or render_close'
200 by Holger Rapp
Fixed line endings in some python files
664
        self.no_breaks_count += 1
665
666
    def end_no_breaks(self):
667
        """Re-enables auto-replacing of newlines with break tags (see begin_no_breaks)."""
668
438.1.6 by franku
run the script
669
        assert self.phase == 1, 'Can not be called from render_open or render_close'
200 by Holger Rapp
Fixed line endings in some python files
670
        if self.no_breaks_count:
671
            self.no_breaks_count -= 1
672
673
674
class PostMarkup(object):
675
532.1.1 by franku
converted to python 3.6 using 2to3 script
676
    standard_replace = MultiReplace({'<': '&lt;',
677
                                     '>': '&gt;',
678
                                     '&': '&amp;',
679
                                     '\n': '<br/>'})
680
681
    standard_replace_no_break = MultiReplace({'<': '&lt;',
682
                                              '>': '&gt;',
683
                                              '&': '&amp;', })
684
685
    TOKEN_TAG, TOKEN_PTAG, TOKEN_TEXT = list(range(3))
200 by Holger Rapp
Fixed line endings in some python files
686
687
    # I tried to use RE's. Really I did.
688
    @classmethod
689
    def tokenize(cls, post):
690
691
        text = True
692
        pos = 0
693
694
        def find_first(post, pos, c):
695
            f1 = post.find(c[0], pos)
696
            f2 = post.find(c[1], pos)
697
            if f1 == -1:
698
                return f2
699
            if f2 == -1:
700
                return f1
701
            return min(f1, f2)
702
703
        while True:
704
532.1.1 by franku
converted to python 3.6 using 2to3 script
705
            brace_pos = post.find('[', pos)
200 by Holger Rapp
Fixed line endings in some python files
706
            if brace_pos == -1:
438.1.6 by franku
run the script
707
                if pos < len(post):
200 by Holger Rapp
Fixed line endings in some python files
708
                    yield PostMarkup.TOKEN_TEXT, post[pos:], pos, len(post)
709
                return
710
            if brace_pos - pos > 0:
711
                yield PostMarkup.TOKEN_TEXT, post[pos:brace_pos], pos, brace_pos
712
713
            pos = brace_pos
438.1.6 by franku
run the script
714
            end_pos = pos + 1
200 by Holger Rapp
Fixed line endings in some python files
715
532.1.1 by franku
converted to python 3.6 using 2to3 script
716
            open_tag_pos = post.find('[', end_pos)
717
            end_pos = find_first(post, end_pos, ']=')
200 by Holger Rapp
Fixed line endings in some python files
718
            if end_pos == -1:
719
                yield PostMarkup.TOKEN_TEXT, post[pos:], pos, len(post)
720
                return
721
722
            if open_tag_pos != -1 and open_tag_pos < end_pos:
723
                yield PostMarkup.TOKEN_TEXT, post[pos:open_tag_pos], pos, open_tag_pos
724
                end_pos = open_tag_pos
725
                pos = end_pos
726
                continue
727
728
            if post[end_pos] == ']':
438.1.6 by franku
run the script
729
                yield PostMarkup.TOKEN_TAG, post[pos:end_pos + 1], pos, end_pos + 1
730
                pos = end_pos + 1
200 by Holger Rapp
Fixed line endings in some python files
731
                continue
732
733
            if post[end_pos] == '=':
734
                try:
735
                    end_pos += 1
736
                    while post[end_pos] == ' ':
737
                        end_pos += 1
738
                    if post[end_pos] != '"':
532.1.1 by franku
converted to python 3.6 using 2to3 script
739
                        end_pos = post.find(']', end_pos + 1)
200 by Holger Rapp
Fixed line endings in some python files
740
                        if end_pos == -1:
741
                            return
438.1.6 by franku
run the script
742
                        yield PostMarkup.TOKEN_TAG, post[pos:end_pos + 1], pos, end_pos + 1
200 by Holger Rapp
Fixed line endings in some python files
743
                    else:
532.1.1 by franku
converted to python 3.6 using 2to3 script
744
                        end_pos = find_first(post, end_pos, '"]')
200 by Holger Rapp
Fixed line endings in some python files
745
438.1.6 by franku
run the script
746
                        if end_pos == -1:
200 by Holger Rapp
Fixed line endings in some python files
747
                            return
748
                        if post[end_pos] == '"':
532.1.1 by franku
converted to python 3.6 using 2to3 script
749
                            end_pos = post.find('"', end_pos + 1)
438.1.6 by franku
run the script
750
                            if end_pos == -1:
751
                                return
532.1.1 by franku
converted to python 3.6 using 2to3 script
752
                            end_pos = post.find(']', end_pos + 1)
438.1.6 by franku
run the script
753
                            if end_pos == -1:
754
                                return
755
                            yield PostMarkup.TOKEN_PTAG, post[pos:end_pos + 1], pos, end_pos + 1
200 by Holger Rapp
Fixed line endings in some python files
756
                        else:
438.1.6 by franku
run the script
757
                            yield PostMarkup.TOKEN_TAG, post[pos:end_pos + 1], pos, end_pos
758
                    pos = end_pos + 1
200 by Holger Rapp
Fixed line endings in some python files
759
                except IndexError:
760
                    return
761
438.1.6 by franku
run the script
762
    def tagify_urls(self, postmarkup):
763
        """Surrounds urls with url bbcode tags."""
200 by Holger Rapp
Fixed line endings in some python files
764
765
        def repl(match):
532.1.1 by franku
converted to python 3.6 using 2to3 script
766
            return '[url]%s[/url]' % match.group(0)
200 by Holger Rapp
Fixed line endings in some python files
767
768
        text_tokens = []
769
        for tag_type, tag_token, start_pos, end_pos in self.tokenize(postmarkup):
770
771
            if tag_type == PostMarkup.TOKEN_TEXT:
772
                text_tokens.append(re_url.sub(repl, tag_token))
773
            else:
774
                text_tokens.append(tag_token)
775
532.1.1 by franku
converted to python 3.6 using 2to3 script
776
        return "".join(text_tokens)
200 by Holger Rapp
Fixed line endings in some python files
777
778
    def __init__(self, tag_factory=None):
779
780
        self.tag_factory = tag_factory or TagFactory()
781
782
    def default_tags(self):
438.1.6 by franku
run the script
783
        """Add some basic tags."""
200 by Holger Rapp
Fixed line endings in some python files
784
785
        add_tag = self.tag_factory.add_tag
786
532.1.1 by franku
converted to python 3.6 using 2to3 script
787
        add_tag(SimpleTag, 'b', 'strong')
788
        add_tag(SimpleTag, 'i', 'em')
789
        add_tag(SimpleTag, 'u', 'u')
790
        add_tag(SimpleTag, 's', 's')
200 by Holger Rapp
Fixed line endings in some python files
791
792
    def get_supported_tags(self):
438.1.6 by franku
run the script
793
        """Returns a list of the supported tags."""
200 by Holger Rapp
Fixed line endings in some python files
794
795
        return sorted(self.tag_factory.tags.keys())
796
797
    def render_to_html(self,
798
                       post_markup,
438.1.6 by franku
run the script
799
                       encoding='ascii',
200 by Holger Rapp
Fixed line endings in some python files
800
                       exclude_tags=None,
801
                       auto_urls=True):
802
        """Converts Post Markup to XHTML.
803
804
        post_markup -- String containing bbcode.
805
        encoding -- Encoding of string, defaults to "ascii".
806
        exclude_tags -- A collection of tag names to ignore.
807
        auto_urls -- If True, then urls will be wrapped with url bbcode tags.
808
809
        """
810
532.1.1 by franku
converted to python 3.6 using 2to3 script
811
        if not isinstance(post_markup, str):
812
            post_markup = str(post_markup, encoding, 'replace')
200 by Holger Rapp
Fixed line endings in some python files
813
814
        if auto_urls:
815
            post_markup = self.tagify_urls(post_markup)
816
817
        parser = _Parser(self)
818
        parser.markup = post_markup
819
820
        if exclude_tags is None:
821
            exclude_tags = []
822
823
        tag_factory = self.tag_factory
824
825
        nodes = []
826
        parser.nodes = nodes
827
828
        parser.phase = 1
829
        parser.no_breaks_count = 0
830
        enclosed_count = 0
831
        open_stack = []
832
        tag_stack = []
833
        break_stack = []
834
        remove_next_newline = False
835
836
        def check_tag_stack(tag_name):
837
838
            for tag in reversed(tag_stack):
839
                if tag_name == tag.name:
840
                    return True
841
            return False
842
843
        def redo_break_stack():
844
845
            while break_stack:
846
                tag = break_stack.pop()
847
                open_tag(tag)
848
                tag_stack.append(tag)
849
850
        def break_inline_tags():
851
852
            while tag_stack:
853
                if tag_stack[-1].inline:
854
                    tag = tag_stack.pop()
855
                    close_tag(tag)
856
                    break_stack.append(tag)
857
                else:
858
                    break
859
860
        def open_tag(tag):
861
            def call(node_index):
862
                return tag.render_open(parser, node_index)
863
            nodes.append(call)
864
865
        def close_tag(tag):
866
            def call(node_index):
867
                return tag.render_close(parser, node_index)
868
            nodes.append(call)
869
870
        # Pass 1
871
        for tag_type, tag_token, start_pos, end_pos in self.tokenize(post_markup):
872
873
            raw_tag_token = tag_token
874
875
            if tag_type == PostMarkup.TOKEN_TEXT:
876
                if parser.no_breaks_count:
877
                    tag_token = tag_token.strip()
878
                    if not tag_token:
879
                        continue
880
                if remove_next_newline:
881
                    tag_token = tag_token.lstrip(' ')
882
                    if tag_token.startswith('\n'):
883
                        tag_token = tag_token.lstrip(' ')[1:]
884
                        if not tag_token:
885
                            continue
886
                    remove_next_newline = False
887
888
                if tag_stack and tag_stack[-1].strip_first_newline:
889
                    tag_token = tag_token.lstrip()
890
                    tag_stack[-1].strip_first_newline = False
891
                    if not tag_stack[-1]:
892
                        tag_stack.pop()
893
                        continue
894
895
                if not enclosed_count:
896
                    redo_break_stack()
897
898
                nodes.append(self.standard_replace(tag_token))
899
                continue
900
901
            elif tag_type == PostMarkup.TOKEN_TAG:
902
                tag_token = tag_token[1:-1].lstrip()
903
                if ' ' in tag_token:
532.1.1 by franku
converted to python 3.6 using 2to3 script
904
                    tag_name, tag_attribs = tag_token.split(' ', 1)
200 by Holger Rapp
Fixed line endings in some python files
905
                    tag_attribs = tag_attribs.strip()
906
                else:
907
                    if '=' in tag_token:
532.1.1 by franku
converted to python 3.6 using 2to3 script
908
                        tag_name, tag_attribs = tag_token.split('=', 1)
200 by Holger Rapp
Fixed line endings in some python files
909
                        tag_attribs = tag_attribs.strip()
910
                    else:
911
                        tag_name = tag_token
532.1.1 by franku
converted to python 3.6 using 2to3 script
912
                        tag_attribs = ""
200 by Holger Rapp
Fixed line endings in some python files
913
            else:
914
                tag_token = tag_token[1:-1].lstrip()
532.1.1 by franku
converted to python 3.6 using 2to3 script
915
                tag_name, tag_attribs = tag_token.split('=', 1)
200 by Holger Rapp
Fixed line endings in some python files
916
                tag_attribs = tag_attribs.strip()[1:-1]
917
918
            tag_name = tag_name.strip().lower()
919
920
            end_tag = False
532.1.1 by franku
converted to python 3.6 using 2to3 script
921
            if tag_name.startswith('/'):
200 by Holger Rapp
Fixed line endings in some python files
922
                end_tag = True
923
                tag_name = tag_name[1:]
924
925
            if enclosed_count and tag_stack[-1].name != tag_name:
926
                continue
927
928
            if tag_name in exclude_tags:
929
                continue
930
931
            if not end_tag:
932
933
                tag = tag_factory.get(tag_name, None)
934
                if tag is None:
935
                    continue
936
937
                redo_break_stack()
938
939
                if not tag.inline:
940
                    break_inline_tags()
941
942
                tag.open(parser, tag_attribs, end_pos, len(nodes))
943
                if tag.enclosed:
944
                    enclosed_count += 1
945
                tag_stack.append(tag)
946
947
                open_tag(tag)
948
949
                if tag.auto_close:
950
                    tag = tag_stack.pop()
438.1.6 by franku
run the script
951
                    tag.close(self, start_pos, len(nodes) - 1)
200 by Holger Rapp
Fixed line endings in some python files
952
                    close_tag(tag)
953
954
            else:
955
956
                if break_stack and break_stack[-1].name == tag_name:
957
                    break_stack.pop()
958
                    tag.close(parser, start_pos, len(nodes))
959
                elif check_tag_stack(tag_name):
960
                    while tag_stack[-1].name != tag_name:
961
                        tag = tag_stack.pop()
962
                        break_stack.append(tag)
963
                        close_tag(tag)
964
965
                    tag = tag_stack.pop()
966
                    tag.close(parser, start_pos, len(nodes))
967
                    if tag.enclosed:
968
                        enclosed_count -= 1
969
970
                    close_tag(tag)
971
972
                    if not tag.inline:
973
                        remove_next_newline = True
974
975
        if tag_stack:
976
            redo_break_stack()
977
            while tag_stack:
978
                tag = tag_stack.pop()
979
                tag.close(parser, len(post_markup), len(nodes))
980
                if tag.enclosed:
981
                    enclosed_count -= 1
982
                close_tag(tag)
983
984
        parser.phase = 2
985
        # Pass 2
986
        parser.nodes = nodes
987
988
        text = []
989
        parser.render_node_index = 0
990
        while parser.render_node_index < len(parser.nodes):
991
            i = parser.render_node_index
992
            node_text = parser.nodes[i]
993
            if callable(node_text):
994
                node_text = node_text(i)
995
            if node_text is not None:
996
                text.append(node_text)
997
            parser.render_node_index += 1
998
532.1.1 by franku
converted to python 3.6 using 2to3 script
999
        return "".join(text)
200 by Holger Rapp
Fixed line endings in some python files
1000
1001
    __call__ = render_to_html
1002
1003
1004
def _tests():
1005
1006
    import sys
1007
    #sys.stdout=open('test.htm', 'w')
1008
1009
    post_markup = create(use_pygments=True)
1010
1011
    tests = []
532.1.1 by franku
converted to python 3.6 using 2to3 script
1012
    print("""<link rel="stylesheet" href="code.css" type="text/css" />\n""")
200 by Holger Rapp
Fixed line endings in some python files
1013
1014
    tests.append(']')
1015
    tests.append('[')
1016
    tests.append(':-[ Hello, [b]World[/b]')
1017
438.1.6 by franku
run the script
1018
    tests.append('[link=http://www.willmcgugan.com]My homepage[/link]')
200 by Holger Rapp
Fixed line endings in some python files
1019
    tests.append('[link="http://www.willmcgugan.com"]My homepage[/link]')
438.1.6 by franku
run the script
1020
    tests.append('[link http://www.willmcgugan.com]My homepage[/link]')
1021
    tests.append('[link]http://www.willmcgugan.com[/link]')
200 by Holger Rapp
Fixed line endings in some python files
1022
532.1.1 by franku
converted to python 3.6 using 2to3 script
1023
    tests.append("[b]Hello AndrУЉ[/b]")
1024
    tests.append("[google]AndrУЉ[/google]")
438.1.6 by franku
run the script
1025
    tests.append('[s]Strike through[/s]')
1026
    tests.append('[b]bold [i]bold and italic[/b] italic[/i]')
1027
    tests.append('[google]Will McGugan[/google]')
1028
    tests.append('[wiki Will McGugan]Look up my name in Wikipedia[/wiki]')
200 by Holger Rapp
Fixed line endings in some python files
1029
438.1.6 by franku
run the script
1030
    tests.append('[quote Will said...]BBCode is very cool[/quote]')
200 by Holger Rapp
Fixed line endings in some python files
1031
1032
    tests.append("""[code python]
1033
# A proxy object that calls a callback when converted to a string
1034
class TagStringify(object):
1035
    def __init__(self, callback, raw):
1036
        self.callback = callback
1037
        self.raw = raw
1038
        r[b]=3
1039
    def __str__(self):
1040
        return self.callback()
1041
    def __repr__(self):
1042
        return self.__str__()
1043
[/code]""")
1044
532.1.1 by franku
converted to python 3.6 using 2to3 script
1045
    tests.append("[img]http://upload.wikimedia.org/wikipedia/commons"
438.1.6 by franku
run the script
1046
                 '/6/61/Triops_longicaudatus.jpg[/img]')
1047
1048
    tests.append('[list][*]Apples[*]Oranges[*]Pears[/list]')
200 by Holger Rapp
Fixed line endings in some python files
1049
    tests.append("""[list=1]
1050
    [*]Apples
1051
    [*]Oranges
1052
    are not the only fruit
1053
    [*]Pears
1054
[/list]""")
438.1.6 by franku
run the script
1055
    tests.append('[list=a][*]Apples[*]Oranges[*]Pears[/list]')
1056
    tests.append('[list=A][*]Apples[*]Oranges[*]Pears[/list]')
200 by Holger Rapp
Fixed line endings in some python files
1057
438.1.6 by franku
run the script
1058
    long_test = """[b]Long test[/b]
200 by Holger Rapp
Fixed line endings in some python files
1059
1060
New lines characters are converted to breaks."""\
1061
"""Tags my be [b]ove[i]rl[/b]apped[/i].
1062
1063
[i]Open tags will be closed.
1064
[b]Test[/b]"""
1065
1066
    tests.append(long_test)
1067
438.1.6 by franku
run the script
1068
    tests.append('[dict]Will[/dict]')
1069
1070
    tests.append(
1071
        "[code unknownlanguage]10 print 'In yr code'; 20 goto 10[/code]")
1072
1073
    tests.append(
1074
        '[url=http://www.google.com/coop/cse?cx=006850030468302103399%3Amqxv78bdfdo]CakePHP Google Groups[/url]')
1075
    tests.append('[url=http://www.google.com/search?hl=en&safe=off&client=opera&rls=en&hs=pO1&q=python+bbcode&btnG=Search]Search for Python BBCode[/url]')
200 by Holger Rapp
Fixed line endings in some python files
1076
    #tests = []
1077
    # Attempt to inject html in to unicode
438.1.6 by franku
run the script
1078
    tests.append(
1079
        "[url=http://www.test.com/sfsdfsdf/ter?t=\"></a><h1>HACK</h1><a>\"]Test Hack[/url]")
200 by Holger Rapp
Fixed line endings in some python files
1080
438.1.6 by franku
run the script
1081
    tests.append(
1082
        'Nested urls, i.e. [url][url]www.becontrary.com[/url][/url], are condensed in to a single tag.')
200 by Holger Rapp
Fixed line endings in some python files
1083
532.1.1 by franku
converted to python 3.6 using 2to3 script
1084
    tests.append('[google]ЩИЮВfvЮИУАsz[/google]')
1085
1086
    tests.append('[size 30]Hello, World![/size]')
1087
1088
    tests.append('[color red]This should be red[/color]')
1089
    tests.append('[color #0f0]This should be green[/color]')
1090
    tests.append("[center]This should be in the center!")
200 by Holger Rapp
Fixed line endings in some python files
1091
438.1.6 by franku
run the script
1092
    tests.append(
1093
        'Nested urls, i.e. [url][url]www.becontrary.com[/url][/url], are condensed in to a single tag.')
200 by Holger Rapp
Fixed line endings in some python files
1094
1095
    #tests = []
1096
    tests.append('[b]Hello, [i]World[/b]! [/i]')
1097
1098
    tests.append('[b][center]This should be centered![/center][/b]')
1099
1100
    tests.append('[list][*]Hello[i][*]World![/i][/list]')
1101
1102
    tests.append("""[list=1]
1103
    [*]Apples
1104
    [*]Oranges
1105
    are not the only fruit
1106
    [*]Pears
1107
[/list]""")
1108
438.1.6 by franku
run the script
1109
    tests.append(
1110
        '[b]urls such as http://www.willmcgugan.com are authomaticaly converted to links[/b]')
200 by Holger Rapp
Fixed line endings in some python files
1111
1112
    tests.append("""
1113
[b]
1114
[code python]
1115
parser.markup[self.open_pos:self.close_pos]
1116
[/code]
1117
asdasdasdasdqweqwe
1118
""")
1119
1120
    tests.append("""[list 1]
1121
[*]Hello
1122
[*]World
1123
[/list]""")
1124
438.1.6 by franku
run the script
1125
    # tests=["""[b]b[i]i[/b][/i]"""]
200 by Holger Rapp
Fixed line endings in some python files
1126
1127
    for test in tests:
532.1.1 by franku
converted to python 3.6 using 2to3 script
1128
        print("<pre>%s</pre>" % str(test.encode('ascii', 'xmlcharrefreplace')))
1129
        print("<p>%s</p>" % str(post_markup(test).encode('ascii', 'xmlcharrefreplace')))
1130
        print("<hr/>")
1131
        print()
1132
1133
    print(repr(post_markup('[url=<script>Attack</script>]Attack[/url]')))
1134
1135
    print(repr(post_markup('http://www.google.com/search?as_q=bbcode&btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA')))
200 by Holger Rapp
Fixed line endings in some python files
1136
1137
    p = create(use_pygments=False)
532.1.1 by franku
converted to python 3.6 using 2to3 script
1138
    print((p('[code]foo\nbar[/code]')))
200 by Holger Rapp
Fixed line endings in some python files
1139
438.1.6 by franku
run the script
1140
    # print render_bbcode("[b]For the lazy, use the http://www.willmcgugan.com
1141
    # render_bbcode function.[/b]")
200 by Holger Rapp
Fixed line endings in some python files
1142
1143
1144
def _run_unittests():
1145
1146
    # TODO: Expand tests for better coverage!
1147
1148
    import unittest
1149
1150
    class TestPostmarkup(unittest.TestCase):
1151
1152
        def testsimpletag(self):
1153
1154
            postmarkup = create()
1155
438.1.6 by franku
run the script
1156
            tests = [('[b]Hello[/b]', '<strong>Hello</strong>'),
1157
                     ('[i]Italic[/i]', '<em>Italic</em>'),
1158
                     ('[s]Strike[/s]', '<strike>Strike</strike>'),
1159
                     ('[u]underlined[/u]', '<u>underlined</u>'),
200 by Holger Rapp
Fixed line endings in some python files
1160
                     ]
1161
1162
            for test, result in tests:
1163
                self.assertEqual(postmarkup(test), result)
1164
1165
        def testoverlap(self):
1166
1167
            postmarkup = create()
1168
438.1.6 by franku
run the script
1169
            tests = [('[i][b]Hello[/i][/b]', '<em><strong>Hello</strong></em>'),
1170
                     ('[b]bold [u]both[/b] underline[/u]',
1171
                      '<strong>bold <u>both</u></strong><u> underline</u>')
200 by Holger Rapp
Fixed line endings in some python files
1172
                     ]
1173
1174
            for test, result in tests:
1175
                self.assertEqual(postmarkup(test), result)
1176
1177
        def testlinks(self):
1178
1179
            postmarkup = create(annotate_links=False)
1180
438.1.6 by franku
run the script
1181
            tests = [('[link=http://www.willmcgugan.com]blog1[/link]', '<a href="http://www.willmcgugan.com">blog1</a>'),
1182
                     ('[link="http://www.willmcgugan.com"]blog2[/link]',
1183
                      '<a href="http://www.willmcgugan.com">blog2</a>'),
1184
                     ('[link http://www.willmcgugan.com]blog3[/link]',
1185
                      '<a href="http://www.willmcgugan.com">blog3</a>'),
1186
                     ('[link]http://www.willmcgugan.com[/link]',
1187
                      '<a href="http://www.willmcgugan.com">http://www.willmcgugan.com</a>')
200 by Holger Rapp
Fixed line endings in some python files
1188
                     ]
1189
1190
            for test, result in tests:
1191
                self.assertEqual(postmarkup(test), result)
1192
1193
    suite = unittest.TestLoader().loadTestsFromTestCase(TestPostmarkup)
1194
    unittest.TextTestRunner(verbosity=2).run(suite)
1195
1196
438.1.6 by franku
run the script
1197
if __name__ == '__main__':
200 by Holger Rapp
Fixed line endings in some python files
1198
1199
    _tests()
1200
    _run_unittests()