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.""" 

11 

12import re 

13 

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 

18 

19register = template.Library() 

20 

21 

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) 

30 

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)) 

37 

38 

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])) 

51 

52 nodelist = parser.parse(('endrepeat',)) 

53 parser.delete_first_token() 

54 return RepeatNode(nodelist, count) 

55 

56 

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)) 

64 

65 return mark_safe(render_to_string( 

66 'core/octicon.html', 

67 {'name': name, 'title': title, 'content': content, 'role': role} 

68 ).rstrip()) 

69 

70 

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) 

80 

81 

82@register.filter(name='zip') 

83def zip_iterables(first, second): 

84 """ 

85 A convenience template filter to :func:`zip` two sequences in the template. 

86 

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) 

91 

92 

93@register.filter() 

94def lookup(dictionary, key): 

95 """ 

96 A filter to retrieve values from dictionaries. 

97 

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, '') 

104 

105 

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 '' 

115 

116 if len(content) >= 10: 

117 content = conditional_escape(content) 

118 return mark_safe(re.sub(r'([-~+\.])', '\\1<wbr>', content)) 

119 

120 return content