| 1107 | |
| 1108 | |
| 1109 | class SwitchNode(Node): |
| 1110 | def __init__(self, var1, nodelist_true, nodelist_false): |
| 1111 | self.comparison_base = Variable(var1) |
| 1112 | self.nodelist_true = nodelist_true |
| 1113 | self.nodelist_false = nodelist_false |
| 1114 | self.varname = var1 |
| 1115 | |
| 1116 | def __repr__(self): |
| 1117 | return "<SwitchNode>" |
| 1118 | |
| 1119 | def render(self, context): |
| 1120 | try: |
| 1121 | val1 = self.comparison_base.resolve(context) |
| 1122 | bhash = "__%s__" % md5.new(self.varname).hexdigest() |
| 1123 | context[bhash] = val1 |
| 1124 | except VariableDoesNotExist: |
| 1125 | return NodeList().render(context) |
| 1126 | |
| 1127 | ok = False |
| 1128 | for node in self.nodelist_true: |
| 1129 | if isinstance(node, CaseNode): |
| 1130 | node.set_source(bhash) |
| 1131 | if node.get_bool(context): |
| 1132 | ok = True |
| 1133 | if ok: |
| 1134 | return self.nodelist_true.render(context) |
| 1135 | else: |
| 1136 | return self.nodelist_false.render(context) |
| 1137 | |
| 1138 | def do_switch(parser, token): |
| 1139 | """ |
| 1140 | Create a context to use case-like coditional |
| 1141 | template rendering. |
| 1142 | |
| 1143 | For example:: |
| 1144 | |
| 1145 | {% switch person.name %} |
| 1146 | {% case 'John Doe' %} |
| 1147 | Hi! My name is John, the master! |
| 1148 | {% endcase %} |
| 1149 | {% case 'Mary Jane' %} |
| 1150 | Hello! My name is Mary. Nice to meet you! |
| 1151 | {% endcase %} |
| 1152 | {% default %} |
| 1153 | Oh my God! I have no name! |
| 1154 | {% endswitch %} |
| 1155 | """ |
| 1156 | |
| 1157 | bits = list(token.split_contents()) |
| 1158 | if len(bits) != 2: |
| 1159 | raise TemplateSyntaxError, "%r takes one argument" % bits[0] |
| 1160 | end_tag = 'end' + bits[0] |
| 1161 | nodelist_true = parser.parse(('default', end_tag,)) |
| 1162 | token = parser.next_token() |
| 1163 | if token.contents == 'default': |
| 1164 | nodelist_false = parser.parse((end_tag,)) |
| 1165 | parser.delete_first_token() |
| 1166 | else: |
| 1167 | nodelist_false = NodeList() |
| 1168 | return SwitchNode(bits[1], nodelist_true, nodelist_false) |
| 1169 | do_switch = register.tag('switch', do_switch) |
| 1170 | |
| 1171 | class CaseNode(Node): |
| 1172 | def __init__(self, var, nodelist): |
| 1173 | self.var = Variable(var) |
| 1174 | self.nodelist = nodelist |
| 1175 | |
| 1176 | def __repr__(self): |
| 1177 | return "<CaseNode>" |
| 1178 | |
| 1179 | def set_source(self, var): |
| 1180 | """ Sets the varname to lookup in |
| 1181 | context and make the comparisons""" |
| 1182 | self.base_comparison = var |
| 1183 | |
| 1184 | def get_bool(self, context): |
| 1185 | try: |
| 1186 | val = self.var.resolve(context) |
| 1187 | except VariableDoesNotExist: |
| 1188 | val = None |
| 1189 | |
| 1190 | base_comparison = getattr(self, "base_comparison", None) |
| 1191 | if not base_comparison: |
| 1192 | raise LookupError("Could not find base_comparison. " |
| 1193 | "Ensure to use {% case %} node " |
| 1194 | "within a {% switch %} node") |
| 1195 | if context.get(self.base_comparison, None) == val: |
| 1196 | return True |
| 1197 | else: |
| 1198 | return False |
| 1199 | |
| 1200 | def render(self, context): |
| 1201 | if self.get_bool(context): |
| 1202 | return self.nodelist.render(context) |
| 1203 | else: |
| 1204 | return NodeList().render(context) |
| 1205 | |
| 1206 | @register.tag |
| 1207 | def do_case(parser, token): |
| 1208 | bits = list(token.split_contents()) |
| 1209 | if len(bits) != 2: |
| 1210 | raise TemplateSyntaxError, "%r takes one argument" % bits[0] |
| 1211 | end_tag = 'end' + bits[0] |
| 1212 | nodelist = parser.parse((end_tag,)) |
| 1213 | parser.delete_first_token() |
| 1214 | return CaseNode(bits[1], nodelist) |
| 1215 | |
| 1216 | do_case = register.tag('case', do_case) |