1# Copyright 2013-2016 The Distro Tracker Developers
2# See the COPYRIGHT file at the top-level directory of this distribution and
3# at https://deb.li/DTAuthors
4#
5# This file is part of Distro Tracker. It is subject to the license terms
6# in the LICENSE file found in the top-level directory of this
7# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
8# including this file, may be copied, modified, propagated, or distributed
9# except according to the terms contained in the LICENSE file.
10"""Additional distro-tracker specific template tags."""
12import re
14from django import template
15from django.template.loader import render_to_string
16from django.utils.html import conditional_escape
17from django.utils.safestring import mark_safe
19register = template.Library()
22class RepeatNode(template.Node):
23 """
24 A :class:`Node <django.template.base.Node>` for implementing the
25 :func:`repeat` template tag.
26 """
27 def __init__(self, nodelist, count):
28 self.nodelist = nodelist
29 self.count = template.Variable(count)
31 def render(self, context):
32 """
33 Renders the contents of the template tag :attr:`count` times.
34 """
35 output = self.nodelist.render(context)
36 return output * int(self.count.resolve(context))
39@register.tag
40def repeat(parser, token):
41 """
42 Repeats the string enclosed in the tag the number of times given in
43 the parameter of the tag.
44 """
45 try:
46 tag_name, count = token.split_contents()
47 except ValueError:
48 raise template.TemplateSyntaxError(
49 '{tag} tag requires an argument'.format(
50 tag=token.contents.split()[0]))
52 nodelist = parser.parse(('endrepeat',))
53 parser.delete_first_token()
54 return RepeatNode(nodelist, count)
57@register.simple_tag()
58def octicon(name, title='', content=None, role="img"):
59 """
60 Renders an octicon with alternate text.
61 """
62 if content is None:
63 content = mark_safe('<span class="sr-only">[{}]</span>'.format(title))
65 return mark_safe(render_to_string(
66 'core/octicon.html',
67 {'name': name, 'title': title, 'content': content, 'role': role}
68 ).rstrip())
71@register.simple_tag()
72def toggle_chevron(title='Toggle details'):
73 """
74 Renders a chevron to toggle details.
75 """
76 chevron = \
77 '<span role="button" aria-label="{}">{}</span>'.format(
78 title, octicon('chevron-down', title=title, content=''))
79 return mark_safe(chevron)
82@register.filter(name='zip')
83def zip_iterables(first, second):
84 """
85 A convenience template filter to :func:`zip` two sequences in the template.
87 Using this filter it is possible to iterate through the values of two
88 sequences in the same time in the template itself.
89 """
90 return zip(first, second)
93@register.filter()
94def lookup(dictionary, key):
95 """
96 A filter to retrieve values from dictionaries.
98 The lookup filter can access dictionary entries by their key, where the
99 key can be a variable and not only a literal value. It can be used
100 like this "dictionary|lookup:key" where both "dictionary" and "key"
101 are variables.
102 """
103 return dictionary.get(key, '')
106@register.filter()
107def breakable(content):
108 """
109 A filter that adds <wbr> (word breakpoints) to long words. Useful for
110 very long versions strings that would otherwise cause text overflows in
111 small cells. Returns an empty string when passed None.
112 """
113 if content is None:
114 return ''
116 if len(content) >= 10:
117 content = conditional_escape(content)
118 return mark_safe(re.sub(r'([-~+\.])', '\\1<wbr>', content))
120 return content