mdx_neboard.py
202 lines
| 4.9 KiB
| text/x-python
|
PythonLexer
/ boards / mdx_neboard.py
|
r699 | # coding=utf-8 | ||
|
r736 | import re | ||
import bbcode | ||||
|
r721 | |||
|
r98 | import boards | ||
|
r52 | |||
|
r721 | |||
|
r89 | __author__ = 'neko259' | ||
|
r52 | |||
|
r799 | REFLINK_PATTERN = re.compile(r'^\d+$') | ||
|
r841 | GLOBAL_REFLINK_PATTERN = re.compile(r'^(\w+)::([^:]+)::(\d+)$') | ||
|
r754 | MULTI_NEWLINES_PATTERN = re.compile(r'(\r?\n){2,}') | ||
ONE_NEWLINE = '\n' | ||||
|
r302 | |||
|
r398 | |||
|
r438 | class TextFormatter(): | ||
""" | ||||
An interface for formatter that can be used in the text format panel | ||||
""" | ||||
|
r721 | def __init__(self): | ||
pass | ||||
|
r438 | name = '' | ||
# Left and right tags for the button preview | ||||
preview_left = '' | ||||
preview_right = '' | ||||
# Left and right characters for the textarea input | ||||
format_left = '' | ||||
format_right = '' | ||||
|
r736 | class AutolinkPattern(): | ||
|
r52 | def handleMatch(self, m): | ||
link_element = etree.Element('a') | ||||
href = m.group(2) | ||||
link_element.set('href', href) | ||||
link_element.text = href | ||||
return link_element | ||||
|
r736 | class QuotePattern(TextFormatter): | ||
name = 'q' | ||||
preview_left = '<span class="multiquote">' | ||||
|
r438 | preview_right = '</span>' | ||
|
r736 | format_left = '[quote]' | ||
format_right = '[/quote]' | ||||
|
r52 | |||
|
r736 | class SpoilerPattern(TextFormatter): | ||
name = 'spoiler' | ||||
|
r438 | preview_left = '<span class="spoiler">' | ||
preview_right = '</span>' | ||||
|
r736 | format_left = '[spoiler]' | ||
format_right = '[/spoiler]' | ||||
|
r438 | |||
|
r56 | def handleMatch(self, m): | ||
quote_element = etree.Element('span') | ||||
quote_element.set('class', 'spoiler') | ||||
quote_element.text = m.group(2) | ||||
return quote_element | ||||
|
r736 | class CommentPattern(TextFormatter): | ||
|
r438 | name = '' | ||
preview_left = '<span class="comment">// ' | ||||
preview_right = '</span>' | ||||
|
r736 | format_left = '[comment]' | ||
format_right = '[/comment]' | ||||
|
r56 | |||
|
r755 | # TODO Use <s> tag here | ||
|
r736 | class StrikeThroughPattern(TextFormatter): | ||
|
r438 | name = 's' | ||
preview_left = '<span class="strikethrough">' | ||||
preview_right = '</span>' | ||||
|
r736 | format_left = '[s]' | ||
format_right = '[/s]' | ||||
|
r330 | |||
|
r438 | class ItalicPattern(TextFormatter): | ||
name = 'i' | ||||
preview_left = '<i>' | ||||
preview_right = '</i>' | ||||
|
r736 | format_left = '[i]' | ||
format_right = '[/i]' | ||||
|
r438 | |||
class BoldPattern(TextFormatter): | ||||
name = 'b' | ||||
preview_left = '<b>' | ||||
preview_right = '</b>' | ||||
|
r736 | format_left = '[b]' | ||
format_right = '[/b]' | ||||
|
r438 | |||
|
r440 | class CodePattern(TextFormatter): | ||
name = 'code' | ||||
preview_left = '<code>' | ||||
preview_right = '</code>' | ||||
|
r736 | format_left = '[code]' | ||
format_right = '[/code]' | ||||
|
r699 | |||
|
r736 | def render_reflink(tag_name, value, options, parent, context): | ||
|
r841 | post_id = None | ||
|
r100 | |||
|
r841 | matches = REFLINK_PATTERN.findall(value) | ||
if matches: | ||||
post_id = int(matches[0][0]) | ||||
else: | ||||
match = GLOBAL_REFLINK_PATTERN.match(value) | ||||
if match: | ||||
key_type = match.group(1) | ||||
key = match.group(2) | ||||
local_id = match.group(3) | ||||
try: | ||||
global_id = boards.models.GlobalId.objects.get(key_type=key_type, | ||||
key=key, local_id=local_id) | ||||
for post in boards.models.Post.objects.filter(global_id=global_id).only('id'): | ||||
post_id = post.id | ||||
except boards.models.GlobalId.DoesNotExist: | ||||
pass | ||||
if not post_id: | ||||
return value | ||||
|
r100 | |||
|
r736 | posts = boards.models.Post.objects.filter(id=post_id) | ||
if posts.exists(): | ||||
post = posts[0] | ||||
|
r52 | |||
|
r831 | return '<a href="%s">>>%s</a>' % (post.get_url(), post_id) | ||
|
r736 | else: | ||
|
r831 | return '>>%s' % value | ||
|
r90 | |||
|
r52 | |||
|
r755 | def render_quote(tag_name, value, options, parent, context): | ||
|
r831 | source = '' | ||
|
r755 | if 'source' in options: | ||
source = options['source'] | ||||
|
r831 | result = '' | ||
|
r755 | if source: | ||
|
r831 | result = '<div class="multiquote"><div class="quote-header">%s</div><div class="quote-text">%s</div></div>' % (source, value) | ||
|
r755 | else: | ||
|
r831 | result = '<div class="multiquote"><div class="quote-text">%s</div></div>' % value | ||
|
r755 | |||
return result | ||||
|
r754 | def preparse_text(text): | ||
""" | ||||
Performs manual parsing before the bbcode parser is used. | ||||
""" | ||||
return MULTI_NEWLINES_PATTERN.sub(ONE_NEWLINE, text) | ||||
|
r736 | def bbcode_extended(markup): | ||
|
r831 | # The newline hack is added because br's margin does not work in all | ||
# browsers except firefox, when the div's does. | ||||
parser = bbcode.Parser(newline='<div class="br"></div>') | ||||
|
r736 | parser.add_formatter('post', render_reflink, strip=True) | ||
|
r755 | parser.add_formatter('quote', render_quote, strip=True) | ||
|
r736 | parser.add_simple_formatter('comment', | ||
|
r881 | '<span class="comment">//%(value)s</span>') | ||
|
r736 | parser.add_simple_formatter('spoiler', | ||
|
r881 | '<span class="spoiler">%(value)s</span>') | ||
|
r815 | # TODO Use <s> here | ||
|
r736 | parser.add_simple_formatter('s', | ||
|
r881 | '<span class="strikethrough">%(value)s</span>') | ||
|
r815 | # TODO Why not use built-in tag? | ||
|
r736 | parser.add_simple_formatter('code', | ||
|
r881 | '<pre><code>%(value)s</pre></code>', | ||
render_embedded=False) | ||||
|
r754 | |||
text = preparse_text(markup) | ||||
return parser.format(text) | ||||
|
r438 | |||
formatters = [ | ||||
QuotePattern, | ||||
SpoilerPattern, | ||||
ItalicPattern, | ||||
BoldPattern, | ||||
CommentPattern, | ||||
StrikeThroughPattern, | ||||
|
r440 | CodePattern, | ||
|
r438 | ] | ||