Show More
@@ -1,8 +1,7 b'' | |||||
1 | # coding=utf-8 |
|
1 | # coding=utf-8 | |
2 |
|
2 | |||
3 |
import |
|
3 | import re | |
4 | from markdown.inlinepatterns import Pattern |
|
4 | import bbcode | |
5 | from markdown.util import etree |
|
|||
6 |
|
5 | |||
7 | import boards |
|
6 | import boards | |
8 |
|
7 | |||
@@ -10,13 +9,7 b' import boards' | |||||
10 | __author__ = 'neko259' |
|
9 | __author__ = 'neko259' | |
11 |
|
10 | |||
12 |
|
11 | |||
13 | AUTOLINK_PATTERN = r'(https?://\S+)' |
|
12 | REFLINK_PATTERN = re.compile(r'\d+') | |
14 | QUOTE_PATTERN = r'^(?<!>)(>[^>].*)$' |
|
|||
15 | REFLINK_PATTERN = r'((>>)(\d+))' |
|
|||
16 | SPOILER_PATTERN = r'%%([^(%%)]+)%%' |
|
|||
17 | COMMENT_PATTERN = r'^(//(.+))' |
|
|||
18 | STRIKETHROUGH_PATTERN = r'~(.+)~' |
|
|||
19 | DASH_PATTERN = r'--' |
|
|||
20 |
|
13 | |||
21 |
|
14 | |||
22 | class TextFormatter(): |
|
15 | class TextFormatter(): | |
@@ -38,7 +31,7 b' class TextFormatter():' | |||||
38 | format_right = '' |
|
31 | format_right = '' | |
39 |
|
32 | |||
40 |
|
33 | |||
41 |
class AutolinkPattern( |
|
34 | class AutolinkPattern(): | |
42 | def handleMatch(self, m): |
|
35 | def handleMatch(self, m): | |
43 | link_element = etree.Element('a') |
|
36 | link_element = etree.Element('a') | |
44 | href = m.group(2) |
|
37 | href = m.group(2) | |
@@ -48,44 +41,22 b' class AutolinkPattern(Pattern):' | |||||
48 | return link_element |
|
41 | return link_element | |
49 |
|
42 | |||
50 |
|
43 | |||
51 |
class QuotePattern( |
|
44 | class QuotePattern(TextFormatter): | |
52 | name = '' |
|
45 | name = 'q' | |
53 |
preview_left = '<span class="quote"> |
|
46 | preview_left = '<span class="multiquote">' | |
54 | preview_right = '</span>' |
|
47 | preview_right = '</span>' | |
55 |
|
48 | |||
56 |
format_left = ' |
|
49 | format_left = '[quote]' | |
57 |
|
50 | format_right = '[/quote]' | ||
58 | def handleMatch(self, m): |
|
|||
59 | quote_element = etree.Element('span') |
|
|||
60 | quote_element.set('class', 'quote') |
|
|||
61 | quote_element.text = m.group(2) |
|
|||
62 |
|
||||
63 | return quote_element |
|
|||
64 |
|
51 | |||
65 |
|
52 | |||
66 |
class |
|
53 | class SpoilerPattern(TextFormatter): | |
67 | def handleMatch(self, m): |
|
54 | name = 'spoiler' | |
68 | post_id = m.group(4) |
|
|||
69 |
|
||||
70 | posts = boards.models.Post.objects.filter(id=post_id) |
|
|||
71 | if posts.count() > 0: |
|
|||
72 | ref_element = etree.Element('a') |
|
|||
73 |
|
||||
74 | post = posts[0] |
|
|||
75 |
|
||||
76 | ref_element.set('href', post.get_url()) |
|
|||
77 | ref_element.text = m.group(2) |
|
|||
78 |
|
||||
79 | return ref_element |
|
|||
80 |
|
||||
81 |
|
||||
82 | class SpoilerPattern(Pattern, TextFormatter): |
|
|||
83 | name = 's' |
|
|||
84 | preview_left = '<span class="spoiler">' |
|
55 | preview_left = '<span class="spoiler">' | |
85 | preview_right = '</span>' |
|
56 | preview_right = '</span>' | |
86 |
|
57 | |||
87 |
format_left = ' |
|
58 | format_left = '[spoiler]' | |
88 |
format_right = ' |
|
59 | format_right = '[/spoiler]' | |
89 |
|
60 | |||
90 | def handleMatch(self, m): |
|
61 | def handleMatch(self, m): | |
91 | quote_element = etree.Element('span') |
|
62 | quote_element = etree.Element('span') | |
@@ -95,35 +66,22 b' class SpoilerPattern(Pattern, TextFormat' | |||||
95 | return quote_element |
|
66 | return quote_element | |
96 |
|
67 | |||
97 |
|
68 | |||
98 |
class CommentPattern( |
|
69 | class CommentPattern(TextFormatter): | |
99 | name = '' |
|
70 | name = '' | |
100 | preview_left = '<span class="comment">// ' |
|
71 | preview_left = '<span class="comment">// ' | |
101 | preview_right = '</span>' |
|
72 | preview_right = '</span>' | |
102 |
|
73 | |||
103 |
format_left = ' |
|
74 | format_left = '[comment]' | |
104 |
|
75 | format_right = '[/comment]' | ||
105 | def handleMatch(self, m): |
|
|||
106 | quote_element = etree.Element('span') |
|
|||
107 | quote_element.set('class', 'comment') |
|
|||
108 | quote_element.text = '//' + m.group(3) |
|
|||
109 |
|
||||
110 | return quote_element |
|
|||
111 |
|
76 | |||
112 |
|
77 | |||
113 |
class StrikeThroughPattern( |
|
78 | class StrikeThroughPattern(TextFormatter): | |
114 | name = 's' |
|
79 | name = 's' | |
115 | preview_left = '<span class="strikethrough">' |
|
80 | preview_left = '<span class="strikethrough">' | |
116 | preview_right = '</span>' |
|
81 | preview_right = '</span>' | |
117 |
|
82 | |||
118 |
format_left = ' |
|
83 | format_left = '[s]' | |
119 |
format_right = ' |
|
84 | format_right = '[/s]' | |
120 |
|
||||
121 | def handleMatch(self, m): |
|
|||
122 | quote_element = etree.Element('span') |
|
|||
123 | quote_element.set('class', 'strikethrough') |
|
|||
124 | quote_element.text = m.group(2) |
|
|||
125 |
|
||||
126 | return quote_element |
|
|||
127 |
|
85 | |||
128 |
|
86 | |||
129 | class ItalicPattern(TextFormatter): |
|
87 | class ItalicPattern(TextFormatter): | |
@@ -131,8 +89,8 b' class ItalicPattern(TextFormatter):' | |||||
131 | preview_left = '<i>' |
|
89 | preview_left = '<i>' | |
132 | preview_right = '</i>' |
|
90 | preview_right = '</i>' | |
133 |
|
91 | |||
134 |
format_left = ' |
|
92 | format_left = '[i]' | |
135 |
format_right = ' |
|
93 | format_right = '[/i]' | |
136 |
|
94 | |||
137 |
|
95 | |||
138 | class BoldPattern(TextFormatter): |
|
96 | class BoldPattern(TextFormatter): | |
@@ -140,8 +98,8 b' class BoldPattern(TextFormatter):' | |||||
140 | preview_left = '<b>' |
|
98 | preview_left = '<b>' | |
141 | preview_right = '</b>' |
|
99 | preview_right = '</b>' | |
142 |
|
100 | |||
143 |
format_left = ' |
|
101 | format_left = '[b]' | |
144 |
format_right = ' |
|
102 | format_right = '[/b]' | |
145 |
|
103 | |||
146 |
|
104 | |||
147 | class CodePattern(TextFormatter): |
|
105 | class CodePattern(TextFormatter): | |
@@ -149,52 +107,39 b' class CodePattern(TextFormatter):' | |||||
149 | preview_left = '<code>' |
|
107 | preview_left = '<code>' | |
150 | preview_right = '</code>' |
|
108 | preview_right = '</code>' | |
151 |
|
109 | |||
152 |
format_left = ' |
|
110 | format_left = '[code]' | |
153 |
|
111 | format_right = '[/code]' | ||
154 |
|
||||
155 | class DashPattern(Pattern): |
|
|||
156 | def handleMatch(self, m): |
|
|||
157 | return u'—' |
|
|||
158 |
|
112 | |||
159 |
|
113 | |||
160 | class NeboardMarkdown(markdown.Extension): |
|
114 | def render_reflink(tag_name, value, options, parent, context): | |
161 | def extendMarkdown(self, md, md_globals): |
|
115 | if not REFLINK_PATTERN.match(value): | |
162 | self._add_neboard_patterns(md) |
|
116 | return u'>>%s' % value | |
163 | self._delete_patterns(md) |
|
|||
164 |
|
117 | |||
165 | def _delete_patterns(self, md): |
|
118 | post_id = int(value) | |
166 | del md.parser.blockprocessors['quote'] |
|
|||
167 |
|
||||
168 | del md.inlinePatterns['image_link'] |
|
|||
169 | del md.inlinePatterns['image_reference'] |
|
|||
170 |
|
119 | |||
171 | def _add_neboard_patterns(self, md): |
|
120 | posts = boards.models.Post.objects.filter(id=post_id) | |
172 | autolink = AutolinkPattern(AUTOLINK_PATTERN, md) |
|
121 | if posts.exists(): | |
173 | quote = QuotePattern(QUOTE_PATTERN, md) |
|
122 | post = posts[0] | |
174 | reflink = ReflinkPattern(REFLINK_PATTERN, md) |
|
|||
175 | spoiler = SpoilerPattern(SPOILER_PATTERN, md) |
|
|||
176 | comment = CommentPattern(COMMENT_PATTERN, md) |
|
|||
177 | strikethrough = StrikeThroughPattern(STRIKETHROUGH_PATTERN, md) |
|
|||
178 | dash = DashPattern(DASH_PATTERN, md) |
|
|||
179 |
|
123 | |||
180 | md.inlinePatterns[u'autolink_ext'] = autolink |
|
124 | return u'<a href=%s>>>%s</a>' % (post.get_url(), post_id) | |
181 | md.inlinePatterns[u'spoiler'] = spoiler |
|
125 | else: | |
182 | md.inlinePatterns[u'strikethrough'] = strikethrough |
|
126 | return u'>>%s' % value | |
183 | md.inlinePatterns[u'comment'] = comment |
|
|||
184 | md.inlinePatterns[u'reflink'] = reflink |
|
|||
185 | md.inlinePatterns[u'quote'] = quote |
|
|||
186 | md.inlinePatterns[u'dash'] = dash |
|
|||
187 |
|
127 | |||
188 |
|
128 | |||
189 | def make_extension(configs=None): |
|
129 | def bbcode_extended(markup): | |
190 | return NeboardMarkdown(configs=configs) |
|
130 | parser = bbcode.Parser() | |
191 |
|
131 | parser.add_formatter('post', render_reflink, strip=True) | ||
192 | neboard_extension = make_extension() |
|
132 | parser.add_simple_formatter('quote', | |
193 |
|
133 | u'<span class="multiquote">%(value)s</span>') | ||
194 |
|
134 | parser.add_simple_formatter('comment', | ||
195 | def markdown_extended(markup): |
|
135 | u'<span class="comment">//%(value)s</span>') | |
196 | return markdown.markdown(markup, [neboard_extension, 'nl2br'], |
|
136 | parser.add_simple_formatter('spoiler', | |
197 | safe_mode='escape') |
|
137 | u'<span class="spoiler">%(value)s</span>') | |
|
138 | parser.add_simple_formatter('s', | |||
|
139 | u'<span class="strikethrough">%(value)s</span>') | |||
|
140 | parser.add_simple_formatter('code', | |||
|
141 | u'<pre><code>%(value)s</pre></code>') | |||
|
142 | return parser.format(markup) | |||
198 |
|
143 | |||
199 | formatters = [ |
|
144 | formatters = [ | |
200 | QuotePattern, |
|
145 | QuotePattern, |
@@ -28,7 +28,7 b' IMAGE_THUMB_SIZE = (200, 150)' | |||||
28 |
|
28 | |||
29 | TITLE_MAX_LENGTH = 200 |
|
29 | TITLE_MAX_LENGTH = 200 | |
30 |
|
30 | |||
31 |
DEFAULT_MARKUP_TYPE = ' |
|
31 | DEFAULT_MARKUP_TYPE = 'bbcode' | |
32 |
|
32 | |||
33 | # TODO This should be removed |
|
33 | # TODO This should be removed | |
34 | NO_IP = '0.0.0.0' |
|
34 | NO_IP = '0.0.0.0' | |
@@ -346,4 +346,4 b' class Post(models.Model, Viewable):' | |||||
346 |
|
346 | |||
347 | self.images.all().delete() |
|
347 | self.images.all().delete() | |
348 |
|
348 | |||
349 | super(Post, self).delete(using) No newline at end of file |
|
349 | super(Post, self).delete(using) |
@@ -225,6 +225,14 b' blockquote {' | |||||
225 | font-style: italic; |
|
225 | font-style: italic; | |
226 | } |
|
226 | } | |
227 |
|
227 | |||
|
228 | .multiquote { | |||
|
229 | color: #92cf38; | |||
|
230 | font-style: italic; | |||
|
231 | border-left: solid 3px #00aa00; | |||
|
232 | padding-left: 3px; | |||
|
233 | display: inline-block; | |||
|
234 | } | |||
|
235 | ||||
228 | .spoiler { |
|
236 | .spoiler { | |
229 | background: white; |
|
237 | background: white; | |
230 | color: white; |
|
238 | color: white; |
@@ -35,10 +35,10 b' function moveCaretToEnd(el) {' | |||||
35 | } |
|
35 | } | |
36 |
|
36 | |||
37 | function addQuickReply(postId) { |
|
37 | function addQuickReply(postId) { | |
38 |
var textToAdd = ' |
|
38 | var textToAdd = '[post]' + postId + '[/post]\n\n'; | |
39 | var selection = window.getSelection().toString(); |
|
39 | var selection = window.getSelection().toString(); | |
40 | if (selection.length > 0) { |
|
40 | if (selection.length > 0) { | |
41 |
textToAdd += ' |
|
41 | textToAdd += '[quote]' + selection + '[/quote]\n\n'; | |
42 | } |
|
42 | } | |
43 |
|
43 | |||
44 | var textAreaId = 'textarea'; |
|
44 | var textAreaId = 'textarea'; |
@@ -8,13 +8,11 b'' | |||||
8 |
|
8 | |||
9 | {% block staticcontent %} |
|
9 | {% block staticcontent %} | |
10 | <h2>{% trans 'Syntax' %}</h2> |
|
10 | <h2>{% trans 'Syntax' %}</h2> | |
11 | <p>{% trans '2 line breaks for a new line.' %}</p> |
|
11 | <p>[i]<i>{% trans 'Italic text' %}</i>[/i]</p> | |
12 |
<p> |
|
12 | <p>[b]<b>{% trans 'Bold text' %}</b>[/b]</p> | |
13 | <p>__<b>{% trans 'Bold text' %}</b>__</p> |
|
13 | <p>[spoiler]<span class="spoiler">{% trans 'Spoiler' %}</span>[/spoiler]</p> | |
14 | <p>%%<span class="spoiler">{% trans 'Spoiler' %}</span>%%</p> |
|
14 | <p>[post]123[/post] -- {% trans 'Link to a post' %}</p> | |
15 | <p><a>>>123</a> -- {% trans 'Link to a post' %}</p> |
|
15 | <p>[s]<span class="strikethrough">{% trans 'Strikethrough text' %}</span>[/s]</p> | |
16 |
<p> |
|
16 | <p>[comment]<span class="comment">{% trans 'Comment' %}</span>[/comment]</p> | |
17 | <p>{% trans 'You need to new line before:' %}</p> |
|
17 | <p>[quote]<span class="multiquote">{% trans 'Quote' %}</span>[/quote]</p> | |
18 | <p><span class="comment">//{% trans 'Comment' %}</span></p> |
|
|||
19 | <p><span class="quote">> {% trans 'Quote' %}</span></p> |
|
|||
20 | {% endblock %} |
|
18 | {% endblock %} |
@@ -1,6 +1,6 b'' | |||||
1 | # Django settings for neboard project. |
|
1 | # Django settings for neboard project. | |
2 | import os |
|
2 | import os | |
3 |
from boards.mdx_neboard import |
|
3 | from boards.mdx_neboard import bbcode_extended | |
4 |
|
4 | |||
5 | DEBUG = True |
|
5 | DEBUG = True | |
6 | TEMPLATE_DEBUG = DEBUG |
|
6 | TEMPLATE_DEBUG = DEBUG | |
@@ -217,7 +217,7 b' HAYSTACK_CONNECTIONS = {' | |||||
217 | } |
|
217 | } | |
218 |
|
218 | |||
219 | MARKUP_FIELD_TYPES = ( |
|
219 | MARKUP_FIELD_TYPES = ( | |
220 |
(' |
|
220 | ('bbcode', bbcode_extended), | |
221 | ) |
|
221 | ) | |
222 |
|
222 | |||
223 | THEMES = [ |
|
223 | THEMES = [ |
General Comments 0
You need to be logged in to leave comments.
Login now