Uncrazy the caching, more.
[wolnelektury.git] / src / wolnelektury / templatetags / switch_tag.py
1 # -*- coding: utf-8 -*-
2 # Source: http://djangosnippets.org/snippets/967/
3 # Author: adurdin
4 # Posted: August 13, 2008
5 #
6 #
7 # We can use it based on djangosnippets Terms of Service:
8 # (http://djangosnippets.org/about/tos/)
9 #
10 # 2. That you grant any third party who sees the code you post
11 # a royalty-free, non-exclusive license to copy and distribute that code
12 # and to make and distribute derivative works based on that code. You may
13 # include license terms in snippets you post, if you wish to use
14 # a particular license (such as the BSD license or GNU GPL), but that
15 # license must permit royalty-free copying, distribution and modification
16 # of the code to which it is applied.
17
18 from django import template
19 from django.template import Library, Node, VariableDoesNotExist
20
21 register = Library()
22
23
24 @register.tag(name="switch")
25 def do_switch(parser, token):
26     """
27     The ``{% switch %}`` tag compares a variable against one or more values in
28     ``{% case %}`` tags, and outputs the contents of the matching block.  An
29     optional ``{% else %}`` tag sets off the default output if no matches
30     could be found::
31
32         {% switch result_count %}
33             {% case 0 %}
34                 There are no search results.
35             {% case 1 %}
36                 There is one search result.
37             {% else %}
38                 Jackpot! Your search found {{ result_count }} results.
39         {% endswitch %}
40
41     Each ``{% case %}`` tag can take multiple values to compare the variable
42     against::
43
44         {% switch username %}
45             {% case "Jim" "Bob" "Joe" %}
46                 Me old mate {{ username }}! How ya doin?
47             {% else %}
48                 Hello {{ username }}
49         {% endswitch %}
50     """
51     bits = token.contents.split()
52     tag_name = bits[0]
53     if len(bits) != 2:
54         raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name)
55     variable = parser.compile_filter(bits[1])
56
57     class BlockTagList(object):
58         # This is a bit of a hack, as it embeds knowledge of the behaviour
59         # of Parser.parse() relating to the "parse_until" argument.
60         def __init__(self, *names):
61             self.names = set(names)
62
63         def __contains__(self, token_contents):
64             name = token_contents.split()[0]
65             return name in self.names
66
67     # Skip over everything before the first {% case %} tag
68     parser.parse(BlockTagList('case', 'endswitch'))
69
70     cases = []
71     token = parser.next_token()
72     got_case = False
73     got_else = False
74     while token.contents != 'endswitch':
75         nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch'))
76
77         if got_else:
78             raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name)
79
80         contents = token.contents.split()
81         token_name, token_args = contents[0], contents[1:]
82
83         if token_name == 'case':
84             tests = map(parser.compile_filter, token_args)
85             case = (tests, nodelist)
86             got_case = True
87         else:
88             # The {% else %} tag
89             case = (None, nodelist)
90             got_else = True
91         cases.append(case)
92         token = parser.next_token()
93
94     if not got_case:
95         raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name)
96
97     return SwitchNode(variable, cases)
98
99
100 class SwitchNode(Node):
101     def __init__(self, variable, cases):
102         self.variable = variable
103         self.cases = cases
104
105     def __repr__(self):
106         return "<Switch node>"
107
108     def __iter__(self):
109         for tests, nodelist in self.cases:
110             for node in nodelist:
111                 yield node
112
113     def get_nodes_by_type(self, nodetype):
114         nodes = []
115         if isinstance(self, nodetype):
116             nodes.append(self)
117         for tests, nodelist in self.cases:
118             nodes.extend(nodelist.get_nodes_by_type(nodetype))
119         return nodes
120
121     def render(self, context):
122         try:
123             value_missing = False
124             value = self.variable.resolve(context, True)
125         except VariableDoesNotExist:
126             no_value = True
127             value_missing = None
128             value = None
129
130         for tests, nodelist in self.cases:
131             if tests is None:
132                 return nodelist.render(context)
133             elif not value_missing:
134                 for test in tests:
135                     test_value = test.resolve(context, True)
136                     if value == test_value:
137                         return nodelist.render(context)
138         else:
139             return ""