##// END OF EJS Templates
Use old-style quotes when no source is specified
neko259 -
r1067:c1bcb1e6 default
parent child Browse files
Show More
@@ -1,233 +1,233 b''
1 1 # coding=utf-8
2 2
3 3 import re
4 4 import bbcode
5 5
6 6 from urllib.parse import unquote
7 7
8 8 from django.core.exceptions import ObjectDoesNotExist
9 9 from django.core.urlresolvers import reverse
10 10
11 11 import boards
12 12
13 13
14 14 __author__ = 'neko259'
15 15
16 16
17 17 REFLINK_PATTERN = re.compile(r'^\d+$')
18 18 MULTI_NEWLINES_PATTERN = re.compile(r'(\r?\n){2,}')
19 19 ONE_NEWLINE = '\n'
20 20 REGEX_URL = re.compile(r'https?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?')
21 21
22 22
23 23 class TextFormatter():
24 24 """
25 25 An interface for formatter that can be used in the text format panel
26 26 """
27 27
28 28 def __init__(self):
29 29 pass
30 30
31 31 name = ''
32 32
33 33 # Left and right tags for the button preview
34 34 preview_left = ''
35 35 preview_right = ''
36 36
37 37 # Left and right characters for the textarea input
38 38 format_left = ''
39 39 format_right = ''
40 40
41 41
42 42 class AutolinkPattern():
43 43 def handleMatch(self, m):
44 44 link_element = etree.Element('a')
45 45 href = m.group(2)
46 46 link_element.set('href', href)
47 47 link_element.text = href
48 48
49 49 return link_element
50 50
51 51
52 52 class QuotePattern(TextFormatter):
53 53 name = 'q'
54 54 preview_left = '<span class="multiquote">'
55 55 preview_right = '</span>'
56 56
57 57 format_left = '[quote]'
58 58 format_right = '[/quote]'
59 59
60 60
61 61 class SpoilerPattern(TextFormatter):
62 62 name = 'spoiler'
63 63 preview_left = '<span class="spoiler">'
64 64 preview_right = '</span>'
65 65
66 66 format_left = '[spoiler]'
67 67 format_right = '[/spoiler]'
68 68
69 69 def handleMatch(self, m):
70 70 quote_element = etree.Element('span')
71 71 quote_element.set('class', 'spoiler')
72 72 quote_element.text = m.group(2)
73 73
74 74 return quote_element
75 75
76 76
77 77 class CommentPattern(TextFormatter):
78 78 name = ''
79 79 preview_left = '<span class="comment">// '
80 80 preview_right = '</span>'
81 81
82 82 format_left = '[comment]'
83 83 format_right = '[/comment]'
84 84
85 85
86 86 # TODO Use <s> tag here
87 87 class StrikeThroughPattern(TextFormatter):
88 88 name = 's'
89 89 preview_left = '<span class="strikethrough">'
90 90 preview_right = '</span>'
91 91
92 92 format_left = '[s]'
93 93 format_right = '[/s]'
94 94
95 95
96 96 class ItalicPattern(TextFormatter):
97 97 name = 'i'
98 98 preview_left = '<i>'
99 99 preview_right = '</i>'
100 100
101 101 format_left = '[i]'
102 102 format_right = '[/i]'
103 103
104 104
105 105 class BoldPattern(TextFormatter):
106 106 name = 'b'
107 107 preview_left = '<b>'
108 108 preview_right = '</b>'
109 109
110 110 format_left = '[b]'
111 111 format_right = '[/b]'
112 112
113 113
114 114 class CodePattern(TextFormatter):
115 115 name = 'code'
116 116 preview_left = '<code>'
117 117 preview_right = '</code>'
118 118
119 119 format_left = '[code]'
120 120 format_right = '[/code]'
121 121
122 122
123 123 def render_reflink(tag_name, value, options, parent, context):
124 124 result = '>>%s' % value
125 125
126 126 if REFLINK_PATTERN.match(value):
127 127 post_id = int(value)
128 128
129 129 try:
130 130 post = boards.models.Post.objects.get(id=post_id)
131 131
132 132 result = '<a href="%s">&gt;&gt;%s</a>' % (post.get_url(), post_id)
133 133 except ObjectDoesNotExist:
134 134 pass
135 135
136 136 return result
137 137
138 138
139 139 def render_multithread(tag_name, value, options, parent, context):
140 140 result = '>>>%s' % value
141 141
142 142 if REFLINK_PATTERN.match(value):
143 143 post_id = int(value)
144 144
145 145 try:
146 146 post = boards.models.Post.objects.get(id=post_id)
147 147
148 148 if post.is_opening():
149 149 result = '<a href="%s">&gt;&gt;&gt;%s</a>' % (post.get_url(), post_id)
150 150 except ObjectDoesNotExist:
151 151 pass
152 152
153 153 return result
154 154
155 155
156 156 def render_quote(tag_name, value, options, parent, context):
157 157 source = ''
158 158 if 'source' in options:
159 159 source = options['source']
160 160
161 161 if source:
162 162 result = '<div class="multiquote"><div class="quote-header">%s</div><div class="quote-text">%s</div></div>' % (source, value)
163 163 else:
164 result = '<div class="multiquote"><div class="quote-text">%s</div></div>' % value
164 result = '<span class="quote">&gt;%s</span>' % value
165 165
166 166 return result
167 167
168 168
169 169 def render_notification(tag_name, value, options, parent, content):
170 170 username = value.lower()
171 171
172 172 return '<a href="{}" class="user-cast">@{}</a>'.format(
173 173 reverse('notifications', kwargs={'username': username}), username)
174 174
175 175
176 176 formatters = [
177 177 QuotePattern,
178 178 SpoilerPattern,
179 179 ItalicPattern,
180 180 BoldPattern,
181 181 CommentPattern,
182 182 StrikeThroughPattern,
183 183 CodePattern,
184 184 ]
185 185
186 186
187 187 PREPARSE_PATTERNS = {
188 188 r'>>>(\d+)': r'[thread]\1[/thread]', # Multi-thread post ">>>123"
189 189 r'(?<!>)>>(\d+)': r'[post]\1[/post]', # Reflink ">>123"
190 190 r'^>([^>].+)': r'[quote]\1[/quote]', # Quote ">text"
191 191 r'^//(.+)': r'[comment]\1[/comment]', # Comment "//text"
192 192 r'\B@(\w+)': r'[user]\1[/user]', # User notification "@user"
193 193 }
194 194
195 195
196 196 class Parser:
197 197 def __init__(self):
198 198 # The newline hack is added because br's margin does not work in all
199 199 # browsers except firefox, when the div's does.
200 200 self.parser = bbcode.Parser(newline='<div class="br"></div>')
201 201
202 202 self.parser.add_formatter('post', render_reflink, strip=True)
203 203 self.parser.add_formatter('thread', render_multithread, strip=True)
204 204 self.parser.add_formatter('quote', render_quote, strip=True)
205 205 self.parser.add_formatter('user', render_notification, strip=True)
206 206 self.parser.add_simple_formatter(
207 207 'comment', '<span class="comment">//%(value)s</span>')
208 208 self.parser.add_simple_formatter(
209 209 'spoiler', '<span class="spoiler">%(value)s</span>')
210 210 self.parser.add_simple_formatter(
211 211 's', '<span class="strikethrough">%(value)s</span>')
212 212 # TODO Why not use built-in tag?
213 213 self.parser.add_simple_formatter('code',
214 214 '<pre><code>%(value)s</pre></code>',
215 215 render_embedded=False)
216 216
217 217 def preparse(self, text):
218 218 """
219 219 Performs manual parsing before the bbcode parser is used.
220 220 Preparsed text is saved as raw and the text before preparsing is lost.
221 221 """
222 222 new_text = MULTI_NEWLINES_PATTERN.sub(ONE_NEWLINE, text)
223 223
224 224 for key, value in PREPARSE_PATTERNS.items():
225 225 new_text = re.sub(key, value, new_text, flags=re.MULTILINE)
226 226
227 227 for link in REGEX_URL.findall(text):
228 228 new_text = new_text.replace(link, unquote(link))
229 229
230 230 return new_text
231 231
232 232 def parse(self, text):
233 return self.parser.format(text) No newline at end of file
233 return self.parser.format(text)
General Comments 0
You need to be logged in to leave comments. Login now