# coding=utf-8 import re import bbcode from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse import boards __author__ = 'neko259' REFLINK_PATTERN = re.compile(r'^\d+$') MULTI_NEWLINES_PATTERN = re.compile(r'(\r?\n){2,}') ONE_NEWLINE = '\n' class TextFormatter(): """ An interface for formatter that can be used in the text format panel """ def __init__(self): pass 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 = '' class AutolinkPattern(): 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 class QuotePattern(TextFormatter): name = 'q' preview_left = '' preview_right = '' format_left = '[quote]' format_right = '[/quote]' class SpoilerPattern(TextFormatter): name = 'spoiler' preview_left = '' preview_right = '' format_left = '[spoiler]' format_right = '[/spoiler]' def handleMatch(self, m): quote_element = etree.Element('span') quote_element.set('class', 'spoiler') quote_element.text = m.group(2) return quote_element class CommentPattern(TextFormatter): name = '' preview_left = '// ' preview_right = '' format_left = '[comment]' format_right = '[/comment]' # TODO Use tag here class StrikeThroughPattern(TextFormatter): name = 's' preview_left = '' preview_right = '' format_left = '[s]' format_right = '[/s]' class ItalicPattern(TextFormatter): name = 'i' preview_left = '' preview_right = '' format_left = '[i]' format_right = '[/i]' class BoldPattern(TextFormatter): name = 'b' preview_left = '' preview_right = '' format_left = '[b]' format_right = '[/b]' class CodePattern(TextFormatter): name = 'code' preview_left = '' preview_right = '' format_left = '[code]' format_right = '[/code]' def render_reflink(tag_name, value, options, parent, context): result = '>>%s' % value if REFLINK_PATTERN.match(value): post_id = int(value) try: post = boards.models.Post.objects.get(id=post_id) result = '>>%s' % (post.get_url(), post_id) except ObjectDoesNotExist: pass return result def render_multithread(tag_name, value, options, parent, context): result = '>>>%s' % value if REFLINK_PATTERN.match(value): post_id = int(value) try: post = boards.models.Post.objects.get(id=post_id) if post.is_opening(): result = '>>>%s' % (post.get_url(), post_id) except ObjectDoesNotExist: pass return result def render_quote(tag_name, value, options, parent, context): source = '' if 'source' in options: source = options['source'] if source: result = '
%s
%s
' % (source, value) else: result = '
%s
' % value return result def render_notification(tag_name, value, options, parent, content): username = value.lower() return '@{}'.format( reverse('notifications', kwargs={'username': username}), username) def preparse_text(text): """ Performs manual parsing before the bbcode parser is used. """ return MULTI_NEWLINES_PATTERN.sub(ONE_NEWLINE, text) def bbcode_extended(markup): # 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='
') parser.add_formatter('post', render_reflink, strip=True) parser.add_formatter('thread', render_multithread, strip=True) parser.add_formatter('quote', render_quote, strip=True) parser.add_formatter('user', render_notification, strip=True) parser.add_simple_formatter('comment', '//%(value)s') parser.add_simple_formatter('spoiler', '%(value)s') parser.add_simple_formatter('s', '%(value)s') # TODO Why not use built-in tag? parser.add_simple_formatter('code', '
%(value)s
', render_embedded=False) text = preparse_text(markup) return parser.format(text) formatters = [ QuotePattern, SpoilerPattern, ItalicPattern, BoldPattern, CommentPattern, StrikeThroughPattern, CodePattern, ]