|
|
import re
|
|
|
|
|
|
from django.shortcuts import get_object_or_404
|
|
|
from django import template
|
|
|
from django.utils.text import re_tag
|
|
|
|
|
|
from boards.mdx_neboard import LINE_BREAK_HTML
|
|
|
|
|
|
|
|
|
IMG_ACTION_URL = '[<a href="{}">{}</a>]'
|
|
|
REGEX_NEWLINE = re.compile(LINE_BREAK_HTML)
|
|
|
TRUNCATOR = '...'
|
|
|
HTML4_SINGLETS =(
|
|
|
'br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input'
|
|
|
)
|
|
|
|
|
|
|
|
|
register = template.Library()
|
|
|
|
|
|
actions = [
|
|
|
{
|
|
|
'name': 'google',
|
|
|
'link': 'http://google.com/searchbyimage?image_url=%s',
|
|
|
},
|
|
|
{
|
|
|
'name': 'iqdb',
|
|
|
'link': 'http://iqdb.org/?url=%s',
|
|
|
},
|
|
|
]
|
|
|
|
|
|
|
|
|
@register.simple_tag(name='post_url')
|
|
|
def post_url(*args, **kwargs):
|
|
|
post_id = args[0]
|
|
|
|
|
|
post = get_object_or_404('Post', id=post_id)
|
|
|
|
|
|
return post.get_absolute_url()
|
|
|
|
|
|
|
|
|
@register.simple_tag(name='image_actions')
|
|
|
def image_actions(*args, **kwargs):
|
|
|
image_link = args[0]
|
|
|
if len(args) > 1:
|
|
|
image_link = 'http://' + args[1] + image_link # TODO https?
|
|
|
|
|
|
return ', '.join([IMG_ACTION_URL.format(
|
|
|
action['link'] % image_link, action['name']) for action in actions])
|
|
|
|
|
|
|
|
|
@register.inclusion_tag('boards/post.html', name='post_view', takes_context=True)
|
|
|
def post_view(context, post, *args, **kwargs):
|
|
|
kwargs['perms'] = context['perms']
|
|
|
return post.get_view_params(*args, **kwargs)
|
|
|
|
|
|
|
|
|
@register.simple_tag(name='page_url')
|
|
|
def page_url(paginator, page_number, *args, **kwargs):
|
|
|
if paginator.supports_urls():
|
|
|
return paginator.get_page_url(page_number)
|
|
|
|
|
|
|
|
|
@register.filter(name='truncatenewlines_html')
|
|
|
def truncatenewlines_html(value, arg):
|
|
|
end_pos = 0
|
|
|
start_pos = 0
|
|
|
match_count = 0
|
|
|
|
|
|
# Collect places for truncation
|
|
|
while match_count <= arg:
|
|
|
m = REGEX_NEWLINE.search(value, end_pos)
|
|
|
if m is None:
|
|
|
break
|
|
|
else:
|
|
|
match_count += 1
|
|
|
end_pos = m.end()
|
|
|
start_pos = m.start()
|
|
|
|
|
|
# Find and close open tags
|
|
|
if match_count > arg:
|
|
|
truncate_pos = start_pos
|
|
|
|
|
|
open_tags = []
|
|
|
text = value[:truncate_pos]
|
|
|
current_pos = 0
|
|
|
while True:
|
|
|
tag = re_tag.search(text, current_pos)
|
|
|
if tag is None:
|
|
|
break
|
|
|
else:
|
|
|
closing_tag, tagname, self_closing = tag.groups()
|
|
|
tagname = tagname.lower()
|
|
|
if self_closing or tagname in HTML4_SINGLETS:
|
|
|
pass
|
|
|
elif closing_tag:
|
|
|
# Check for match in open tags list
|
|
|
try:
|
|
|
i = open_tags.index(tagname)
|
|
|
except ValueError:
|
|
|
pass
|
|
|
else:
|
|
|
# SGML: An end tag closes, back to the matching start tag,
|
|
|
# all unclosed intervening start tags with omitted end tags
|
|
|
open_tags = open_tags[i + 1:]
|
|
|
else:
|
|
|
# Add it to the start of the open tags list
|
|
|
open_tags.insert(0, tagname)
|
|
|
|
|
|
current_pos = tag.end()
|
|
|
|
|
|
if not text.endswith(TRUNCATOR):
|
|
|
text += TRUNCATOR
|
|
|
for tag in open_tags:
|
|
|
text += '</{}>'.format(tag)
|
|
|
else:
|
|
|
text = value
|
|
|
|
|
|
return text
|
|
|
|
|
|
|