9 from django import template
10 from django.utils.encoding import smart_unicode
11 from django.utils.safestring import mark_safe
12 from forum.models import Question, Answer, QuestionRevision, AnswerRevision, NodeRevision
13 from django.utils.translation import ugettext as _
14 from django.utils.translation import ungettext
15 from django.utils import simplejson
16 from forum import settings
17 from django.template.defaulttags import url as default_url
18 from forum import skins
19 from forum.utils import html
20 from extra_filters import decorated_int
21 from django.core.urlresolvers import reverse
23 register = template.Library()
25 GRAVATAR_TEMPLATE = ('<img class="gravatar" width="%(size)s" height="%(size)s" '
26 'src="http://www.gravatar.com/avatar/%(gravatar_hash)s'
27 '?s=%(size)s&d=%(default)s&r=%(rating)s" '
28 'alt="%(username)s\'s gravatar image" />')
31 def gravatar(user, size):
33 gravatar = user['gravatar']
34 username = user['username']
35 except (TypeError, AttributeError, KeyError):
36 gravatar = user.gravatar
37 username = user.username
38 return mark_safe(GRAVATAR_TEMPLATE % {
40 'gravatar_hash': gravatar,
41 'default': settings.GRAVATAR_DEFAULT_IMAGE,
42 'rating': settings.GRAVATAR_ALLOWED_RATING,
43 'username': template.defaultfilters.urlencode(username),
48 def get_score_badge(user):
49 if user.is_suspended():
50 return _("(suspended)")
52 repstr = decorated_int(user.reputation, "")
54 BADGE_TEMPLATE = '<span class="score" title="%(reputation)s %(reputationword)s">%(repstr)s</span>'
56 BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(gold)s %(badgesword)s">'
57 '<span class="badge1">●</span>'
58 '<span class="badgecount">%(gold)s</span>'
61 BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(silver)s %(badgesword)s">'
62 '<span class="silver">●</span>'
63 '<span class="badgecount">%(silver)s</span>'
66 BADGE_TEMPLATE = '%s%s' % (BADGE_TEMPLATE, '<span title="%(bronze)s %(badgesword)s">'
67 '<span class="bronze">●</span>'
68 '<span class="badgecount">%(bronze)s</span>'
70 BADGE_TEMPLATE = smart_unicode(BADGE_TEMPLATE, encoding='utf-8', strings_only=False, errors='strict')
71 return mark_safe(BADGE_TEMPLATE % {
72 'reputation' : user.reputation,
75 'silver' : user.silver,
76 'bronze' : user.bronze,
77 'badgesword' : _('badges'),
78 'reputationword' : _('reputation points'),
83 def get_age(birthday):
84 current_time = datetime.datetime(*time.localtime()[0:6])
86 month = birthday.month
88 diff = current_time - datetime.datetime(year, month, day, 0, 0, 0)
89 return diff.days / 365
92 def diff_date(date, limen=2):
96 now = datetime.datetime.now()
99 hours = int(diff.seconds/3600)
100 minutes = int(diff.seconds/60)
103 if date.year == now.year:
104 return date.strftime(_("%b %d at %H:%M").encode())
106 return date.strftime(_("%b %d '%y at %H:%M").encode())
108 return _('2 days ago')
110 return _('yesterday')
112 return ungettext('%(hr)d ' + _("hour ago"), '%(hr)d ' + _("hours ago"), hours) % {'hr':hours}
113 elif diff.seconds >= 60:
114 return ungettext('%(min)d ' + _("min ago"), '%(min)d ' + _("mins ago"), minutes) % {'min':minutes}
116 return ungettext('%(sec)d ' + _("sec ago"), '%(sec)d ' + _("secs ago"), diff.seconds) % {'sec':diff.seconds}
120 url = skins.find_media_source(url)
122 # Create the URL prefix.
123 url_prefix = settings.FORCE_SCRIPT_NAME + '/m/'
125 # Make sure any duplicate forward slashes are replaced with a single
127 url_prefix = re.sub("/+", "/", url_prefix)
129 url = url_prefix + url
132 class ItemSeparatorNode(template.Node):
133 def __init__(self, separator):
134 sep = separator.strip()
135 if sep[0] == sep[-1] and sep[0] in ('\'', '"'):
138 raise template.TemplateSyntaxError('separator in joinitems tag must be quoted')
141 def render(self, context):
144 class BlockMediaUrlNode(template.Node):
145 def __init__(self, nodelist):
146 self.items = nodelist
148 def render(self, context):
149 prefix = settings.APP_URL + 'm/'
153 for item in self.items:
154 url += item.render(context)
156 url = skins.find_media_source(url)
159 return out.replace(' ', '')
161 @register.tag(name='blockmedia')
162 def blockmedia(parser, token):
164 tagname = token.split_contents()
166 raise template.TemplateSyntaxError("blockmedia tag does not use arguments")
169 nodelist.append(parser.parse(('endblockmedia')))
170 next = parser.next_token()
171 if next.contents == 'endblockmedia':
173 return BlockMediaUrlNode(nodelist)
178 domain = settings.APP_BASE_URL
179 #protocol = getattr(settings, "PROTOCOL", "http")
181 return "%s%s" % (domain, path)
184 class SimpleVarNode(template.Node):
185 def __init__(self, name, value):
187 self.value = template.Variable(value)
189 def render(self, context):
190 context[self.name] = self.value.resolve(context)
193 class BlockVarNode(template.Node):
194 def __init__(self, name, block):
198 def render(self, context):
199 source = self.block.render(context)
200 context[self.name] = source.strip()
204 @register.tag(name='var')
205 def do_var(parser, token):
206 tokens = token.split_contents()[1:]
208 if not len(tokens) or not re.match('^\w+$', tokens[0]):
209 raise template.TemplateSyntaxError("Expected variable name")
212 nodelist = parser.parse(('endvar',))
213 parser.delete_first_token()
214 return BlockVarNode(tokens[0], nodelist)
215 elif len(tokens) == 3:
216 return SimpleVarNode(tokens[0], tokens[2])
218 raise template.TemplateSyntaxError("Invalid number of arguments")
220 class DeclareNode(template.Node):
221 dec_re = re.compile('^\s*(\w+)\s*(:?=)\s*(.*)$')
223 def __init__(self, block):
226 def render(self, context):
227 source = self.block.render(context)
229 for line in source.splitlines():
230 m = self.dec_re.search(line)
232 clist = list(context)
238 d['reverse'] = reverse
242 context[m.group(1).strip()] = eval(m.group(3).strip(), d)
244 logging.error("Error in declare tag, when evaluating: %s" % m.group(3).strip())
248 @register.tag(name='declare')
249 def do_declare(parser, token):
250 nodelist = parser.parse(('enddeclare',))
251 parser.delete_first_token()
252 return DeclareNode(nodelist)
254 # Usage: {% random 1 999 %}
255 # Generates random number in the template
256 class RandomNumberNode(template.Node):
257 # We get the limiting numbers
258 def __init__(self, int_from, int_to):
259 self.int_from = int(int_from)
260 self.int_to = int(int_to)
262 # We generate the random number using the standard python interface
263 def render(self, context):
264 return str(random.randint(self.int_from, self.int_to))
266 @register.tag(name="random")
267 def random_number(parser, token):
268 # Try to get the limiting numbers from the token
270 tag_name, int_from, int_to = token.split_contents()
272 # If we had no success -- raise an exception
273 raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
275 # Call the random Node
276 return RandomNumberNode(int_from, int_to)