Show More
@@ -83,7 +83,7 b'' | |||||
83 | {% endcomment %} |
|
83 | {% endcomment %} | |
84 | <div class="message"> |
|
84 | <div class="message"> | |
85 | {% if truncated %} |
|
85 | {% if truncated %} | |
86 | {{ post.get_text|truncatewords_html:50|safe }} |
|
86 | {{ post.get_text|truncatewords_html:50|truncatenewlines_html:3|safe }} | |
87 | {% else %} |
|
87 | {% else %} | |
88 | {{ post.get_text|safe }} |
|
88 | {{ post.get_text|safe }} | |
89 | {% endif %} |
|
89 | {% endif %} |
@@ -1,9 +1,18 b'' | |||||
1 | import re |
|
1 | import re | |
|
2 | ||||
2 | from django.shortcuts import get_object_or_404 |
|
3 | from django.shortcuts import get_object_or_404 | |
3 | from django import template |
|
4 | from django import template | |
|
5 | from django.utils.text import re_tag | |||
|
6 | ||||
|
7 | from boards.mdx_neboard import LINE_BREAK_HTML | |||
4 |
|
8 | |||
5 |
|
9 | |||
6 | IMG_ACTION_URL = '[<a href="{}">{}</a>]' |
|
10 | IMG_ACTION_URL = '[<a href="{}">{}</a>]' | |
|
11 | REGEX_NEWLINE = re.compile(LINE_BREAK_HTML) | |||
|
12 | TRUNCATOR = '...' | |||
|
13 | HTML4_SINGLETS =( | |||
|
14 | 'br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input' | |||
|
15 | ) | |||
7 |
|
16 | |||
8 |
|
17 | |||
9 | register = template.Library() |
|
18 | register = template.Library() | |
@@ -49,3 +58,59 b' def post_view(context, post, *args, **kw' | |||||
49 | def page_url(paginator, page_number, *args, **kwargs): |
|
58 | def page_url(paginator, page_number, *args, **kwargs): | |
50 | if paginator.supports_urls(): |
|
59 | if paginator.supports_urls(): | |
51 | return paginator.get_page_url(page_number) |
|
60 | return paginator.get_page_url(page_number) | |
|
61 | ||||
|
62 | ||||
|
63 | @register.filter(name='truncatenewlines_html') | |||
|
64 | def truncatenewlines_html(value, arg): | |||
|
65 | current_pos = 0 | |||
|
66 | match_count = 0 | |||
|
67 | ||||
|
68 | # Collect places for truncation | |||
|
69 | while match_count <= arg: | |||
|
70 | m = REGEX_NEWLINE.search(value, current_pos) | |||
|
71 | if m is None: | |||
|
72 | break | |||
|
73 | else: | |||
|
74 | match_count += 1 | |||
|
75 | current_pos = m.end() | |||
|
76 | ||||
|
77 | # Find and close open tags | |||
|
78 | if match_count > arg: | |||
|
79 | truncate_pos = current_pos | |||
|
80 | ||||
|
81 | open_tags = [] | |||
|
82 | text = value[:truncate_pos] | |||
|
83 | current_pos = 0 | |||
|
84 | while True: | |||
|
85 | tag = re_tag.search(text, current_pos) | |||
|
86 | if tag is None: | |||
|
87 | break | |||
|
88 | else: | |||
|
89 | closing_tag, tagname, self_closing = tag.groups() | |||
|
90 | tagname = tagname.lower() | |||
|
91 | if self_closing or tagname in HTML4_SINGLETS: | |||
|
92 | pass | |||
|
93 | elif closing_tag: | |||
|
94 | # Check for match in open tags list | |||
|
95 | try: | |||
|
96 | i = open_tags.index(tagname) | |||
|
97 | except ValueError: | |||
|
98 | pass | |||
|
99 | else: | |||
|
100 | # SGML: An end tag closes, back to the matching start tag, | |||
|
101 | # all unclosed intervening start tags with omitted end tags | |||
|
102 | open_tags = open_tags[i + 1:] | |||
|
103 | else: | |||
|
104 | # Add it to the start of the open tags list | |||
|
105 | open_tags.insert(0, tagname) | |||
|
106 | ||||
|
107 | current_pos = tag.end() | |||
|
108 | ||||
|
109 | for tag in open_tags: | |||
|
110 | text += '</%s>'.format(tag) | |||
|
111 | text += TRUNCATOR | |||
|
112 | else: | |||
|
113 | text = value | |||
|
114 | ||||
|
115 | return text | |||
|
116 |
General Comments 0
You need to be logged in to leave comments.
Login now