##// END OF EJS Templates
Truncate posts by lines
neko259 -
r1000:32843027 default
parent child Browse files
Show More
@@ -63,7 +63,7 b''
63 <div class="message">
63 <div class="message">
64 {% autoescape off %}
64 {% autoescape off %}
65 {% if truncated %}
65 {% if truncated %}
66 {{ post.get_text|truncatewords_html:50 }}
66 {{ post.get_text|truncatewords_html:50|truncate_lines:3 }}
67 {% else %}
67 {% else %}
68 {{ post.get_text }}
68 {{ post.get_text }}
69 {% endif %}
69 {% endif %}
@@ -1,6 +1,12 b''
1 import re
1 from django.shortcuts import get_object_or_404
2 from django.shortcuts import get_object_or_404
2 from django import template
3 from django import template
3
4
5 ELLIPSIZER = '...'
6
7 REGEX_LINES = re.compile(r'(<div class="br"></div>)', re.U | re.S)
8 REGEX_TAG = re.compile(r'<(/)?([^ ]+?)(?:(\s*/)| .*?)?>', re.S)
9
4
10
5 register = template.Library()
11 register = template.Library()
6
12
@@ -72,3 +78,68 b' def post_view(post, moderator=False, nee'
72 'truncated': truncated,
78 'truncated': truncated,
73 'opening_post_id': opening_post_id,
79 'opening_post_id': opening_post_id,
74 }
80 }
81
82
83 @register.filter(is_safe=True)
84 def truncate_lines(text, length):
85 if length <= 0:
86 return ''
87
88 html4_singlets = (
89 'br', 'col', 'link', 'base', 'img',
90 'param', 'area', 'hr', 'input'
91 )
92
93 # Count non-HTML chars/words and keep note of open tags
94 pos = 0
95 end_text_pos = 0
96 current_len = 0
97 open_tags = []
98
99 while current_len <= length:
100 m = REGEX_LINES.search(text, pos)
101 if not m:
102 # Checked through whole string
103 break
104 pos = m.end(0)
105 if m.group(1):
106 # It's an actual non-HTML word or char
107 current_len += 1
108 if current_len == length:
109 end_text_pos = pos
110 continue
111 # Check for tag
112 tag = REGEX_TAG.match(m.group(0))
113 if not tag or current_len >= length:
114 # Don't worry about non tags or tags after our truncate point
115 continue
116 closing_tag, tagname, self_closing = tag.groups()
117 # Element names are always case-insensitive
118 tagname = tagname.lower()
119 if self_closing or tagname in html4_singlets:
120 pass
121 elif closing_tag:
122 # Check for match in open tags list
123 try:
124 i = open_tags.index(tagname)
125 except ValueError:
126 pass
127 else:
128 # SGML: An end tag closes, back to the matching start tag,
129 # all unclosed intervening start tags with omitted end tags
130 open_tags = open_tags[i + 1:]
131 else:
132 # Add it to the start of the open tags list
133 open_tags.insert(0, tagname)
134
135 if current_len <= length:
136 return text
137 out = text[:end_text_pos]
138
139 if not out.endswith(ELLIPSIZER):
140 out += ELLIPSIZER
141 # Close any tags still open
142 for tag in open_tags:
143 out += '</%s>' % tag
144 # Return string
145 return out
General Comments 0
You need to be logged in to leave comments. Login now